Compare commits

..
2 Commits
Author SHA1 Message Date
zicla b983a115c2 Finish the oss uploading feature. 2021-08-27 20:09:33 +08:00
zicla 9d11fbe7ea Add the basic config for oss. 2021-08-27 15:54:18 +08:00
107 changed files with 1323 additions and 3151 deletions
+3 -31
View File
@@ -27,7 +27,7 @@ docker container prune
# 构建新版本 (最后的.不能少)
docker build -t eyeblue/tank:x.x.x .
# 本地测试
docker run --name dockermysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=tank -e MYSQL_USER=tank -e MYSQL_PASSWORD=tank123 -v ~/data/dockermysql:/var/lib/mysql -e TZ=Asia/Shanghai -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
docker run --name dockermysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=tank -e MYSQL_USER=tank -e MYSQL_PASSWORD=tank123 -v ~/data/dockermysql:/var/lib/mysql -d mysql:5.7
docker run --name tank -p 6010:6010 --link dockermysql:mysql -v ~/data/dockermatter:/data/build/matter -d eyeblue/tank:x.x.x
# 没问题后,推送到远程
docker push eyeblue/tank:x.x.x
@@ -47,36 +47,8 @@ c. 在github上发布新版本。
3.更新tank-doc 下载内容
## useful commands
go get xxx/xxx
go mod tidy
tank-3.1.5 2022-03-21
1. Support Sqlite.
2. Upgrade webpack.
1. 支持Sqlite
2. 升级了前端的webpack
tank-3.1.4 2022-03-20
1. Support Sqlite.
2. Upgrade webpack.
1. 支持Sqlite
2. 升级了前端的webpack
tank-3.1.3 2022-03-10
1. Add kkfileview 3.x support
2. Fix search bug https://github.com/eyebluecn/tank/issues/148
3. Fix bug of totalSize in dashboard
1. 添加了kkfileview 3.x的预览支持
2. 修复了一个搜索的bug https://github.com/eyebluecn/tank/issues/148
3. 修复了文件大小统计的bug
tank-3.1.3 2021-08-27
1.tank.json中新增5个字段。
tank-3.1.2 2021-01-02
+4 -8
View File
@@ -1,5 +1,5 @@
# use golang 1.17
FROM golang:1.17
# use golang 1.12
FROM golang:1.12
# maintainer. Author's name and email.
MAINTAINER eyeblue "eyebluecn@126.com"
@@ -14,14 +14,10 @@ COPY . /data
VOLUME /data/build/matter
# proxy
ENV GOPROXY=https://goproxy.cn
# Handle time-zone
ENV TZ=Asia/Shanghai
RUN apt-get install -y tzdata
ENV GOPROXY=https://goproxy.io
# prepare the config file
RUN go build \
RUN go build -mod=readonly \
&& cp -r /data/tank /data/build
# use 6010 as default.
+5 -24
View File
@@ -2,8 +2,8 @@
[English Version](https://tank-doc.eyeblue.cn/en)
# 蓝眼云盘(4.0.0.beta1)
[在线Demo](https://tanker.eyeblue.cn) (体验账号: demo 密码:123456)
# 蓝眼云盘(3.1.2)
[在线Demo](https://tank.eyeblue.cn) (体验账号: demo 密码:123456)
蓝眼云盘是蓝眼开源系列代表作品之一,致力于打造精致,优雅,简约的云盘。核心功能如下:
1. 文件列表
@@ -15,8 +15,6 @@
7. [WebDav](https://tank-doc.eyeblue.cn/advance/webdav.html)
8. [扫描磁盘任务](https://tank-doc.eyeblue.cn/advance/scan.html)
9. [在线预览及自定义配置预览引擎](https://tank-doc.eyeblue.cn/advance/preview.html)
10. 支持Sqlite和Mysql数据库用以存储文件元信息,Sqlite可以做到开箱即用。
[更多内容请移步至文档](https://tank-doc.eyeblue.cn/)
@@ -37,34 +35,17 @@
## [安装文档](https://tank-doc.eyeblue.cn/basic/install.html)
### 快速运行
安装依赖
```shell
go mod tidy
```
运行main文件即可:
```shell
./main.go
```
### Contribution
感谢所有蓝眼云盘的贡献者 [@zicla](https://github.com/zicla),[@seaheart](https://github.com/seaheart),[@yemuhe](https://github.com/yemuhe),[@hxsherry](https://github.com/hxsherry)
如果您也想参与进来,请尽情的fork, star, post issue, pull requests
当然你可以加入钉钉群(一群已满员)一起直接交流,在钉钉群中可以获取最新beta版本。
当然你可以加入钉钉群一起直接交流,在钉钉群中可以获取最新beta版本。
![](./build/doc/img/dingding.jpeg)
群号:44754005
### Support
IDE for this project is supported by [Jetbrains](https://jb.gg/OpenSourceSupport).
[![](./build/doc/img/jb_beam.png)](https://jb.gg/OpenSourceSupport)
![](./build/doc/img/dingding.jpg)
群号:23156361
### License
-16
View File
@@ -1,16 +0,0 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| master | :white_check_mark: |
## Reporting a Vulnerability
We strongly encourage you to report security vulnerabilities to
our private security mailing list: security@cilium.io - first, before
disclosing them in any public forums.
This is a private mailing list where only members of the Cilium internal
security team are subscribed to, and is treated as top priority.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

+31 -21
View File
@@ -1,28 +1,38 @@
{
"files": {
"main.css": "/static/css/main.d3300c6a.css",
"main.js": "/static/js/main.e6a355f9.js",
"static/media/logo.png": "/static/media/logo.847e54ef7fb4b744fad4.png",
"static/media/empty.svg": "/static/media/empty.1ac6f6fb3e1d8c985f32df632ded4fe1.svg",
"static/media/psd.svg": "/static/media/psd.f2767f53369b5e75d7708a857d8381f4.svg",
"static/media/xls.svg": "/static/media/xls.9f55e13113424a3cc3316acbf072f072.svg",
"static/media/ppt.svg": "/static/media/ppt.8696321d8f3893a15681473769c8283c.svg",
"static/media/doc.svg": "/static/media/doc.017d14ee10ef3d2427494d1b0e52b03e.svg",
"static/media/pdf.svg": "/static/media/pdf.67d0061b2cef7912ed36b895cb8a328a.svg",
"static/media/video.svg": "/static/media/video.09bf3324c0e699b3611bf6bb0fc1b50e.svg",
"static/media/file.svg": "/static/media/file.b6be968e09dc04a45ec49a0dbcef53da.svg",
"static/media/default-skin.svg": "/static/media/default-skin.f64c3af3d0d25b9e4e00.svg",
"static/media/text.svg": "/static/media/text.fa66aadee4b7dd9d51f4d1c863e5f75e.svg",
"static/media/audio.svg": "/static/media/audio.59dab6a9512494e5a34c8a424ab68f39.svg",
"static/media/image.svg": "/static/media/image.ee35022875b37a7962afa08bce8bc1fd.svg",
"static/media/folder.svg": "/static/media/folder.b4ce8a2960e8da846081c692d3065dff.svg",
"static/media/archive.svg": "/static/media/archive.f58837716d1fc6f2e61dc1618dad27a6.svg",
"main.css": "/static/css/main.8aa2b3c6.chunk.css",
"main.js": "/static/js/main.692308e3.chunk.js",
"main.js.map": "/static/js/main.692308e3.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.9bf84af1.js",
"runtime-main.js.map": "/static/js/runtime-main.9bf84af1.js.map",
"static/css/2.e86c2f44.chunk.css": "/static/css/2.e86c2f44.chunk.css",
"static/js/2.789172e0.chunk.js": "/static/js/2.789172e0.chunk.js",
"static/js/2.789172e0.chunk.js.map": "/static/js/2.789172e0.chunk.js.map",
"index.html": "/index.html",
"main.d3300c6a.css.map": "/static/css/main.d3300c6a.css.map",
"main.e6a355f9.js.map": "/static/js/main.e6a355f9.js.map"
"static/css/2.e86c2f44.chunk.css.map": "/static/css/2.e86c2f44.chunk.css.map",
"static/css/main.8aa2b3c6.chunk.css.map": "/static/css/main.8aa2b3c6.chunk.css.map",
"static/js/2.789172e0.chunk.js.LICENSE.txt": "/static/js/2.789172e0.chunk.js.LICENSE.txt",
"static/media/archive.svg": "/static/media/archive.77d78eb7.svg",
"static/media/audio.svg": "/static/media/audio.30a1ea02.svg",
"static/media/default-skin.css": "/static/media/default-skin.b257fa9c.svg",
"static/media/doc.svg": "/static/media/doc.1e70a87c.svg",
"static/media/empty.svg": "/static/media/empty.babf4d08.svg",
"static/media/file.svg": "/static/media/file.fd3e15f8.svg",
"static/media/folder.svg": "/static/media/folder.f8d1b500.svg",
"static/media/image.svg": "/static/media/image.06f036ce.svg",
"static/media/logo.png": "/static/media/logo.21458adb.png",
"static/media/pdf.svg": "/static/media/pdf.c256fdcb.svg",
"static/media/ppt.svg": "/static/media/ppt.9ec3e018.svg",
"static/media/psd.svg": "/static/media/psd.be6691be.svg",
"static/media/text.svg": "/static/media/text.49dc13ae.svg",
"static/media/video.svg": "/static/media/video.4387235d.svg",
"static/media/xls.svg": "/static/media/xls.ef5ba31b.svg"
},
"entrypoints": [
"static/css/main.d3300c6a.css",
"static/js/main.e6a355f9.js"
"static/js/runtime-main.9bf84af1.js",
"static/css/2.e86c2f44.chunk.css",
"static/js/2.789172e0.chunk.js",
"static/css/main.8aa2b3c6.chunk.css",
"static/js/main.692308e3.chunk.js"
]
}
+1 -1
View File
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="eyeblue tank"/><title>EyeblueTank</title><script defer="defer" src="/static/js/main.e6a355f9.js"></script><link href="/static/css/main.d3300c6a.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run EyeblueTank.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="eyeblue tank"/><title>EyeblueTank</title><link href="/static/css/2.e86c2f44.chunk.css" rel="stylesheet"><link href="/static/css/main.8aa2b3c6.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run EyeblueTank.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,f,l=t[0],a=t[1],i=t[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,i||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=f(f.s=r[0]))}return e}var n={},o={1:0},u=[];function f(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=e,f.c=n,f.d=function(e,t,r){f.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,t){if(1&t&&(e=f(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(f.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)f.d(r,n,function(t){return e[t]}.bind(null,n));return r},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,"a",t),t},f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},f.p="/";var l=this["webpackJsonptank-front"]=this["webpackJsonptank-front"]||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var i=0;i<l.length;i++)t(l[i]);var p=a;r()}([])</script><script src="/static/js/2.789172e0.chunk.js"></script><script src="/static/js/main.692308e3.chunk.js"></script></body></html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@ object-assign
*/
/*!
Copyright (c) 2018 Jed Watson.
Copyright (c) 2017 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
@@ -22,7 +22,7 @@ object-assign
/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */
/** @license React v0.20.2
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
@@ -31,6 +31,15 @@ object-assign
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
@@ -40,25 +49,7 @@ object-assign
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
/** @license React v16.13.1
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
@@ -66,5 +57,3 @@ object-assign
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
//! moment.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
!function(e){function webpackJsonpCallback(r){for(var n,o,u=r[0],c=r[1],p=r[2],i=0,l=[];i<u.length;i++)o=u[i],Object.prototype.hasOwnProperty.call(_,o)&&_[o]&&l.push(_[o][0]),_[o]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(a&&a(r);l.length;)l.shift()();return t.push.apply(t,p||[]),checkDeferredModules()}function checkDeferredModules(){for(var e,r=0;r<t.length;r++){for(var n=t[r],o=!0,u=1;u<n.length;u++){var a=n[u];0!==_[a]&&(o=!1)}o&&(t.splice(r--,1),e=__webpack_require__(__webpack_require__.s=n[0]))}return e}var r={},_={1:0},t=[];function __webpack_require__(_){if(r[_])return r[_].exports;var t=r[_]={i:_,l:!1,exports:{}};return e[_].call(t.exports,t,t.exports,__webpack_require__),t.l=!0,t.exports}__webpack_require__.m=e,__webpack_require__.c=r,__webpack_require__.d=function(e,r,_){__webpack_require__.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:_})},__webpack_require__.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.t=function(e,r){if(1&r&&(e=__webpack_require__(e)),8&r)return e;if(4&r&&"object"===typeof e&&e&&e.__esModule)return e;var _=Object.create(null);if(__webpack_require__.r(_),Object.defineProperty(_,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var t in e)__webpack_require__.d(_,t,function(r){return e[r]}.bind(null,t));return _},__webpack_require__.n=function(e){var r=e&&e.__esModule?function getDefault(){return e.default}:function getModuleExports(){return e};return __webpack_require__.d(r,"a",r),r},__webpack_require__.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},__webpack_require__.p="/";var n=this["webpackJsonptank-front"]=this["webpackJsonptank-front"]||[],o=n.push.bind(n);n.push=webpackJsonpCallback,n=n.slice();for(var u=0;u<n.length;u++)webpackJsonpCallback(n[u]);var a=o;checkDeferredModules()}([]);
//# sourceMappingURL=runtime-main.9bf84af1.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514189353878" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1197" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M9.367 0h992.97v341.333H9.366z" fill="#55C7F7" p-id="1198"></path><path d="M9.367 341.333h992.97v341.334H9.366z" fill="#F95F5D" p-id="1199"></path><path d="M9.367 682.667h992.97V1024H9.366z" fill="#7ECF3B" p-id="1200"></path><path d="M350.7 0h310.303v1024H350.7z" fill="#FDAF42" p-id="1201"></path><path d="M304.154 386.638V646.05h403.394V386.638H304.154z m356.849 215.97H350.7V429.46h310.303v173.15z" fill="#FFFFFF" p-id="1202"></path></svg>

After

Width:  |  Height:  |  Size: 828 B

@@ -1,14 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514189353878" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1197" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M9.367 0h992.97v341.333H9.366z" fill="#55C7F7" p-id="1198"></path>
<path d="M9.367 341.333h992.97v341.334H9.366z" fill="#F95F5D" p-id="1199"></path>
<path d="M9.367 682.667h992.97V1024H9.366z" fill="#7ECF3B" p-id="1200"></path>
<path d="M350.7 0h310.303v1024H350.7z" fill="#FDAF42" p-id="1201"></path>
<path d="M304.154 386.638V646.05h403.394V386.638H304.154z m356.849 215.97H350.7V429.46h310.303v173.15z"
fill="#FFFFFF" p-id="1202"></path>
</svg>

Before

Width:  |  Height:  |  Size: 855 B

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543321997742" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3887" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M160 32c-12 0-24.8 4.8-33.6 14.4S112 68 112 80v864c0 12 4.8 24.8 14.4 33.6C136 987.2 148 992 160 992h704c12 0 24.8-4.8 33.6-14.4C907.2 968 912 956 912 944V304L640 32H160z" fill="#FF5562" p-id="3888"></path><path d="M912 304H688c-12 0-24.8-4.8-33.6-14.4-9.6-8.8-14.4-21.6-14.4-33.6V32l272 272z" fill="#FFBBC0" p-id="3889"></path><path d="M669.6 491.2c0-1.6 0.8-4 0-6.4V369.6c0-4.8-2.4-8.8-5.6-12-4-3.2-8-4-12.8-3.2l-250.4 70.4c-7.2 1.6-12 7.2-12 14.4v275.2c-9.6-4-20.8-6.4-32.8-6.4-8.8 0-17.6 0.8-26.4 3.2-40.8 11.2-66.4 43.2-58.4 72.8 6.4 23.2 30.4 37.6 60.8 37.6 8.8 0 17.6-1.6 26.4-3.2 36.8-10.4 60.8-36.8 60-63.2 0.8-1.6 0.8-3.2 0.8-5.6V570.4l220-61.6v136c-9.6-4-20.8-6.4-32.8-6.4-8.8 0-17.6 0.8-26.4 3.2-40.8 11.2-66.4 43.2-58.4 72.8C528 737.6 552 752 582.4 752c8.8 0 17.6-0.8 26.4-3.2 36-9.6 60-36 60-62.4 0.8-1.6 0.8-3.2 0.8-5.6V491.2z m-250.4 48v-53.6l220-61.6v53.6l-220 61.6z" fill="#FFFFFF" p-id="3890"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,14 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1543321997742" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="3887" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M160 32c-12 0-24.8 4.8-33.6 14.4S112 68 112 80v864c0 12 4.8 24.8 14.4 33.6C136 987.2 148 992 160 992h704c12 0 24.8-4.8 33.6-14.4C907.2 968 912 956 912 944V304L640 32H160z"
fill="#FF5562" p-id="3888"></path>
<path d="M912 304H688c-12 0-24.8-4.8-33.6-14.4-9.6-8.8-14.4-21.6-14.4-33.6V32l272 272z" fill="#FFBBC0"
p-id="3889"></path>
<path d="M669.6 491.2c0-1.6 0.8-4 0-6.4V369.6c0-4.8-2.4-8.8-5.6-12-4-3.2-8-4-12.8-3.2l-250.4 70.4c-7.2 1.6-12 7.2-12 14.4v275.2c-9.6-4-20.8-6.4-32.8-6.4-8.8 0-17.6 0.8-26.4 3.2-40.8 11.2-66.4 43.2-58.4 72.8 6.4 23.2 30.4 37.6 60.8 37.6 8.8 0 17.6-1.6 26.4-3.2 36.8-10.4 60.8-36.8 60-63.2 0.8-1.6 0.8-3.2 0.8-5.6V570.4l220-61.6v136c-9.6-4-20.8-6.4-32.8-6.4-8.8 0-17.6 0.8-26.4 3.2-40.8 11.2-66.4 43.2-58.4 72.8C528 737.6 552 752 582.4 752c8.8 0 17.6-0.8 26.4-3.2 36-9.6 60-36 60-62.4 0.8-1.6 0.8-3.2 0.8-5.6V491.2z m-250.4 48v-53.6l220-61.6v53.6l-220 61.6z"
fill="#FFFFFF" p-id="3890"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,12 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1543300132402" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="2107" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M533.947184 38.36489h65.880106v88.119185c117.859409 0.660894 235.60867-1.211639 353.35793 0.660894 25.102953-2.533427 44.81962 16.962943 42.506492 42.07691 1.872533 216.993492-0.440596 434.097133 1.112505 651.090626-1.112505 22.250094 2.191965 46.923466-10.695466 66.640133-16.081751 11.455494-36.899909 10.023557-55.625236 10.904749-110.25913-0.550745-220.408111-0.330447-330.656225-0.330447v88.119185h-68.843113c-167.657764-30.621417-335.745108-58.709407-503.722304-88.119185-0.110149-256.977572 0-513.955144 0-770.822567 168.858388-29.519927 337.826924-58.268811 506.685311-88.339483z"
fill="#2A5699" p-id="2108"></path>
<path d="M599.816275 159.528769h363.491637v704.953477h-363.491637v-88.119185h286.38735v-44.059592h-286.38735v-55.07449h286.38735v-44.059593h-286.38735v-55.07449h286.38735v-44.059592h-286.38735v-55.074491h286.38735v-44.059592h-286.38735v-55.074491h286.38735v-44.059592h-286.38735v-55.07449h286.38735v-44.059593h-286.38735v-77.104286zM254.829667 354.162018c20.928306-1.211639 41.856613-2.092831 62.784919-3.19432 14.649814 74.350562 29.619061 148.590975 45.491529 222.61109 12.446835-76.443393 26.215457-152.666487 39.543484-228.999731 22.029796-0.771043 44.059592-1.982682 65.97924-3.30447-24.89367 106.734362-46.703168 214.349917-73.909966 320.423385-18.39488 9.582961-45.932125-0.440596-67.741623 1.10149-14.649814-72.90761-31.722906-145.38564-44.819621-218.645727-12.898446 71.156242-29.641091 141.651589-44.390039 212.367235a4187.754101 4187.754101 0 0 1-63.666111-3.866229c-18.284731-96.931103-39.763782-193.190297-56.836874-290.341698 18.835476-0.881192 37.792115-1.652235 56.627591-2.313129 11.33433 70.164901 24.221761 139.999355 34.146184 210.274404 15.508976-72.037433 31.37043-144.074867 46.791287-216.1123z"
fill="#FFFFFF" p-id="2109"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543300132402" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2107" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M533.947184 38.36489h65.880106v88.119185c117.859409 0.660894 235.60867-1.211639 353.35793 0.660894 25.102953-2.533427 44.81962 16.962943 42.506492 42.07691 1.872533 216.993492-0.440596 434.097133 1.112505 651.090626-1.112505 22.250094 2.191965 46.923466-10.695466 66.640133-16.081751 11.455494-36.899909 10.023557-55.625236 10.904749-110.25913-0.550745-220.408111-0.330447-330.656225-0.330447v88.119185h-68.843113c-167.657764-30.621417-335.745108-58.709407-503.722304-88.119185-0.110149-256.977572 0-513.955144 0-770.822567 168.858388-29.519927 337.826924-58.268811 506.685311-88.339483z" fill="#2A5699" p-id="2108"></path><path d="M599.816275 159.528769h363.491637v704.953477h-363.491637v-88.119185h286.38735v-44.059592h-286.38735v-55.07449h286.38735v-44.059593h-286.38735v-55.07449h286.38735v-44.059592h-286.38735v-55.074491h286.38735v-44.059592h-286.38735v-55.074491h286.38735v-44.059592h-286.38735v-55.07449h286.38735v-44.059593h-286.38735v-77.104286zM254.829667 354.162018c20.928306-1.211639 41.856613-2.092831 62.784919-3.19432 14.649814 74.350562 29.619061 148.590975 45.491529 222.61109 12.446835-76.443393 26.215457-152.666487 39.543484-228.999731 22.029796-0.771043 44.059592-1.982682 65.97924-3.30447-24.89367 106.734362-46.703168 214.349917-73.909966 320.423385-18.39488 9.582961-45.932125-0.440596-67.741623 1.10149-14.649814-72.90761-31.722906-145.38564-44.819621-218.645727-12.898446 71.156242-29.641091 141.651589-44.390039 212.367235a4187.754101 4187.754101 0 0 1-63.666111-3.866229c-18.284731-96.931103-39.763782-193.190297-56.836874-290.341698 18.835476-0.881192 37.792115-1.652235 56.627591-2.313129 11.33433 70.164901 24.221761 139.999355 34.146184 210.274404 15.508976-72.037433 31.37043-144.074867 46.791287-216.1123z" fill="#FFFFFF" p-id="2109"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -1,20 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1582644951614" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3842"
width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M692.906667 385.024c-11.605333-2.730667-23.210667-6.144-34.816-11.605333l-63.488 25.258666-5.461334 2.048h-5.461333c-8.874667 0-17.749333-4.096-23.210667-11.605333-5.461333-7.509333-6.826667-17.066667-4.778666-25.258667l8.874666-30.72-97.621333-19.797333v400.725333L901.12 402.090667l-105.130667-21.162667c-18.432 5.461333-38.229333 8.874667-59.392 8.874667-13.653333 0-28.672-1.365333-43.690666-4.778667z"
fill="#A6DAFC" p-id="3843"></path>
<path d="M512 502.442667v467.626666l389.802667-100.352V402.090667zM111.274667 413.696l356.352-100.352V580.266667z"
fill="#568EC8" p-id="3844"></path>
<path d="M111.274667 413.696v456.021333L512 970.069333V502.442667z" fill="#A6DAFC" p-id="3845"></path>
<path d="M512 502.442667l389.802667-100.352L1024 546.816 645.802667 658.090667z" fill="#78C5FD" p-id="3846"></path>
<path d="M111.274667 413.696l400.725333 88.746667-122.197333 167.253333L0 569.344z" fill="#CFF0FF"
p-id="3847"></path>
<path d="M886.784 160.426667c-2.730667-6.826667-6.144-13.653333-9.557333-20.48-1.365333-2.048-2.730667-4.096-4.096-6.826667-4.096-6.144-8.192-12.970667-13.653334-18.432s-10.24-11.605333-16.384-16.384c-2.048-2.048-4.096-3.413333-6.144-4.778667-8.192-6.826667-17.066667-12.288-25.941333-17.749333-2.048-1.365333-4.778667-2.730667-6.826667-3.413333-4.778667-2.048-9.557333-4.778667-15.018666-6.144-7.509333-2.730667-15.701333-5.461333-23.893334-6.826667-2.730667-0.682667-6.144-1.365333-8.874666-2.048-0.682667 0-2.048 0-2.730667-0.682667-2.048 0-4.096-0.682667-6.144-0.682666-1.365333 0-2.048 0-3.413333-0.682667-2.048 0-3.413333 0-5.461334-0.682667H727.04c-4.096 0-8.192 0-11.605333 0.682667h-2.048c-4.096 0.682667-8.192 0.682667-12.288 1.365333h-0.682667c-4.096 0.682667-7.509333 1.365333-11.605333 2.048-0.682667 0-1.365333 0-1.365334 0.682667-4.096 0.682667-7.509333 2.048-10.922666 3.413333-0.682667 0-1.365333 0.682667-2.048 0.682667-3.413333 1.365333-7.509333 2.730667-10.922667 4.096-0.682667 0-0.682667 0.682667-1.365333 0.682667-3.413333 1.365333-6.826667 3.413333-10.24 4.778666 0 0-0.682667 0-0.682667 0.682667-3.413333 2.048-6.826667 3.413333-10.24 5.461333-0.682667 0.682667-1.365333 0.682667-2.048 1.365334-3.413333 2.048-6.144 4.096-9.557333 6.144-0.682667 0.682667-1.365333 0.682667-1.365334 1.365333-3.413333 2.048-6.144 4.778667-8.874666 7.509333l-8.192 8.192-1.365334 1.365334c-2.730667 2.730667-4.778667 5.461333-7.509333 8.192-0.682667 0.682667-0.682667 1.365333-1.365333 1.365333-2.048 2.730667-4.778667 6.144-6.826667 8.874667 0 0.682667-0.682667 0.682667-0.682667 1.365333-2.048 3.413333-4.096 6.144-5.461333 9.557333 0 0.682667-0.682667 0.682667-0.682667 1.365334-2.048 3.413333-3.413333 6.826667-4.778666 10.24 0 0.682667-0.682667 1.365333-0.682667 2.048-1.365333 3.413333-2.730667 6.826667-4.096 10.922666 0 0.682667-0.682667 1.365333-0.682667 2.048-1.365333 4.096-2.048 7.509333-3.413333 11.605334-10.24 46.421333 2.730667 92.16 32.085333 127.658666L593.92 339.968l-9.557333 32.768v0.682667h0.682666l58.709334-23.210667 16.384-6.826667c6.144 3.413333 12.970667 6.144 19.797333 8.192s13.653333 4.778667 21.162667 6.144c2.730667 0.682667 6.144 1.365333 8.874666 2.048 0.682667 0 2.048 0 2.730667 0.682667 2.048 0 4.096 0.682667 6.144 0.682667 1.365333 0 2.048 0 3.413333 0.682666 2.048 0 3.413333 0 5.461334 0.682667H739.328c4.096 0 8.192 0 11.605333-0.682667h2.048c4.096-0.682667 8.192-0.682667 12.288-1.365333h0.682667c4.096-0.682667 7.509333-1.365333 11.605333-2.048 0.682667 0 1.365333 0 2.048-0.682667 4.096-0.682667 7.509333-2.048 10.922667-3.413333 0.682667 0 1.365333-0.682667 2.048-0.682667 3.413333-1.365333 7.509333-2.730667 10.922667-4.096 0.682667 0 0.682667-0.682667 1.365333-0.682666 3.413333-1.365333 6.826667-3.413333 10.24-4.778667 0 0 0.682667 0 0.682667-0.682667 3.413333-2.048 6.826667-3.413333 10.24-5.461333 0.682667-0.682667 1.365333-0.682667 2.048-1.365333 3.413333-2.048 6.144-4.096 9.557333-6.144 0.682667-0.682667 1.365333-0.682667 1.365333-1.365334 3.413333-2.048 6.144-4.778667 8.874667-7.509333l8.192-8.192 1.365333-1.365333c2.730667-2.730667 4.778667-5.461333 7.509334-8.192 0.682667-0.682667 0.682667-1.365333 1.365333-2.048 2.048-2.730667 4.778667-6.144 6.826667-8.874667 0-0.682667 0.682667-0.682667 0.682666-1.365333 2.048-3.413333 4.096-6.144 5.461334-9.557334 0-0.682667 0.682667-0.682667 0.682666-1.365333 2.048-3.413333 3.413333-6.826667 4.778667-10.24 0-0.682667 0.682667-1.365333 0.682667-2.048 1.365333-3.413333 2.730667-6.826667 4.096-10.922667 0-0.682667 0.682667-1.365333 0.682666-2.048 1.365333-4.096 2.048-7.509333 3.413334-11.605333 5.461333-28.672 2.730667-57.344-6.826667-83.285333z"
fill="#F9DA3E" p-id="3848"></path>
<path d="M739.328 167.936h48.469333v27.989333h-13.653333v-15.701333h-83.968v15.701333h-13.653333v-27.989333h48.469333c-1.365333-3.413333-3.413333-6.826667-4.778667-10.24l14.336-2.048c2.048 3.413333 3.413333 7.509333 4.778667 12.288z m37.546667 52.565333v12.288h-37.546667v25.258667h48.469333v12.970667H677.205333v-12.970667h48.469334v-25.258667h-37.546667v-12.288h88.746667z m-51.882667-24.576c-10.24 8.874667-22.528 16.384-37.546667 22.528l-5.461333-12.288c14.336-5.461333 25.941333-11.605333 34.816-19.797333l8.192 9.557333z m56.661333 10.922667l-7.509333 11.605333c-11.605333-9.557333-23.210667-17.066667-35.498667-22.528l6.826667-10.24c13.653333 6.144 25.258667 12.970667 36.181333 21.162667z"
fill="#FFFFFF" p-id="3849"></path>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

@@ -1,19 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514189511483" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="6709" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M676.297143 0H145.609143C130.834286 0 118.857143 11.977143 118.857143 35.218286V1005.714286c0 6.308571 11.977143 18.285714 26.752 18.285714h732.781714c14.774857 0 26.752-11.977143 26.752-18.285714V237.312c0-12.726857-1.700571-16.822857-4.699428-19.84L687.670857 4.699429A16.164571 16.164571 0 0 0 676.297143 0z"
fill="#E9E9E0" p-id="6710"></path>
<path d="M685.714286 2.761143V219.428571h216.667428z" fill="#D9D7CA" p-id="6711"></path>
<path d="M878.390857 1024H145.609143A26.752 26.752 0 0 1 118.857143 997.248V713.142857h786.285714v284.105143c0 14.774857-11.977143 26.752-26.752 26.752z"
fill="#C8BDB8" p-id="6712"></path>
<path d="M338.285714 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z"
fill="#FFFFFF" p-id="6713"></path>
<path d="M521.142857 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z"
fill="#FFFFFF" p-id="6714"></path>
<path d="M704 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z"
fill="#FFFFFF" p-id="6715"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514189511483" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6709" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M676.297143 0H145.609143C130.834286 0 118.857143 11.977143 118.857143 35.218286V1005.714286c0 6.308571 11.977143 18.285714 26.752 18.285714h732.781714c14.774857 0 26.752-11.977143 26.752-18.285714V237.312c0-12.726857-1.700571-16.822857-4.699428-19.84L687.670857 4.699429A16.164571 16.164571 0 0 0 676.297143 0z" fill="#E9E9E0" p-id="6710"></path><path d="M685.714286 2.761143V219.428571h216.667428z" fill="#D9D7CA" p-id="6711"></path><path d="M878.390857 1024H145.609143A26.752 26.752 0 0 1 118.857143 997.248V713.142857h786.285714v284.105143c0 14.774857-11.977143 26.752-26.752 26.752z" fill="#C8BDB8" p-id="6712"></path><path d="M338.285714 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z" fill="#FFFFFF" p-id="6713"></path><path d="M521.142857 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z" fill="#FFFFFF" p-id="6714"></path><path d="M704 859.428571m-54.857143 0a54.857143 54.857143 0 1 0 109.714286 0 54.857143 54.857143 0 1 0-109.714286 0Z" fill="#FFFFFF" p-id="6715"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1,10 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514189634329" class="icon" style="" viewBox="0 0 1219 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="10648" width="238.0859375" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M1197.787429 327.192381a19.504762 19.504762 0 0 1 19.553523 19.407238v614.156191c0 34.913524-28.574476 63.24419-63.878095 63.24419H63.878095C28.623238 1024 0 995.718095 0 960.75581V346.599619a19.504762 19.504762 0 0 1 19.602286-19.358476h1178.185143z m-66.80381-213.089524C1179.550476 114.102857 1219.047619 153.209905 1219.047619 201.386667v80.213333H1.657905V88.259048C1.657905 39.497143 41.593905 0 90.794667 0h290.864762c17.408 0 33.987048 7.655619 45.104761 20.967619l78.214096 93.135238h626.005333z"
fill="#23B7E5" p-id="10649"></path>
</svg>

Before

Width:  |  Height:  |  Size: 949 B

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514189634329" class="icon" style="" viewBox="0 0 1219 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10648" xmlns:xlink="http://www.w3.org/1999/xlink" width="238.0859375" height="200"><defs><style type="text/css"></style></defs><path d="M1197.787429 327.192381a19.504762 19.504762 0 0 1 19.553523 19.407238v614.156191c0 34.913524-28.574476 63.24419-63.878095 63.24419H63.878095C28.623238 1024 0 995.718095 0 960.75581V346.599619a19.504762 19.504762 0 0 1 19.602286-19.358476h1178.185143z m-66.80381-213.089524C1179.550476 114.102857 1219.047619 153.209905 1219.047619 201.386667v80.213333H1.657905V88.259048C1.657905 39.497143 41.593905 0 90.794667 0h290.864762c17.408 0 33.987048 7.655619 45.104761 20.967619l78.214096 93.135238h626.005333z" fill="#23B7E5" p-id="10649"></path></svg>

After

Width:  |  Height:  |  Size: 943 B

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514190539077" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14917" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M128 0h597.3l227.6 227.9v739.2c0 31.4-25.5 56.9-56.9 56.9H128c-31.4 0-56.9-25.5-56.9-56.9V56.9C71.1 25.5 96.6 0 128 0z" fill="#13BE93" p-id="14918"></path><path d="M630.5 1024H128c-25.7 0-47.4-17-54.4-40.4l218.1-218.1c22.2-22.2 58.2-22.2 80.5 0L630.5 1024z" fill="#6BD8BD" p-id="14919"></path><path d="M952.9 858v109.1c0 31.4-25.5 56.9-56.9 56.9H322.4l-4.7-4.7 358-358c22.2-22.2 58.2-22.2 80.5 0L952.9 858z" fill="#9CF9E2" p-id="14920"></path><path d="M725.3 0l227.6 227.6H782.2c-31.4 0-56.9-25.5-56.9-56.9V0z" fill="#69DCC0" p-id="14921"></path><path d="M327.1 483.6m-85.3 0a85.3 85.3 0 1 0 170.6 0 85.3 85.3 0 1 0-170.6 0Z" fill="#E9FFFA" p-id="14922"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -1,16 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514190539077" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="14917" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M128 0h597.3l227.6 227.9v739.2c0 31.4-25.5 56.9-56.9 56.9H128c-31.4 0-56.9-25.5-56.9-56.9V56.9C71.1 25.5 96.6 0 128 0z"
fill="#13BE93" p-id="14918"></path>
<path d="M630.5 1024H128c-25.7 0-47.4-17-54.4-40.4l218.1-218.1c22.2-22.2 58.2-22.2 80.5 0L630.5 1024z"
fill="#6BD8BD" p-id="14919"></path>
<path d="M952.9 858v109.1c0 31.4-25.5 56.9-56.9 56.9H322.4l-4.7-4.7 358-358c22.2-22.2 58.2-22.2 80.5 0L952.9 858z"
fill="#9CF9E2" p-id="14920"></path>
<path d="M725.3 0l227.6 227.6H782.2c-31.4 0-56.9-25.5-56.9-56.9V0z" fill="#69DCC0" p-id="14921"></path>
<path d="M327.1 483.6m-85.3 0a85.3 85.3 0 1 0 170.6 0 85.3 85.3 0 1 0-170.6 0Z" fill="#E9FFFA" p-id="14922"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

@@ -1,13 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514284130163" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1551" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M915.114667 1024H108.885333V0h587.776v218.112H914.773333V1024z m-785.066667-20.821333h763.904V238.933333H675.84V20.821333H129.706667v982.357334z"
fill="#F90E09" p-id="1552"></path>
<path d="M708.266667 10.581333L904.533333 206.848h-196.266666z" fill="#F90E09" p-id="1553"></path>
<path d="M282.965333 792.576c33.450667-23.210667 55.637333-57.344 76.8-91.136-30.378667 25.941333-59.050667 54.954667-76.8 91.136z m396.629334-169.642667c31.402667 15.018667 65.877333 31.061333 101.376 21.504-24.576-29.696-67.584-21.504-101.376-21.504z m-246.101334 23.210667c45.397333-16.725333 91.818667-29.696 138.922667-39.594667-30.378667-26.965333-55.978667-58.368-76.458667-93.525333-16.725333 46.08-38.912 90.112-62.464 133.12z m67.925334-243.370667c14.677333-37.546667 19.114667-83.285333-5.802667-117.418666-7.168 38.912-4.096 79.189333 5.802667 117.418666z m-45.397334-105.130666c4.096-24.917333 35.84-29.696 55.637334-22.186667 12.288 7.850667 18.432 22.869333 18.773333 37.205333 1.365333 44.032-6.485333 87.381333-12.629333 130.730667-3.413333 20.138667 8.874667 38.229333 17.749333 55.296 21.845333 40.277333 52.224 76.458667 92.16 99.669333 48.128-5.802667 98.645333-12.970667 145.749333 2.389334 35.157333 11.946667 26.965333 77.141333-11.264 77.824-53.589333 2.730667-102.058667-23.893333-150.186666-43.349334-66.218667 4.778667-130.730667 24.917333-194.218667 44.032-28.672 46.762667-54.613333 98.986667-101.034667 130.730667-23.210667 18.090667-76.458667 3.072-64.512-32.085333 20.138667-49.152 70.314667-76.117333 114.346667-100.693334 12.629333-6.485333 19.797333-18.773333 26.282667-31.061333 30.037333-57.685333 60.074667-115.370667 84.309333-175.786667-12.629333-56.661333-31.061333-114.688-21.162667-172.714666z"
fill="#F90E09" p-id="1554"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514284130163" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1551" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M915.114667 1024H108.885333V0h587.776v218.112H914.773333V1024z m-785.066667-20.821333h763.904V238.933333H675.84V20.821333H129.706667v982.357334z" fill="#F90E09" p-id="1552"></path><path d="M708.266667 10.581333L904.533333 206.848h-196.266666z" fill="#F90E09" p-id="1553"></path><path d="M282.965333 792.576c33.450667-23.210667 55.637333-57.344 76.8-91.136-30.378667 25.941333-59.050667 54.954667-76.8 91.136z m396.629334-169.642667c31.402667 15.018667 65.877333 31.061333 101.376 21.504-24.576-29.696-67.584-21.504-101.376-21.504z m-246.101334 23.210667c45.397333-16.725333 91.818667-29.696 138.922667-39.594667-30.378667-26.965333-55.978667-58.368-76.458667-93.525333-16.725333 46.08-38.912 90.112-62.464 133.12z m67.925334-243.370667c14.677333-37.546667 19.114667-83.285333-5.802667-117.418666-7.168 38.912-4.096 79.189333 5.802667 117.418666z m-45.397334-105.130666c4.096-24.917333 35.84-29.696 55.637334-22.186667 12.288 7.850667 18.432 22.869333 18.773333 37.205333 1.365333 44.032-6.485333 87.381333-12.629333 130.730667-3.413333 20.138667 8.874667 38.229333 17.749333 55.296 21.845333 40.277333 52.224 76.458667 92.16 99.669333 48.128-5.802667 98.645333-12.970667 145.749333 2.389334 35.157333 11.946667 26.965333 77.141333-11.264 77.824-53.589333 2.730667-102.058667-23.893333-150.186666-43.349334-66.218667 4.778667-130.730667 24.917333-194.218667 44.032-28.672 46.762667-54.613333 98.986667-101.034667 130.730667-23.210667 18.090667-76.458667 3.072-64.512-32.085333 20.138667-49.152 70.314667-76.117333 114.346667-100.693334 12.629333-6.485333 19.797333-18.773333 26.282667-31.061333 30.037333-57.685333 60.074667-115.370667 84.309333-175.786667-12.629333-56.661333-31.061333-114.688-21.162667-172.714666z" fill="#F90E09" p-id="1554"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -1,18 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1543300178225" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="5733" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M537.372818 38.36489h62.454472v99.134083c117.738246 0.660894 235.60867-1.211639 353.236766 0.550745 25.334266-2.423278 45.172097 17.29339 42.627656 42.627655 1.872533 205.758296-0.440596 411.626741 1.10149 617.506201-1.10149 22.250094 2.20298 46.923466-10.574302 66.640134-16.081751 11.664777-36.999043 10.133706-55.834519 11.014898-110.148981-0.550745-220.297962-0.330447-330.557091-0.330447v110.148981h-68.523681c-167.856032-30.621417-336.06454-58.599258-504.041736-88.119185-0.110149-256.977572 0-513.955144 0-770.822567 169.970892-29.420793 339.93077-59.381316 510.110945-88.350498z"
fill="#D24625" p-id="5734"></path>
<path d="M599.82729 170.543667h363.491636v671.908783h-363.491636v-88.119185h264.357554v-44.059592h-264.357554v-55.074491h264.357554v-44.059592h-264.247405c-0.110149-21.5892-0.110149-43.1784-0.231313-64.767601 43.630011 13.53731 93.307202 13.217878 132.299941-13.008594 42.18706-25.003819 64.216856-72.698327 67.851772-120.271672-48.366417-0.330447-96.710805-0.220298-144.956059-0.220298-0.121164-47.914807 0.550745-95.829613-0.991341-143.634271-18.075448 3.524767-36.128866 7.269833-54.083149 11.125047v-109.818534z"
fill="#FFFFFF" p-id="5735"></path>
<path d="M677.041725 246.216017c76.553542 3.524767 140.880546 67.961921 144.956059 144.295165-48.366417 0.550745-96.710805 0.330447-145.066208 0.330447 0-48.245254-0.121164-96.490507 0.110149-144.625612z"
fill="#D24625" p-id="5736"></path>
<path d="M203.940838 329.378497c59.810897 2.863874 132.288926-23.682031 181.855967 21.148605 47.485226 57.607917 34.917227 163.571236-35.467972 198.047867-25.003819 12.777282-53.642554 11.014898-80.849351 10.133706-0.110149 43.068251-0.220298 86.136503-0.110149 129.19374-21.820513-1.872533-43.74016-3.745065-65.538644-5.507449-0.980326-117.628097-1.211639-235.377357 0.110149-353.016469z"
fill="#FFFFFF" p-id="5737"></path>
<path d="M269.380347 388.969096c21.699349-0.991341 48.575701-4.956704 63.214501 15.420857 12.567999 21.5892 11.89609 50.007637 1.442951 72.257732-12.567999 22.69069-40.986436 20.48771-62.895068 23.131286-2.313129-36.899909-2.092831-73.799817-1.762384-110.809875z"
fill="#D24625" p-id="5738"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543300178225" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5733" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M537.372818 38.36489h62.454472v99.134083c117.738246 0.660894 235.60867-1.211639 353.236766 0.550745 25.334266-2.423278 45.172097 17.29339 42.627656 42.627655 1.872533 205.758296-0.440596 411.626741 1.10149 617.506201-1.10149 22.250094 2.20298 46.923466-10.574302 66.640134-16.081751 11.664777-36.999043 10.133706-55.834519 11.014898-110.148981-0.550745-220.297962-0.330447-330.557091-0.330447v110.148981h-68.523681c-167.856032-30.621417-336.06454-58.599258-504.041736-88.119185-0.110149-256.977572 0-513.955144 0-770.822567 169.970892-29.420793 339.93077-59.381316 510.110945-88.350498z" fill="#D24625" p-id="5734"></path><path d="M599.82729 170.543667h363.491636v671.908783h-363.491636v-88.119185h264.357554v-44.059592h-264.357554v-55.074491h264.357554v-44.059592h-264.247405c-0.110149-21.5892-0.110149-43.1784-0.231313-64.767601 43.630011 13.53731 93.307202 13.217878 132.299941-13.008594 42.18706-25.003819 64.216856-72.698327 67.851772-120.271672-48.366417-0.330447-96.710805-0.220298-144.956059-0.220298-0.121164-47.914807 0.550745-95.829613-0.991341-143.634271-18.075448 3.524767-36.128866 7.269833-54.083149 11.125047v-109.818534z" fill="#FFFFFF" p-id="5735"></path><path d="M677.041725 246.216017c76.553542 3.524767 140.880546 67.961921 144.956059 144.295165-48.366417 0.550745-96.710805 0.330447-145.066208 0.330447 0-48.245254-0.121164-96.490507 0.110149-144.625612z" fill="#D24625" p-id="5736"></path><path d="M203.940838 329.378497c59.810897 2.863874 132.288926-23.682031 181.855967 21.148605 47.485226 57.607917 34.917227 163.571236-35.467972 198.047867-25.003819 12.777282-53.642554 11.014898-80.849351 10.133706-0.110149 43.068251-0.220298 86.136503-0.110149 129.19374-21.820513-1.872533-43.74016-3.745065-65.538644-5.507449-0.980326-117.628097-1.211639-235.377357 0.110149-353.016469z" fill="#FFFFFF" p-id="5737"></path><path d="M269.380347 388.969096c21.699349-0.991341 48.575701-4.956704 63.214501 15.420857 12.567999 21.5892 11.89609 50.007637 1.442951 72.257732-12.567999 22.69069-40.986436 20.48771-62.895068 23.131286-2.313129-36.899909-2.092831-73.799817-1.762384-110.809875z" fill="#D24625" p-id="5738"></path></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1545064197737" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14227" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M759.725253 0H134.464646v1024h817.131314V191.870707z" fill="#02007A" p-id="14228"></path><path d="M72.40404 708.525253h687.838384v258.585858H72.40404z" fill="#230091" p-id="14229"></path><path d="M82.747475 718.868687h667.151515v237.89899H82.747475zM755.070707 5.171717l191.353535 191.353536h-191.353535z" fill="#FFFFFF" p-id="14230"></path><path d="M506.828283 791.272727v93.090909h25.858586c28.444444 0 41.373737-12.929293 41.373737-45.511111s-12.929293-47.579798-41.373737-47.579798h-25.858586z m-25.858586-25.858586h51.717172c42.408081 0 67.232323 29.99596 67.232323 74.989899S575.612121 910.222222 532.686869 910.222222H480.969697v-144.808081z m-132.39596 104.468687c1.034343 26.375758 22.755556 42.408081 55.337374 42.408081 34.650505 0 55.854545-17.066667 55.854546-43.959596 0-21.20404-12.412121-33.09899-40.856566-39.822222l-16.549495-3.620202c-17.583838-4.137374-24.824242-9.826263-24.824242-19.135354 0-11.894949 10.860606-19.652525 26.892929-19.652525s27.410101 7.757576 28.444444 21.204041h24.307071c-0.517172-24.824242-21.20404-41.890909-52.751515-41.89091S351.676768 782.480808 351.676768 807.822222c0 20.169697 12.412121 33.09899 38.787878 38.787879l18.618182 4.137374c18.10101 4.137374 25.341414 10.343434 25.341414 20.169697 0 11.894949-11.894949 20.169697-28.961616 20.169697s-30.513131-8.791919-32.064646-21.721212l-24.824243 0.517171zM258.585859 788.686869v53.785858h20.686868c18.10101 0 31.030303-9.826263 31.030303-26.892929s-12.412121-26.892929-31.030303-26.892929h-20.686868z m-25.858586-23.272728h56.888889c28.444444 0 46.545455 20.686869 46.545454 49.131314s-17.583838 49.131313-46.545454 49.131313h-31.030303v46.545454h-25.858586v-144.808081z" fill="#230091" p-id="14231"></path><path d="M415.806061 443.216162h-31.030303v137.567676H321.163636V196.525253h93.090909c91.022222 0 140.670707 35.684848 140.670708 122.052525 0.517172 103.434343-92.573737 124.638384-139.119192 124.638384z m-5.688889-192.905051c-6.206061 0-14.99798 0.517172-26.89293 1.551515V387.878788h36.202021C461.834343 387.878788 491.313131 366.157576 491.313131 312.888889c0-40.856566-32.064646-62.577778-81.195959-62.577778z m258.068687 337.19596c70.852525 0 96.711111-50.165657 96.711111-84.816162 0-54.820202-35.684848-67.749495-66.19798-87.40202-25.858586-17.066667-49.648485-23.272727-49.648485-40.856566 0-22.755556 15.515152-27.410101 36.20202-27.410101 25.858586 0 54.820202 2.068687 67.232323 16.032323V306.682828c-12.929293-10.343434-37.236364-13.446465-68.783838-13.446464-67.749495 0-93.608081 44.993939-93.608081 84.29899 0 50.682828 33.616162 65.680808 66.19798 83.781818 21.20404 11.894949 46.545455 20.686869 46.545455 44.476767 0 13.963636-8.791919 27.927273-37.753536 27.927273-26.892929 0-59.991919-10.343434-74.989899-23.789899v59.991919c13.446465 10.343434 40.339394 17.583838 78.09293 17.583839z" fill="#7AB7FF" p-id="14232"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -1,16 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1545064197737" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="14227" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M759.725253 0H134.464646v1024h817.131314V191.870707z" fill="#02007A" p-id="14228"></path>
<path d="M72.40404 708.525253h687.838384v258.585858H72.40404z" fill="#230091" p-id="14229"></path>
<path d="M82.747475 718.868687h667.151515v237.89899H82.747475zM755.070707 5.171717l191.353535 191.353536h-191.353535z"
fill="#FFFFFF" p-id="14230"></path>
<path d="M506.828283 791.272727v93.090909h25.858586c28.444444 0 41.373737-12.929293 41.373737-45.511111s-12.929293-47.579798-41.373737-47.579798h-25.858586z m-25.858586-25.858586h51.717172c42.408081 0 67.232323 29.99596 67.232323 74.989899S575.612121 910.222222 532.686869 910.222222H480.969697v-144.808081z m-132.39596 104.468687c1.034343 26.375758 22.755556 42.408081 55.337374 42.408081 34.650505 0 55.854545-17.066667 55.854546-43.959596 0-21.20404-12.412121-33.09899-40.856566-39.822222l-16.549495-3.620202c-17.583838-4.137374-24.824242-9.826263-24.824242-19.135354 0-11.894949 10.860606-19.652525 26.892929-19.652525s27.410101 7.757576 28.444444 21.204041h24.307071c-0.517172-24.824242-21.20404-41.890909-52.751515-41.89091S351.676768 782.480808 351.676768 807.822222c0 20.169697 12.412121 33.09899 38.787878 38.787879l18.618182 4.137374c18.10101 4.137374 25.341414 10.343434 25.341414 20.169697 0 11.894949-11.894949 20.169697-28.961616 20.169697s-30.513131-8.791919-32.064646-21.721212l-24.824243 0.517171zM258.585859 788.686869v53.785858h20.686868c18.10101 0 31.030303-9.826263 31.030303-26.892929s-12.412121-26.892929-31.030303-26.892929h-20.686868z m-25.858586-23.272728h56.888889c28.444444 0 46.545455 20.686869 46.545454 49.131314s-17.583838 49.131313-46.545454 49.131313h-31.030303v46.545454h-25.858586v-144.808081z"
fill="#230091" p-id="14231"></path>
<path d="M415.806061 443.216162h-31.030303v137.567676H321.163636V196.525253h93.090909c91.022222 0 140.670707 35.684848 140.670708 122.052525 0.517172 103.434343-92.573737 124.638384-139.119192 124.638384z m-5.688889-192.905051c-6.206061 0-14.99798 0.517172-26.89293 1.551515V387.878788h36.202021C461.834343 387.878788 491.313131 366.157576 491.313131 312.888889c0-40.856566-32.064646-62.577778-81.195959-62.577778z m258.068687 337.19596c70.852525 0 96.711111-50.165657 96.711111-84.816162 0-54.820202-35.684848-67.749495-66.19798-87.40202-25.858586-17.066667-49.648485-23.272727-49.648485-40.856566 0-22.755556 15.515152-27.410101 36.20202-27.410101 25.858586 0 54.820202 2.068687 67.232323 16.032323V306.682828c-12.929293-10.343434-37.236364-13.446465-68.783838-13.446464-67.749495 0-93.608081 44.993939-93.608081 84.29899 0 50.682828 33.616162 65.680808 66.19798 83.781818 21.20404 11.894949 46.545455 20.686869 46.545455 44.476767 0 13.963636-8.791919 27.927273-37.753536 27.927273-26.892929 0-59.991919-10.343434-74.989899-23.789899v59.991919c13.446465 10.343434 40.339394 17.583838 78.09293 17.583839z"
fill="#7AB7FF" p-id="14232"></path>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514189544355" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8186" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M176 1024l672 0c26.464 0 48-21.536 48-48l0-672c0-0.544-0.256-0.992-0.288-1.504-0.064-0.736-0.256-1.376-0.416-2.08-0.544-2.272-1.472-4.32-2.88-6.112-0.224-0.288-0.192-0.64-0.416-0.928l-256-288c-0.096-0.096-0.224-0.096-0.32-0.192-1.92-2.048-4.352-3.456-7.136-4.288-0.608-0.192-1.152-0.256-1.792-0.352-0.928-0.16-1.792-0.544-2.752-0.544l-448 0c-26.464 0-48 21.536-48 48l0 928c0 26.464 21.536 48 48 48zM640 58.08l204.384 229.92-188.384 0c-7.04 0-16-13.44-16-24l0-205.92zM160 48c0-8.832 7.2-16 16-16l432 0 0 232c0 25.888 20.96 56 48 56l208 0 0 656c0 8.832-7.2 16-16 16l-672 0c-8.96 0-16-7.04-16-16l0-928zM304 448l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 576l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 320l192 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-192 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 704l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 832l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16z" p-id="8187"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,10 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514189544355" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="8186" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M176 1024l672 0c26.464 0 48-21.536 48-48l0-672c0-0.544-0.256-0.992-0.288-1.504-0.064-0.736-0.256-1.376-0.416-2.08-0.544-2.272-1.472-4.32-2.88-6.112-0.224-0.288-0.192-0.64-0.416-0.928l-256-288c-0.096-0.096-0.224-0.096-0.32-0.192-1.92-2.048-4.352-3.456-7.136-4.288-0.608-0.192-1.152-0.256-1.792-0.352-0.928-0.16-1.792-0.544-2.752-0.544l-448 0c-26.464 0-48 21.536-48 48l0 928c0 26.464 21.536 48 48 48zM640 58.08l204.384 229.92-188.384 0c-7.04 0-16-13.44-16-24l0-205.92zM160 48c0-8.832 7.2-16 16-16l432 0 0 232c0 25.888 20.96 56 48 56l208 0 0 656c0 8.832-7.2 16-16 16l-672 0c-8.96 0-16-7.04-16-16l0-928zM304 448l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 576l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 320l192 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-192 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 704l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16zM304 832l416 0c8.832 0 16-7.168 16-16s-7.168-16-16-16l-416 0c-8.832 0-16 7.168-16 16s7.168 16 16 16z"
p-id="8187"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,23 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1514189554639" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="8871" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M80 34.4h864v960H80z" fill="#8095FF" p-id="8872"></path>
<path d="M176 112m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8873"></path>
<path d="M176 272m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8874"></path>
<path d="M176 432m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8875"></path>
<path d="M176 592m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8876"></path>
<path d="M176 752m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8877"></path>
<path d="M176 912m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8878"></path>
<path d="M864 112m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8879"></path>
<path d="M864 272m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8880"></path>
<path d="M864 432m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8881"></path>
<path d="M864 592m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8882"></path>
<path d="M864 752m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8883"></path>
<path d="M864 912m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8884"></path>
<path d="M648 508L436 362.4c-4.8-3.2-11.2-4-16.8-0.8-5.6 3.2-8.8 8.8-8.8 14.4v290.4c0 5.6 3.2 11.2 8.8 14.4 5.6 3.2 12 2.4 16.8-0.8L648 533.6c4.8-2.4 7.2-8 7.2-12.8 0-4.8-3.2-9.6-7.2-12.8z"
fill="#FFFFFF" p-id="8885"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1514189554639" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8871" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M80 34.4h864v960H80z" fill="#8095FF" p-id="8872"></path><path d="M176 112m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8873"></path><path d="M176 272m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8874"></path><path d="M176 432m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8875"></path><path d="M176 592m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8876"></path><path d="M176 752m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8877"></path><path d="M176 912m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8878"></path><path d="M864 112m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8879"></path><path d="M864 272m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8880"></path><path d="M864 432m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8881"></path><path d="M864 592m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8882"></path><path d="M864 752m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8883"></path><path d="M864 912m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#FFFFFF" p-id="8884"></path><path d="M648 508L436 362.4c-4.8-3.2-11.2-4-16.8-0.8-5.6 3.2-8.8 8.8-8.8 14.4v290.4c0 5.6 3.2 11.2 8.8 14.4 5.6 3.2 12 2.4 16.8-0.8L648 533.6c4.8-2.4 7.2-8 7.2-12.8 0-4.8-3.2-9.6-7.2-12.8z" fill="#FFFFFF" p-id="8885"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -1,17 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1543300142282" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="2233" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path d="M534.310676 38.36489h65.428495v88.119185c110.25913 0 220.507245 0.220298 330.766374-0.330447 18.615178 0.771043 39.113903-0.550745 55.305803 10.574302 11.345345 16.302049 10.023557 37.010058 10.783586 55.746399-0.550745 191.218631-0.319432 382.327112-0.220298 573.435594-0.550745 32.053353 2.974022 64.767601-3.745066 96.380358-4.405959 22.910988-31.943204 23.461733-50.338084 24.232776-114.114344 0.330447-228.338837-0.220298-342.56333 0v99.134083h-68.402517c-167.867047-30.511268-336.075555-58.709407-504.151885-88.119185v-770.932716c169.0897-29.420793 338.168386-58.389975 507.136922-88.240349z"
fill="#207245" p-id="2234"></path>
<path d="M599.739171 159.528769h363.491636v693.938579h-363.491636v-66.089389h88.119184v-77.104286h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-66.089388z"
fill="#FFFFFF" p-id="2235"></path>
<path d="M731.917948 225.618157h154.208573v77.104287h-154.208573v-77.104287z" fill="#207245" p-id="2236"></path>
<path d="M353.44605 328.827752c24.89367-1.762384 49.897488-3.304469 74.901307-4.516108-29.409778 60.251492-58.929705 120.502985-88.879213 180.53418 30.29097 61.683429 61.242833 122.926263 91.632937 184.609692-26.545904-1.553101-52.98166-3.19432-79.527564-5.066854-18.725327-45.932125-41.526166-90.322164-54.964342-138.358134-14.969246 44.731501-36.349164 86.918561-53.521389 130.74684-24.122627-0.330447-48.256268-1.321788-72.367881-2.313129 28.308288-55.404937 55.625235-111.250471 84.814716-166.324961-24.783521-56.726725-52.001334-112.35196-77.544883-168.748238 24.232776-1.431937 48.454537-2.863874 72.698327-4.185662 16.412198 43.068251 34.366482 85.585758 47.925822 129.7555 14.506621-46.802302 36.216985-90.861894 54.832163-136.133126z"
fill="#FFFFFF" p-id="2237"></path>
<path d="M731.917948 346.782036h154.208573v77.104287h-154.208573v-77.104287zM731.917948 467.945915h154.208573v77.104287h-154.208573v-77.104287zM731.917948 589.109794h154.208573v77.104287h-154.208573v-77.104287zM731.917948 710.273673h154.208573v77.104286h-154.208573v-77.104286z"
fill="#207245" p-id="2238"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543300142282" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2233" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M534.310676 38.36489h65.428495v88.119185c110.25913 0 220.507245 0.220298 330.766374-0.330447 18.615178 0.771043 39.113903-0.550745 55.305803 10.574302 11.345345 16.302049 10.023557 37.010058 10.783586 55.746399-0.550745 191.218631-0.319432 382.327112-0.220298 573.435594-0.550745 32.053353 2.974022 64.767601-3.745066 96.380358-4.405959 22.910988-31.943204 23.461733-50.338084 24.232776-114.114344 0.330447-228.338837-0.220298-342.56333 0v99.134083h-68.402517c-167.867047-30.511268-336.075555-58.709407-504.151885-88.119185v-770.932716c169.0897-29.420793 338.168386-58.389975 507.136922-88.240349z" fill="#207245" p-id="2234"></path><path d="M599.739171 159.528769h363.491636v693.938579h-363.491636v-66.089389h88.119184v-77.104286h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-44.059592h88.119184v-77.104287h-88.119184v-66.089388z" fill="#FFFFFF" p-id="2235"></path><path d="M731.917948 225.618157h154.208573v77.104287h-154.208573v-77.104287z" fill="#207245" p-id="2236"></path><path d="M353.44605 328.827752c24.89367-1.762384 49.897488-3.304469 74.901307-4.516108-29.409778 60.251492-58.929705 120.502985-88.879213 180.53418 30.29097 61.683429 61.242833 122.926263 91.632937 184.609692-26.545904-1.553101-52.98166-3.19432-79.527564-5.066854-18.725327-45.932125-41.526166-90.322164-54.964342-138.358134-14.969246 44.731501-36.349164 86.918561-53.521389 130.74684-24.122627-0.330447-48.256268-1.321788-72.367881-2.313129 28.308288-55.404937 55.625235-111.250471 84.814716-166.324961-24.783521-56.726725-52.001334-112.35196-77.544883-168.748238 24.232776-1.431937 48.454537-2.863874 72.698327-4.185662 16.412198 43.068251 34.366482 85.585758 47.925822 129.7555 14.506621-46.802302 36.216985-90.861894 54.832163-136.133126z" fill="#FFFFFF" p-id="2237"></path><path d="M731.917948 346.782036h154.208573v77.104287h-154.208573v-77.104287zM731.917948 467.945915h154.208573v77.104287h-154.208573v-77.104287zM731.917948 589.109794h154.208573v77.104287h-154.208573v-77.104287zM731.917948 710.273673h154.208573v77.104286h-154.208573v-77.104286z" fill="#207245" p-id="2238"></path></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+2 -2
View File
@@ -11,10 +11,10 @@
@REM prepare the variables.
@REM version name
SET VERSION_NAME=tank-4.0.0.beta1
SET VERSION_NAME=tank-3.1.2
ECHO VERSION_NAME: %VERSION_NAME%
@REM golang proxy
SET GOPROXY=https://goproxy.cn
SET GOPROXY=https://athens.azurefd.net
ECHO GOPROXY: %GOPROXY%
@REM assign variable like Linux GOARCH=$(go env GOARCH) eg. amd64
FOR /f %%i IN ('go env GOARCH') DO SET GOARCH=%%i
+2 -3
View File
@@ -1,5 +1,4 @@
#!/bin/bash
set -e
###########################################################################
#
@@ -10,10 +9,10 @@ set -e
#prepare the variables.
# version name
VERSION_NAME=tank-4.0.0.beta1
VERSION_NAME=tank-3.1.2
echo "VERSION_NAME: ${VERSION_NAME}"
# golang proxy
GOPROXY=https://goproxy.cn
GOPROXY=https://athens.azurefd.net
echo "GOPROXY: ${GOPROXY}"
# eg. amd64
GOARCH=$(go env GOARCH)
+11 -12
View File
@@ -1,7 +1,5 @@
package core
import "gorm.io/gorm/schema"
const (
//authentication key of cookie
COOKIE_AUTH_KEY = "_ak"
@@ -11,25 +9,26 @@ const (
DEFAULT_SERVER_PORT = 6010
//db table's prefix. tank40_ means current version is tank:4.0.x
TABLE_PREFIX = "tank40_"
//db table's prefix. tank31_ means current version is tank:3.1.x
TABLE_PREFIX = "tank31_"
VERSION = "4.0.0.beta1"
VERSION = "3.1.2"
)
type Config interface {
Installed() bool
ServerPort() int
//get the db type
DbType() string
//get the mysql url. eg. tank:tank123@tcp(127.0.0.1:3306)/tank?charset=utf8&parseTime=True&loc=Local
MysqlUrl() string
//get the sqlite path
SqliteFolder() string
//files storage location.
MatterPath() string
//table name strategy
NamingStrategy() schema.NamingStrategy
OssAccessKey() string
OssSecretKey() string
OssEndpoint() string
OssCustomHost() string
OssBucket() string
//when installed by user. Write configs to tank.json
FinishInstall(dbType string, mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string, mysqlCharset string)
FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string, mysqlCharset string)
}
+1 -1
View File
@@ -2,7 +2,7 @@ package core
import (
"github.com/eyebluecn/tank/code/tool/cache"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"net/http"
)
+30 -47
View File
@@ -12,16 +12,14 @@ import (
type AlienController struct {
BaseController
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
matterDao *MatterDao
spaceDao *SpaceDao
matterService *MatterService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
alienService *AlienService
shareService *ShareService
spaceMemberService *SpaceMemberService
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
matterDao *MatterDao
matterService *MatterService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
alienService *AlienService
shareService *ShareService
}
func (this *AlienController) Init() {
@@ -42,11 +40,6 @@ func (this *AlienController) Init() {
this.matterDao = c
}
b = core.CONTEXT.GetBean(this.spaceDao)
if c, ok := b.(*SpaceDao); ok {
this.spaceDao = c
}
b = core.CONTEXT.GetBean(this.matterService)
if c, ok := b.(*MatterService); ok {
this.matterService = c
@@ -71,11 +64,6 @@ func (this *AlienController) Init() {
if c, ok := b.(*ShareService); ok {
this.shareService = c
}
b = core.CONTEXT.GetBean(this.spaceMemberService)
if b, ok := b.(*SpaceMemberService); ok {
this.spaceMemberService = b
}
}
func (this *AlienController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
@@ -92,7 +80,7 @@ func (this *AlienController) RegisterRoutes() map[string]func(writer http.Respon
return routeMap
}
// handle some special routes, eg. params in the url.
//handle some special routes, eg. params in the url.
func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) {
path := request.URL.Path
@@ -120,7 +108,7 @@ func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *h
return nil, false
}
// fetch a upload token for guest. Guest can upload file with this token.
//fetch a upload token for guest. Guest can upload file with this token.
func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, request *http.Request) *result.WebResult {
filename := request.FormValue("filename")
@@ -163,8 +151,7 @@ func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, reques
}
user := this.checkUser(request)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
dirMatter := this.matterService.CreateDirectories(request, user, space, dirPath)
dirMatter := this.matterService.CreateDirectories(request, user, dirPath)
uploadToken := &UploadToken{
UserUuid: user.Uuid,
@@ -183,7 +170,7 @@ func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, reques
}
// user confirm a file whether uploaded successfully.
//user confirm a file whether uploaded successfully.
func (this *AlienController) Confirm(writer http.ResponseWriter, request *http.Request) *result.WebResult {
matterUuid := request.FormValue("matterUuid")
@@ -201,7 +188,7 @@ func (this *AlienController) Confirm(writer http.ResponseWriter, request *http.R
return this.Success(matter)
}
// a guest upload a file with a upload token.
//a guest upload a file with a upload token.
func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Request) *result.WebResult {
//allow cors.
this.allowCORS(writer)
@@ -229,7 +216,6 @@ func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Re
}
user := this.userDao.CheckByUuid(uploadToken.UserUuid)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
err = request.ParseMultipartForm(32 << 20)
this.PanicError(err)
@@ -242,9 +228,9 @@ func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Re
panic(result.BadRequest("file size doesn't the one in uploadToken"))
}
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, space)
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, user)
matter := this.matterService.Upload(request, file, handler, user, space, dirMatter, uploadToken.Filename, uploadToken.Privacy)
matter := this.matterService.Upload(request, file, user, dirMatter, uploadToken.Filename, uploadToken.Privacy)
//expire the upload token.
uploadToken.ExpireTime = time.Now()
@@ -253,7 +239,7 @@ func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Re
return this.Success(matter)
}
// crawl a url with uploadToken. guest can visit this method.
//crawl a url with uploadToken. guest can visit this method.
func (this *AlienController) CrawlToken(writer http.ResponseWriter, request *http.Request) *result.WebResult {
//allow cors.
@@ -277,11 +263,10 @@ func (this *AlienController) CrawlToken(writer http.ResponseWriter, request *htt
}
user := this.userDao.CheckByUuid(uploadToken.UserUuid)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, space)
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, user)
matter := this.matterService.AtomicCrawl(request, url, uploadToken.Filename, user, space, dirMatter, uploadToken.Privacy)
matter := this.matterService.AtomicCrawl(request, url, uploadToken.Filename, user, dirMatter, uploadToken.Privacy)
//expire the upload token.
uploadToken.ExpireTime = time.Now()
@@ -290,7 +275,7 @@ func (this *AlienController) CrawlToken(writer http.ResponseWriter, request *htt
return this.Success(matter)
}
// crawl a url directly. only user can visit this method.
//crawl a url directly. only user can visit this method.
func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *http.Request) *result.WebResult {
filename := request.FormValue("filename")
@@ -306,15 +291,14 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht
}
user := this.checkUser(request)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
dirMatter := this.matterService.CreateDirectories(request, user, space, dirPath)
dirMatter := this.matterService.CreateDirectories(request, user, dirPath)
matter := this.matterService.AtomicCrawl(request, url, filename, user, space, dirMatter, privacy)
matter := this.matterService.AtomicCrawl(request, url, filename, user, dirMatter, privacy)
return this.Success(matter)
}
// fetch a download token for guest. Guest can download file with this token.
//fetch a download token for guest. Guest can download file with this token.
func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, request *http.Request) *result.WebResult {
matterUuid := request.FormValue("matterUuid")
@@ -327,9 +311,8 @@ func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, requ
user := this.checkUser(request)
matter := this.matterDao.CheckByUuid(matterUuid)
canRead := this.spaceMemberService.canRead(user, matter.SpaceUuid)
if !canRead {
panic(result.BadRequest("no auth to visit this file."))
if matter.UserUuid != user.Uuid {
panic(result.BadRequest("matter not belong to you"))
}
var expireTime time.Time
@@ -355,14 +338,14 @@ func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, requ
}
// preview a file.
//preview a file.
func (this *AlienController) Preview(writer http.ResponseWriter, request *http.Request, uuid string, filename string) {
matter := this.alienService.ValidMatter(writer, request, uuid, filename)
this.alienService.PreviewOrDownload(writer, request, matter, false)
this.alienService.PreviewOrDownload(writer, request, uuid, filename, false)
}
// download a file.
//download a file.
func (this *AlienController) Download(writer http.ResponseWriter, request *http.Request, uuid string, filename string) {
matter := this.alienService.ValidMatter(writer, request, uuid, filename)
this.alienService.PreviewOrDownload(writer, request, matter, true)
this.alienService.PreviewOrDownload(writer, request, uuid, filename, true)
}
+13 -27
View File
@@ -8,7 +8,7 @@ import (
"time"
)
// @Service
//@Service
type AlienService struct {
BaseBean
matterDao *MatterDao
@@ -19,7 +19,6 @@ type AlienService struct {
shareService *ShareService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
spaceService *SpaceService
}
func (this *AlienService) Init() {
@@ -64,18 +63,14 @@ func (this *AlienService) Init() {
if c, ok := b.(*ImageCacheService); ok {
this.imageCacheService = c
}
b = core.CONTEXT.GetBean(this.spaceService)
if c, ok := b.(*SpaceService); ok {
this.spaceService = c
}
}
// check whether the request params ok.
func (this *AlienService) ValidMatter(
func (this *AlienService) PreviewOrDownload(
writer http.ResponseWriter,
request *http.Request,
uuid string,
filename string) *Matter {
filename string,
withContentDisposition bool) {
matter := this.matterDao.CheckByUuid(uuid)
@@ -109,28 +104,18 @@ func (this *AlienService) ValidMatter(
} else {
//whether this is myself's matter.
operator := this.findUser(request)
if operator == nil {
panic(result.BadRequest("no auth"))
}
if matter.SpaceUuid != operator.SpaceUuid {
//whether user has the space's read auth.
this.spaceService.CheckReadableByUuid(request, operator, matter.SpaceUuid)
}
//use share code to auth.
shareUuid := request.FormValue("shareUuid")
shareCode := request.FormValue("shareCode")
shareRootUuid := request.FormValue("shareRootUuid")
this.shareService.ValidateMatter(request, shareUuid, shareCode, operator, shareRootUuid, matter)
}
}
return matter
}
func (this *AlienService) PreviewOrDownload(
writer http.ResponseWriter,
request *http.Request,
matter *Matter,
withContentDisposition bool,
) {
//download directory
if matter.Dir {
@@ -150,7 +135,7 @@ func (this *AlienService) PreviewOrDownload(
}
//download the cache image file.
this.matterService.DownloadFile(writer, request, GetSpaceCacheRootDir(imageCache.Username)+imageCache.Path, imageCache.Name, withContentDisposition)
this.matterService.DownloadFile(writer, request, GetUserCacheRootDir(imageCache.Username)+imageCache.Path, imageCache.Name, withContentDisposition)
} else {
this.matterService.DownloadFile(writer, request, matter.AbsolutePath(), matter.Name, withContentDisposition)
@@ -160,6 +145,7 @@ func (this *AlienService) PreviewOrDownload(
//async increase the download times.
go core.RunWithRecovery(func() {
this.matterDao.TimesIncrement(matter.Uuid)
this.matterDao.TimesIncrement(uuid)
})
}
+6 -61
View File
@@ -13,10 +13,8 @@ import (
type BaseController struct {
BaseBean
userDao *UserDao
spaceDao *SpaceDao
spaceService *SpaceService
sessionDao *SessionDao
userDao *UserDao
sessionDao *SessionDao
}
func (this *BaseController) Init() {
@@ -28,16 +26,6 @@ func (this *BaseController) Init() {
this.userDao = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.spaceService)
if b, ok := b.(*SpaceService); ok {
this.spaceService = b
}
b = core.CONTEXT.GetBean(this.sessionDao)
if b, ok := b.(*SessionDao); ok {
this.sessionDao = b
@@ -50,12 +38,12 @@ func (this *BaseController) RegisterRoutes() map[string]func(writer http.Respons
return make(map[string]func(writer http.ResponseWriter, request *http.Request))
}
// handle some special routes, eg. params in the url.
//handle some special routes, eg. params in the url.
func (this *BaseController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) {
return nil, false
}
// wrap the handle method.
//wrap the handle method.
func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *http.Request) *result.WebResult, qualifiedRole string) func(w http.ResponseWriter, r *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
@@ -99,50 +87,7 @@ func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *htt
}
}
// wrap the handle method without result.
func (this *BaseController) WrapPure(f func(writer http.ResponseWriter, request *http.Request), qualifiedRole string) func(w http.ResponseWriter, r *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
var webResult *result.WebResult = nil
//if the api not annotated with GUEST. login is required.
if qualifiedRole != USER_ROLE_GUEST {
user := this.checkUser(request)
if user.Status == USER_STATUS_DISABLED {
//check user's status
webResult = result.CustomWebResultI18n(request, result.USER_DISABLED, i18n.UserDisabled)
} else {
if qualifiedRole == USER_ROLE_ADMINISTRATOR && user.Role != USER_ROLE_ADMINISTRATOR {
webResult = result.ConstWebResult(result.UNAUTHORIZED)
}
}
}
//if webResult not nil. response a json. if webResult is nil, return empty body or binary content.
if webResult != nil {
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
b, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(webResult)
this.PanicError(err)
writer.WriteHeader(result.FetchHttpStatus(webResult.Code))
_, err = fmt.Fprintf(writer, string(b))
this.PanicError(err)
}
//no error.
f(writer, request)
}
}
// response a success result. 1.string 2. WebResult 3.nil pointer 4.any type
//response a success result. 1.string 2. WebResult 3.nil pointer 4.any type
func (this *BaseController) Success(data interface{}) *result.WebResult {
var webResult *result.WebResult = nil
if value, ok := data.(string); ok {
@@ -161,7 +106,7 @@ func (this *BaseController) Success(data interface{}) *result.WebResult {
return webResult
}
// allow cors.
//allow cors.
func (this *BaseController) allowCORS(writer http.ResponseWriter) {
util.AllowCORS(writer)
}
+19
View File
@@ -2,6 +2,7 @@ package rest
import (
"math"
"time"
)
const (
@@ -15,6 +16,24 @@ const (
EMPTY_JSON_ARRAY = "[]"
)
type IBase interface {
//name of db table
TableName() string
}
// Mysql 5.5 only support one CURRENT_TIMESTAMP
// so we use 2018-01-01 00:00:00 as default, which is the first release date of EyeblueTank
type Base struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
}
func (this *Base) TableName() string {
panic("you should overwrite TableName()")
}
//pager
type Pager struct {
Page int `json:"page"`
+3 -3
View File
@@ -5,7 +5,7 @@ import (
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"time"
)
@@ -69,7 +69,7 @@ func (this *BridgeDao) PlainPage(page int, pageSize int, shareUuid string, sortA
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Bridge{}).Where(wp.Query, wp.Args...)
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
@@ -77,7 +77,7 @@ func (this *BridgeDao) PlainPage(page int, pageSize int, shareUuid string, sortA
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&bridges)
this.PanicError(db.Error)
return int(count), bridges
return count, bridges
}
//get pager
+10 -7
View File
@@ -1,15 +1,18 @@
package rest
import "time"
import (
"github.com/eyebluecn/tank/code/core"
)
/**
* the link table for Share and Matter.
*/
type Bridge struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
ShareUuid string `json:"shareUuid" gorm:"type:char(36)"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36)"`
Base
ShareUuid string `json:"shareUuid" gorm:"type:char(36)"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36)"`
}
func (this *Bridge) TableName() string {
return core.TABLE_PREFIX + "bridge"
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"time"
)
@@ -61,14 +61,14 @@ func (this *DashboardDao) Page(page int, pageSize int, dt string, sortArray []bu
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Dashboard{}).Where(wp.Query, wp.Args...)
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var dashboards []*Dashboard
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&dashboards)
this.PanicError(db.Error)
pager := NewPager(page, pageSize, int(count), dashboards)
pager := NewPager(page, pageSize, count, dashboards)
return pager
}
+17 -15
View File
@@ -1,25 +1,27 @@
package rest
import "time"
import "github.com/eyebluecn/tank/code/core"
/**
* application's dashboard.
*/
type Dashboard struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
InvokeNum int64 `json:"invokeNum" gorm:"type:bigint(20) not null"` //api invoke num.
TotalInvokeNum int64 `json:"totalInvokeNum" gorm:"type:bigint(20) not null;default:0"` //total invoke num up to now.
Uv int64 `json:"uv" gorm:"type:bigint(20) not null;default:0"` //today's uv
TotalUv int64 `json:"totalUv" gorm:"type:bigint(20) not null;default:0"` //total uv
MatterNum int64 `json:"matterNum" gorm:"type:bigint(20) not null;default:0"` //file's num
TotalMatterNum int64 `json:"totalMatterNum" gorm:"type:bigint(20) not null;default:0"` //file's total number
FileSize int64 `json:"fileSize" gorm:"type:bigint(20) not null;default:0"` //today's file size
TotalFileSize int64 `json:"totalFileSize" gorm:"type:bigint(20) not null;default:0"` //total file's size
AvgCost int64 `json:"avgCost" gorm:"type:bigint(20) not null;default:0"` //api time cost in ms
Dt string `json:"dt" gorm:"type:varchar(45) not null;index:idx_dt"` //date. index should unique globally.
Base
InvokeNum int64 `json:"invokeNum" gorm:"type:bigint(20) not null"` //api invoke num.
TotalInvokeNum int64 `json:"totalInvokeNum" gorm:"type:bigint(20) not null;default:0"` //total invoke num up to now.
Uv int64 `json:"uv" gorm:"type:bigint(20) not null;default:0"` //today's uv
TotalUv int64 `json:"totalUv" gorm:"type:bigint(20) not null;default:0"` //total uv
MatterNum int64 `json:"matterNum" gorm:"type:bigint(20) not null;default:0"` //file's num
TotalMatterNum int64 `json:"totalMatterNum" gorm:"type:bigint(20) not null;default:0"` //file's total number
FileSize int64 `json:"fileSize" gorm:"type:bigint(20) not null;default:0"` //today's file size
TotalFileSize int64 `json:"totalFileSize" gorm:"type:bigint(20) not null;default:0"` //total file's size
AvgCost int64 `json:"avgCost" gorm:"type:bigint(20) not null;default:0"` //api time cost in ms
Dt string `json:"dt" gorm:"type:varchar(45) not null;index:idx_dt"` //date
}
// set File's table name to be `profiles`
func (this *Dashboard) TableName() string {
return core.TABLE_PREFIX + "dashboard"
}
/**
+3 -16
View File
@@ -25,7 +25,6 @@ type DavController struct {
BaseController
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
spaceDao *SpaceDao
matterDao *MatterDao
matterService *MatterService
imageCacheDao *ImageCacheDao
@@ -51,11 +50,6 @@ func (this *DavController) Init() {
this.matterDao = c
}
b = core.CONTEXT.GetBean(this.spaceDao)
if c, ok := b.(*SpaceDao); ok {
this.spaceDao = c
}
b = core.CONTEXT.GetBean(this.matterService)
if c, ok := b.(*MatterService); ok {
this.matterService = c
@@ -77,7 +71,7 @@ func (this *DavController) Init() {
}
}
// Auth user by BasicAuth
//Auth user by BasicAuth
func (this *DavController) CheckCurrentUser(writer http.ResponseWriter, request *http.Request) *User {
username, password, ok := request.BasicAuth()
@@ -106,7 +100,7 @@ func (this *DavController) RegisterRoutes() map[string]func(writer http.Response
return routeMap
}
// handle some special routes, eg. params in the url.
//handle some special routes, eg. params in the url.
func (this *DavController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) {
path := request.URL.Path
@@ -117,16 +111,10 @@ func (this *DavController) HandleRoutes(writer http.ResponseWriter, request *htt
strs := reg.FindStringSubmatch(path)
if len(strs) == 2 {
var f = func(writer http.ResponseWriter, request *http.Request) {
if err := recover(); err != nil {
this.logger.Error("occur error in webdav: %v", err)
}
subPath := strs[1]
//guarantee subPath not end with /
subPath = strings.TrimSuffix(subPath, "/")
this.Index(writer, request, subPath)
}
return f, true
}
@@ -178,8 +166,7 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque
//this.debug(writer, request, subPath)
user := this.CheckCurrentUser(writer, request)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
this.davService.HandleDav(writer, request, user, space, subPath)
this.davService.HandleDav(writer, request, user, subPath)
}
+17 -17
View File
@@ -9,19 +9,19 @@ import (
"strconv"
)
// webdav url prefix.
//webdav url prefix.
var WEBDAV_PREFIX = "/api/dav"
// live prop.
//live prop.
type LiveProp struct {
findFn func(space *Space, matter *Matter) string
findFn func(user *User, matter *Matter) string
dir bool
}
// all live prop map.
//all live prop map.
var LivePropMap = map[xml.Name]LiveProp{
{Space: "DAV:", Local: "resourcetype"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
if matter.Dir {
return `<D:collection xmlns:D="DAV:"/>`
} else {
@@ -31,7 +31,7 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: true,
},
{Space: "DAV:", Local: "displayname"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
if path.Clean("/"+matter.Name) == "/" {
return ""
} else {
@@ -41,13 +41,13 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: true,
},
{Space: "DAV:", Local: "getcontentlength"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
return strconv.FormatInt(matter.Size, 10)
},
dir: false,
},
{Space: "DAV:", Local: "getlastmodified"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
return matter.UpdateTime.UTC().Format(http.TimeFormat)
},
// http://webdav.org/specs/rfc4918.html#PROPERTY_getlastmodified
@@ -68,7 +68,7 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: false,
},
{Space: "DAV:", Local: "getcontenttype"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
if matter.Dir {
return ""
} else {
@@ -78,7 +78,7 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: false,
},
{Space: "DAV:", Local: "getetag"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
return fmt.Sprintf(`"%x%x"`, matter.UpdateTime.UnixNano(), matter.Size)
},
// findETag implements ETag as the concatenated hex values of a file's
@@ -91,7 +91,7 @@ var LivePropMap = map[xml.Name]LiveProp{
// active locks on a resource.
{Space: "DAV:", Local: "lockdiscovery"}: {},
{Space: "DAV:", Local: "supportedlock"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
return `` +
`<D:lockentry xmlns:D="DAV:">` +
`<D:lockscope><D:exclusive/></D:lockscope>` +
@@ -101,11 +101,11 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: true,
},
{Space: "DAV:", Local: "quota-available-bytes"}: {
findFn: func(space *Space, matter *Matter) string {
findFn: func(user *User, matter *Matter) string {
var size int64 = 0
if space.TotalSizeLimit >= 0 {
if space.TotalSizeLimit-space.TotalSize > 0 {
size = space.TotalSizeLimit - space.TotalSize
if user.TotalSizeLimit >= 0 {
if user.TotalSizeLimit-user.TotalSize > 0 {
size = user.TotalSizeLimit - user.TotalSize
} else {
size = 0
}
@@ -118,8 +118,8 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: true,
},
{Space: "DAV:", Local: "quota-used-bytes"}: {
findFn: func(space *Space, matter *Matter) string {
return fmt.Sprintf(`%d`, space.TotalSize)
findFn: func(user *User, matter *Matter) string {
return fmt.Sprintf(`%d`, user.TotalSize)
},
dir: true,
},
+60 -60
View File
@@ -49,7 +49,7 @@ func (this *DavService) Init() {
this.lockSystem = webdav.NewMemLS()
}
// get the depth in header. Not support infinity yet.
//get the depth in header. Not support infinity yet.
func (this *DavService) ParseDepth(request *http.Request) int {
depth := 1
@@ -88,8 +88,8 @@ func (this *DavService) makePropstatResponse(href string, pstats []dav.Propstat)
return &resp
}
// fetch a matter's []dav.Propstat
func (this *DavService) PropstatsFromXmlNames(user *User, space *Space, matter *Matter, xmlNames []xml.Name) []dav.Propstat {
//fetch a matter's []dav.Propstat
func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNames []xml.Name) []dav.Propstat {
propstats := make([]dav.Propstat, 0)
@@ -101,7 +101,7 @@ func (this *DavService) PropstatsFromXmlNames(user *User, space *Space, matter *
// Otherwise, it must either be a live property or we don't know it.
if liveProp := LivePropMap[xmlName]; liveProp.findFn != nil && (liveProp.dir || !matter.Dir) {
innerXML := liveProp.findFn(space, matter)
innerXML := liveProp.findFn(user, matter)
okProperties = append(okProperties, dav.Property{
XMLName: xmlName,
@@ -162,7 +162,7 @@ func (this *DavService) AllPropXmlNames(matter *Matter) []xml.Name {
return pnames
}
func (this *DavService) Propstats(user *User, space *Space, matter *Matter, propfind *dav.Propfind) []dav.Propstat {
func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Propfind) []dav.Propstat {
propstats := make([]dav.Propstat, 0)
if propfind.Propname != nil {
@@ -172,18 +172,18 @@ func (this *DavService) Propstats(user *User, space *Space, matter *Matter, prop
//TODO: if include other things. add to it.
xmlNames := this.AllPropXmlNames(matter)
propstats = this.PropstatsFromXmlNames(user, space, matter, xmlNames)
propstats = this.PropstatsFromXmlNames(user, matter, xmlNames)
} else {
propstats = this.PropstatsFromXmlNames(user, space, matter, propfind.Prop)
propstats = this.PropstatsFromXmlNames(user, matter, propfind.Prop)
}
return propstats
}
// list the directory.
func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//list the directory.
func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("PROPFIND %s\n", subPath)
@@ -193,7 +193,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
propfind := dav.ReadPropfind(request.Body)
//find the matter, if subPath is null, means the root directory.
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
var matters []*Matter
if depth == 0 {
@@ -213,7 +213,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
fmt.Printf("handle Matter %s\n", matter.Path)
propstats := this.Propstats(user, space, matter, propfind)
propstats := this.Propstats(user, matter, propfind)
visitPath := fmt.Sprintf("%s%s", WEBDAV_PREFIX, matter.Path)
response := this.makePropstatResponse(visitPath, propstats)
@@ -228,7 +228,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
}
// change the file's property
//change the file's property
func (this *DavService) HandleProppatch(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("PROPPATCH %s\n", subPath)
@@ -251,7 +251,7 @@ func (this *DavService) HandleProppatch(writer http.ResponseWriter, request *htt
patches, status, err := webdav.ReadProppatch(request.Body)
this.PanicError(err)
fmt.Printf("status:%v\n", status)
fmt.Println("status:%v", status)
//prepare a multiStatusWriter.
multiStatusWriter := &dav.MultiStatusWriter{Writer: writer}
@@ -296,16 +296,16 @@ func (this *DavService) HandleProppatch(writer http.ResponseWriter, request *htt
}
// handle download
func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//handle download
func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("GET %s\n", subPath)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
//if this is a Directory, it means Propfind
if matter.Dir {
this.HandlePropfind(writer, request, user, space, subPath)
this.HandlePropfind(writer, request, user, subPath)
return
}
@@ -314,8 +314,8 @@ func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *h
}
// upload a file
func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//upload a file
func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("PUT %s\n", subPath)
@@ -339,23 +339,23 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ
filename := util.GetFilenameOfPath(subPath)
dirPath := util.GetDirOfPath(subPath)
dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user, space)
dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user)
//if exist delete it.
srcMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, subPath)
if srcMatter != nil {
this.matterService.AtomicDelete(request, srcMatter, user, space)
this.matterService.AtomicDelete(request, srcMatter, user)
}
this.matterService.Upload(request, request.Body, nil, user, space, dirMatter, filename, true)
this.matterService.Upload(request, request.Body, user, dirMatter, filename, true)
//set the status code 201
writer.WriteHeader(http.StatusCreated)
}
// delete file
func (this *DavService) HandleDelete(w http.ResponseWriter, r *http.Request, user *User, space *Space, subPath string) {
//delete file
func (this *DavService) HandleDelete(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
fmt.Printf("DELETE %s\n", subPath)
@@ -371,13 +371,13 @@ func (this *DavService) HandleDelete(w http.ResponseWriter, r *http.Request, use
defer release()
}
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
this.matterService.AtomicDelete(r, matter, user, space)
this.matterService.AtomicDelete(r, matter, user)
}
// crate a directory
func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//crate a directory
func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("MKCOL %s\n", subPath)
@@ -395,34 +395,34 @@ func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Re
thisDirName := util.GetFilenameOfPath(subPath)
dirPath := util.GetDirOfPath(subPath)
dirMatter := this.matterDao.FindWithRootByPath(dirPath, user, space)
dirMatter := this.matterDao.FindWithRootByPath(dirPath, user)
if dirMatter == nil {
//throw conflict error
panic(result.CustomWebResult(result.CONFLICT, fmt.Sprintf("%s not exist", dirPath)))
}
//check whether col exists. (RFC2518:8.3.1)
dbMatter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, dirMatter.Uuid, TRUE, thisDirName)
dbMatter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, TRUE, thisDirName)
if dbMatter != nil {
panic(result.CustomWebResult(result.METHOD_NOT_ALLOWED, fmt.Sprintf("%s already exists", dirPath)))
}
//check whether file exists. (RFC2518:8.3.1)
fileMatter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, dirMatter.Uuid, FALSE, thisDirName)
fileMatter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, FALSE, thisDirName)
if fileMatter != nil {
panic(result.CustomWebResult(result.METHOD_NOT_ALLOWED, fmt.Sprintf("%s file already exists", dirPath)))
}
this.matterService.AtomicCreateDirectory(request, dirMatter, thisDirName, user, space)
this.matterService.AtomicCreateDirectory(request, dirMatter, thisDirName, user)
}
// cors options
func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, user *User, space *Space, subPath string) {
//cors options
func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
fmt.Printf("OPTIONS %s\n", subPath)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
allow := "OPTIONS, LOCK, PUT, MKCOL"
if matter.Dir {
@@ -439,11 +439,11 @@ func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, us
}
// prepare for moving or copying
//prepare for moving or copying
func (this *DavService) prepareMoveCopy(
writer http.ResponseWriter,
request *http.Request,
user *User, space *Space, subPath string) (
user *User, subPath string) (
srcMatter *Matter,
destDirMatter *Matter,
srcDirPath string,
@@ -506,14 +506,14 @@ func (this *DavService) prepareMoveCopy(
}
//source matter
srcMatter = this.matterDao.CheckWithRootByPath(subPath, user, space)
srcMatter = this.matterDao.CheckWithRootByPath(subPath, user)
//if source matter is root.
if srcMatter.Uuid == MATTER_ROOT {
panic(result.BadRequest("you cannot move the root directory"))
}
destDirMatter = this.matterDao.FindWithRootByPath(destinationDirPath, user, space)
destDirMatter = this.matterDao.FindWithRootByPath(destinationDirPath, user)
if destDirMatter == nil {
//throw conflict error
panic(result.CustomWebResult(result.CONFLICT, fmt.Sprintf("%s not exist", destinationDirPath)))
@@ -523,8 +523,8 @@ func (this *DavService) prepareMoveCopy(
}
// move or rename.
func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//move or rename.
func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("MOVE %s\n", subPath)
@@ -541,14 +541,14 @@ func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Req
defer release()
}
srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, space, subPath)
srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath)
//move to the new directory
if destinationDirPath == srcDirPath {
//if destination path not change. it means rename.
this.matterService.AtomicRename(request, srcMatter, destinationName, overwrite, user, space)
this.matterService.AtomicRename(request, srcMatter, destinationName, overwrite, user)
} else {
this.matterService.AtomicMove(request, srcMatter, destDirMatter, overwrite, user, space)
this.matterService.AtomicMove(request, srcMatter, destDirMatter, overwrite, user)
}
this.logger.Info("finish moving %s => %s", subPath, destDirMatter.Path)
@@ -562,12 +562,12 @@ func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Req
}
}
// copy file/directory
func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//copy file/directory
func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
fmt.Printf("COPY %s\n", subPath)
srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, space, subPath)
srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath)
// handle the lock feature.
release, status, err := this.confirmLocks(request, destDirMatter.Path+"/"+destinationName, "")
@@ -579,7 +579,7 @@ func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Req
}
//copy to the new directory
this.matterService.AtomicCopy(request, srcMatter, destDirMatter, destinationName, overwrite, user, space)
this.matterService.AtomicCopy(request, srcMatter, destDirMatter, destinationName, overwrite, user)
this.logger.Info("finish copying %s => %s", subPath, destDirMatter.Path)
@@ -688,7 +688,7 @@ func (h *DavService) confirmLocks(r *http.Request, src, dst string) (release fun
return nil, http.StatusLocked, webdav.ErrLocked
}
// lock.
//lock.
func (this *DavService) HandleLock(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
duration, err := webdav.ParseTimeout(r.Header.Get("Timeout"))
@@ -785,7 +785,7 @@ func (this *DavService) HandleLock(w http.ResponseWriter, r *http.Request, user
}
// unlock
//unlock
func (this *DavService) HandleUnlock(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
// http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the
@@ -810,44 +810,44 @@ func (this *DavService) HandleUnlock(w http.ResponseWriter, r *http.Request, use
}
}
// hanle all the request.
func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
//hanle all the request.
func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
method := request.Method
if method == "OPTIONS" {
//cors option
this.HandleOptions(writer, request, user, space, subPath)
this.HandleOptions(writer, request, user, subPath)
} else if method == "GET" || method == "HEAD" || method == "POST" {
//get the detail of file. download
this.HandleGetHeadPost(writer, request, user, space, subPath)
this.HandleGetHeadPost(writer, request, user, subPath)
} else if method == "DELETE" {
//delete file
this.HandleDelete(writer, request, user, space, subPath)
this.HandleDelete(writer, request, user, subPath)
} else if method == "PUT" {
//upload file
this.HandlePut(writer, request, user, space, subPath)
this.HandlePut(writer, request, user, subPath)
} else if method == "MKCOL" {
//crate directory
this.HandleMkcol(writer, request, user, space, subPath)
this.HandleMkcol(writer, request, user, subPath)
} else if method == "COPY" {
//copy file/directory
this.HandleCopy(writer, request, user, space, subPath)
this.HandleCopy(writer, request, user, subPath)
} else if method == "MOVE" {
//move/rename a file or directory
this.HandleMove(writer, request, user, space, subPath)
this.HandleMove(writer, request, user, subPath)
} else if method == "LOCK" {
@@ -862,7 +862,7 @@ func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Requ
} else if method == "PROPFIND" {
//list a directory
this.HandlePropfind(writer, request, user, space, subPath)
this.HandlePropfind(writer, request, user, subPath)
} else if method == "PROPPATCH" {
+7 -5
View File
@@ -1,16 +1,18 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
type DownloadToken struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Base
UserUuid string `json:"userUuid" gorm:"type:char(36) not null"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null;index:idx_mu"` //index should unique globally.
MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null;index:idx_mu"`
ExpireTime time.Time `json:"expireTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Ip string `json:"ip" gorm:"type:varchar(128) not null"`
}
func (this *DownloadToken) TableName() string {
return core.TABLE_PREFIX + "download_token"
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"github.com/eyebluecn/tank/code/tool/uuid"
"time"
@@ -48,14 +48,14 @@ func (this *FootprintDao) Page(page int, pageSize int, userUuid string, sortArra
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Footprint{}).Where(wp.Query, wp.Args...)
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var footprints []*Footprint
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&footprints)
this.PanicError(db.Error)
pager := NewPager(page, pageSize, int(count), footprints)
pager := NewPager(page, pageSize, count, footprints)
return pager
}
+17 -15
View File
@@ -1,20 +1,22 @@
package rest
import "time"
import "github.com/eyebluecn/tank/code/core"
// Footprint /**
// Mysql 5.5 only support one CURRENT_TIMESTAMP
// so we use 2018-01-01 00:00:00 as default, which is the first release date of EyeblueTank
/**
* visit record.
*/
type Footprint struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
Ip string `json:"ip" gorm:"type:varchar(128) not null"`
Host string `json:"host" gorm:"type:varchar(45) not null"`
Uri string `json:"uri" gorm:"type:varchar(255) not null"`
Params string `json:"params" gorm:"type:text"`
Cost int64 `json:"cost" gorm:"type:bigint(20) not null;default:0"`
Success bool `json:"success" gorm:"type:tinyint(1) not null;default:0"`
Base
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
Ip string `json:"ip" gorm:"type:varchar(128) not null"`
Host string `json:"host" gorm:"type:varchar(45) not null"`
Uri string `json:"uri" gorm:"type:varchar(255) not null"`
Params string `json:"params" gorm:"type:text"`
Cost int64 `json:"cost" gorm:"type:bigint(20) not null;default:0"`
Success bool `json:"success" gorm:"type:tinyint(1) not null;default:0"`
}
// set File's table name to be `profiles`
func (this *Footprint) TableName() string {
return core.TABLE_PREFIX + "footprint"
}
+10 -10
View File
@@ -7,7 +7,7 @@ import (
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"os"
"path/filepath"
"time"
@@ -17,7 +17,7 @@ type ImageCacheDao struct {
BaseDao
}
// find by uuid. if not found return nil.
//find by uuid. if not found return nil.
func (this *ImageCacheDao) FindByUuid(uuid string) *ImageCache {
var entity = &ImageCache{}
db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity)
@@ -31,7 +31,7 @@ func (this *ImageCacheDao) FindByUuid(uuid string) *ImageCache {
return entity
}
// find by uuid. if not found panic NotFound error
//find by uuid. if not found panic NotFound error
func (this *ImageCacheDao) CheckByUuid(uuid string) *ImageCache {
entity := this.FindByUuid(uuid)
if entity == nil {
@@ -67,7 +67,7 @@ func (this *ImageCacheDao) CheckByUuidAndUserUuid(uuid string, userUuid string)
// Read
var imageCache = &ImageCache{}
db := core.CONTEXT.GetDB().Where(&ImageCache{Uuid: uuid, UserUuid: userUuid}).First(imageCache)
db := core.CONTEXT.GetDB().Where(&ImageCache{Base: Base{Uuid: uuid}, UserUuid: userUuid}).First(imageCache)
this.PanicError(db.Error)
return imageCache
@@ -101,14 +101,14 @@ func (this *ImageCacheDao) Page(page int, pageSize int, userUuid string, matterU
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&ImageCache{}).Where(wp.Query, wp.Args...)
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var imageCaches []*ImageCache
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&imageCaches)
this.PanicError(db.Error)
pager := NewPager(page, pageSize, int(count), imageCaches)
pager := NewPager(page, pageSize, count, imageCaches)
return pager
}
@@ -137,7 +137,7 @@ func (this *ImageCacheDao) Save(imageCache *ImageCache) *ImageCache {
func (this *ImageCacheDao) deleteFileAndDir(imageCache *ImageCache) {
filePath := GetSpaceCacheRootDir(imageCache.Username) + imageCache.Path
filePath := GetUserCacheRootDir(imageCache.Username) + imageCache.Path
dirPath := filepath.Dir(filePath)
@@ -152,7 +152,7 @@ func (this *ImageCacheDao) deleteFileAndDir(imageCache *ImageCache) {
}
// delete a file from db and disk.
//delete a file from db and disk.
func (this *ImageCacheDao) Delete(imageCache *ImageCache) {
db := core.CONTEXT.GetDB().Delete(&imageCache)
@@ -162,7 +162,7 @@ func (this *ImageCacheDao) Delete(imageCache *ImageCache) {
}
// delete all the cache of a matter.
//delete all the cache of a matter.
func (this *ImageCacheDao) DeleteByMatterUuid(matterUuid string) {
var wp = &builder.WherePair{}
@@ -208,7 +208,7 @@ func (this *ImageCacheDao) SizeBetweenTime(startTime time.Time, endTime time.Tim
return size
}
// System cleanup.
//System cleanup.
func (this *ImageCacheDao) Cleanup() {
this.logger.Info("[ImageCacheDao]clean up. Delete all ImageCache ")
db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(ImageCache{})
+20 -16
View File
@@ -1,28 +1,32 @@
package rest
import "time"
import (
"github.com/eyebluecn/tank/code/core"
)
/**
* image cache.
*/
type ImageCache struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Name string `json:"name" gorm:"type:varchar(255) not null"`
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
Username string `json:"username" gorm:"type:varchar(45) not null"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36);index:idx_mu"` //index should unique globally.
MatterName string `json:"matterName" gorm:"type:varchar(255) not null"`
Mode string `json:"mode" gorm:"type:varchar(512)"`
Md5 string `json:"md5" gorm:"type:varchar(45)"`
Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"`
Path string `json:"path" gorm:"type:varchar(512)"`
Matter *Matter `json:"matter" gorm:"-"`
Base
Name string `json:"name" gorm:"type:varchar(255) not null"`
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
Username string `json:"username" gorm:"type:varchar(45) not null"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36);index:idx_mu"`
MatterName string `json:"matterName" gorm:"type:varchar(255) not null"`
Mode string `json:"mode" gorm:"type:varchar(512)"`
Md5 string `json:"md5" gorm:"type:varchar(45)"`
Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"`
Path string `json:"path" gorm:"type:varchar(512)"`
Matter *Matter `json:"matter" gorm:"-"`
}
// set File's table name to be `profiles`
func (this *ImageCache) TableName() string {
return core.TABLE_PREFIX + "image_cache"
}
// get the absolute path. path in db means relative path.
func (this *ImageCache) AbsolutePath() string {
return GetSpaceCacheRootDir(this.Username) + this.Path
return GetUserCacheRootDir(this.Username) + this.Path
}
+4 -4
View File
@@ -14,7 +14,7 @@ import (
"strings"
)
// @Service
//@Service
type ImageCacheService struct {
BaseBean
imageCacheDao *ImageCacheDao
@@ -92,7 +92,7 @@ func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess
}
// resize image.
//resize image.
func (this *ImageCacheService) ResizeImage(request *http.Request, filePath string) *image.NRGBA {
diskFile, err := os.Open(filePath)
@@ -148,7 +148,7 @@ func (this *ImageCacheService) ResizeImage(request *http.Request, filePath strin
}
}
// cache an image
//cache an image
func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *http.Request, matter *Matter) *ImageCache {
//only these image can do.
@@ -177,7 +177,7 @@ func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *h
cacheImageName := util.GetSimpleFileName(matter.Name) + "_" + mode + extension
cacheImageRelativePath := util.GetSimpleFileName(matter.Path) + "_" + mode + extension
cacheImageAbsolutePath := GetSpaceCacheRootDir(user.Username) + util.GetSimpleFileName(matter.Path) + "_" + mode + extension
cacheImageAbsolutePath := GetUserCacheRootDir(user.Username) + util.GetSimpleFileName(matter.Path) + "_" + mode + extension
//create directory
dir := filepath.Dir(cacheImageAbsolutePath)
+46 -143
View File
@@ -6,24 +6,16 @@ import (
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/i18n"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/third"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/eyebluecn/tank/code/tool/uuid"
"github.com/glebarez/sqlite"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"log"
"github.com/jinzhu/gorm"
"net/http"
"os"
"regexp"
"strconv"
"sync"
"time"
)
// install apis. Only when installing period can be visited.
//install apis. Only when installing period can be visited.
type InstallController struct {
BaseController
uploadTokenDao *UploadTokenDao
@@ -32,7 +24,7 @@ type InstallController struct {
matterService *MatterService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
tableNames []interface{}
tableNames []IBase
}
func (this *InstallController) Init() {
@@ -68,7 +60,7 @@ func (this *InstallController) Init() {
this.imageCacheService = c
}
this.tableNames = []interface{}{
this.tableNames = []IBase{
&Dashboard{},
&Bridge{},
&DownloadToken{},
@@ -78,8 +70,6 @@ func (this *InstallController) Init() {
&Preference{},
&Session{},
&Share{},
&Space{},
&SpaceMember{},
&UploadToken{},
&User{},
}
@@ -102,7 +92,6 @@ func (this *InstallController) RegisterRoutes() map[string]func(writer http.Resp
}
func (this *InstallController) openDbConnection(writer http.ResponseWriter, request *http.Request) *gorm.DB {
dbType := request.FormValue("dbType")
mysqlPortStr := request.FormValue("mysqlPort")
mysqlHost := request.FormValue("mysqlHost")
mysqlSchema := request.FormValue("mysqlSchema")
@@ -117,114 +106,55 @@ func (this *InstallController) openDbConnection(writer http.ResponseWriter, requ
mysqlPort = tmp
}
//log config
dbLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // slow SQL 1s
LogLevel: logger.Silent, // log level. open when debug.
IgnoreRecordNotFoundError: true, // ignore ErrRecordNotFound
Colorful: false, // colorful print
},
)
//table name strategy
namingStrategy := core.CONFIG.NamingStrategy()
mysqlUrl := util.GetMysqlUrl(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword, mysqlCharset)
if dbType == "sqlite" {
this.logger.Info("Connect MySQL %s", mysqlUrl)
var err error = nil
sqliteFolder := core.CONFIG.SqliteFolder() + "/tank.sqlite"
this.logger.Info("Connect Sqlite %s", sqliteFolder)
db, err := gorm.Open(sqlite.Open(sqliteFolder), &gorm.Config{Logger: dbLogger, NamingStrategy: namingStrategy})
var err error = nil
db, err := gorm.Open("mysql", mysqlUrl)
this.PanicError(err)
if err != nil {
core.LOGGER.Panic("failed to connect sqlite database")
}
db.LogMode(false)
//sqlite lock issue. https://gist.github.com/mrnugget/0eda3b2b53a70fa4a894
phyDb, err := db.DB()
phyDb.SetMaxOpenConns(1)
return db
} else {
mysqlUrl := util.GetMysqlUrl(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword, mysqlCharset)
this.logger.Info("Connect MySQL %s", mysqlUrl)
var err error = nil
db, err := gorm.Open(mysql.Open(mysqlUrl), &gorm.Config{Logger: dbLogger, NamingStrategy: namingStrategy})
this.PanicError(err)
return db
}
return db
}
func (this *InstallController) closeDbConnection(db *gorm.DB) {
if db != nil {
sqlDB, err := db.DB()
err := db.Close()
if err != nil {
core.LOGGER.Error("occur error when get *sql.DB %s", err.Error())
}
err = sqlDB.Close()
if err != nil {
core.LOGGER.Error("occur error when closing db %s", err.Error())
this.logger.Error("occur error when close db. %v", err)
}
}
}
// (tableName, exists, allFields, missingFields)
func (this *InstallController) getTableMeta(gormDb *gorm.DB, entity interface{}) (string, bool, []*InstallFieldInfo, []*InstallFieldInfo) {
func (this *InstallController) getTableMeta(gormDb *gorm.DB, entity IBase) (bool, []*gorm.StructField, []*gorm.StructField) {
//get all useful fields from model.
entitySchema, err := schema.Parse(entity, &sync.Map{}, core.CONFIG.NamingStrategy())
this.PanicError(err)
db := gormDb.Unscoped()
scope := db.NewScope(entity)
tableName := entitySchema.Table
tableName := scope.TableName()
modelStruct := scope.GetModelStruct()
allFields := modelStruct.StructFields
var missingFields = make([]*gorm.StructField, 0)
var allFields = make([]*InstallFieldInfo, 0)
for _, field := range entitySchema.Fields {
allFields = append(allFields, &InstallFieldInfo{
Name: field.DBName,
DataType: string(field.DataType),
})
}
var missingFields = make([]*InstallFieldInfo, 0)
if !gormDb.Migrator().HasTable(tableName) {
if !scope.Dialect().HasTable(tableName) {
missingFields = append(missingFields, allFields...)
return tableName, false, allFields, missingFields
return false, allFields, missingFields
} else {
for _, field := range allFields {
//tag with `gorm:"-"` will be ""
if field.Name != "" {
database := gormDb.Migrator().CurrentDatabase()
//if sqlite
if _, ok := gormDb.Dialector.(*sqlite.Dialector); ok {
if !gormDb.Migrator().HasColumn(tableName, field.Name) {
missingFields = append(missingFields, field)
}
} else {
if !third.MysqlMigratorHasColumn(gormDb, database, tableName, field.Name) {
missingFields = append(missingFields, field)
}
if !scope.Dialect().HasColumn(tableName, field.DBName) {
if field.IsNormal {
missingFields = append(missingFields, field)
}
}
}
return tableName, true, allFields, missingFields
return true, allFields, missingFields
}
}
@@ -234,10 +164,9 @@ func (this *InstallController) getTableMetaList(db *gorm.DB) []*InstallTableInfo
var installTableInfos []*InstallTableInfo
for _, iBase := range this.tableNames {
tableName, exist, allFields, missingFields := this.getTableMeta(db, iBase)
exist, allFields, missingFields := this.getTableMeta(db, iBase)
installTableInfos = append(installTableInfos, &InstallTableInfo{
Name: tableName,
Name: iBase.TableName(),
TableExist: exist,
AllFields: allFields,
MissingFields: missingFields,
@@ -256,7 +185,7 @@ func (this *InstallController) validateTableMetaList(tableInfoList []*InstallTab
var strs []string
for _, v := range tableInfo.MissingFields {
strs = append(strs, v.Name)
strs = append(strs, v.DBName)
}
panic(result.BadRequest(fmt.Sprintf("table %s miss the following fields %v", tableInfo.Name, strs)))
@@ -268,16 +197,14 @@ func (this *InstallController) validateTableMetaList(tableInfoList []*InstallTab
}
// Ping db.
//Ping db.
func (this *InstallController) Verify(writer http.ResponseWriter, request *http.Request) *result.WebResult {
db := this.openDbConnection(writer, request)
defer this.closeDbConnection(db)
this.logger.Info("Ping DB")
phyDb, err := db.DB()
this.PanicError(err)
err = phyDb.Ping()
err := db.DB().Ping()
this.PanicError(err)
return this.Success("OK")
@@ -300,21 +227,13 @@ func (this *InstallController) CreateTable(writer http.ResponseWriter, request *
for _, iBase := range this.tableNames {
if _, ok := db.Dialector.(*sqlite.Dialector); ok {
//if sqlite. no need to set CHARSET.
err := db.AutoMigrate(iBase)
this.PanicError(err)
} else {
//use utf8 charset
mysqlCharset := request.FormValue("mysqlCharset")
err := db.Set("gorm:table_options", fmt.Sprintf("CHARSET=%s", mysqlCharset)).AutoMigrate(iBase)
this.PanicError(err)
}
//complete the missing fields or create table. use utf8 charset
db1 := db.Set("gorm:table_options", "CHARSET=utf8mb4").AutoMigrate(iBase)
this.PanicError(db1.Error)
//complete the missing fields or create table.
tableName, exist, allFields, missingFields := this.getTableMeta(db, iBase)
exist, allFields, missingFields := this.getTableMeta(db, iBase)
installTableInfos = append(installTableInfos, &InstallTableInfo{
Name: tableName,
Name: iBase.TableName(),
TableExist: exist,
AllFields: allFields,
MissingFields: missingFields,
@@ -326,7 +245,7 @@ func (this *InstallController) CreateTable(writer http.ResponseWriter, request *
}
// get the list of admin.
//get the list of admin.
func (this *InstallController) AdminList(writer http.ResponseWriter, request *http.Request) *result.WebResult {
db := this.openDbConnection(writer, request)
@@ -344,7 +263,7 @@ func (this *InstallController) AdminList(writer http.ResponseWriter, request *ht
return this.Success(users)
}
// create admin
//create admin
func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request *http.Request) *result.WebResult {
db := this.openDbConnection(writer, request)
@@ -370,20 +289,9 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request *
panic(result.BadRequestI18n(request, i18n.UsernameExist, adminUsername))
}
space := &Space{}
timeUUID, _ := uuid.NewV4()
space.Uuid = timeUUID.String()
space.CreateTime = time.Now()
space.UpdateTime = time.Now()
space.UserUuid = ""
space.SizeLimit = -1
space.Type = SPACE_TYPE_PRIVATE
db3 := db.Create(space)
this.PanicError(db3.Error)
user := &User{}
timeUUID, _ = uuid.NewV4()
user.Uuid = timeUUID.String()
timeUUID, _ := uuid.NewV4()
user.Uuid = string(timeUUID.String())
user.CreateTime = time.Now()
user.UpdateTime = time.Now()
user.LastTime = time.Now()
@@ -391,21 +299,17 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request *
user.Role = USER_ROLE_ADMINISTRATOR
user.Username = adminUsername
user.Password = util.GetBcrypt(adminPassword)
user.SpaceUuid = space.Uuid
user.SizeLimit = -1
user.Status = USER_STATUS_OK
db4 := db.Create(user)
this.PanicError(db4.Error)
space.UserUuid = user.Uuid
db5 := db.Save(space)
this.PanicError(db5.Error)
db3 := db.Create(user)
this.PanicError(db3.Error)
return this.Success("OK")
}
// (if there is admin in db)Validate admin.
//(if there is admin in db)Validate admin.
func (this *InstallController) ValidateAdmin(writer http.ResponseWriter, request *http.Request) *result.WebResult {
db := this.openDbConnection(writer, request)
@@ -439,10 +343,9 @@ func (this *InstallController) ValidateAdmin(writer http.ResponseWriter, request
}
// Finish the installation
//Finish the installation
func (this *InstallController) Finish(writer http.ResponseWriter, request *http.Request) *result.WebResult {
dbType := request.FormValue("dbType")
mysqlPortStr := request.FormValue("mysqlPort")
mysqlHost := request.FormValue("mysqlHost")
mysqlSchema := request.FormValue("mysqlSchema")
@@ -474,7 +377,7 @@ func (this *InstallController) Finish(writer http.ResponseWriter, request *http.
}
//announce the config to write config to tank.json
core.CONFIG.FinishInstall(dbType, mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword, mysqlCharset)
core.CONFIG.FinishInstall(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword, mysqlCharset)
//announce the context to broadcast the installation news to bean.
core.CONTEXT.InstallOk()
+6 -11
View File
@@ -1,18 +1,13 @@
package rest
// InstallTableInfo /**
// table meta info.
type InstallTableInfo struct {
Name string `json:"name"`
TableExist bool `json:"tableExist"`
AllFields []*InstallFieldInfo `json:"allFields"`
MissingFields []*InstallFieldInfo `json:"missingFields"`
}
import "github.com/jinzhu/gorm"
/**
* table meta info.
*/
type InstallFieldInfo struct {
Name string `json:"name"`
DataType string `json:"dataType"`
type InstallTableInfo struct {
Name string `json:"name"`
TableExist bool `json:"tableExist"`
AllFields []*gorm.StructField `json:"allFields"`
MissingFields []*gorm.StructField `json:"missingFields"`
}
+287 -177
View File
@@ -2,10 +2,12 @@ package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/i18n"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"math"
"net/http"
"strconv"
"strings"
)
@@ -17,10 +19,12 @@ type MatterController struct {
downloadTokenDao *DownloadTokenDao
imageCacheDao *ImageCacheDao
shareDao *ShareDao
spaceDao *SpaceDao
shareService *ShareService
bridgeDao *BridgeDao
imageCacheService *ImageCacheService
ossService *OssService
ossUploading bool
}
func (this *MatterController) Init() {
@@ -51,11 +55,6 @@ func (this *MatterController) Init() {
this.shareDao = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.shareService)
if b, ok := b.(*ShareService); ok {
this.shareService = b
@@ -70,13 +69,17 @@ func (this *MatterController) Init() {
if b, ok := b.(*ImageCacheService); ok {
this.imageCacheService = b
}
b = core.CONTEXT.GetBean(this.ossService)
if b, ok := b.(*OssService); ok {
this.ossService = b
}
this.ossUploading = false
}
func (this *MatterController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
routeMap["/api/matter/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
routeMap["/api/matter/page"] = this.Wrap(this.Page, USER_ROLE_USER)
routeMap["/api/matter/create/directory"] = this.Wrap(this.CreateDirectory, USER_ROLE_USER)
routeMap["/api/matter/upload"] = this.Wrap(this.Upload, USER_ROLE_USER)
@@ -91,111 +94,160 @@ func (this *MatterController) RegisterRoutes() map[string]func(writer http.Respo
routeMap["/api/matter/rename"] = this.Wrap(this.Rename, USER_ROLE_USER)
routeMap["/api/matter/change/privacy"] = this.Wrap(this.ChangePrivacy, USER_ROLE_USER)
routeMap["/api/matter/move"] = this.Wrap(this.Move, USER_ROLE_USER)
routeMap["/api/matter/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
routeMap["/api/matter/page"] = this.Wrap(this.Page, USER_ROLE_GUEST)
//mirror local files.
routeMap["/api/matter/mirror"] = this.Wrap(this.Mirror, USER_ROLE_USER)
routeMap["/api/matter/zip"] = this.Wrap(this.Zip, USER_ROLE_USER)
routeMap["/api/matter/oss"] = this.Wrap(this.Oss, USER_ROLE_ADMINISTRATOR)
routeMap["/api/matter/stop"] = this.Wrap(this.Stop, USER_ROLE_ADMINISTRATOR)
return routeMap
}
func (this *MatterController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckReadableByUuid(request, user, spaceUuid)
uuid := request.FormValue("uuid")
if uuid == "" {
panic(result.BadRequest("uuid cannot be null"))
}
matter := this.matterService.Detail(request, uuid)
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
//add the user's info.
if space.Uuid == user.SpaceUuid {
matter.User = user
} else {
matter.User = this.userDao.FindByUuid(user.Uuid)
}
return this.Success(matter)
}
func (this *MatterController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
page := util.ExtractRequestOptionalInt(request, "page", 0)
pageSize := util.ExtractRequestOptionalInt(request, "pageSize", 200)
orderCreateTime := util.ExtractRequestOptionalString(request, "orderCreateTime", "")
orderUpdateTime := util.ExtractRequestOptionalString(request, "orderUpdateTime", "")
orderDeleteTime := util.ExtractRequestOptionalString(request, "orderDeleteTime", "")
orderSort := util.ExtractRequestOptionalString(request, "orderSort", "")
orderTimes := util.ExtractRequestOptionalString(request, "orderTimes", "")
orderDir := util.ExtractRequestOptionalString(request, "orderDir", "")
orderSize := util.ExtractRequestOptionalString(request, "orderSize", "")
orderName := util.ExtractRequestOptionalString(request, "orderName", "")
pageStr := request.FormValue("page")
pageSizeStr := request.FormValue("pageSize")
orderCreateTime := request.FormValue("orderCreateTime")
orderUpdateTime := request.FormValue("orderUpdateTime")
orderDeleteTime := request.FormValue("orderDeleteTime")
orderSort := request.FormValue("orderSort")
orderTimes := request.FormValue("orderTimes")
puuid := util.ExtractRequestOptionalString(request, "puuid", "")
name := util.ExtractRequestOptionalString(request, "name", "")
dir := util.ExtractRequestOptionalString(request, "dir", "")
deleted := util.ExtractRequestOptionalString(request, "deleted", "")
extensionsStr := util.ExtractRequestOptionalString(request, "extensions", "")
puuid := request.FormValue("puuid")
name := request.FormValue("name")
dir := request.FormValue("dir")
deleted := request.FormValue("deleted")
orderDir := request.FormValue("orderDir")
orderSize := request.FormValue("orderSize")
orderName := request.FormValue("orderName")
extensionsStr := request.FormValue("extensions")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
this.spaceService.CheckReadableByUuid(request, user, spaceUuid)
var userUuid string
//auth by shareUuid.
shareUuid := request.FormValue("shareUuid")
shareCode := request.FormValue("shareCode")
shareRootUuid := request.FormValue("shareRootUuid")
if shareUuid != "" {
if puuid == "" {
panic(result.BadRequest("puuid cannot be null"))
}
dirMatter := this.matterDao.CheckByUuid(puuid)
if !dirMatter.Dir {
panic(result.BadRequest("puuid is not a directory"))
}
user := this.findUser(request)
this.shareService.ValidateMatter(request, shareUuid, shareCode, user, shareRootUuid, dirMatter)
puuid = dirMatter.Uuid
} else {
//if cannot auth by share. Then login is required.
user := this.checkUser(request)
userUuid = user.Uuid
}
var page int
if pageStr != "" {
page, _ = strconv.Atoi(pageStr)
}
pageSize := 200
if pageSizeStr != "" {
tmp, err := strconv.Atoi(pageSizeStr)
if err == nil {
pageSize = tmp
}
}
var extensions []string
if extensionsStr != "" {
extensions = strings.Split(extensionsStr, ",")
}
pager := this.matterService.Page(
request,
page,
pageSize,
orderCreateTime,
orderUpdateTime,
orderDeleteTime,
orderSort,
orderTimes,
orderDir,
orderSize,
orderName,
puuid,
name,
dir,
deleted,
extensions,
spaceUuid,
)
sortArray := []builder.OrderPair{
{
Key: "dir",
Value: orderDir,
},
{
Key: "create_time",
Value: orderCreateTime,
},
{
Key: "update_time",
Value: orderUpdateTime,
},
{
Key: "delete_time",
Value: orderDeleteTime,
},
{
Key: "sort",
Value: orderSort,
},
{
Key: "size",
Value: orderSize,
},
{
Key: "name",
Value: orderName,
},
{
Key: "times",
Value: orderTimes,
},
}
pager := this.matterDao.Page(page, pageSize, puuid, userUuid, name, dir, deleted, extensions, sortArray)
return this.Success(pager)
}
func (this *MatterController) CreateDirectory(writer http.ResponseWriter, request *http.Request) *result.WebResult {
puuid := util.ExtractRequestString(request, "puuid")
name := util.ExtractRequestString(request, "name")
puuid := request.FormValue("puuid")
name := request.FormValue("name")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
var dirMatter = this.matterDao.CheckWithRootByUuid(puuid, space)
var dirMatter = this.matterDao.CheckWithRootByUuid(puuid, user)
matter := this.matterService.AtomicCreateDirectory(request, dirMatter, name, user, space)
matter := this.matterService.AtomicCreateDirectory(request, dirMatter, name, user)
return this.Success(matter)
}
func (this *MatterController) Upload(writer http.ResponseWriter, request *http.Request) *result.WebResult {
puuid := util.ExtractRequestString(request, "puuid")
privacy := util.ExtractRequestOptionalBool(request, "privacy", true)
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
puuid := request.FormValue("puuid")
privacyStr := request.FormValue("privacy")
file, handler, err := request.FormFile("file")
this.PanicError(err)
defer func() {
@@ -203,10 +255,14 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R
this.PanicError(err)
}()
user := this.checkUser(request)
privacy := privacyStr == TRUE
err = request.ParseMultipartForm(32 << 20)
this.PanicError(err)
//for IE browser. filename may contain filepath.
//for IE browser. filename may contains filepath.
fileName := handler.Filename
pos := strings.LastIndex(fileName, "\\")
if pos != -1 {
@@ -217,77 +273,65 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R
fileName = fileName[pos+1:]
}
dirMatter := this.matterDao.CheckWithRootByUuid(puuid, space)
dirMatter := this.matterDao.CheckWithRootByUuid(puuid, user)
//support upload simultaneously
matter := this.matterService.Upload(request, file, handler, user, space, dirMatter, fileName, privacy)
matter := this.matterService.Upload(request, file, user, dirMatter, fileName, privacy)
return this.Success(matter)
}
// crawl a file by url.
//crawl a file by url.
func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Request) *result.WebResult {
url := util.ExtractRequestString(request, "url")
destPath := util.ExtractRequestOptionalString(request, "destPath", "")
puuid := util.ExtractRequestOptionalString(request, "puuid", "")
filename := util.ExtractRequestString(request, "filename")
url := request.FormValue("url")
destPath := request.FormValue("destPath")
filename := request.FormValue("filename")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
var dirMatter *Matter
if puuid != "" {
dirMatter = this.matterDao.CheckWithRootByUuid(puuid, space)
if dirMatter.SpaceUuid != space.Uuid {
panic(result.UNAUTHORIZED)
}
if !dirMatter.Dir {
panic(" puuid is not a dir.")
}
} else {
if destPath == "" {
panic(" puuid or destPath cannot be null")
}
dirMatter = this.matterService.CreateDirectories(request, user, space, destPath)
}
dirMatter := this.matterService.CreateDirectories(request, user, destPath)
if url == "" || (!strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://")) {
panic(" url must start with http:// or https://")
}
matter := this.matterService.AtomicCrawl(request, url, filename, user, space, dirMatter, true)
if filename == "" {
panic("filename cannot be null")
}
matter := this.matterService.AtomicCrawl(request, url, filename, user, dirMatter, true)
return this.Success(matter)
}
// soft delete.
//soft delete.
func (this *MatterController) SoftDelete(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuid := request.FormValue("uuid")
if uuid == "" {
panic(result.BadRequest("uuid cannot be null"))
}
matter := this.matterDao.CheckByUuid(uuid)
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
this.matterService.AtomicSoftDelete(request, matter, user, space)
this.matterService.AtomicSoftDelete(request, matter, user)
return this.Success("OK")
}
func (this *MatterController) SoftDeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuids := util.ExtractRequestString(request, "uuids")
uuids := request.FormValue("uuids")
if uuids == "" {
panic(result.BadRequest("uuids cannot be null"))
}
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuidArray := strings.Split(uuids, ",")
@@ -309,24 +353,24 @@ func (this *MatterController) SoftDeleteBatch(writer http.ResponseWriter, reques
}
for _, matter := range matters {
this.matterService.AtomicSoftDelete(request, matter, user, space)
this.matterService.AtomicSoftDelete(request, matter, user)
}
return this.Success("OK")
}
// recovery delete.
//recovery delete.
func (this *MatterController) Recovery(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuid := request.FormValue("uuid")
if uuid == "" {
panic(result.BadRequest("uuid cannot be null"))
}
matter := this.matterDao.CheckByUuid(uuid)
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
@@ -335,13 +379,13 @@ func (this *MatterController) Recovery(writer http.ResponseWriter, request *http
return this.Success("OK")
}
// recovery batch.
//recovery batch.
func (this *MatterController) RecoveryBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuids := util.ExtractRequestString(request, "uuids")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuids := request.FormValue("uuids")
if uuids == "" {
panic(result.BadRequest("uuids cannot be null"))
}
uuidArray := strings.Split(uuids, ",")
@@ -354,7 +398,8 @@ func (this *MatterController) RecoveryBatch(writer http.ResponseWriter, request
continue
}
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
@@ -365,34 +410,35 @@ func (this *MatterController) RecoveryBatch(writer http.ResponseWriter, request
return this.Success("OK")
}
// complete delete.
//complete delete.
func (this *MatterController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuid := request.FormValue("uuid")
if uuid == "" {
panic(result.BadRequest("uuid cannot be null"))
}
matter := this.matterDao.CheckByUuid(uuid)
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
this.matterService.AtomicDelete(request, matter, user, space)
this.matterService.AtomicDelete(request, matter, user)
return this.Success("OK")
}
func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuids := util.ExtractRequestString(request, "uuids")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuids := request.FormValue("uuids")
if uuids == "" {
panic(result.BadRequest("uuids cannot be null"))
}
uuidArray := strings.Split(uuids, ",")
user := this.checkUser(request)
matters := make([]*Matter, 0)
for _, uuid := range uuidArray {
@@ -403,7 +449,7 @@ func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *h
continue
}
if matter.SpaceUuid != space.Uuid {
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
@@ -412,13 +458,13 @@ func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *h
for _, matter := range matters {
this.matterService.AtomicDelete(request, matter, user, space)
this.matterService.AtomicDelete(request, matter, user)
}
return this.Success("OK")
}
// manual clean expired deleted matters.
//manual clean expired deleted matters.
func (this *MatterController) CleanExpiredDeletedMatters(writer http.ResponseWriter, request *http.Request) *result.WebResult {
this.matterService.CleanExpiredDeletedMatters()
@@ -428,32 +474,29 @@ func (this *MatterController) CleanExpiredDeletedMatters(writer http.ResponseWri
func (this *MatterController) Rename(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
name := util.ExtractRequestString(request, "name")
uuid := request.FormValue("uuid")
name := request.FormValue("name")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
matter := this.matterDao.CheckByUuid(uuid)
if matter.SpaceUuid != space.Uuid {
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
this.matterService.AtomicRename(request, matter, name, false, user, space)
this.matterService.AtomicRename(request, matter, name, false, user)
return this.Success(matter)
}
func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
privacy := util.ExtractRequestOptionalBool(request, "privacy", false)
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
uuid := request.FormValue("uuid")
privacyStr := request.FormValue("privacy")
privacy := false
if privacyStr == TRUE {
privacy = true
}
matter := this.matterDao.CheckByUuid(uuid)
@@ -465,7 +508,8 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request
panic(result.BadRequest("not changed. Invalid operation."))
}
if matter.SpaceUuid != space.Uuid {
user := this.checkUser(request)
if matter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
@@ -476,21 +520,25 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request
}
func (this *MatterController) Move(writer http.ResponseWriter, request *http.Request) *result.WebResult {
srcUuidsStr := util.ExtractRequestString(request, "srcUuids")
destUuid := util.ExtractRequestString(request, "destUuid")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
srcUuidsStr := request.FormValue("srcUuids")
destUuid := request.FormValue("destUuid")
var srcUuids []string
srcUuids = strings.Split(srcUuidsStr, ",")
if srcUuidsStr == "" {
panic(result.BadRequest("srcUuids cannot be null"))
} else {
srcUuids = strings.Split(srcUuidsStr, ",")
}
var destMatter = this.matterDao.CheckWithRootByUuid(destUuid, space)
user := this.checkUser(request)
var destMatter = this.matterDao.CheckWithRootByUuid(destUuid, user)
if !destMatter.Dir {
panic(result.BadRequest("destination is not a directory"))
}
if destMatter.SpaceUuid != space.Uuid {
if destMatter.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
@@ -517,41 +565,49 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req
panic(result.BadRequestI18n(request, i18n.MatterExist, srcMatter.Name))
}
if srcMatter.SpaceUuid != destMatter.SpaceUuid {
panic("space not the same")
if srcMatter.UserUuid != destMatter.UserUuid {
panic("owner not the same")
}
srcMatters = append(srcMatters, srcMatter)
}
this.matterService.AtomicMoveBatch(request, srcMatters, destMatter, user, space)
this.matterService.AtomicMoveBatch(request, srcMatters, destMatter, user)
return this.Success(nil)
}
// mirror local files to EyeblueTank
//mirror local files to EyeblueTank
func (this *MatterController) Mirror(writer http.ResponseWriter, request *http.Request) *result.WebResult {
srcPath := util.ExtractRequestString(request, "srcPath")
destPath := util.ExtractRequestString(request, "destPath")
overwrite := util.ExtractRequestOptionalBool(request, "overwrite", false)
srcPath := request.FormValue("srcPath")
destPath := request.FormValue("destPath")
overwriteStr := request.FormValue("overwrite")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckWritableByUuid(request, user, spaceUuid)
if srcPath == "" {
panic(result.BadRequest("srcPath cannot be null"))
}
this.matterService.AtomicMirror(request, srcPath, destPath, overwrite, user, space)
overwrite := false
if overwriteStr == TRUE {
overwrite = true
}
user := this.userDao.checkUser(request)
this.matterService.AtomicMirror(request, srcPath, destPath, overwrite, user)
return this.Success(nil)
}
// download zip.
//download zip.
func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuids := util.ExtractRequestString(request, "uuids")
user := this.checkUser(request)
spaceUuid := util.ExtractRequestOptionalString(request, "spaceUuid", user.SpaceUuid)
space := this.spaceService.CheckReadableByUuid(request, user, spaceUuid)
uuids := request.FormValue("uuids")
if uuids == "" {
panic(result.BadRequest("uuids cannot be null"))
}
uuidArray := strings.Split(uuids, ",")
@@ -567,10 +623,11 @@ func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Requ
}
}
user := this.checkUser(request)
puuid := matters[0].Puuid
for _, m := range matters {
if m.SpaceUuid != space.Uuid {
if m.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
} else if m.Puuid != puuid {
panic(result.BadRequest("puuid not same"))
@@ -581,3 +638,56 @@ func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Requ
return nil
}
//upload to oss.
func (this *MatterController) Oss(writer http.ResponseWriter, request *http.Request) *result.WebResult {
if this.ossUploading {
return this.Success("oss is running")
} else {
this.ossUploading = true
}
pageSize := 100
count, _ := this.matterDao.PlainPage(0, pageSize, "", "", "", "false", "", nil, nil, nil)
if count > 0 {
var totalPages = int(math.Ceil(float64(count) / float64(pageSize)))
var page int
for page = 0; page < totalPages; page++ {
this.logger.Info("-- processing %d/%d", page+1, totalPages)
if !this.ossUploading {
break
}
_, matters := this.matterDao.PlainPage(page, pageSize, "", "", "", "false", "", nil, nil, nil)
for _, matter := range matters {
if !this.ossUploading {
break
}
//保证不抛异常
core.RunWithRecovery(func() {
this.ossService.Upload(matter)
})
}
}
}
this.ossUploading = false
return this.Success(nil)
}
//stop uploading to oss.
func (this *MatterController) Stop(writer http.ResponseWriter, request *http.Request) *result.WebResult {
this.ossUploading = false
this.logger.Info("-- stop processing --")
return this.Success("OK")
}
+32 -137
View File
@@ -6,7 +6,7 @@ import (
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"math"
"os"
"time"
@@ -46,7 +46,7 @@ func (this *MatterDao) FindByUuid(uuid string) *Matter {
return entity
}
// find by uuid. if not found panic NotFound error
//find by uuid. if not found panic NotFound error
func (this *MatterDao) CheckByUuid(uuid string) *Matter {
entity := this.FindByUuid(uuid)
if entity == nil {
@@ -56,7 +56,7 @@ func (this *MatterDao) CheckByUuid(uuid string) *Matter {
}
// find by uuid. if uuid=root, then return the Root Matter
func (this *MatterDao) CheckWithRootByUuid(uuid string, space *Space) *Matter {
func (this *MatterDao) CheckWithRootByUuid(uuid string, user *User) *Matter {
if uuid == "" {
panic(result.BadRequest("uuid cannot be null."))
@@ -64,10 +64,10 @@ func (this *MatterDao) CheckWithRootByUuid(uuid string, space *Space) *Matter {
var matter *Matter
if uuid == MATTER_ROOT {
if space == nil {
panic(result.BadRequest("space cannot be null."))
if user == nil {
panic(result.BadRequest("user cannot be null."))
}
matter = NewRootMatter(space)
matter = NewRootMatter(user)
} else {
matter = this.CheckByUuid(uuid)
}
@@ -76,7 +76,7 @@ func (this *MatterDao) CheckWithRootByUuid(uuid string, space *Space) *Matter {
}
// find by path. if path=/, then return the Root Matter
func (this *MatterDao) CheckWithRootByPath(path string, user *User, space *Space) *Matter {
func (this *MatterDao) CheckWithRootByPath(path string, user *User) *Matter {
var matter *Matter
@@ -85,7 +85,7 @@ func (this *MatterDao) CheckWithRootByPath(path string, user *User, space *Space
}
if path == "" || path == "/" {
matter = NewRootMatter(space)
matter = NewRootMatter(user)
} else {
matter = this.checkByUserUuidAndPath(user.Uuid, path)
}
@@ -94,7 +94,7 @@ func (this *MatterDao) CheckWithRootByPath(path string, user *User, space *Space
}
// find by path. if path=/, then return the Root Matter
func (this *MatterDao) FindWithRootByPath(path string, user *User, space *Space) *Matter {
func (this *MatterDao) FindWithRootByPath(path string, user *User) *Matter {
var matter *Matter
@@ -103,7 +103,7 @@ func (this *MatterDao) FindWithRootByPath(path string, user *User, space *Space)
}
if path == "" || path == "/" {
matter = NewRootMatter(space)
matter = NewRootMatter(user)
} else {
matter = this.findByUserUuidAndPath(user.Uuid, path)
}
@@ -138,7 +138,7 @@ func (this *MatterDao) FindByUserUuidAndPuuidAndDirTrue(userUuid string, puuid s
func (this *MatterDao) CheckByUuidAndUserUuid(uuid string, userUuid string) *Matter {
var matter = &Matter{}
db := core.CONTEXT.GetDB().Where(&Matter{Uuid: uuid, UserUuid: userUuid}).First(matter)
db := core.CONTEXT.GetDB().Where(&Matter{Base: Base{Uuid: uuid}, UserUuid: userUuid}).First(matter)
this.PanicError(db.Error)
return matter
@@ -148,7 +148,7 @@ func (this *MatterDao) CheckByUuidAndUserUuid(uuid string, userUuid string) *Mat
func (this *MatterDao) CountByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) int {
var matter Matter
var count int64
var count int
var wp = &builder.WherePair{}
@@ -172,37 +172,7 @@ func (this *MatterDao) CountByUserUuidAndPuuidAndDirAndName(userUuid string, puu
Count(&count)
this.PanicError(db.Error)
return int(count)
}
func (this *MatterDao) CountBySpaceUuidAndPuuidAndDirAndName(spaceUuid string, puuid string, dir bool, name string) int {
var matter Matter
var count int64
var wp = &builder.WherePair{}
if puuid != "" {
wp = wp.And(&builder.WherePair{Query: "puuid = ?", Args: []interface{}{puuid}})
}
if spaceUuid != "" {
wp = wp.And(&builder.WherePair{Query: "space_uuid = ?", Args: []interface{}{spaceUuid}})
}
if name != "" {
wp = wp.And(&builder.WherePair{Query: "name = ?", Args: []interface{}{name}})
}
wp = wp.And(&builder.WherePair{Query: "dir = ?", Args: []interface{}{dir}})
db := core.CONTEXT.GetDB().
Model(&matter).
Where(wp.Query, wp.Args...).
Count(&count)
this.PanicError(db.Error)
return int(count)
return count
}
func (this *MatterDao) FindByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir string, name string) *Matter {
@@ -242,43 +212,6 @@ func (this *MatterDao) FindByUserUuidAndPuuidAndDirAndName(userUuid string, puui
return matter
}
func (this *MatterDao) FindBySpaceNameAndPuuidAndDirAndName(spaceName string, puuid string, dir string, name string) *Matter {
var matter = &Matter{}
var wp = &builder.WherePair{}
if puuid != "" {
wp = wp.And(&builder.WherePair{Query: "puuid = ?", Args: []interface{}{puuid}})
}
if spaceName != "" {
wp = wp.And(&builder.WherePair{Query: "space_name = ?", Args: []interface{}{spaceName}})
}
if name != "" {
wp = wp.And(&builder.WherePair{Query: "name = ?", Args: []interface{}{name}})
}
if dir == TRUE {
wp = wp.And(&builder.WherePair{Query: "dir = ?", Args: []interface{}{true}})
} else if dir == FALSE {
wp = wp.And(&builder.WherePair{Query: "dir = ?", Args: []interface{}{false}})
}
db := core.CONTEXT.GetDB().Where(wp.Query, wp.Args...).First(matter)
if db.Error != nil {
if db.Error.Error() == result.DB_ERROR_NOT_FOUND {
return nil
} else {
this.PanicError(db.Error)
}
}
return matter
}
func (this *MatterDao) FindByPuuidAndUserUuid(puuid string, userUuid string, sortArray []builder.OrderPair) []*Matter {
return this.FindByPuuidAndUserUuidAndDeleted(puuid, userUuid, "", sortArray)
}
@@ -327,7 +260,6 @@ func (this *MatterDao) PlainPage(
pageSize int,
puuid string,
userUuid string,
spaceUuid string,
name string,
dir string,
deleted string,
@@ -345,10 +277,6 @@ func (this *MatterDao) PlainPage(
wp = wp.And(&builder.WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}})
}
if spaceUuid != "" {
wp = wp.And(&builder.WherePair{Query: "space_uuid = ?", Args: []interface{}{spaceUuid}})
}
if name != "" {
wp = wp.And(&builder.WherePair{Query: "name LIKE ?", Args: []interface{}{"%" + name + "%"}})
}
@@ -382,7 +310,7 @@ func (this *MatterDao) PlainPage(
conditionDB = core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...)
}
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
@@ -390,21 +318,20 @@ func (this *MatterDao) PlainPage(
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&matters)
this.PanicError(db.Error)
return int(count), matters
return count, matters
}
func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, spaceUuid string, name string, dir string, deleted string, extensions []string, sortArray []builder.OrderPair) *Pager {
func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, name string, dir string, deleted string, extensions []string, sortArray []builder.OrderPair) *Pager {
count, matters := this.PlainPage(page, pageSize, puuid, userUuid, spaceUuid, name, dir, deleted, nil, extensions, sortArray)
count, matters := this.PlainPage(page, pageSize, puuid, userUuid, name, dir, deleted, nil, extensions, sortArray)
pager := NewPager(page, pageSize, count, matters)
return pager
}
// handle matter page by page.
//handle matter page by page.
func (this *MatterDao) PageHandle(
puuid string,
userUuid string,
spaceUuid string,
name string,
dir string,
deleted string,
@@ -422,13 +349,13 @@ func (this *MatterDao) PageHandle(
}
}
count, _ := this.PlainPage(0, pageSize, puuid, userUuid, spaceUuid, name, dir, deleted, deleteTimeBefore, nil, sortArray)
count, _ := this.PlainPage(0, pageSize, puuid, userUuid, name, dir, deleted, deleteTimeBefore, nil, sortArray)
if count > 0 {
var totalPages = int(math.Ceil(float64(count) / float64(pageSize)))
var page int
for page = 0; page < totalPages; page++ {
_, matters := this.PlainPage(0, pageSize, puuid, userUuid, spaceUuid, name, dir, deleted, deleteTimeBefore, nil, sortArray)
_, matters := this.PlainPage(page, pageSize, puuid, userUuid, name, dir, deleted, deleteTimeBefore, nil, sortArray)
for _, matter := range matters {
fun(matter)
}
@@ -458,9 +385,9 @@ func (this *MatterDao) Save(matter *Matter) *Matter {
return matter
}
// download time add 1
//download time add 1
func (this *MatterDao) TimesIncrement(matterUuid string) {
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Updates(map[string]interface{}{"times": gorm.Expr("times + 1"), "visit_time": time.Now()})
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Update(map[string]interface{}{"times": gorm.Expr("times + 1"), "visit_time": time.Now()})
this.PanicError(db.Error)
}
@@ -484,27 +411,7 @@ func (this *MatterDao) SizeByPuuidAndUserUuid(matterUuid string, userUuid string
return sumSize
}
func (this *MatterDao) SizeByPuuidAndSpaceUuid(matterUuid string, spaceUuid string) int64 {
var wp = &builder.WherePair{Query: "puuid = ? AND space_uuid = ?", Args: []interface{}{matterUuid, spaceUuid}}
var count int64
db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count)
if count == 0 {
return 0
}
var sumSize int64
db = core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Select("SUM(size)")
this.PanicError(db.Error)
row := db.Row()
err := row.Scan(&sumSize)
core.PanicError(err)
return sumSize
}
// delete a file from db and disk.
//delete a file from db and disk.
func (this *MatterDao) Delete(matter *Matter) {
// recursive if dir
@@ -543,20 +450,20 @@ func (this *MatterDao) Delete(matter *Matter) {
}
}
// soft delete a file or dir
//soft delete a file or dir
func (this *MatterDao) SoftDelete(matter *Matter) {
//soft delete from db.
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Updates(map[string]interface{}{"deleted": true, "delete_time": time.Now()})
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Update(map[string]interface{}{"deleted": true, "delete_time": time.Now()})
this.PanicError(db.Error)
}
// recovery a file
//recovery a file
func (this *MatterDao) Recovery(matter *Matter) {
//recovery from db.
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Updates(map[string]interface{}{"deleted": false, "delete_time": time.Now()})
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Update(map[string]interface{}{"deleted": false, "delete_time": time.Now()})
this.PanicError(db.Error)
}
@@ -577,7 +484,7 @@ func (this *MatterDao) CountBetweenTime(startTime time.Time, endTime time.Time)
func (this *MatterDao) SizeBetweenTime(startTime time.Time, endTime time.Time) int64 {
var wp = &builder.WherePair{Query: "dir = 0 AND create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}}
var wp = &builder.WherePair{Query: "create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}}
var count int64
db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count)
@@ -594,7 +501,7 @@ func (this *MatterDao) SizeBetweenTime(startTime time.Time, endTime time.Time) i
return size
}
// find by userUuid and path. if not found, return nil
//find by userUuid and path. if not found, return nil
func (this *MatterDao) findByUserUuidAndPath(userUuid string, path string) *Matter {
var wp = &builder.WherePair{Query: "user_uuid = ? AND path = ?", Args: []interface{}{userUuid, path}}
@@ -613,7 +520,7 @@ func (this *MatterDao) findByUserUuidAndPath(userUuid string, path string) *Matt
return matter
}
// find by userUuid and path. if not found, panic
//find by userUuid and path. if not found, panic
func (this *MatterDao) checkByUserUuidAndPath(userUuid string, path string) *Matter {
if path == "" {
@@ -660,19 +567,7 @@ func (this *MatterDao) CountByUserUuidAndPath(userUuid string, path string) int6
}
func (this *MatterDao) CountByUserUuid(userUuid string) int64 {
var wp = &builder.WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}}
var count int64
db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count)
core.PanicError(db.Error)
return count
}
// 统计总共有多少条。
//统计总共有多少条。
func (this *MatterDao) Count() int64 {
var count int64
@@ -683,7 +578,7 @@ func (this *MatterDao) Count() int64 {
}
// System cleanup.
//System cleanup.
func (this *MatterDao) Cleanup() {
this.logger.Info("[MatterDao] clean up. Delete all Matter record in db and on disk.")
db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Matter{})
+33 -34
View File
@@ -30,57 +30,55 @@ const (
* file is too common. so we use matter as file.
*/
type Matter struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Puuid string `json:"puuid" gorm:"type:char(36);index:idx_puuid"` //index should unique globally.
Base
Puuid string `json:"puuid" gorm:"type:char(36);index:idx_puuid"`
UserUuid string `json:"userUuid" gorm:"type:char(36);index:idx_uu"`
//TODO: check field usage.
SpaceName string `json:"space_name" gorm:"type:varchar(45) not null"`
Username string `json:"username" gorm:"type:varchar(45) not null"`
Dir bool `json:"dir" gorm:"type:tinyint(1) not null;default:0"`
Name string `json:"name" gorm:"type:varchar(255) not null"`
Md5 string `json:"md5" gorm:"type:varchar(45)"`
Md5 string `json:"md5" gorm:"type:varchar(512)"`
Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"`
Privacy bool `json:"privacy" gorm:"type:tinyint(1) not null;default:0"`
Path string `json:"path" gorm:"type:varchar(1024)"`
Times int64 `json:"times" gorm:"type:bigint(20) not null;default:0"`
Parent *Matter `json:"parent" gorm:"-"`
Children []*Matter `json:"-" gorm:"-"`
Prop string `json:"prop" gorm:"type:varchar(1024) not null;default:'{}'"`
VisitTime time.Time `json:"visitTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Deleted bool `json:"deleted" gorm:"type:tinyint(1) not null;index:idx_del;default:0"`
DeleteTime time.Time `json:"deleteTime" gorm:"type:timestamp not null;index:idx_delt;default:'2018-01-01 00:00:00'"`
SpaceUuid string `json:"spaceUuid" gorm:"type:char(36) not null;index:idx_space_uuid"`
User *User `json:"user" gorm:"-"`
Parent *Matter `json:"parent" gorm:"-"`
Children []*Matter `json:"-" gorm:"-"`
}
// set File's table name to be `profiles`
func (Matter) TableName() string {
return core.TABLE_PREFIX + "matter"
}
// get matter's absolute path. the Path property is relative path in db.
func (this *Matter) AbsolutePath() string {
return GetSpaceMatterRootDir(this.SpaceName) + this.Path
return GetUserMatterRootDir(this.Username) + this.Path
}
func (this *Matter) MimeType() string {
return util.GetMimeType(util.GetExtension(this.Name))
}
// Create a root matter. It's convenient for copy and move
func NewRootMatter(space *Space) *Matter {
//Create a root matter. It's convenient for copy and move
func NewRootMatter(user *User) *Matter {
matter := &Matter{}
matter.Uuid = MATTER_ROOT
matter.UserUuid = space.UserUuid
matter.SpaceUuid = space.Uuid
matter.SpaceName = space.Name
matter.UserUuid = user.Uuid
matter.Username = user.Username
matter.Dir = true
matter.Path = ""
matter.CreateTime = space.CreateTime
matter.UpdateTime = space.UpdateTime
matter.VisitTime = space.UpdateTime
matter.CreateTime = user.CreateTime
matter.UpdateTime = user.UpdateTime
matter.VisitTime = user.UpdateTime
return matter
}
// get user's space absolute path
//get user's space absolute path
func GetUserSpaceRootDir(username string) (rootDirPath string) {
rootDirPath = fmt.Sprintf("%s/%s", core.CONFIG.MatterPath(), username)
@@ -88,31 +86,31 @@ func GetUserSpaceRootDir(username string) (rootDirPath string) {
return rootDirPath
}
// get user's root absolute path
func GetSpaceMatterRootDir(spaceName string) (rootDirPath string) {
//get user's root absolute path
func GetUserMatterRootDir(username string) (rootDirPath string) {
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), spaceName, MATTER_ROOT)
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), username, MATTER_ROOT)
return rootDirPath
}
// get user's cache absolute path
func GetSpaceCacheRootDir(spaceName string) (rootDirPath string) {
//get user's cache absolute path
func GetUserCacheRootDir(username string) (rootDirPath string) {
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), spaceName, MATTER_CACHE)
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), username, MATTER_CACHE)
return rootDirPath
}
// get user's zip absolute path
func GetSpaceZipRootDir(spaceName string) (rootDirPath string) {
//get user's zip absolute path
func GetUserZipRootDir(username string) (rootDirPath string) {
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), spaceName, MATTER_ZIP)
rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.MatterPath(), username, MATTER_ZIP)
return rootDirPath
}
// check matter's name. If error, panic.
//check matter's name. If error, panic.
func CheckMatterName(request *http.Request, name string) string {
if name == "" {
@@ -131,7 +129,7 @@ func CheckMatterName(request *http.Request, name string) string {
return name
}
// fetch the props
//fetch the props
func (this *Matter) FetchPropMap() map[string]string {
m := make(map[string]string)
@@ -148,12 +146,13 @@ func (this *Matter) FetchPropMap() map[string]string {
return m
}
// fetch the props
//fetch the props
func (this *Matter) SetPropMap(propMap map[string]string) {
b, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(propMap)
if err != nil {
panic(err)
}
this.Prop = string(b)
}
+150 -243
View File
@@ -11,7 +11,6 @@ import (
"github.com/eyebluecn/tank/code/tool/util"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
@@ -28,7 +27,6 @@ import (
type MatterService struct {
BaseBean
matterDao *MatterDao
spaceDao *SpaceDao
userDao *UserDao
userService *UserService
imageCacheDao *ImageCacheDao
@@ -49,11 +47,6 @@ func (this *MatterService) Init() {
this.userDao = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.userService)
if b, ok := b.(*UserService); ok {
this.userService = b
@@ -76,68 +69,7 @@ func (this *MatterService) Init() {
}
// get the page of matters.
func (this *MatterService) Page(
request *http.Request,
page int,
pageSize int,
orderCreateTime string,
orderUpdateTime string,
orderDeleteTime string,
orderSort string,
orderTimes string,
orderDir string,
orderSize string,
orderName string,
puuid string,
name string,
dir string,
deleted string,
extensions []string,
spaceUuid string,
) *Pager {
sortArray := []builder.OrderPair{
{
Key: "dir",
Value: orderDir,
},
{
Key: "create_time",
Value: orderCreateTime,
},
{
Key: "update_time",
Value: orderUpdateTime,
},
{
Key: "delete_time",
Value: orderDeleteTime,
},
{
Key: "sort",
Value: orderSort,
},
{
Key: "size",
Value: orderSize,
},
{
Key: "name",
Value: orderName,
},
{
Key: "times",
Value: orderTimes,
},
}
pager := this.matterDao.Page(page, pageSize, puuid, "", spaceUuid, name, dir, deleted, extensions, sortArray)
return pager
}
// Download. Support chunk download.
//Download. Support chunk download.
func (this *MatterService) DownloadFile(
writer http.ResponseWriter,
request *http.Request,
@@ -148,7 +80,7 @@ func (this *MatterService) DownloadFile(
download.DownloadFile(writer, request, filePath, filename, withContentDisposition)
}
// Download specified matters. matters must have the same puuid.
//Download specified matters. matters must have the same puuid.
func (this *MatterService) DownloadZip(
writer http.ResponseWriter,
request *http.Request,
@@ -195,7 +127,7 @@ func (this *MatterService) DownloadZip(
}
//prepare the temp zip dir
destZipDirPath := fmt.Sprintf("%s/%d", GetSpaceZipRootDir(matters[0].SpaceName), time.Now().UnixNano()/1e6)
destZipDirPath := fmt.Sprintf("%s/%d", GetUserZipRootDir(matters[0].Username), time.Now().UnixNano()/1e6)
util.MakeDirAll(destZipDirPath)
destZipName := fmt.Sprintf("%s.zip", matters[0].Name)
@@ -218,7 +150,7 @@ func (this *MatterService) DownloadZip(
}
// zip matters.
//zip matters.
func (this *MatterService) zipMatters(request *http.Request, matters []*Matter, destPath string) {
if util.PathExists(destPath) {
@@ -311,8 +243,8 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
}
}
// delete files.
func (this *MatterService) Delete(request *http.Request, matter *Matter, user *User, space *Space) {
//delete files.
func (this *MatterService) Delete(request *http.Request, matter *Matter, user *User) {
if matter == nil {
panic(result.BadRequest("matter cannot be nil"))
@@ -321,10 +253,10 @@ func (this *MatterService) Delete(request *http.Request, matter *Matter, user *U
this.matterDao.Delete(matter)
//re compute the size of Route.
this.ComputeRouteSize(matter.Puuid, user, space)
this.ComputeRouteSize(matter.Puuid, user)
}
// soft delete files.
//soft delete files.
func (this *MatterService) SoftDelete(request *http.Request, matter *Matter, user *User) {
if matter == nil {
@@ -339,7 +271,7 @@ func (this *MatterService) SoftDelete(request *http.Request, matter *Matter, use
//no need to recompute size.
}
// recovery delete files.
//recovery delete files.
func (this *MatterService) Recovery(request *http.Request, matter *Matter, user *User) {
if matter == nil {
@@ -354,8 +286,8 @@ func (this *MatterService) Recovery(request *http.Request, matter *Matter, user
//no need to recompute size.
}
// atomic delete files
func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter, user *User, space *Space) {
//atomic delete files
func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter, user *User) {
if matter == nil {
panic(result.BadRequest("matter cannot be nil"))
@@ -365,11 +297,11 @@ func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter, u
this.userService.MatterLock(matter.UserUuid)
defer this.userService.MatterUnlock(matter.UserUuid)
this.Delete(request, matter, user, space)
this.Delete(request, matter, user)
}
// atomic soft delete files
func (this *MatterService) AtomicSoftDelete(request *http.Request, matter *Matter, user *User, space *Space) {
//atomic soft delete files
func (this *MatterService) AtomicSoftDelete(request *http.Request, matter *Matter, user *User) {
if matter == nil {
panic(result.BadRequest("matter cannot be nil"))
@@ -386,14 +318,14 @@ func (this *MatterService) AtomicSoftDelete(request *http.Request, matter *Matte
//if disabled the recycle feature. then we hard delete.
preference := this.preferenceService.Fetch()
if preference.DeletedKeepDays == 0 {
this.Delete(request, matter, user, space)
this.Delete(request, matter, user)
} else {
this.SoftDelete(request, matter, user)
}
}
// atomic recovery delete files
//atomic recovery delete files
func (this *MatterService) AtomicRecovery(request *http.Request, matter *Matter, user *User) {
if matter == nil {
@@ -411,8 +343,8 @@ func (this *MatterService) AtomicRecovery(request *http.Request, matter *Matter,
this.Recovery(request, matter, user)
}
// upload files.
func (this *MatterService) Upload(request *http.Request, file io.Reader, fileHeader *multipart.FileHeader, user *User, space *Space, dirMatter *Matter, filename string, privacy bool) *Matter {
//upload files.
func (this *MatterService) Upload(request *http.Request, file io.Reader, user *User, dirMatter *Matter, filename string, privacy bool) *Matter {
if user == nil {
panic(result.BadRequest("user cannot be nil."))
@@ -430,26 +362,9 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, fileHea
panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(filename), MATTER_NAME_MAX_LENGTH))
}
//if fileHeader.Size not nill . check size in advance.
if fileHeader != nil {
//check the size limit.
if space.SizeLimit >= 0 {
if fileHeader.Size > space.SizeLimit {
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedLimit, util.HumanFileSize(fileHeader.Size), util.HumanFileSize(space.SizeLimit)))
}
}
//check total size.
if space.TotalSizeLimit >= 0 {
if space.TotalSize+fileHeader.Size > space.TotalSizeLimit {
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedTotalLimit, util.HumanFileSize(space.TotalSize), util.HumanFileSize(space.TotalSizeLimit)))
}
}
}
dirAbsolutePath := dirMatter.AbsolutePath()
count := this.matterDao.CountBySpaceUuidAndPuuidAndDirAndName(space.Uuid, dirMatter.Uuid, false, filename)
count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, false, filename)
if count > 0 {
panic(result.BadRequestI18n(request, i18n.MatterExist, filename))
}
@@ -468,53 +383,47 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, fileHea
destFile, err := os.OpenFile(fileAbsolutePath, os.O_WRONLY|os.O_CREATE, 0777)
this.PanicError(err)
closeDestFile := func() {
defer func() {
err := destFile.Close()
this.PanicError(err)
}
}()
fileSize, err := io.Copy(destFile, file)
this.PanicError(err)
this.logger.Info("upload %s %v ", filename, util.HumanFileSize(fileSize))
if fileHeader == nil {
//check the size limit.
if space.SizeLimit >= 0 {
if fileSize > space.SizeLimit {
closeDestFile()
//check the size limit.
if user.SizeLimit >= 0 {
if fileSize > user.SizeLimit {
//delete the file on disk.
err = os.Remove(fileAbsolutePath)
this.PanicError(err)
//delete the file on disk.
err = os.Remove(fileAbsolutePath)
this.PanicError(err)
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedLimit, util.HumanFileSize(fileSize), util.HumanFileSize(space.SizeLimit)))
}
}
//check total size.
if space.TotalSizeLimit >= 0 {
if space.TotalSize+fileSize > space.TotalSizeLimit {
closeDestFile()
//delete the file on disk.
err = os.Remove(fileAbsolutePath)
this.PanicError(err)
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedTotalLimit, util.HumanFileSize(space.TotalSize), util.HumanFileSize(space.TotalSizeLimit)))
}
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedLimit, util.HumanFileSize(fileSize), util.HumanFileSize(user.SizeLimit)))
}
}
closeDestFile()
//check total size.
if user.TotalSizeLimit >= 0 {
if user.TotalSize+fileSize > user.TotalSizeLimit {
matter := this.createNonDirMatter(dirMatter, filename, fileSize, privacy, user, space)
//delete the file on disk.
err = os.Remove(fileAbsolutePath)
this.PanicError(err)
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedTotalLimit, util.HumanFileSize(user.TotalSize), util.HumanFileSize(user.TotalSizeLimit)))
}
}
matter := this.createNonDirMatter(dirMatter, filename, fileSize, privacy, user)
return matter
}
// create a non dir matter.
func (this *MatterService) createNonDirMatter(dirMatter *Matter, filename string, fileSize int64, privacy bool, user *User, space *Space) *Matter {
func (this *MatterService) createNonDirMatter(dirMatter *Matter, filename string, fileSize int64, privacy bool, user *User) *Matter {
dirRelativePath := dirMatter.Path
fileRelativePath := dirRelativePath + "/" + filename
@@ -522,8 +431,7 @@ func (this *MatterService) createNonDirMatter(dirMatter *Matter, filename string
matter := &Matter{
Puuid: dirMatter.Uuid,
UserUuid: user.Uuid,
SpaceName: space.Name,
SpaceUuid: space.Uuid,
Username: user.Username,
Dir: false,
Name: filename,
Md5: "",
@@ -537,14 +445,14 @@ func (this *MatterService) createNonDirMatter(dirMatter *Matter, filename string
//compute the size of directory
go core.RunWithRecovery(func() {
this.ComputeRouteSize(dirMatter.Uuid, user, space)
this.ComputeRouteSize(dirMatter.Uuid, user)
})
return matter
}
// create a non dir matter.
func (this *MatterService) updateNonDirMatter(matter *Matter, fileSize int64, user *User, space *Space) *Matter {
func (this *MatterService) updateNonDirMatter(matter *Matter, fileSize int64, user *User) *Matter {
matter.Size = fileSize
@@ -552,24 +460,25 @@ func (this *MatterService) updateNonDirMatter(matter *Matter, fileSize int64, us
//compute the size of directory
go core.RunWithRecovery(func() {
this.ComputeRouteSize(matter.Puuid, user, space)
this.ComputeRouteSize(matter.Puuid, user)
})
return matter
}
// compute route size. It will compute upward until root directory
func (this *MatterService) ComputeRouteSize(matterUuid string, user *User, space *Space) {
func (this *MatterService) ComputeRouteSize(matterUuid string, user *User) {
//if to root directory, then update to user's info.
if matterUuid == MATTER_ROOT {
size := this.matterDao.SizeByPuuidAndSpaceUuid(MATTER_ROOT, space.Uuid)
size := this.matterDao.SizeByPuuidAndUserUuid(MATTER_ROOT, user.Uuid)
this.spaceDao.UpdateTotalSize(space.Uuid, size)
db := core.CONTEXT.GetDB().Model(&User{}).Where("uuid = ?", user.Uuid).Update("total_size", size)
this.PanicError(db.Error)
//update user total size info in cache.
space.TotalSize = size
user.TotalSize = size
return
}
@@ -579,63 +488,66 @@ func (this *MatterService) ComputeRouteSize(matterUuid string, user *User, space
//only compute dir
if matter.Dir {
//compute the total size.
size := this.matterDao.SizeByPuuidAndSpaceUuid(matterUuid, space.Uuid)
size := this.matterDao.SizeByPuuidAndUserUuid(matterUuid, user.Uuid)
//when changed, we update
if matter.Size != size {
this.spaceDao.UpdateTotalSize(space.Uuid, size)
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Update("size", size)
this.PanicError(db.Error)
}
}
//update parent recursively.
this.ComputeRouteSize(matter.Puuid, user, space)
this.ComputeRouteSize(matter.Puuid, user)
}
// compute all dir's size.
func (this *MatterService) ComputeAllDirSize(user *User, space *Space) {
func (this *MatterService) ComputeAllDirSize(user *User) {
this.logger.Info("Compute all dir's size for user %s %s", user.Uuid, user.Username)
rootMatter := NewRootMatter(space)
this.ComputeDirSize(rootMatter, user, space)
rootMatter := NewRootMatter(user)
this.ComputeDirSize(rootMatter, user)
}
// compute a dir's size.
func (this *MatterService) ComputeDirSize(dirMatter *Matter, user *User, space *Space) {
func (this *MatterService) ComputeDirSize(dirMatter *Matter, user *User) {
this.logger.Info("Compute dir's size %s %s", dirMatter.Uuid, dirMatter.Name)
//update sub dir first
childrenDirMatters := this.matterDao.FindByUserUuidAndPuuidAndDirTrue(user.Uuid, dirMatter.Uuid)
for _, childrenDirMatter := range childrenDirMatters {
this.ComputeDirSize(childrenDirMatter, user, space)
this.ComputeDirSize(childrenDirMatter, user)
}
//if to root directory, then update to user's info.
if dirMatter.Uuid == MATTER_ROOT {
size := this.matterDao.SizeByPuuidAndSpaceUuid(MATTER_ROOT, space.Uuid)
size := this.matterDao.SizeByPuuidAndUserUuid(MATTER_ROOT, user.Uuid)
this.spaceDao.UpdateTotalSize(space.Uuid, size)
db := core.CONTEXT.GetDB().Model(&User{}).Where("uuid = ?", user.Uuid).Update("total_size", size)
this.PanicError(db.Error)
//update user total size info in cache.
space.TotalSize = size
user.TotalSize = size
} else {
//compute self.
size := this.matterDao.SizeByPuuidAndSpaceUuid(dirMatter.Uuid, user.Uuid)
size := this.matterDao.SizeByPuuidAndUserUuid(dirMatter.Uuid, user.Uuid)
//when changed, we update
if dirMatter.Size != size {
this.spaceDao.UpdateTotalSize(space.Uuid, size)
db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", dirMatter.Uuid).Update("size", size)
this.PanicError(db.Error)
}
}
}
// inner create directory.
func (this *MatterService) createDirectory(request *http.Request, dirMatter *Matter, name string, user *User, space *Space) *Matter {
//inner create directory.
func (this *MatterService) createDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
if dirMatter == nil {
panic(result.BadRequest("dirMatter cannot be nil"))
@@ -649,9 +561,9 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
panic(result.BadRequest("Dir has been deleted. Cannot create dir under it."))
}
if dirMatter.SpaceUuid != space.Uuid {
if dirMatter.UserUuid != user.Uuid {
panic(result.BadRequest("file's space not the same"))
panic(result.BadRequest("file's user not the same"))
}
name = strings.TrimSpace(name)
@@ -670,7 +582,7 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
}
//if exist. return.
matter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, dirMatter.Uuid, TRUE, name)
matter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, TRUE, name)
if matter != nil {
return matter
}
@@ -681,7 +593,7 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
panic(result.BadRequestI18n(request, i18n.MatterDepthExceedLimit, len(parts), MATTER_NAME_MAX_DEPTH))
}
absolutePath := GetSpaceMatterRootDir(space.Name) + dirMatter.Path + "/" + name
absolutePath := GetUserMatterRootDir(user.Username) + dirMatter.Path + "/" + name
relativePath := dirMatter.Path + "/" + name
@@ -693,8 +605,7 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
matter = &Matter{
Puuid: dirMatter.Uuid,
UserUuid: user.Uuid,
SpaceUuid: space.Uuid,
SpaceName: space.Name,
Username: user.Username,
Dir: true,
Name: name,
Path: relativePath,
@@ -706,7 +617,7 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
return matter
}
func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatter *Matter, name string, user *User, space *Space) *Matter {
func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
if dirMatter.Deleted {
panic(result.BadRequest("Dir has been deleted. Cannot create sub dir under it."))
@@ -715,20 +626,20 @@ func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatte
this.userService.MatterLock(user.Uuid)
defer this.userService.MatterUnlock(user.Uuid)
matter := this.createDirectory(request, dirMatter, name, user, space)
matter := this.createDirectory(request, dirMatter, name, user)
return matter
}
// copy or move may overwrite.
func (this *MatterService) handleOverwrite(request *http.Request, user *User, space *Space, destinationPath string, overwrite bool) {
//copy or move may overwrite.
func (this *MatterService) handleOverwrite(request *http.Request, user *User, destinationPath string, overwrite bool) {
destMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, destinationPath)
if destMatter != nil {
//if exist
if overwrite {
//delete.
this.Delete(request, destMatter, user, space)
this.Delete(request, destMatter, user)
} else {
//throw precondition failed. (RFC4918:10.6)
panic(result.CustomWebResult(result.PRECONDITION_FAILED, fmt.Sprintf("%s exists", destMatter.Path)))
@@ -737,8 +648,8 @@ func (this *MatterService) handleOverwrite(request *http.Request, user *User, sp
}
// move srcMatter to destMatter. invoker must handled the overwrite and lock.
func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDirMatter *Matter, user *User, space *Space) {
//move srcMatter to destMatter. invoker must handled the overwrite and lock.
func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDirMatter *Matter, user *User) {
if srcMatter == nil {
panic(result.BadRequest("srcMatter cannot be nil."))
@@ -793,13 +704,13 @@ func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDi
}
//reCompute the size of src and dest.
this.ComputeRouteSize(srcPuuid, user, space)
this.ComputeRouteSize(destDirUuid, user, space)
this.ComputeRouteSize(srcPuuid, user)
this.ComputeRouteSize(destDirUuid, user)
}
// move srcMatter to destMatter(must be dir)
func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter, destDirMatter *Matter, overwrite bool, user *User, space *Space) {
//move srcMatter to destMatter(must be dir)
func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter, destDirMatter *Matter, overwrite bool, user *User) {
if srcMatter == nil {
panic(result.BadRequest("srcMatter cannot be nil."))
@@ -827,14 +738,14 @@ func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter,
//handle the overwrite
destinationPath := destDirMatter.Path + "/" + srcMatter.Name
this.handleOverwrite(request, user, space, destinationPath, overwrite)
this.handleOverwrite(request, user, destinationPath, overwrite)
//do the move operation.
this.move(request, srcMatter, destDirMatter, user, space)
this.move(request, srcMatter, destDirMatter, user)
}
// move srcMatters to destMatter(must be dir)
func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*Matter, destDirMatter *Matter, user *User, space *Space) {
//move srcMatters to destMatter(must be dir)
func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*Matter, destDirMatter *Matter, user *User) {
if destDirMatter == nil {
panic(result.BadRequest("destDirMatter cannot be nil."))
@@ -865,12 +776,12 @@ func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*
}
for _, srcMatter := range srcMatters {
this.move(request, srcMatter, destDirMatter, user, space)
this.move(request, srcMatter, destDirMatter, user)
}
}
// copy srcMatter to destMatter. invoker must handled the overwrite and lock.
//copy srcMatter to destMatter. invoker must handled the overwrite and lock.
func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string) {
this.logger.Info("copy srcPath = %s destPath = %s/%s", srcMatter.Path, destDirMatter.Path, name)
@@ -880,7 +791,7 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
newMatter := &Matter{
Puuid: destDirMatter.Uuid,
UserUuid: srcMatter.UserUuid,
SpaceName: srcMatter.SpaceName,
Username: srcMatter.Username,
Dir: srcMatter.Dir,
Name: name,
Md5: "",
@@ -913,7 +824,7 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
newMatter := &Matter{
Puuid: destDirMatter.Uuid,
UserUuid: srcMatter.UserUuid,
SpaceName: srcMatter.SpaceName,
Username: srcMatter.Username,
Dir: srcMatter.Dir,
Name: name,
Md5: "",
@@ -928,8 +839,8 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
}
}
// copy srcMatter to destMatter.
func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string, overwrite bool, user *User, space *Space) {
//copy srcMatter to destMatter.
func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string, overwrite bool, user *User) {
if srcMatter == nil {
panic(result.BadRequest("srcMatter cannot be nil."))
@@ -943,13 +854,13 @@ func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter,
}
destinationPath := destDirMatter.Path + "/" + name
this.handleOverwrite(request, user, space, destinationPath, overwrite)
this.handleOverwrite(request, user, destinationPath, overwrite)
this.copy(request, srcMatter, destDirMatter, name)
}
// rename matter to name
func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, name string, overwrite bool, user *User, space *Space) {
//rename matter to name
func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, name string, overwrite bool, user *User) {
this.logger.Info("Try to rename srcPath = %s to name = %s", matter.Path, name)
@@ -971,11 +882,11 @@ func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, n
}
//check whether the name used by another matter.
oldMatter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, matter.Puuid, "", name)
oldMatter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, matter.Puuid, "", name)
if oldMatter != nil {
if overwrite {
//delete this one.
this.Delete(request, oldMatter, user, space)
this.Delete(request, oldMatter, user)
} else {
panic(result.CustomWebResult(result.PRECONDITION_FAILED, fmt.Sprintf("%s already exists", name)))
}
@@ -1030,8 +941,8 @@ func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, n
return
}
// 将本地文件映射到蓝眼云盘中去。
func (this *MatterService) AtomicMirror(request *http.Request, srcPath string, destPath string, overwrite bool, user *User, space *Space) {
//将本地文件映射到蓝眼云盘中去。
func (this *MatterService) AtomicMirror(request *http.Request, srcPath string, destPath string, overwrite bool, user *User) {
if user == nil {
panic(result.BadRequest("user cannot be nil"))
@@ -1046,17 +957,17 @@ func (this *MatterService) AtomicMirror(request *http.Request, srcPath string, d
panic(result.BadRequest("dest cannot be null"))
}
destDirMatter := this.CreateDirectories(request, user, space, destPath)
destDirMatter := this.CreateDirectories(request, user, destPath)
if destDirMatter.Deleted {
panic(result.BadRequest("dest matter has been deleted. Cannot mirror."))
}
this.mirror(request, srcPath, destDirMatter, overwrite, user, space)
this.mirror(request, srcPath, destDirMatter, overwrite, user)
}
// 将本地文件/文件夹映射到蓝眼云盘中去。
func (this *MatterService) mirror(request *http.Request, srcPath string, destDirMatter *Matter, overwrite bool, user *User, space *Space) {
//将本地文件/文件夹映射到蓝眼云盘中去。
func (this *MatterService) mirror(request *http.Request, srcPath string, destDirMatter *Matter, overwrite bool, user *User) {
if user == nil {
panic(result.BadRequest("user cannot be nil"))
@@ -1079,10 +990,10 @@ func (this *MatterService) mirror(request *http.Request, srcPath string, destDir
if fileStat.IsDir() {
//判断当前文件夹下,文件是否已经存在了。
srcDirMatter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, destDirMatter.Uuid, TRUE, fileStat.Name())
srcDirMatter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, destDirMatter.Uuid, TRUE, fileStat.Name())
if srcDirMatter == nil {
srcDirMatter = this.createDirectory(request, destDirMatter, fileStat.Name(), user, space)
srcDirMatter = this.createDirectory(request, destDirMatter, fileStat.Name(), user)
}
fileInfos, err := ioutil.ReadDir(srcPath)
@@ -1092,17 +1003,17 @@ func (this *MatterService) mirror(request *http.Request, srcPath string, destDir
for _, fileInfo := range fileInfos {
path := fmt.Sprintf("%s/%s", srcPath, fileInfo.Name())
this.mirror(request, path, srcDirMatter, overwrite, user, space)
this.mirror(request, path, srcDirMatter, overwrite, user)
}
} else {
//判断当前文件夹下,文件是否已经存在了。
matter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, destDirMatter.Uuid, FALSE, fileStat.Name())
matter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, destDirMatter.Uuid, FALSE, fileStat.Name())
if matter != nil {
//如果是覆盖,那么删除之前的文件
if overwrite {
this.Delete(request, matter, user, space)
this.Delete(request, matter, user)
} else {
//直接完成。
return
@@ -1117,19 +1028,19 @@ func (this *MatterService) mirror(request *http.Request, srcPath string, destDir
this.PanicError(err)
}()
this.Upload(request, file, nil, user, space, destDirMatter, fileStat.Name(), true)
this.Upload(request, file, user, destDirMatter, fileStat.Name(), true)
}
}
// 根据一个文件夹路径,依次创建,找到最后一个文件夹的matter,如果中途出错,返回err. 如果存在了那就直接返回即可。
func (this *MatterService) CreateDirectories(request *http.Request, user *User, space *Space, dirPath string) *Matter {
//根据一个文件夹路径,依次创建,找到最后一个文件夹的matter,如果中途出错,返回err. 如果存在了那就直接返回即可。
func (this *MatterService) CreateDirectories(request *http.Request, user *User, dirPath string) *Matter {
dirPath = path.Clean(dirPath)
if dirPath == "/" {
return NewRootMatter(space)
return NewRootMatter(user)
}
//ignore the last slash.
@@ -1154,17 +1065,17 @@ func (this *MatterService) CreateDirectories(request *http.Request, user *User,
//ignore the first element.
if k == 0 {
dirMatter = NewRootMatter(space)
dirMatter = NewRootMatter(user)
continue
}
dirMatter = this.createDirectory(request, dirMatter, name, user, space)
dirMatter = this.createDirectory(request, dirMatter, name, user)
}
return dirMatter
}
// wrap a matter. put its parent.
//wrap a matter. put its parent.
func (this *MatterService) WrapParentDetail(request *http.Request, matter *Matter) *Matter {
if matter == nil {
@@ -1187,7 +1098,7 @@ func (this *MatterService) WrapParentDetail(request *http.Request, matter *Matte
return matter
}
// wrap a matter ,put its children
//wrap a matter ,put its children
func (this *MatterService) WrapChildrenDetail(request *http.Request, matter *Matter) {
if matter == nil {
@@ -1206,14 +1117,14 @@ func (this *MatterService) WrapChildrenDetail(request *http.Request, matter *Mat
}
// fetch a matter's detail with parent info.
//fetch a matter's detail with parent info.
func (this *MatterService) Detail(request *http.Request, uuid string) *Matter {
matter := this.matterDao.CheckByUuid(uuid)
return this.WrapParentDetail(request, matter)
}
// crawl a url to dirMatter
func (this *MatterService) AtomicCrawl(request *http.Request, url string, filename string, user *User, space *Space, dirMatter *Matter, privacy bool) *Matter {
//crawl a url to dirMatter
func (this *MatterService) AtomicCrawl(request *http.Request, url string, filename string, user *User, dirMatter *Matter, privacy bool) *Matter {
if user == nil {
panic(result.BadRequest("user cannot be nil."))
@@ -1237,15 +1148,11 @@ func (this *MatterService) AtomicCrawl(request *http.Request, url string, filena
//download from url.
resp, err := http.Get(url)
this.PanicError(err)
//if resp is not ok.
if resp.StatusCode != 200 {
panic(result.BadRequest("error when crawl from url."))
}
return this.Upload(request, resp.Body, nil, user, space, dirMatter, filename, privacy)
return this.Upload(request, resp.Body, user, dirMatter, filename, privacy)
}
// adjust a matter's path.
//adjust a matter's path.
func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) {
if matter.Dir {
@@ -1269,45 +1176,45 @@ func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) {
}
// delete someone's EyeblueTank files according to physics files.
func (this *MatterService) DeleteByPhysics(request *http.Request, user *User, space *Space) {
//delete someone's EyeblueTank files according to physics files.
func (this *MatterService) DeleteByPhysics(request *http.Request, user *User) {
if user == nil {
panic(result.BadRequest("user cannot be nil."))
}
//scan user's file. scan level by level.
rootMatter := NewRootMatter(space)
this.deleteFolderByPhysics(request, rootMatter, user, space)
rootMatter := NewRootMatter(user)
this.deleteFolderByPhysics(request, rootMatter, user)
}
func (this *MatterService) deleteFolderByPhysics(request *http.Request, dirMatter *Matter, user *User, space *Space) {
func (this *MatterService) deleteFolderByPhysics(request *http.Request, dirMatter *Matter, user *User) {
//scan user's file. scan level by level.
this.matterDao.PageHandle(dirMatter.Uuid, "", space.Uuid, "", "", "", nil, nil, func(matter *Matter) {
this.matterDao.PageHandle(dirMatter.Uuid, user.Uuid, "", "", "", nil, nil, func(matter *Matter) {
if matter.Dir {
//delete children first.
this.deleteFolderByPhysics(request, matter, user, space)
this.deleteFolderByPhysics(request, matter, user)
}
if !util.PathExists(matter.AbsolutePath()) {
this.logger.Info("physics file not exist. delete from tank. %s", matter.Name)
this.AtomicDelete(nil, matter, user, space)
this.AtomicDelete(nil, matter, user)
}
})
}
// scan someone's physics files to EyeblueTank
func (this *MatterService) ScanPhysics(request *http.Request, user *User, space *Space) {
//scan someone's physics files to EyeblueTank
func (this *MatterService) ScanPhysics(request *http.Request, user *User) {
if user == nil {
panic(result.BadRequest("user cannot be nil."))
}
rootDirPath := GetSpaceMatterRootDir(user.Username)
rootDirPath := GetUserMatterRootDir(user.Username)
this.logger.Info("scan %s's root dir %s", user.Username, rootDirPath)
rootExists := util.PathExists(rootDirPath)
@@ -1319,17 +1226,17 @@ func (this *MatterService) ScanPhysics(request *http.Request, user *User, space
panic(result.BadRequest("cannot get root file info."))
}
rootMatter := NewRootMatter(space)
this.scanPhysicsFolder(request, rootFileInfo, rootMatter, user, space)
rootMatter := NewRootMatter(user)
this.scanPhysicsFolder(request, rootFileInfo, rootMatter, user)
}
func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.FileInfo, dirMatter *Matter, user *User, space *Space) {
func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.FileInfo, dirMatter *Matter, user *User) {
if !dirInfo.IsDir() {
return
}
//fetch all matters under this folder.
_, matters := this.matterDao.PlainPage(0, 1000, dirMatter.Uuid, "", space.Uuid, "", "", "", nil, nil, nil)
_, matters := this.matterDao.PlainPage(0, 1000, dirMatter.Uuid, user.Uuid, "", "", "", nil, nil, nil)
nameMatterMap := make(map[string]*Matter)
for _, m := range matters {
nameMatterMap[m.Name] = m
@@ -1359,12 +1266,12 @@ func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.F
if !matter.Dir {
if matter.Size != fileInfo.Size() {
this.logger.Info("update matter: %s size:%d -> %d", name, matter.Size, fileInfo.Size())
this.updateNonDirMatter(matter, fileInfo.Size(), user, space)
this.updateNonDirMatter(matter, fileInfo.Size(), user)
}
} else {
//recursive scan this folder.
this.scanPhysicsFolder(request, fileInfo, matter, user, space)
this.scanPhysicsFolder(request, fileInfo, matter, user)
}
@@ -1373,16 +1280,16 @@ func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.F
if fileInfo.IsDir() {
//create folder.
matter = this.createDirectory(request, dirMatter, name, user, space)
matter = this.createDirectory(request, dirMatter, name, user)
//recursive scan this folder.
this.scanPhysicsFolder(request, fileInfo, matter, user, space)
this.scanPhysicsFolder(request, fileInfo, matter, user)
} else {
//not exist. add basic info.
this.logger.Info("Create matter: %s size:%d", name, fileInfo.Size())
matter = this.createNonDirMatter(dirMatter, name, fileInfo.Size(), true, user, space)
matter = this.createNonDirMatter(dirMatter, name, fileInfo.Size(), true, user)
}
@@ -1390,14 +1297,14 @@ func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.F
}
}
// clean all the expired deleted matters
//clean all the expired deleted matters
func (this *MatterService) CleanExpiredDeletedMatters() {
//mock a request.
request := &http.Request{}
preference := this.preferenceService.Fetch()
this.userDao.PageHandle("", "", func(user *User, space *Space) {
this.userDao.PageHandle("", "", func(user *User) {
this.logger.Info("Clean %s 's deleted matters", user.Username)
@@ -1408,8 +1315,8 @@ func (this *MatterService) CleanExpiredDeletedMatters() {
}
//first remove all the matter(not dir).
this.matterDao.PageHandle("", "", "", "", FALSE, TRUE, &thenDate, nil, func(matter *Matter) {
this.Delete(request, matter, user, space)
this.matterDao.PageHandle("", "", "", FALSE, TRUE, &thenDate, nil, func(matter *Matter) {
this.Delete(request, matter, user)
})
sortArray := []builder.OrderPair{
@@ -1420,8 +1327,8 @@ func (this *MatterService) CleanExpiredDeletedMatters() {
}
//remove all the deleted directories. sort by path.
this.matterDao.PageHandle("", "", "", "", TRUE, TRUE, &thenDate, sortArray, func(matter *Matter) {
this.Delete(request, matter, user, space)
this.matterDao.PageHandle("", "", "", TRUE, TRUE, &thenDate, sortArray, func(matter *Matter) {
this.Delete(request, matter, user)
})
})
+81
View File
@@ -0,0 +1,81 @@
package rest
import (
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/eyebluecn/tank/code/core"
)
// oss service
//@Service
type OssService struct {
BaseBean
matterDao *MatterDao
//whether scan task is running
client *oss.Client
bucket *oss.Bucket
}
func (this *OssService) Init() {
this.BaseBean.Init()
b := core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
}
//upload a matter to oss.
func (this *OssService) Upload(matter *Matter) {
//只上传文件,忽略文件夹。
if matter.Dir {
return
}
//只上传没有传过的。
if matter.Md5 != "" {
return
}
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
objectName := matter.Path
if len(matter.Path) > 1 {
objectName = matter.Path[1:]
}
// <yourLocalFileName>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
localFileName := matter.AbsolutePath()
// 上传文件。
err := this.bucket.PutObjectFromFile(objectName, localFileName)
this.PanicError(err)
// 修改本地文件的md5字段
matter.Md5 = fmt.Sprintf("%s/%s", core.CONFIG.OssCustomHost(), objectName)
this.matterDao.Save(matter)
this.logger.Info("upload %s %s to oss path = %s", matter.Uuid, matter.Name, objectName)
}
func (this *OssService) Bootstrap() {
// Endpoint以杭州为例,其它Region请按实际情况填写。
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
// 创建OSSClient实例。
client, err := oss.New(fmt.Sprintf("http://%s", core.CONFIG.OssEndpoint()), core.CONFIG.OssAccessKey(), core.CONFIG.OssSecretKey())
this.client = client
this.PanicError(err)
// 获取存储空间。
bucket, err := this.client.Bucket(core.CONFIG.OssBucket())
this.bucket = bucket
this.PanicError(err)
this.logger.Info("OssService bootstrap.")
}
+20 -18
View File
@@ -1,28 +1,30 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
jsoniter "github.com/json-iterator/go"
"time"
)
type Preference struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Name string `json:"name" gorm:"type:varchar(45)"`
LogoUrl string `json:"logoUrl" gorm:"type:varchar(255)"`
FaviconUrl string `json:"faviconUrl" gorm:"type:varchar(255)"`
Copyright string `json:"copyright" gorm:"type:varchar(1024)"`
Record string `json:"record" gorm:"type:varchar(1024)"`
DownloadDirMaxSize int64 `json:"downloadDirMaxSize" gorm:"type:bigint(20) not null;default:-1"`
DownloadDirMaxNum int64 `json:"downloadDirMaxNum" gorm:"type:bigint(20) not null;default:-1"`
DefaultTotalSizeLimit int64 `json:"defaultTotalSizeLimit" gorm:"type:bigint(20) not null;default:-1"`
AllowRegister bool `json:"allowRegister" gorm:"type:tinyint(1) not null;default:0"`
PreviewConfig string `json:"previewConfig" gorm:"type:text"`
ScanConfig string `json:"scanConfig" gorm:"type:text"`
DeletedKeepDays int64 `json:"deletedKeepDays" gorm:"type:bigint(20) not null;default:7"`
Version string `json:"version" gorm:"-"`
Base
Name string `json:"name" gorm:"type:varchar(45)"`
LogoUrl string `json:"logoUrl" gorm:"type:varchar(255)"`
FaviconUrl string `json:"faviconUrl" gorm:"type:varchar(255)"`
Copyright string `json:"copyright" gorm:"type:varchar(1024)"`
Record string `json:"record" gorm:"type:varchar(1024)"`
DownloadDirMaxSize int64 `json:"downloadDirMaxSize" gorm:"type:bigint(20) not null;default:-1"`
DownloadDirMaxNum int64 `json:"downloadDirMaxNum" gorm:"type:bigint(20) not null;default:-1"`
DefaultTotalSizeLimit int64 `json:"defaultTotalSizeLimit" gorm:"type:bigint(20) not null;default:-1"`
AllowRegister bool `json:"allowRegister" gorm:"type:tinyint(1) not null;default:0"`
PreviewConfig string `json:"previewConfig" gorm:"type:text"`
ScanConfig string `json:"scanConfig" gorm:"type:text"`
DeletedKeepDays int64 `json:"deletedKeepDays" gorm:"type:bigint(20) not null;default:7"`
Version string `json:"version" gorm:"-"`
}
// set File's table name to be `profiles`
func (this *Preference) TableName() string {
return core.TABLE_PREFIX + "preference"
}
const (
+7 -4
View File
@@ -1,15 +1,18 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
type Session struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Base
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
Ip string `json:"ip" gorm:"type:varchar(128) not null"`
ExpireTime time.Time `json:"expireTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
}
// set User's table name to be `profiles`
func (this *Session) TableName() string {
return core.TABLE_PREFIX + "session"
}
+29 -112
View File
@@ -19,7 +19,6 @@ type ShareController struct {
matterDao *MatterDao
matterService *MatterService
shareService *ShareService
alienService *AlienService
}
func (this *ShareController) Init() {
@@ -50,11 +49,6 @@ func (this *ShareController) Init() {
this.shareService = b
}
b = core.CONTEXT.GetBean(this.alienService)
if b, ok := b.(*AlienService); ok {
this.alienService = b
}
}
func (this *ShareController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
@@ -69,28 +63,43 @@ func (this *ShareController) RegisterRoutes() map[string]func(writer http.Respon
routeMap["/api/share/browse"] = this.Wrap(this.Browse, USER_ROLE_GUEST)
routeMap["/api/share/zip"] = this.Wrap(this.Zip, USER_ROLE_GUEST)
routeMap["/api/share/matter/page"] = this.Wrap(this.MatterPage, USER_ROLE_GUEST)
routeMap["/api/share/matter/preview"] = this.WrapPure(this.MatterPreview, USER_ROLE_GUEST)
routeMap["/api/share/matter/download"] = this.WrapPure(this.MatterDownload, USER_ROLE_GUEST)
return routeMap
}
func (this *ShareController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuidArray := util.ExtractRequestArray(request, "matterUuids")
expireInfinity := util.ExtractRequestBool(request, "expireInfinity")
spaceUuid := util.ExtractRequestString(request, "spaceUuid")
matterUuids := request.FormValue("matterUuids")
expireInfinityStr := request.FormValue("expireInfinity")
expireTimeStr := request.FormValue("expireTime")
if matterUuids == "" {
panic(result.BadRequest("matterUuids cannot be null"))
}
var expireTime time.Time
expireInfinity := false
if expireInfinityStr == TRUE {
expireInfinity = true
expireTime = time.Now()
} else {
if expireTimeStr == "" {
panic(result.BadRequest("time format error"))
} else {
expireTime = util.ConvertDateTimeStringToTime(expireTimeStr)
}
var expireTime = time.Now()
if !expireInfinity {
expireTime = util.ExtractRequestTime(request, "expireTime")
if expireTime.Before(time.Now()) {
panic(result.BadRequest("expire time cannot before now"))
}
}
if len(uuidArray) > SHARE_MAX_NUM {
uuidArray := strings.Split(matterUuids, ",")
if len(uuidArray) == 0 {
panic(result.BadRequest("share at least one file"))
} else if len(uuidArray) > SHARE_MAX_NUM {
panic(result.BadRequestI18n(request, i18n.ShareNumExceedLimit, len(uuidArray), SHARE_MAX_NUM))
}
@@ -139,7 +148,6 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re
Code: util.RandomString4(),
ExpireInfinity: expireInfinity,
ExpireTime: expireTime,
SpaceUuid: spaceUuid,
}
this.shareDao.Create(share)
@@ -184,14 +192,14 @@ func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *ht
for _, uuid := range uuidArray {
share := this.shareDao.FindByUuid(uuid)
imageCache := this.shareDao.FindByUuid(uuid)
user := this.checkUser(request)
if share.UserUuid != user.Uuid {
if imageCache.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
this.shareDao.Delete(share)
this.shareDao.Delete(imageCache)
}
return this.Success("OK")
@@ -258,7 +266,6 @@ func (this *ShareController) CheckShare(writer http.ResponseWriter, request *htt
return this.shareService.CheckShare(request, shareUuid, code, user)
}
// get the basic info of this share.
func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Request) *result.WebResult {
shareUuid := request.FormValue("shareUuid")
@@ -271,10 +278,6 @@ func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Re
user := this.findUser(request)
share := this.shareService.CheckShare(request, shareUuid, code, user)
bridges := this.bridgeDao.FindByShareUuid(share.Uuid)
shareOwner := this.userDao.FindByUuid(share.UserUuid)
if shareOwner.Status == USER_STATUS_DISABLED {
panic(result.BadRequestI18n(request, i18n.UserDisabled))
}
if puuid == MATTER_ROOT {
@@ -368,89 +371,3 @@ func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Reque
return nil
}
// matter list under a share.
func (this *ShareController) MatterPage(writer http.ResponseWriter, request *http.Request) *result.WebResult {
page := util.ExtractRequestOptionalInt(request, "page", 0)
pageSize := util.ExtractRequestOptionalInt(request, "pageSize", 200)
orderCreateTime := util.ExtractRequestOptionalString(request, "orderCreateTime", "")
orderUpdateTime := util.ExtractRequestOptionalString(request, "orderUpdateTime", "")
orderDeleteTime := util.ExtractRequestOptionalString(request, "orderDeleteTime", "")
orderSort := util.ExtractRequestOptionalString(request, "orderSort", "")
orderTimes := util.ExtractRequestOptionalString(request, "orderTimes", "")
orderDir := util.ExtractRequestOptionalString(request, "orderDir", "")
orderSize := util.ExtractRequestOptionalString(request, "orderSize", "")
orderName := util.ExtractRequestOptionalString(request, "orderName", "")
puuid := util.ExtractRequestString(request, "puuid")
name := util.ExtractRequestOptionalString(request, "name", "")
dir := util.ExtractRequestOptionalString(request, "dir", "")
deleted := util.ExtractRequestOptionalString(request, "deleted", "")
extensionsStr := util.ExtractRequestOptionalString(request, "extensions", "")
//auth by shareUuid.
shareUuid := util.ExtractRequestString(request, "shareUuid")
shareCode := util.ExtractRequestString(request, "shareCode")
shareRootUuid := util.ExtractRequestString(request, "shareRootUuid")
//validate the puuid.
dirMatter := this.matterDao.CheckByUuid(puuid)
if !dirMatter.Dir {
panic(result.BadRequest("puuid is not a directory"))
}
//validate the shareUuid,shareCode,shareRootUuid.
user := this.findUser(request)
share := this.shareService.ValidateMatter(request, shareUuid, shareCode, user, shareRootUuid, dirMatter)
puuid = dirMatter.Uuid
var extensions []string
if extensionsStr != "" {
extensions = strings.Split(extensionsStr, ",")
}
pager := this.matterService.Page(
request,
page,
pageSize,
orderCreateTime,
orderUpdateTime,
orderDeleteTime,
orderSort,
orderTimes,
orderDir,
orderSize,
orderName,
puuid,
name,
dir,
deleted,
extensions,
share.SpaceUuid,
)
return this.Success(pager)
}
func (this *ShareController) MatterPreviewOrDownload(writer http.ResponseWriter, request *http.Request, withContentDisposition bool) {
//auth by shareUuid.
matterUuid := util.ExtractRequestString(request, "matterUuid")
shareUuid := util.ExtractRequestString(request, "shareUuid")
shareCode := util.ExtractRequestString(request, "shareCode")
shareRootUuid := util.ExtractRequestString(request, "shareRootUuid")
matter := this.matterDao.CheckByUuid(matterUuid)
operator := this.findUser(request)
this.shareService.ValidateMatter(request, shareUuid, shareCode, operator, shareRootUuid, matter)
this.alienService.PreviewOrDownload(writer, request, matter, withContentDisposition)
}
func (this *ShareController) MatterPreview(writer http.ResponseWriter, request *http.Request) {
this.MatterPreviewOrDownload(writer, request, false)
}
func (this *ShareController) MatterDownload(writer http.ResponseWriter, request *http.Request) {
this.MatterPreviewOrDownload(writer, request, true)
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"gorm.io/gorm"
"github.com/jinzhu/gorm"
"github.com/eyebluecn/tank/code/tool/uuid"
"time"
@@ -56,7 +56,7 @@ func (this *ShareDao) PlainPage(page int, pageSize int, userUuid string, sortArr
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Share{}).Where(wp.Query, wp.Args...)
var count int64 = 0
count := 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
@@ -64,7 +64,7 @@ func (this *ShareDao) PlainPage(page int, pageSize int, userUuid string, sortArr
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&shares)
this.PanicError(db.Error)
return int(count), shares
return count, shares
}
func (this *ShareDao) Create(share *Share) *Share {
+7 -5
View File
@@ -1,6 +1,7 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
@@ -21,10 +22,7 @@ const (
* share record
*/
type Share struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Base
Name string `json:"name" gorm:"type:varchar(255)"`
ShareType string `json:"shareType" gorm:"type:varchar(45)"`
Username string `json:"username" gorm:"type:varchar(45)"`
@@ -33,7 +31,11 @@ type Share struct {
Code string `json:"code" gorm:"type:varchar(45) not null"`
ExpireInfinity bool `json:"expireInfinity" gorm:"type:tinyint(1) not null;default:0"`
ExpireTime time.Time `json:"expireTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
SpaceUuid string `json:"spaceUuid" gorm:"type:char(36) not null;index:idx_space_uuid"`
DirMatter *Matter `json:"dirMatter" gorm:"-"`
Matters []*Matter `json:"matters" gorm:"-"`
}
// set File's table name to be `profiles`
func (this *Share) TableName() string {
return core.TABLE_PREFIX + "share"
}
+9 -16
View File
@@ -11,7 +11,7 @@ import (
"time"
)
// @Service
//@Service
type ShareService struct {
BaseBean
shareDao *ShareDao
@@ -74,24 +74,24 @@ func (this *ShareService) CheckShare(request *http.Request, shareUuid string, co
return share
}
// check whether a user can access a matter. shareRootUuid is matter's parent(or parent's parent and so on)
func (this *ShareService) ValidateMatter(request *http.Request, shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) *Share {
//check whether a user can access a matter. shareRootUuid is matter's parent(or parent's parent and so on)
func (this *ShareService) ValidateMatter(request *http.Request, shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) {
if matter == nil {
panic(result.Unauthorized("matter cannot be nil"))
}
//if self's matter, ok.
if user != nil && matter.UserUuid == user.Uuid {
return
}
if shareUuid == "" || code == "" || shareRootUuid == "" {
panic(result.Unauthorized("shareUuid,code,shareRootUuid cannot be null"))
}
share := this.CheckShare(request, shareUuid, code, user)
shareOwner := this.userDao.FindByUuid(share.UserUuid)
if shareOwner.Status == USER_STATUS_DISABLED {
panic(result.BadRequestI18n(request, i18n.UserDisabled))
}
//if shareRootUuid is root. Bridge must has record.
if shareRootUuid == MATTER_ROOT {
@@ -109,11 +109,9 @@ func (this *ShareService) ValidateMatter(request *http.Request, shareUuid string
}
}
return share
}
// delete user's shares and corresponding bridges.
//delete user's shares and corresponding bridges.
func (this *ShareService) DeleteSharesByUser(request *http.Request, currentUser *User) {
//delete share and bridges.
@@ -137,8 +135,3 @@ func (this *ShareService) DeleteSharesByUser(request *http.Request, currentUser
}
}
// edit space's info.
func (this *ShareService) Edit(spaceUuid string, sizeLimit int64, totalSizeLimit int64) {
}
-160
View File
@@ -1,160 +0,0 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/i18n"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"net/http"
)
type SpaceController struct {
BaseController
spaceDao *SpaceDao
spaceMemberDao *SpaceMemberDao
spaceMemberService *SpaceMemberService
matterDao *MatterDao
matterService *MatterService
spaceService *SpaceService
userService *UserService
}
func (this *SpaceController) Init() {
this.BaseController.Init()
b := core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.spaceMemberDao)
if b, ok := b.(*SpaceMemberDao); ok {
this.spaceMemberDao = b
}
b = core.CONTEXT.GetBean(this.spaceMemberService)
if b, ok := b.(*SpaceMemberService); ok {
this.spaceMemberService = b
}
b = core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
b = core.CONTEXT.GetBean(this.matterService)
if b, ok := b.(*MatterService); ok {
this.matterService = b
}
b = core.CONTEXT.GetBean(this.spaceService)
if b, ok := b.(*SpaceService); ok {
this.spaceService = b
}
b = core.CONTEXT.GetBean(this.userService)
if b, ok := b.(*UserService); ok {
this.userService = b
}
}
func (this *SpaceController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
routeMap["/api/space/create"] = this.Wrap(this.Create, USER_ROLE_ADMINISTRATOR)
routeMap["/api/space/edit"] = this.Wrap(this.Edit, USER_ROLE_ADMINISTRATOR)
routeMap["/api/space/delete"] = this.Wrap(this.Delete, USER_ROLE_ADMINISTRATOR)
routeMap["/api/space/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
routeMap["/api/space/page"] = this.Wrap(this.Page, USER_ROLE_USER)
return routeMap
}
func (this *SpaceController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult {
//space's name
name := util.ExtractRequestString(request, "name")
sizeLimit := util.ExtractRequestInt64(request, "sizeLimit")
totalSizeLimit := util.ExtractRequestInt64(request, "totalSizeLimit")
//create related space.
space := this.spaceService.CreateSpace(request, name, nil, sizeLimit, totalSizeLimit, SPACE_TYPE_SHARED)
return this.Success(space)
}
func (this *SpaceController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
//space's uuid
uuid := util.ExtractRequestString(request, "uuid")
sizeLimit := util.ExtractRequestInt64(request, "sizeLimit")
totalSizeLimit := util.ExtractRequestInt64(request, "totalSizeLimit")
user := this.checkUser(request)
space := this.spaceService.Edit(request, user, uuid, sizeLimit, totalSizeLimit)
return this.Success(space)
}
func (this *SpaceController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult {
//space's name
uuid := util.ExtractRequestString(request, "uuid")
space := this.spaceDao.CheckByUuid(uuid)
//when space has members, cannot delete.
memberCount := this.spaceMemberDao.CountBySpaceUuid(uuid)
if memberCount > 0 {
panic(result.BadRequest("space has members, cannot be deleted."))
}
//TODO: when space has files, cannot delete.
//delete the space.
this.spaceDao.Delete(space)
return this.Success(nil)
}
func (this *SpaceController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
user := this.checkUser(request)
space := this.spaceDao.CheckByUuid(uuid)
canRead := this.spaceMemberService.canRead(user, space.Uuid)
if !canRead {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
return this.Success(space)
}
func (this *SpaceController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
page := util.ExtractRequestOptionalInt(request, "page", 0)
pageSize := util.ExtractRequestOptionalInt(request, "pageSize", 20)
orderCreateTime := util.ExtractRequestOptionalString(request, "orderCreateTime", "")
spaceType := util.ExtractRequestOptionalString(request, "type", SPACE_TYPE_SHARED)
user := this.checkUser(request)
sortArray := []builder.OrderPair{
{
Key: "create_time",
Value: orderCreateTime,
},
}
var pager *Pager
if user.Role == USER_ROLE_USER {
pager = this.spaceDao.SelfPage(page, pageSize, user.Uuid, spaceType, sortArray)
} else if user.Role == USER_ROLE_ADMINISTRATOR {
pager = this.spaceDao.Page(page, pageSize, spaceType, sortArray)
}
return this.Success(pager)
}
-152
View File
@@ -1,152 +0,0 @@
package rest
import (
"fmt"
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"gorm.io/gorm"
"github.com/eyebluecn/tank/code/tool/uuid"
"time"
)
type SpaceDao struct {
BaseDao
}
// find by uuid. if not found return nil.
func (this *SpaceDao) FindByUuid(uuid string) *Space {
var entity = &Space{}
db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity)
if db.Error != nil {
if db.Error.Error() == result.DB_ERROR_NOT_FOUND {
return nil
} else {
panic(db.Error)
}
}
return entity
}
// find by uuid. if not found panic NotFound error
func (this *SpaceDao) CheckByUuid(uuid string) *Space {
entity := this.FindByUuid(uuid)
if entity == nil {
panic(result.NotFound("not found record with uuid = %s", uuid))
}
return entity
}
func (this *SpaceDao) CountByName(name string) int {
var count int64
db := core.CONTEXT.GetDB().
Model(&Space{}).
Where("name = ?", name).
Count(&count)
this.PanicError(db.Error)
return int(count)
}
func (this *SpaceDao) CountByUserUuid(userUuid string) int {
var count int64
db := core.CONTEXT.GetDB().
Model(&Space{}).
Where("user_uuid = ?", userUuid).
Count(&count)
this.PanicError(db.Error)
return int(count)
}
// TODO:
func (this *SpaceDao) SelfPage(page int, pageSize int, userUuid string, spaceType string, sortArray []builder.OrderPair) *Pager {
countSqlTemplate := fmt.Sprintf("SELECT COUNT(*) FROM `%sspace` WHERE uuid IN (SELECT space_uuid FROM `%sspace_member` WHERE user_uuid = ?) AND type = ?", core.TABLE_PREFIX, core.TABLE_PREFIX)
if spaceType == SPACE_TYPE_PRIVATE {
countSqlTemplate = fmt.Sprintf("SELECT COUNT(*) FROM `%sspace` WHERE user_uuid = ? AND type = ?", core.TABLE_PREFIX)
}
var count int
core.CONTEXT.GetDB().Raw(countSqlTemplate, userUuid, spaceType).Scan(&count)
orderByString := this.GetSortString(sortArray)
if orderByString == "" {
orderByString = "uuid"
}
querySqlTemplate := fmt.Sprintf("SELECT * FROM `%sspace` WHERE uuid IN (SELECT space_uuid FROM `%sspace_member` WHERE user_uuid = ?) AND type = ? ORDER BY ? LIMIT ?,?", core.TABLE_PREFIX, core.TABLE_PREFIX)
if spaceType == SPACE_TYPE_PRIVATE {
querySqlTemplate = fmt.Sprintf("SELECT * FROM `%sspace` WHERE user_uuid = ? AND type = ? ORDER BY ? LIMIT ?,?", core.TABLE_PREFIX)
}
var spaces []*Space
core.CONTEXT.GetDB().Raw(querySqlTemplate, userUuid, spaceType, orderByString, page*pageSize, pageSize).Scan(&spaces)
pager := NewPager(page, pageSize, count, spaces)
return pager
}
func (this *SpaceDao) Page(page int, pageSize int, spaceType string, sortArray []builder.OrderPair) *Pager {
count, spaces := this.PlainPage(page, pageSize, spaceType, sortArray)
pager := NewPager(page, pageSize, count, spaces)
return pager
}
func (this *SpaceDao) PlainPage(page int, pageSize int, spaceType string, sortArray []builder.OrderPair) (int, []*Space) {
var wp = &builder.WherePair{Query: "type = ?", Args: []interface{}{spaceType}}
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Space{}).Where(wp.Query, wp.Args...)
var count int64 = 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var spaces []*Space
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&spaces)
this.PanicError(db.Error)
return int(count), spaces
}
func (this *SpaceDao) Create(space *Space) *Space {
timeUUID, _ := uuid.NewV4()
space.Uuid = string(timeUUID.String())
space.CreateTime = time.Now()
space.UpdateTime = time.Now()
space.Sort = time.Now().UnixNano() / 1e6
db := core.CONTEXT.GetDB().Create(space)
this.PanicError(db.Error)
return space
}
func (this *SpaceDao) Save(space *Space) *Space {
space.UpdateTime = time.Now()
db := core.CONTEXT.GetDB().Save(space)
this.PanicError(db.Error)
return space
}
func (this *SpaceDao) UpdateTotalSize(spaceUuid string, totalSize int64) {
db := core.CONTEXT.GetDB().Model(&Space{}).Where("uuid = ?", spaceUuid).Update("total_size", totalSize)
this.PanicError(db.Error)
}
func (this *SpaceDao) Delete(space *Space) {
db := core.CONTEXT.GetDB().Delete(&space)
this.PanicError(db.Error)
}
// System cleanup.
func (this *SpaceDao) Cleanup() {
this.logger.Info("[SpaceDao] clean up. Delete all Space")
db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Space{})
this.PanicError(db.Error)
}
-205
View File
@@ -1,205 +0,0 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/i18n"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"net/http"
)
type SpaceMemberController struct {
BaseController
spaceMemberDao *SpaceMemberDao
spaceDao *SpaceDao
bridgeDao *BridgeDao
matterDao *MatterDao
matterService *MatterService
spaceMemberService *SpaceMemberService
}
func (this *SpaceMemberController) Init() {
this.BaseController.Init()
b := core.CONTEXT.GetBean(this.spaceMemberDao)
if b, ok := b.(*SpaceMemberDao); ok {
this.spaceMemberDao = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.bridgeDao)
if b, ok := b.(*BridgeDao); ok {
this.bridgeDao = b
}
b = core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
b = core.CONTEXT.GetBean(this.matterService)
if b, ok := b.(*MatterService); ok {
this.matterService = b
}
b = core.CONTEXT.GetBean(this.spaceMemberService)
if b, ok := b.(*SpaceMemberService); ok {
this.spaceMemberService = b
}
}
func (this *SpaceMemberController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
//admin user can create/edit/delete
routeMap["/api/space/member/create"] = this.Wrap(this.Create, USER_ROLE_USER)
routeMap["/api/space/member/edit"] = this.Wrap(this.Edit, USER_ROLE_USER)
routeMap["/api/space/member/delete"] = this.Wrap(this.Delete, USER_ROLE_USER)
routeMap["/api/space/member/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
routeMap["/api/space/member/mine"] = this.Wrap(this.Mine, USER_ROLE_USER)
routeMap["/api/space/member/page"] = this.Wrap(this.Page, USER_ROLE_USER)
return routeMap
}
func (this *SpaceMemberController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult {
spaceUuid := util.ExtractRequestString(request, "spaceUuid")
userUuid := util.ExtractRequestString(request, "userUuid")
spaceRole := util.ExtractRequestString(request, "role")
if spaceRole != SPACE_MEMBER_ROLE_READ_ONLY && spaceRole != SPACE_MEMBER_ROLE_READ_WRITE && spaceRole != SPACE_MEMBER_ROLE_ADMIN {
panic("spaceRole is not correct")
}
currentUser := this.checkUser(request)
canManage := this.spaceMemberService.canManage(currentUser, spaceUuid)
if !canManage {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
//check whether exists.
spaceMember := this.spaceMemberDao.FindBySpaceUuidAndUserUuid(spaceUuid, userUuid)
if spaceMember != nil {
panic(result.BadRequestI18n(request, i18n.SpaceMemberExist))
}
//check whether space exists.
space := this.spaceDao.CheckByUuid(spaceUuid)
user := this.userDao.CheckByUuid(userUuid)
spaceMember = this.spaceMemberService.CreateMember(space, user, spaceRole)
return this.Success(spaceMember)
}
func (this *SpaceMemberController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
spaceRole := util.ExtractRequestString(request, "role")
if spaceRole != SPACE_MEMBER_ROLE_READ_ONLY && spaceRole != SPACE_MEMBER_ROLE_READ_WRITE && spaceRole != SPACE_MEMBER_ROLE_ADMIN {
panic("spaceRole is not correct")
}
spaceMember := this.spaceMemberDao.CheckByUuid(uuid)
currentUser := this.checkUser(request)
canManage := this.spaceMemberService.canManage(currentUser, spaceMember.SpaceUuid)
if !canManage {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
spaceMember.Role = spaceRole
spaceMember = this.spaceMemberDao.Save(spaceMember)
return this.Success(spaceMember)
}
func (this *SpaceMemberController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
spaceMember := this.spaceMemberDao.CheckByUuid(uuid)
user := this.checkUser(request)
canManage := this.spaceMemberService.canManage(user, spaceMember.SpaceUuid)
if !canManage {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
this.spaceMemberDao.Delete(spaceMember)
return this.Success("OK")
}
func (this *SpaceMemberController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := util.ExtractRequestString(request, "uuid")
spaceMember := this.spaceMemberDao.CheckByUuid(uuid)
user := this.checkUser(request)
if spaceMember.UserUuid != user.Uuid {
panic(result.UNAUTHORIZED)
}
return this.Success(spaceMember)
}
// find my role in the space.
func (this *SpaceMemberController) Mine(writer http.ResponseWriter, request *http.Request) *result.WebResult {
spaceUuid := util.ExtractRequestString(request, "spaceUuid")
user := this.checkUser(request)
spaceMember := this.spaceMemberDao.FindBySpaceUuidAndUserUuid(spaceUuid, user.Uuid)
if spaceMember == nil {
spaceMember = &SpaceMember{SpaceUuid: spaceUuid, Role: SPACE_MEMBER_GUEST}
}
if user.Role == USER_ROLE_ADMINISTRATOR {
spaceMember.Role = SPACE_MEMBER_ROLE_ADMIN
}
return this.Success(spaceMember)
}
func (this *SpaceMemberController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
page := util.ExtractRequestOptionalInt(request, "page", 0)
pageSize := util.ExtractRequestOptionalInt(request, "pageSize", 20)
orderCreateTime := util.ExtractRequestOptionalString(request, "orderCreateTime", "")
spaceUuid := util.ExtractRequestString(request, "spaceUuid")
user := this.checkUser(request)
canRead := this.spaceMemberService.canRead(user, spaceUuid)
if !canRead {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
sortArray := []builder.OrderPair{
{
Key: "create_time",
Value: orderCreateTime,
},
}
pager := this.spaceMemberDao.Page(page, pageSize, spaceUuid, sortArray)
//fill the space's user. FIXME: user better way to get User.
if pager != nil {
for _, spaceMember := range pager.Data.([]*SpaceMember) {
spaceMember.User = this.userDao.FindByUuid(spaceMember.UserUuid)
}
}
return this.Success(pager)
}
-139
View File
@@ -1,139 +0,0 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"gorm.io/gorm"
"github.com/eyebluecn/tank/code/tool/uuid"
"time"
)
type SpaceMemberDao struct {
BaseDao
}
// find by uuid. if not found return nil.
func (this *SpaceMemberDao) FindByUuid(uuid string) *SpaceMember {
var entity = &SpaceMember{}
db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity)
if db.Error != nil {
if db.Error.Error() == result.DB_ERROR_NOT_FOUND {
return nil
} else {
panic(db.Error)
}
}
return entity
}
// find by uuid. if not found panic NotFound error
func (this *SpaceMemberDao) CheckByUuid(uuid string) *SpaceMember {
entity := this.FindByUuid(uuid)
if entity == nil {
panic(result.NotFound("not found record with uuid = %s", uuid))
}
return entity
}
// find by spaceUuid and userUuid. if not found return nil.
func (this *SpaceMemberDao) FindBySpaceUuidAndUserUuid(spaceUuid string, userUuid string) *SpaceMember {
var entity = &SpaceMember{}
db := core.CONTEXT.GetDB().Where("space_uuid = ? AND user_uuid = ?", spaceUuid, userUuid).First(entity)
if db.Error != nil {
if db.Error.Error() == result.DB_ERROR_NOT_FOUND {
return nil
} else {
panic(db.Error)
}
}
return entity
}
func (this *SpaceMemberDao) Page(page int, pageSize int, spaceUuid string, sortArray []builder.OrderPair) *Pager {
count, spaceMembers := this.PlainPage(page, pageSize, spaceUuid, sortArray)
pager := NewPager(page, pageSize, count, spaceMembers)
return pager
}
func (this *SpaceMemberDao) PlainPage(page int, pageSize int, spaceUuid string, sortArray []builder.OrderPair) (int, []*SpaceMember) {
var wp = &builder.WherePair{}
if spaceUuid != "" {
wp = wp.And(&builder.WherePair{Query: "space_uuid = ?", Args: []interface{}{spaceUuid}})
}
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&SpaceMember{}).Where(wp.Query, wp.Args...)
var count int64 = 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var spaceMembers []*SpaceMember
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&spaceMembers)
this.PanicError(db.Error)
return int(count), spaceMembers
}
func (this *SpaceMemberDao) Create(spaceMember *SpaceMember) *SpaceMember {
timeUUID, _ := uuid.NewV4()
spaceMember.Uuid = string(timeUUID.String())
spaceMember.CreateTime = time.Now()
spaceMember.UpdateTime = time.Now()
spaceMember.Sort = time.Now().UnixNano() / 1e6
db := core.CONTEXT.GetDB().Create(spaceMember)
this.PanicError(db.Error)
return spaceMember
}
func (this *SpaceMemberDao) Save(spaceMember *SpaceMember) *SpaceMember {
spaceMember.UpdateTime = time.Now()
db := core.CONTEXT.GetDB().Save(spaceMember)
this.PanicError(db.Error)
return spaceMember
}
func (this *SpaceMemberDao) Delete(spaceMember *SpaceMember) {
db := core.CONTEXT.GetDB().Delete(&spaceMember)
this.PanicError(db.Error)
}
func (this *SpaceMemberDao) DeleteBySpaceUuid(spaceUuid string) {
var wp = &builder.WherePair{}
wp = wp.And(&builder.WherePair{Query: "space_uuid = ?", Args: []interface{}{spaceUuid}})
db := core.CONTEXT.GetDB().Where(wp.Query, wp.Args).Delete(SpaceMember{})
this.PanicError(db.Error)
}
func (this *SpaceMemberDao) CountBySpaceUuid(spaceUuid string) int {
var count int64
db := core.CONTEXT.GetDB().
Model(&SpaceMember{}).
Where("space_uuid = ?", spaceUuid).
Count(&count)
this.PanicError(db.Error)
return int(count)
}
// System cleanup.
func (this *SpaceMemberDao) Cleanup() {
this.logger.Info("[SpaceMemberDao] clean up. Delete all SpaceMember")
db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(SpaceMember{})
this.PanicError(db.Error)
}
-30
View File
@@ -1,30 +0,0 @@
package rest
import (
"time"
)
const (
//guest member
SPACE_MEMBER_GUEST = "GUEST"
//read only member
SPACE_MEMBER_ROLE_READ_ONLY = "READ_ONLY"
//read write member
SPACE_MEMBER_ROLE_READ_WRITE = "READ_WRITE"
//admin member
SPACE_MEMBER_ROLE_ADMIN = "ADMIN"
)
/**
* space member
*/
type SpaceMember struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
SpaceUuid string `json:"spaceUuid" gorm:"type:char(36);index:idx_space_uuid"`
UserUuid string `json:"userUuid" gorm:"type:char(36);index:idx_user_uuid"`
Role string `json:"role" gorm:"type:varchar(45)"`
User *User `json:"user" gorm:"-"`
}
-145
View File
@@ -1,145 +0,0 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
)
// @Service
type SpaceMemberService struct {
BaseBean
spaceMemberDao *SpaceMemberDao
matterDao *MatterDao
bridgeDao *BridgeDao
userDao *UserDao
}
func (this *SpaceMemberService) Init() {
this.BaseBean.Init()
b := core.CONTEXT.GetBean(this.spaceMemberDao)
if b, ok := b.(*SpaceMemberDao); ok {
this.spaceMemberDao = b
}
b = core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
b = core.CONTEXT.GetBean(this.bridgeDao)
if b, ok := b.(*BridgeDao); ok {
this.bridgeDao = b
}
b = core.CONTEXT.GetBean(this.userDao)
if b, ok := b.(*UserDao); ok {
this.userDao = b
}
}
func (this *SpaceMemberService) Detail(uuid string) *SpaceMember {
spaceMember := this.spaceMemberDao.CheckByUuid(uuid)
return spaceMember
}
// create space
func (this *SpaceMemberService) CreateMember(space *Space, user *User, spaceRole string) *SpaceMember {
spaceMember := &SpaceMember{
SpaceUuid: space.Uuid,
UserUuid: user.Uuid,
Role: spaceRole,
}
spaceMember = this.spaceMemberDao.Create(spaceMember)
return spaceMember
}
// 当前用户对于此空间,是否有管理权限。
func (this *SpaceMemberService) canManage(user *User, spaceUuid string) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
if user.SpaceUuid == spaceUuid {
return true
}
//only space's admin can add member.
spaceMember := this.spaceMemberDao.FindBySpaceUuidAndUserUuid(spaceUuid, user.Uuid)
return this.canManageBySpaceMember(user, spaceMember)
}
// 当前用户对于此空间,是否有可读权限。
func (this *SpaceMemberService) canRead(user *User, spaceUuid string) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
if user.SpaceUuid == spaceUuid {
return true
}
//only space's admin can add member.
spaceMember := this.spaceMemberDao.FindBySpaceUuidAndUserUuid(spaceUuid, user.Uuid)
return this.canReadBySpaceMember(user, spaceMember)
}
// 当前用户对于此空间,是否有可写权限。
func (this *SpaceMemberService) canWrite(user *User, spaceUuid string) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
if user.SpaceUuid == spaceUuid {
return true
}
//only space's admin can add member.
spaceMember := this.spaceMemberDao.FindBySpaceUuidAndUserUuid(spaceUuid, user.Uuid)
return this.canWriteBySpaceMember(user, spaceMember)
}
// 当前用户对于此空间,是否有管理权限。
func (this *SpaceMemberService) canManageBySpaceMember(user *User, member *SpaceMember) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
//only space's admin can add member.
if member != nil && member.Role == SPACE_MEMBER_ROLE_ADMIN {
return true
}
return false
}
// 当前用户对于此空间,是否有可读权限。
func (this *SpaceMemberService) canReadBySpaceMember(user *User, member *SpaceMember) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
//only space's admin can add member.
if member != nil {
return true
}
return false
}
// 当前用户对于此空间,是否有科协权限。
func (this *SpaceMemberService) canWriteBySpaceMember(user *User, member *SpaceMember) bool {
if user.Role == USER_ROLE_ADMINISTRATOR {
return true
}
//only space's admin can add member.
if member != nil && (member.Role == SPACE_MEMBER_ROLE_ADMIN || member.Role == SPACE_MEMBER_ROLE_READ_WRITE) {
return true
}
return false
}
-29
View File
@@ -1,29 +0,0 @@
package rest
import (
"time"
)
const (
//private space
SPACE_TYPE_PRIVATE = "PRIVATE"
//group shared space.
SPACE_TYPE_SHARED = "SHARED"
)
/**
* shared space
*/
type Space struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Name string `json:"name" gorm:"type:varchar(100) not null;unique"`
UserUuid string `json:"userUuid" gorm:"type:char(36)"`
SizeLimit int64 `json:"sizeLimit" gorm:"type:bigint(20) not null;default:-1"`
TotalSizeLimit int64 `json:"totalSizeLimit" gorm:"type:bigint(20) not null;default:-1"`
TotalSize int64 `json:"totalSize" gorm:"type:bigint(20) not null;default:0"`
Type string `json:"type" gorm:"type:varchar(45)"`
User *User `json:"user" gorm:"-"`
}
-170
View File
@@ -1,170 +0,0 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/i18n"
"github.com/eyebluecn/tank/code/tool/result"
"net/http"
"regexp"
)
// @Service
type SpaceService struct {
BaseBean
spaceDao *SpaceDao
spaceMemberService *SpaceMemberService
matterDao *MatterDao
bridgeDao *BridgeDao
userDao *UserDao
}
func (this *SpaceService) Init() {
this.BaseBean.Init()
b := core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.spaceMemberService)
if b, ok := b.(*SpaceMemberService); ok {
this.spaceMemberService = b
}
b = core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
b = core.CONTEXT.GetBean(this.bridgeDao)
if b, ok := b.(*BridgeDao); ok {
this.bridgeDao = b
}
b = core.CONTEXT.GetBean(this.userDao)
if b, ok := b.(*UserDao); ok {
this.userDao = b
}
}
func (this *SpaceService) Detail(uuid string) *Space {
space := this.spaceDao.CheckByUuid(uuid)
return space
}
// create space
func (this *SpaceService) CreateSpace(
request *http.Request,
name string,
user *User,
sizeLimit int64,
totalSizeLimit int64,
spaceType string) *Space {
userUuid := ""
//validation work.
if m, _ := regexp.MatchString(USERNAME_PATTERN, name); !m {
panic(result.BadRequestI18n(request, i18n.SpaceNameError))
}
if spaceType == SPACE_TYPE_PRIVATE {
if user == nil {
panic("private space requires user.")
}
userUuid = user.Uuid
if this.spaceDao.CountByUserUuid(userUuid) > 0 {
panic(result.BadRequestI18n(request, i18n.SpaceExclusive, name))
}
} else if spaceType == SPACE_TYPE_SHARED {
} else {
panic("Not supported spaceType:" + spaceType)
}
if this.spaceDao.CountByName(name) > 0 {
panic(result.BadRequestI18n(request, i18n.SpaceNameExist, name))
}
space := &Space{
Name: name,
UserUuid: userUuid,
SizeLimit: sizeLimit,
TotalSizeLimit: totalSizeLimit,
TotalSize: 0,
Type: spaceType,
}
space = this.spaceDao.Create(space)
return space
}
// checkout a adminAble space.
func (this *SpaceService) CheckAdminAbleByUuid(request *http.Request, user *User, spaceUuid string) *Space {
space := this.spaceDao.CheckByUuid(spaceUuid)
if space.Type == SPACE_TYPE_PRIVATE && user.Uuid == space.UserUuid {
return space
}
manage := this.spaceMemberService.canManage(user, spaceUuid)
if !manage {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
return space
}
// checkout a writable space.
func (this *SpaceService) CheckWritableByUuid(request *http.Request, user *User, spaceUuid string) *Space {
space := this.spaceDao.CheckByUuid(spaceUuid)
if space.Type == SPACE_TYPE_PRIVATE && user.Uuid == space.UserUuid {
return space
}
writable := this.spaceMemberService.canWrite(user, spaceUuid)
if !writable {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
return space
}
// checkout a readable space.
func (this *SpaceService) CheckReadableByUuid(request *http.Request, user *User, spaceUuid string) *Space {
space := this.spaceDao.CheckByUuid(spaceUuid)
if space.Type == SPACE_TYPE_PRIVATE && user.Uuid == space.UserUuid {
return space
}
manage := this.spaceMemberService.canRead(user, spaceUuid)
if !manage {
panic(result.BadRequestI18n(request, i18n.PermissionDenied))
}
return space
}
// edit space's info
func (this *SpaceService) Edit(request *http.Request, user *User, spaceUuid string, sizeLimit int64, totalSizeLimit int64) *Space {
space := this.CheckAdminAbleByUuid(request, user, spaceUuid)
if sizeLimit < 0 && sizeLimit != -1 {
panic("sizeLimit cannot be negative expect -1.")
}
if totalSizeLimit < 0 && totalSizeLimit != -1 {
panic("totalSizeLimit cannot be negative expect -1.")
}
space.SizeLimit = sizeLimit
space.TotalSizeLimit = totalSizeLimit
space = this.spaceDao.Save(space)
return space
}
+11 -17
View File
@@ -8,7 +8,7 @@ import (
)
// system tasks service
// @Service
//@Service
type TaskService struct {
BaseBean
footprintService *FootprintService
@@ -16,7 +16,6 @@ type TaskService struct {
preferenceService *PreferenceService
matterService *MatterService
userDao *UserDao
spaceDao *SpaceDao
//whether scan task is running
scanTaskRunning bool
@@ -49,15 +48,11 @@ func (this *TaskService) Init() {
if b, ok := b.(*UserDao); ok {
this.userDao = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
this.scanTaskRunning = false
}
// init the clean footprint task.
//init the clean footprint task.
func (this *TaskService) InitCleanFootprintTask() {
//use standard cron expression. 5 fields. ()
@@ -70,7 +65,7 @@ func (this *TaskService) InitCleanFootprintTask() {
this.logger.Info("[cron job] Every day 00:10 delete Footprint data of 8 days ago.")
}
// init the elt task.
//init the elt task.
func (this *TaskService) InitEtlTask() {
expression := "5 0 * * *"
@@ -82,7 +77,7 @@ func (this *TaskService) InitEtlTask() {
this.logger.Info("[cron job] Everyday 00:05 ETL dashboard data.")
}
// init the clean deleted matters task.
//init the clean deleted matters task.
func (this *TaskService) InitCleanDeletedMattersTask() {
expression := "0 1 * * *"
@@ -94,7 +89,7 @@ func (this *TaskService) InitCleanDeletedMattersTask() {
this.logger.Info("[cron job] Everyday 01:00 Clean deleted matters.")
}
// scan task.
//scan task.
func (this *TaskService) doScanTask() {
if this.scanTaskRunning {
@@ -126,12 +121,12 @@ func (this *TaskService) doScanTask() {
if scanConfig.Scope == SCAN_SCOPE_ALL {
//scan all user's root folder.
this.userDao.PageHandle("", "", func(user *User, space *Space) {
this.userDao.PageHandle("", "", func(user *User) {
core.RunWithRecovery(func() {
this.matterService.DeleteByPhysics(request, user, space)
this.matterService.ScanPhysics(request, user, space)
this.matterService.DeleteByPhysics(request, user)
this.matterService.ScanPhysics(request, user)
})
@@ -147,11 +142,10 @@ func (this *TaskService) doScanTask() {
} else {
this.logger.Info("scan custom user folder. username = %s", username)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
core.RunWithRecovery(func() {
this.matterService.DeleteByPhysics(request, user, space)
this.matterService.ScanPhysics(request, user, space)
this.matterService.DeleteByPhysics(request, user)
this.matterService.ScanPhysics(request, user)
})
@@ -161,7 +155,7 @@ func (this *TaskService) doScanTask() {
}
// init the scan task.
//init the scan task.
func (this *TaskService) InitScanTask() {
if this.scanTaskCron != nil {
+6 -4
View File
@@ -1,14 +1,12 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
type UploadToken struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Base
UserUuid string `json:"userUuid" gorm:"type:char(36) not null"`
FolderUuid string `json:"folderUuid" gorm:"type:char(36) not null"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null"`
@@ -18,3 +16,7 @@ type UploadToken struct {
Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"`
Ip string `json:"ip" gorm:"type:varchar(128) not null"`
}
func (this *UploadToken) TableName() string {
return core.TABLE_PREFIX + "upload_token"
}
+77 -57
View File
@@ -16,8 +16,6 @@ type UserController struct {
BaseController
preferenceService *PreferenceService
userService *UserService
spaceDao *SpaceDao
spaceService *SpaceService
matterService *MatterService
}
@@ -34,14 +32,6 @@ func (this *UserController) Init() {
this.userService = b
}
b = core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
b = core.CONTEXT.GetBean(this.spaceService)
if b, ok := b.(*SpaceService); ok {
this.spaceService = b
}
b = core.CONTEXT.GetBean(this.matterService)
if b, ok := b.(*MatterService); ok {
this.matterService = b
@@ -106,7 +96,7 @@ func (this *UserController) innerLogin(writer http.ResponseWriter, request *http
this.userDao.Save(user)
}
// login by username and password
//login by username and password
func (this *UserController) Login(writer http.ResponseWriter, request *http.Request) *result.WebResult {
username := request.FormValue("username")
@@ -126,14 +116,10 @@ func (this *UserController) Login(writer http.ResponseWriter, request *http.Requ
}
this.innerLogin(writer, request, user)
//append the space info.
space := this.spaceDao.FindByUuid(user.SpaceUuid)
user.Space = space
return this.Success(user)
}
// login by authentication.
//login by authentication.
func (this *UserController) AuthenticationLogin(writer http.ResponseWriter, request *http.Request) *result.WebResult {
authentication := request.FormValue("authentication")
@@ -154,18 +140,13 @@ func (this *UserController) AuthenticationLogin(writer http.ResponseWriter, requ
return this.Success(user)
}
// fetch current user's info.
//fetch current user's info.
func (this *UserController) Info(writer http.ResponseWriter, request *http.Request) *result.WebResult {
user := this.checkUser(request)
//append the space info.
space := this.spaceDao.FindByUuid(user.SpaceUuid)
user.Space = space
return this.Success(user)
}
// register by username and password. After registering, will auto login.
//register by username and password. After registering, will auto login.
func (this *UserController) Register(writer http.ResponseWriter, request *http.Request) *result.WebResult {
username := request.FormValue("username")
@@ -188,7 +169,15 @@ func (this *UserController) Register(writer http.ResponseWriter, request *http.R
panic(result.BadRequestI18n(request, i18n.UsernameExist, username))
}
user := this.userService.CreateUser(request, username, -1, preference.DefaultTotalSizeLimit, password, USER_ROLE_USER)
user := &User{
Role: USER_ROLE_USER,
Username: username,
Password: util.GetBcrypt(password),
TotalSizeLimit: preference.DefaultTotalSizeLimit,
Status: USER_STATUS_OK,
}
user = this.userDao.Create(user)
//auto login
this.innerLogin(writer, request, user)
@@ -201,11 +190,32 @@ func (this *UserController) Create(writer http.ResponseWriter, request *http.Req
username := request.FormValue("username")
password := request.FormValue("password")
role := request.FormValue("role")
sizeLimitStr := request.FormValue("sizeLimit")
totalSizeLimitStr := request.FormValue("totalSizeLimit")
sizeLimit := util.ExtractRequestInt64(request, "sizeLimit")
totalSizeLimit := util.ExtractRequestInt64(request, "totalSizeLimit")
//only admin can edit user's sizeLimit
var sizeLimit int64 = 0
if sizeLimitStr == "" {
panic("user's limit size is required")
} else {
intSizeLimit, err := strconv.Atoi(sizeLimitStr)
if err != nil {
this.PanicError(err)
}
sizeLimit = int64(intSizeLimit)
}
var totalSizeLimit int64 = 0
if totalSizeLimitStr == "" {
panic("user's total limit size is required")
} else {
intTotalSizeLimit, err := strconv.Atoi(totalSizeLimitStr)
if err != nil {
this.PanicError(err)
}
totalSizeLimit = int64(intTotalSizeLimit)
}
//validation work.
if m, _ := regexp.MatchString(USERNAME_PATTERN, username); !m {
panic(result.BadRequestI18n(request, i18n.UsernameError))
}
@@ -217,16 +227,21 @@ func (this *UserController) Create(writer http.ResponseWriter, request *http.Req
if this.userDao.CountByUsername(username) > 0 {
panic(result.BadRequestI18n(request, i18n.UsernameExist, username))
}
if this.spaceDao.CountByName(username) > 0 {
panic(result.BadRequestI18n(request, i18n.SpaceNameExist, username))
}
//check user role.
if role != USER_ROLE_USER && role != USER_ROLE_ADMINISTRATOR {
panic(result.BadRequestI18n(request, i18n.UserRoleError))
role = USER_ROLE_USER
}
user := this.userService.CreateUser(request, username, sizeLimit, totalSizeLimit, password, role)
user := &User{
Username: username,
Password: util.GetBcrypt(password),
Role: role,
SizeLimit: sizeLimit,
TotalSizeLimit: totalSizeLimit,
Status: USER_STATUS_OK,
}
user = this.userDao.Create(user)
return this.Success(user)
}
@@ -235,11 +250,10 @@ func (this *UserController) Edit(writer http.ResponseWriter, request *http.Reque
uuid := request.FormValue("uuid")
avatarUrl := request.FormValue("avatarUrl")
sizeLimitStr := request.FormValue("sizeLimit")
totalSizeLimitStr := request.FormValue("totalSizeLimit")
role := request.FormValue("role")
sizeLimit := util.ExtractRequestInt64(request, "sizeLimit")
totalSizeLimit := util.ExtractRequestInt64(request, "totalSizeLimit")
user := this.checkUser(request)
currentUser := this.userDao.CheckByUuid(uuid)
@@ -247,6 +261,29 @@ func (this *UserController) Edit(writer http.ResponseWriter, request *http.Reque
if user.Role == USER_ROLE_ADMINISTRATOR {
//only admin can edit user's sizeLimit
var sizeLimit int64 = 0
if sizeLimitStr == "" {
panic("user's limit size is required")
} else {
intSizeLimit, err := strconv.Atoi(sizeLimitStr)
if err != nil {
this.PanicError(err)
}
sizeLimit = int64(intSizeLimit)
}
currentUser.SizeLimit = sizeLimit
var totalSizeLimit int64 = 0
if totalSizeLimitStr == "" {
panic("user's total limit size is required")
} else {
intTotalSizeLimit, err := strconv.Atoi(totalSizeLimitStr)
if err != nil {
this.PanicError(err)
}
totalSizeLimit = int64(intTotalSizeLimit)
}
currentUser.TotalSizeLimit = totalSizeLimit
if role == USER_ROLE_USER || role == USER_ROLE_ADMINISTRATOR {
currentUser.Role = role
@@ -256,17 +293,11 @@ func (this *UserController) Edit(writer http.ResponseWriter, request *http.Reque
panic(result.UNAUTHORIZED)
}
//edit user's info
currentUser = this.userDao.Save(currentUser)
//edit user's private space info.
space := this.spaceService.Edit(request, user, currentUser.SpaceUuid, sizeLimit, totalSizeLimit)
//remove cache user.
this.userService.RemoveCacheUserByUuid(currentUser.Uuid)
currentUser.Space = space
return this.Success(currentUser)
}
@@ -276,10 +307,6 @@ func (this *UserController) Detail(writer http.ResponseWriter, request *http.Req
user := this.userDao.CheckByUuid(uuid)
//append the space info.
space := this.spaceDao.FindByUuid(user.SpaceUuid)
user.Space = space
return this.Success(user)
}
@@ -364,12 +391,6 @@ func (this *UserController) Page(writer http.ResponseWriter, request *http.Reque
pager := this.userDao.Page(page, pageSize, username, status, sortArray)
//append the space info. FIXME: user better way to get Space.
for _, u := range pager.Data.([]*User) {
space := this.spaceDao.FindByUuid(u.SpaceUuid)
u.Space = space
}
return this.Success(pager)
}
@@ -418,14 +439,13 @@ func (this *UserController) Transfiguration(writer http.ResponseWriter, request
return this.Success(session.Uuid)
}
// scan user's physics files. create index into EyeblueTank
//scan user's physics files. create index into EyeblueTank
func (this *UserController) Scan(writer http.ResponseWriter, request *http.Request) *result.WebResult {
uuid := request.FormValue("uuid")
currentUser := this.userDao.CheckByUuid(uuid)
space := this.spaceDao.CheckByUuid(currentUser.SpaceUuid)
this.matterService.DeleteByPhysics(request, currentUser, space)
this.matterService.ScanPhysics(request, currentUser, space)
this.matterService.DeleteByPhysics(request, currentUser)
this.matterService.ScanPhysics(request, currentUser)
return this.Success("OK")
}
@@ -474,7 +494,7 @@ func (this *UserController) ChangePassword(writer http.ResponseWriter, request *
return this.Success(user)
}
// admin reset password.
//admin reset password.
func (this *UserController) ResetPassword(writer http.ResponseWriter, request *http.Request) *result.WebResult {
userUuid := request.FormValue("userUuid")
+11 -19
View File
@@ -11,17 +11,10 @@ import (
type UserDao struct {
BaseDao
spaceDao *SpaceDao
}
func (this *UserDao) Init() {
this.BaseDao.Init()
b := core.CONTEXT.GetBean(this.spaceDao)
if b, ok := b.(*SpaceDao); ok {
this.spaceDao = b
}
}
func (this *UserDao) Create(user *User) *User {
@@ -43,7 +36,7 @@ func (this *UserDao) Create(user *User) *User {
return user
}
// find by uuid. if not found return nil.
//find by uuid. if not found return nil.
func (this *UserDao) FindByUuid(uuid string) *User {
var entity = &User{}
db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity)
@@ -57,7 +50,7 @@ func (this *UserDao) FindByUuid(uuid string) *User {
return entity
}
// find by uuid. if not found panic NotFound error
//find by uuid. if not found panic NotFound error
func (this *UserDao) CheckByUuid(uuid string) *User {
entity := this.FindByUuid(uuid)
if entity == nil {
@@ -101,7 +94,7 @@ func (this *UserDao) PlainPage(page int, pageSize int, username string, status s
wp = wp.And(&builder.WherePair{Query: "status = ?", Args: []interface{}{status}})
}
var count int64 = 0
count := 0
db := core.CONTEXT.GetDB().Model(&User{}).Where(wp.Query, wp.Args...).Count(&count)
this.PanicError(db.Error)
@@ -115,11 +108,11 @@ func (this *UserDao) PlainPage(page int, pageSize int, username string, status s
this.PanicError(db.Error)
return int(count), users
return count, users
}
// handle user page by page.
func (this *UserDao) PageHandle(username string, status string, fun func(user *User, space *Space)) {
//handle user page by page.
func (this *UserDao) PageHandle(username string, status string, fun func(user *User)) {
//delete share and bridges.
pageSize := 1000
@@ -136,21 +129,20 @@ func (this *UserDao) PageHandle(username string, status string, fun func(user *U
for page = 0; page < totalPages; page++ {
_, users := this.PlainPage(0, pageSize, username, status, sortArray)
for _, u := range users {
space := this.spaceDao.CheckByUuid(u.SpaceUuid)
fun(u, space)
fun(u)
}
}
}
}
func (this *UserDao) CountByUsername(username string) int {
var count int64
var count int
db := core.CONTEXT.GetDB().
Model(&User{}).
Where("username = ?", username).
Count(&count)
this.PanicError(db.Error)
return int(count)
return count
}
func (this *UserDao) Save(user *User) *User {
@@ -162,7 +154,7 @@ func (this *UserDao) Save(user *User) *User {
return user
}
// find all 2.0 users.
//find all 2.0 users.
func (this *UserDao) FindUsers20() []*User {
var users []*User
var wp = &builder.WherePair{}
@@ -187,7 +179,7 @@ func (this *UserDao) Delete(user *User) {
this.PanicError(db.Error)
}
// System cleanup.
//System cleanup.
func (this *UserDao) Cleanup() {
this.logger.Info("[UserDao] clean up. Delete all User")
db := core.CONTEXT.GetDB().Where("uuid is not null and role != ?", USER_ROLE_ADMINISTRATOR).Delete(User{})
+16 -13
View File
@@ -1,6 +1,7 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
@@ -27,18 +28,20 @@ const (
)
type User struct {
Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"`
Sort int64 `json:"sort" gorm:"type:bigint(20) not null"`
UpdateTime time.Time `json:"updateTime" gorm:"type:timestamp not null;default:CURRENT_TIMESTAMP"`
CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Role string `json:"role" gorm:"type:varchar(45)"`
Username string `json:"username" gorm:"type:varchar(45) not null;unique"`
Password string `json:"-" gorm:"type:varchar(255)"`
AvatarUrl string `json:"avatarUrl" gorm:"type:varchar(255)"`
LastIp string `json:"lastIp" gorm:"type:varchar(128)"`
LastTime time.Time `json:"lastTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
Base
Role string `json:"role" gorm:"type:varchar(45)"`
Username string `json:"username" gorm:"type:varchar(45) not null;unique"`
Password string `json:"-" gorm:"type:varchar(255)"`
AvatarUrl string `json:"avatarUrl" gorm:"type:varchar(255)"`
LastIp string `json:"lastIp" gorm:"type:varchar(128)"`
LastTime time.Time `json:"lastTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"`
SizeLimit int64 `json:"sizeLimit" gorm:"type:bigint(20) not null;default:-1"`
TotalSizeLimit int64 `json:"totalSizeLimit" gorm:"type:bigint(20) not null;default:-1"`
TotalSize int64 `json:"totalSize" gorm:"type:bigint(20) not null;default:0"`
Status string `json:"status" gorm:"type:varchar(45)"`
}
SpaceUuid string `json:"spaceUuid" gorm:"type:char(36);unique"`
Status string `json:"status" gorm:"type:varchar(45)"`
Space *Space `json:"space" gorm:"-"`
// set User's table name to be `profiles`
func (this *User) TableName() string {
return core.TABLE_PREFIX + "user"
}
+8 -40
View File
@@ -11,14 +11,12 @@ import (
"time"
)
// @Service
//@Service
type UserService struct {
BaseBean
userDao *UserDao
sessionDao *SessionDao
spaceService *SpaceService
//file lock
locker *cache.Table
@@ -45,11 +43,6 @@ func (this *UserService) Init() {
this.sessionDao = b
}
b = core.CONTEXT.GetBean(this.spaceService)
if b, ok := b.(*SpaceService); ok {
this.spaceService = b
}
b = core.CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
@@ -89,7 +82,7 @@ func (this *UserService) Init() {
this.locker = cache.NewTable()
}
// lock a user's operation. If lock, user cannot operate file.
//lock a user's operation. If lock, user cannot operate file.
func (this *UserService) MatterLock(userUuid string) {
cacheItem, err := this.locker.Value(userUuid)
@@ -105,7 +98,7 @@ func (this *UserService) MatterLock(userUuid string) {
this.locker.Add(userUuid, duration, true)
}
// unlock
//unlock
func (this *UserService) MatterUnlock(userUuid string) {
exist := this.locker.Exists(userUuid)
@@ -117,8 +110,8 @@ func (this *UserService) MatterUnlock(userUuid string) {
}
}
// load session to SessionCache. This method will be invoked in every request.
// authorize by 1. cookie 2. username and password in request form. 3. Basic Auth
//load session to SessionCache. This method will be invoked in every request.
//authorize by 1. cookie 2. username and password in request form. 3. Basic Auth
func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Request) {
sessionId := util.GetSessionUuidFromRequest(request, core.COOKIE_AUTH_KEY)
@@ -189,7 +182,7 @@ func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Req
}
// find a cache user by its userUuid
//find a cache user by its userUuid
func (this *UserService) FindCacheUsersByUuid(userUuid string) []*User {
var users []*User
@@ -211,7 +204,7 @@ func (this *UserService) FindCacheUsersByUuid(userUuid string) []*User {
return users
}
// remove cache user by its userUuid
//remove cache user by its userUuid
func (this *UserService) RemoveCacheUserByUuid(userUuid string) {
var sessionId interface{}
@@ -240,32 +233,7 @@ func (this *UserService) RemoveCacheUserByUuid(userUuid string) {
}
}
// create user
func (this *UserService) CreateUser(request *http.Request, username string, sizeLimit int64, totalSizeLimit int64, password string, role string) *User {
user := &User{
Username: username,
Password: util.GetBcrypt(password),
Role: role,
Status: USER_STATUS_OK,
}
user = this.userDao.Create(user)
//create space.
space := this.spaceService.CreateSpace(request, username, user, sizeLimit, totalSizeLimit, SPACE_TYPE_PRIVATE)
//update user's space.
user.SpaceUuid = space.Uuid
this.userDao.Save(user)
user.Space = space
return user
}
// delete user
//delete user
func (this *UserService) DeleteUser(request *http.Request, currentUser *User) {
//delete from cache
+71 -65
View File
@@ -4,7 +4,6 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/json-iterator/go"
"gorm.io/gorm/schema"
"io/ioutil"
"os"
"time"
@@ -20,8 +19,6 @@ type TankConfig struct {
matterPath string
//mysql url.
mysqlUrl string
//sqlite file path
sqliteFolder string
//configs in tank.json
item *ConfigItem
}
@@ -32,10 +29,7 @@ type ConfigItem struct {
ServerPort int
//file storage location. eg./var/www/matter
MatterPath string
//********db configurations.********
//default value is "mysql"
DbType string
//********mysql configurations..********
//mysql configurations.
//mysql port
MysqlPort int
//mysql host
@@ -48,9 +42,12 @@ type ConfigItem struct {
MysqlPassword string
//mysql charset
MysqlCharset string
//********sqlite configurations..********
//default value is matter/
SqliteFolder string
OssAccessKey string
OssSecretKey string
OssEndpoint string
OssCustomHost string
OssBucket string
}
//validate whether the config file is ok
@@ -61,39 +58,57 @@ func (this *ConfigItem) validate() bool {
return false
}
if this.DbType == "sqlite" {
if this.MysqlUsername == "" {
core.LOGGER.Error("MysqlUsername is not configured")
return false
}
} else {
if this.MysqlPassword == "" {
core.LOGGER.Error("MysqlPassword is not configured")
return false
}
if this.MysqlUsername == "" {
core.LOGGER.Error("MysqlUsername is not configured")
return false
}
if this.MysqlHost == "" {
core.LOGGER.Error("MysqlHost is not configured")
return false
}
if this.MysqlPassword == "" {
core.LOGGER.Error("MysqlPassword is not configured")
return false
}
if this.MysqlPort == 0 {
core.LOGGER.Error("MysqlPort is not configured")
return false
}
if this.MysqlHost == "" {
core.LOGGER.Error("MysqlHost is not configured")
return false
}
if this.MysqlSchema == "" {
core.LOGGER.Error("MysqlSchema is not configured")
return false
}
if this.MysqlCharset == "" {
core.LOGGER.Error("MysqlCharset is not configured")
return false
}
if this.MysqlPort == 0 {
core.LOGGER.Error("MysqlPort is not configured")
return false
}
if this.OssAccessKey == "" {
core.LOGGER.Error("OssAccessKey is not configured")
return false
}
if this.MysqlSchema == "" {
core.LOGGER.Error("MysqlSchema is not configured")
return false
}
if this.OssSecretKey == "" {
core.LOGGER.Error("OssSecretKey is not configured")
return false
}
if this.MysqlCharset == "" {
core.LOGGER.Error("MysqlCharset is not configured")
return false
}
if this.OssEndpoint == "" {
core.LOGGER.Error("OssEndpoint is not configured")
return false
}
if this.OssCustomHost == "" {
core.LOGGER.Error("OssCustomHost is not configured")
return false
}
if this.OssBucket == "" {
core.LOGGER.Error("OssBucket is not configured")
return false
}
return true
@@ -183,49 +198,40 @@ func (this *TankConfig) ServerPort() int {
return this.serverPort
}
//get the db type
func (this *TankConfig) DbType() string {
return this.item.DbType
}
//mysql url
func (this *TankConfig) MysqlUrl() string {
return this.mysqlUrl
}
//get the sqlite path
func (this *TankConfig) SqliteFolder() string {
if this.sqliteFolder == "" {
//use default file location.
if this.item == nil || this.item.SqliteFolder == "" {
this.sqliteFolder = util.GetHomePath() + "/matter"
} else {
this.sqliteFolder = util.UniformPath(this.item.SqliteFolder)
}
util.MakeDirAll(this.sqliteFolder)
}
return this.sqliteFolder
}
//matter path
func (this *TankConfig) MatterPath() string {
return this.matterPath
}
//matter path
func (this *TankConfig) NamingStrategy() schema.NamingStrategy {
return schema.NamingStrategy{
TablePrefix: core.TABLE_PREFIX,
SingularTable: true,
}
func (this *TankConfig) OssAccessKey() string {
return this.item.OssAccessKey
}
//TODO: Finish the installation. Write config to tank.json. add sqlite support.
func (this *TankConfig) FinishInstall(dbType string, mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string, mysqlCharset string) {
func (this *TankConfig) OssSecretKey() string {
return this.item.OssSecretKey
}
func (this *TankConfig) OssEndpoint() string {
return this.item.OssEndpoint
}
func (this *TankConfig) OssCustomHost() string {
return this.item.OssCustomHost
}
func (this *TankConfig) OssBucket() string {
return this.item.OssBucket
}
//Finish the installation. Write config to tank.json
func (this *TankConfig) FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string, mysqlCharset string) {
var configItem = &ConfigItem{
DbType: dbType,
//server port
ServerPort: core.CONFIG.ServerPort(),
//file storage location. eg./var/www/matter
+13 -58
View File
@@ -4,15 +4,9 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/rest"
"github.com/eyebluecn/tank/code/tool/cache"
"github.com/glebarez/sqlite"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"github.com/jinzhu/gorm"
"net/http"
"os"
"reflect"
"time"
)
type TankContext struct {
@@ -69,60 +63,28 @@ func (this *TankContext) Cleanup() {
}
}
// can serve as http server.
//can serve as http server.
func (this *TankContext) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
this.Router.ServeHTTP(writer, request)
}
func (this *TankContext) OpenDb() {
//log strategy.
dbLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // slow SQL 1s
LogLevel: logger.Warn, // log level. open when debug.
IgnoreRecordNotFoundError: true, // ignore ErrRecordNotFound
Colorful: false, // colorful print
},
)
var err error = nil
this.db, err = gorm.Open("mysql", core.CONFIG.MysqlUrl())
//table name strategy.
namingStrategy := core.CONFIG.NamingStrategy()
if core.CONFIG.DbType() == "sqlite" {
var err error = nil
this.db, err = gorm.Open(sqlite.Open(core.CONFIG.SqliteFolder()+"/tank.sqlite"), &gorm.Config{Logger: dbLogger, NamingStrategy: namingStrategy})
if err != nil {
core.LOGGER.Panic("failed to connect mysql database")
}
//sqlite lock issue. https://gist.github.com/mrnugget/0eda3b2b53a70fa4a894
phyDb, err := this.db.DB()
phyDb.SetMaxOpenConns(1)
} else {
var err error = nil
this.db, err = gorm.Open(mysql.Open(core.CONFIG.MysqlUrl()), &gorm.Config{Logger: dbLogger, NamingStrategy: namingStrategy})
if err != nil {
core.LOGGER.Panic("failed to connect mysql database")
}
if err != nil {
core.LOGGER.Panic("failed to connect mysql database")
}
//whether open the db sql log. (only true when debug)
this.db.LogMode(false)
}
func (this *TankContext) CloseDb() {
if this.db != nil {
db, err := this.db.DB()
if err != nil {
core.LOGGER.Error("occur error when get *sql.DB %s", err.Error())
}
err = db.Close()
err := this.db.Close()
if err != nil {
core.LOGGER.Error("occur error when closing db %s", err.Error())
}
@@ -185,6 +147,9 @@ func (this *TankContext) registerBeans() {
this.registerBean(new(rest.MatterDao))
this.registerBean(new(rest.MatterService))
//oss
this.registerBean(new(rest.OssService))
//preference
this.registerBean(new(rest.PreferenceController))
this.registerBean(new(rest.PreferenceDao))
@@ -204,16 +169,6 @@ func (this *TankContext) registerBeans() {
this.registerBean(new(rest.ShareDao))
this.registerBean(new(rest.ShareService))
//space
this.registerBean(new(rest.SpaceController))
this.registerBean(new(rest.SpaceDao))
this.registerBean(new(rest.SpaceService))
//space member
this.registerBean(new(rest.SpaceMemberController))
this.registerBean(new(rest.SpaceMemberDao))
this.registerBean(new(rest.SpaceMemberService))
//uploadToken
this.registerBean(new(rest.UploadTokenDao))
@@ -251,7 +206,7 @@ func (this *TankContext) initBeans() {
}
}
// if application installed. invoke this method.
//if application installed. invoke this method.
func (this *TankContext) InstallOk() {
if core.CONFIG.Installed() {

Some files were not shown because too many files have changed in this diff Show More