Compare commits

...
240 Commits
Author SHA1 Message Date
lishuang f873a4aeb9 feat: upgrade to 4.1.2 2025-02-24 23:01:44 +08:00
eyeblue a49495268f Merge pull request #273 from eyebluecn/fix-batch-download
fix: space files from different space member download batch error
2025-02-24 22:58:15 +08:00
seaheart 389b1bdd2e fix: batch download 2025-02-23 17:14:55 +08:00
eyeblue 09c903ec2d Merge pull request #265 from eyebluecn/fix-space-matter-preview
fix: space matter preview token logic
2024-10-06 21:54:56 +08:00
yinyuchen b4c0455f70 fix: space matter preview token logic 2024-10-06 20:51:06 +08:00
lishuang 6f59fe2b37 feat: update golang version in docker. 2024-07-28 01:17:10 +08:00
lishuang 365853fade feat: upgrade 4.1.0 2024-07-27 23:54:12 +08:00
lishuang 837ce742e0 feat: add changelog 2024-07-27 23:50:43 +08:00
yinyuchen 11bf29fad7 feat: upgrade frontend static 2024-07-27 23:48:19 +08:00
lishuang 350e898bda fix: sort bug. 2024-07-27 22:48:24 +08:00
lishuang 3c29788980 feat: add default sort for matter search. 2024-07-27 21:43:36 +08:00
lishuang 09ff58362b feat: add the api search api. 2024-07-27 17:51:05 +08:00
lishuang 7cb6c148dd fix: soft delete bug. 2024-07-27 17:21:30 +08:00
lishuang e8cca6ea15 feat: update the go mod. 2024-07-25 19:44:30 +08:00
lishuang a067234c64 feat: finish api for search dfs. 2024-07-21 23:15:32 +08:00
lishuang b74463d9e5 feat: search dfs. 2024-07-20 16:09:26 +08:00
lishuang 28f85b4d45 fix: fix issue #232 2024-07-20 14:56:01 +08:00
lishuang e8567524ac fix: fix issue #222 2024-07-20 14:43:14 +08:00
lishuang c0dcee45d4 fix: bug for /api/user/edit 2024-07-20 13:00:54 +08:00
lishuang d51343ba8d feat: refine api for /api/space/member/create 2024-07-20 12:47:30 +08:00
yinyuchen 777a1961d0 update dingding qrcode 2024-06-26 22:54:54 +08:00
lishuang 706cb057bc feat: upgrade to tank-4.0.4 2024-05-05 20:39:43 +08:00
eyeblue 31c0356acc Merge pull request #231 from kuww/master
完善预览视频无法播放的问题
2024-05-05 19:42:31 +08:00
yinyuchen 47de9769d0 fix: share overview problem 2024-04-29 23:00:34 +08:00
lishuang ebb7ad0207 feat: upgrade to 4.0.3 2024-03-26 23:38:59 +08:00
yinyuchen 750c0983f1 chore: upgrade version 2024-03-26 23:28:29 +08:00
yinyuchen f005466293 fix: frontend dir problem 2024-03-26 23:24:07 +08:00
seaheart aacf9e05b9 add static 2023-11-12 15:39:04 +08:00
lishuang 62fba81406 feat: use go 1.18 in docker. 2023-11-10 00:24:36 +08:00
lishuang c644757135 feat: release 4.0.2 2023-11-10 00:06:02 +08:00
lishuang 53a0dcce2f feat: add the privacy false default for dir. 2023-11-09 23:48:41 +08:00
seaheart b1a948dd2a change static file 2023-11-09 23:47:41 +08:00
kuww e19fdb2ad2 完善预览视频无法播放的问题 2023-11-02 16:46:12 +08:00
lishuang b9e2f2cf48 feat: upgrade t tank-4.0.1 2023-09-09 11:56:05 +08:00
lishuang 2de7e6b2d0 feat: fix the scan bug. 2023-09-09 11:47:48 +08:00
eyeblue a2716ed8b8 Merge pull request #224 from gmugu/master
Fix "Scan Disk" abnormality
2023-09-09 11:43:39 +08:00
lishuang 73d60a0907 feat: update the dingding image. 2023-09-07 00:41:25 +08:00
lishuang 15c26a6e1f feat: update the dingding image. 2023-09-07 00:40:55 +08:00
lishuang 09ce9b811e feat: update the dingding image. 2023-09-07 00:12:06 +08:00
MuGu 05737663a2 Fix the user_uuid error in scanning disk local space. 2023-09-02 17:17:26 +08:00
MuGu 9820a1e1f3 1、Fix "Scan Disk" user_uuid error that causes WebDAV unable to display scan list.
2、Fix the problem of abnormality when scanning non-existent folders.
2023-09-01 18:46:20 +08:00
lishuang f4965c8256 feat: add the shared space feature. 2023-08-13 16:14:56 +08:00
lishuang 4892083ee9 feat: upgrade the doc img. 2023-08-13 16:13:47 +08:00
lishuang 8f8295cb68 build: version 4.0.0 2023-08-13 12:31:23 +08:00
lishuang 0be4513349 feat: upgrade frontend res to 4.0.0 2023-08-13 12:26:57 +08:00
lishuang c7219a7516 feat: add the query for space's name. 2023-08-13 01:45:19 +08:00
lishuang f5704f470a feat: fix the create user bug for admin. 2023-08-12 16:56:32 +08:00
lishuang 9b19fd1e9d feat: fix some bugs. 2023-08-12 16:46:36 +08:00
lishuang 3e81d886f6 feat: change the scan. 2023-08-12 16:27:38 +08:00
lishuang f1d31d1c10 feat: fix the bug for size compute. 2023-08-06 22:46:25 +08:00
lishuang 44b811507d feat: fix the matter author bug. 2023-08-06 22:31:42 +08:00
lishuang 3c28140c32 feat: release 4.0.0.beta2 2023-08-06 16:19:32 +08:00
lishuang a12148671a feat: fix the bug for sqlite. 2023-08-05 01:19:50 +08:00
lishuang 3a9199e176 feat: add the change log. 2023-07-22 21:08:49 +08:00
lishuang 3d5c444db0 build: build version 4.0.0.beta0 2023-07-22 20:35:47 +08:00
lishuang 6c385014cc feat: append space. 2023-07-22 20:30:52 +08:00
lishuang f0a1c0ab06 feat: fix the role in space memeber. 2023-07-22 20:05:25 +08:00
lishuang 4ebf15f3c1 fix: fix the auth bug. 2023-07-22 19:41:02 +08:00
lishuang b325a3e9a0 fix: fix the bug of download token. 2023-07-22 19:24:00 +08:00
lishuang c3dd34dac9 fix: make the puuid optional. 2023-07-22 18:13:21 +08:00
lishuang 3eceb3c719 fix: fix the bug for file size. 2023-07-22 18:09:25 +08:00
lishuang f1cbde414f feat: enhance the mine api. 2023-07-22 17:16:55 +08:00
lishuang 9bc02bdfcb build: build the new beta version. 2023-07-22 16:21:31 +08:00
lishuang e34a26c009 fix: fix the status code hint bug. 2023-07-22 15:45:07 +08:00
lishuang 3fc032daa9 fix: fix bug. 2023-07-22 15:40:49 +08:00
lishuang 006554cd0a fix: fix the jsoniter fatal bug. 2023-07-22 15:39:53 +08:00
lishuang 42468e9711 feat: add root dir support. 2023-07-22 15:35:45 +08:00
lishuang da5b04cdb3 feat: add a new api. add puuid for crawl. 2023-07-22 15:11:36 +08:00
lishuang 66486b8810 feat: upgrade the version for jsoniter. 2023-07-22 12:06:48 +08:00
lishuang c9883cafb9 feat: change the zip auth. 2023-07-12 00:30:21 +08:00
lishuang a83b5fa489 feat: the frontend res. 2023-07-08 20:58:32 +08:00
lishuang 49f44a00b2 feat: use version 4.0.0.beta1 2023-07-08 19:18:30 +08:00
lishuang 807a860d07 feat: simplify the index name. 2023-07-08 18:39:15 +08:00
lishuang 3df445e98c feat: upgrade to 4.0.0.beta 2023-07-08 17:54:19 +08:00
lishuang e53abb7c79 feat: add the share matter preview and download. 2023-07-08 17:34:57 +08:00
lishuang 4ca8bc06d8 fix: refine the share's things. 2023-07-08 15:25:39 +08:00
lishuang 76d4752776 fix: fix the share space uuid. 2023-07-08 15:21:05 +08:00
lishuang 95fcaada2b fix: separate the share's matter page. 2023-07-08 14:55:06 +08:00
lishuang 327af9f3fa fix: add space into user info. 2023-07-08 14:11:42 +08:00
lishuang 066ae11ad7 fix: add the space info into user's struct. 2023-07-08 14:09:31 +08:00
lishuang f5c377dab8 fix: fix the bug for moving. 2023-06-30 00:22:06 +08:00
lishuang 963b7fdb82 fix: fix the bugs for space file upload. 2023-06-27 00:03:49 +08:00
lishuang 8f66b5e04b feat: add the space page for private. 2023-06-25 22:29:45 +08:00
lishuang 0b98c6acc0 Merge remote-tracking branch 'origin/master' into v3.2.0 2023-06-25 22:07:57 +08:00
seaheart dfae93bbed change dingding qrcode 2023-06-11 15:48:52 +08:00
lishuang 1a440e1f67 feat: finish the basic space things. 2023-05-27 16:21:35 +08:00
lishuang 270e2253a4 Merge remote-tracking branch 'origin/v3.2.0' into v3.2.0_tmp
# Conflicts:
#	code/rest/space_member_controller.go
2023-05-27 15:45:12 +08:00
lishuang a9a3b524eb feat: finish the basic file operation. 2023-05-27 15:43:38 +08:00
seaheart e4799f0045 change space member create and edit key 2023-05-27 15:28:29 +08:00
lishuang 9e6d2c1043 feat: remove the space props in the user model. 2023-05-27 14:12:35 +08:00
lishuang 691fb2a380 feat: fix the spacemember things. 2023-05-27 12:34:58 +08:00
lishuang f39bf33922 feat: finish the space CRUD. 2023-05-27 12:25:24 +08:00
lishuang 14ff3fea9a feat: ready to refine the space model. 2023-05-13 22:07:33 +08:00
lishuang 246829869a feat: add spaceUuid for matterModel. 2023-05-13 21:19:11 +08:00
lishuang 5f2fa2f033 feat: finish the edit for space and space member. 2023-05-13 19:12:21 +08:00
lishuang 6c52e87396 feat: finish the space delete and space member delete api. 2023-05-13 19:01:20 +08:00
lishuang a4b0bb3e9c feat: finish the permission query for normal user. 2023-05-13 18:29:13 +08:00
lishuang 44b79ab946 feat: upgrade the dependencies. 2023-05-13 18:00:02 +08:00
lishuang 1a39ed726d feat: upgrade the gorm. 2023-05-13 17:33:24 +08:00
lishuang 4c4fa9b2c7 Merge remote-tracking branch 'origin/dependabot/go_modules/golang.org/x/crypto-0.1.0' into v3.2.0
# Conflicts:
#	go.mod
#	go.sum
2023-05-13 17:29:21 +08:00
dependabot[bot] 708110c498 Bump golang.org/x/crypto from 0.0.0-20200709230013-948cd5f35899 to 0.1.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20200709230013-948cd5f35899 to 0.1.0.
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-13 09:28:47 +00:00
lishuang 227efb5471 feat: refine the space member codes. 2023-05-13 17:27:28 +08:00
lishuang 17cbb4b663 Merge remote-tracking branch 'origin/dependabot/go_modules/golang.org/x/text-0.3.8' into v3.2.0 2023-05-13 17:26:41 +08:00
dependabot[bot] 35ecc4c894 Bump golang.org/x/text from 0.3.3 to 0.3.8
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.3 to 0.3.8.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.3...v0.3.8)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-13 09:25:45 +00:00
lishuang d976abdb84 feat: add the member page api. 2023-05-13 17:18:01 +08:00
lishuang bd78b87d6f feat: add some space member api. 2023-05-13 16:46:18 +08:00
lishuang a0869708aa feat: add the spaceMember operations. 2023-05-13 16:12:37 +08:00
lishuang bf53df1dc3 feat: finish the space create and page feature. 2023-05-13 15:45:07 +08:00
lishuang 6f63e1c837 feat: fix the win detect for dev. 2023-05-13 14:49:20 +08:00
lishuang 3e2234c1cd feat: add the space and spaceMember module. 2023-05-13 14:35:33 +08:00
lishuang 42208ac101 feat: prepare work for v3.2.0 2023-05-13 14:07:18 +08:00
lishuang b247364d16 revert: revert the change for v3.2.0 2023-05-13 11:43:59 +08:00
eyeblue d8b86bd302 Update README.md 2023-04-13 02:08:49 +08:00
simba 1ec66adda0 change dingtalk qrcode 2022-06-30 23:28:44 +08:00
simba d3d0ee73a0 stash file 2022-05-12 18:06:08 +08:00
simba e757b471fd stash file 2022-05-12 18:05:57 +08:00
Simba 60c8843734 Merge pull request #175 from eyebluecn/v3.1.6
V3.1.6
2022-05-01 18:01:32 +08:00
lishuang f779053040 Release v3.1.6 2022-05-01 17:55:46 +08:00
lishuang 6becac74d0 Upgrade the front to 3.1.6 2022-05-01 17:51:18 +08:00
lishuang e64a73eb67 Fix the bug of share auth. 2022-05-01 17:38:19 +08:00
lishuang cffa82226d Fix the bug of time-zone. 2022-05-01 16:50:35 +08:00
Simba 6626afa6b6 Merge pull request #165 from eyebluecn/fix/build.sh
fix: throw build.sh error
2022-05-01 10:31:04 +08:00
simba 6d35063027 fix: throw build.sh error 2022-04-29 16:32:14 +08:00
lishuang 09d6db68ff Refine the format. 2022-04-28 18:35:44 +08:00
lishuang f33145d02a Refine the format for png. 2022-04-28 18:35:14 +08:00
lishuang a74e4f1a13 Add support for jetbrains. 2022-04-28 18:27:52 +08:00
lishuang 9344a831be Fix the demo tank website. 2022-04-04 21:43:37 +08:00
lishuang 4fd7e89ff8 Ready to release v3.1.5 2022-03-21 15:30:39 +08:00
eyeblue d0a2774f65 Update README.md 2022-03-20 20:34:24 +08:00
lishuang fb563396fe Add security.md. 2022-03-20 20:16:17 +08:00
lishuang 73ad9f49ef Fix some frontend bugs. 2022-03-20 18:52:26 +08:00
lishuang 10e6bf81f9 Fix a bug in frontend. 2022-03-20 18:18:59 +08:00
lishuang 274b49d66f Fix the sqlite folder bug2. 2022-03-20 17:24:57 +08:00
lishuang ab6749056a Fix the sqlite folder bug. 2022-03-20 17:21:40 +08:00
lishuang 3be2e354c4 Fix a potential bug. 2022-03-20 17:15:16 +08:00
lishuang 0c825c65d4 Change the default goproxy. 2022-03-20 16:18:43 +08:00
lishuang c6836f3654 Release 3.1.4 2022-03-20 16:16:15 +08:00
lishuang c6a5db7740 Finish the sqlite feature. 2022-03-18 22:17:32 +08:00
lishuang 179f34fad2 Refine some comments. 2022-03-15 02:21:41 +08:00
lishuang 161096fbb2 Finish upgrade the gorm framework. 2022-03-15 02:17:26 +08:00
lishuang 69412300b6 Upgrade half or gorm. 2022-03-15 01:19:44 +08:00
lishuang 329751350d release v 3.1.3 2022-03-10 09:54:57 +08:00
lishuang 90675e3ae8 Fix the total size bug. 2022-03-10 09:46:23 +08:00
zicla 238125eb8d Refine the dingding code. 2022-03-09 21:20:27 +08:00
eyeblue d30f02b1c0 Merge pull request #149 from biuaxia/master
Feat 预览功能适配kkFileView,请将预览引擎的 {url} 修改为 {b64Url}.
2021-11-26 17:39:48 +08:00
biuaxia d9ec47f8ea Feat 预览功能适配kkFileView,请将预览引擎的 {url} 修改为 {b64Url}.
tips: 完整的引擎格式如 -> `http://ddns.biuaxia.cn:10002/onlinePreview?url={b64Url}`
2021-11-19 09:56:44 +08:00
lishuang 6020915993 Release 3.1.2 2021-01-02 23:17:51 +08:00
lishuang 07ed4f7922 Support chinese username. 2021-01-02 18:13:20 +08:00
lishuang 13b6d7f98d Fix the hard delete feature. 2021-01-02 17:31:09 +08:00
lishuang 3752d42de8 Fix the 0 day bin feature. 2021-01-02 17:18:20 +08:00
lishuang 847bcd746c Add the keep 0 days feature. 2021-01-02 17:10:49 +08:00
lishuang e1e46457e7 Add the scan once api. 2021-01-02 16:15:50 +08:00
lishuang a2751deac6 Merge remote-tracking branch 'origin/master' 2020-09-08 00:41:21 +08:00
lishuang 74c11e7539 Release 3.1.1 2020-09-08 00:41:00 +08:00
Simba cb0ee30c6b release 3.1.1 2020-09-08 00:25:16 +08:00
eyeblue c518c0c1e6 Merge pull request #110 from user1121114685/patch-1
fix debian user can not start tank bug
2020-09-07 10:34:51 +08:00
联盟少侠 8827c45df1 fix debian user can not start tank bug 2020-09-06 23:40:58 +08:00
Simba b91518136b upgrade version to 3.1.0 2020-07-24 08:57:08 +08:00
lishuang b46cb2501b Release 3.1.0 2020-07-18 16:26:08 +08:00
lishuang c1823e7a83 Fix the docker command. 2020-07-18 15:54:14 +08:00
lishuang 84d5f4e5e2 Add the schema-3.1.0.sql 2020-07-18 15:31:26 +08:00
lishuang ff7416f858 Fix the index syntax. 2020-07-18 15:28:31 +08:00
lishuang b6b4cb1ce4 Release 3.1.0 2020-07-18 15:19:49 +08:00
lishuang 617d5df294 Fix the hard delete bug. 2020-07-18 14:38:47 +08:00
lishuang ff87ea8e39 Add the sort for delete time. 2020-07-18 14:02:36 +08:00
lishuang 36581ded16 Fix the soft delete bug. 2020-07-18 13:59:26 +08:00
lishuang 333682325c Add a todo case. 2020-07-16 02:01:18 +08:00
lishuang 1a1d9e8adf Add pre cast. 2020-07-12 23:41:29 +08:00
lishuang 020e7b0944 Next week release 3.1.0 2020-07-12 23:40:36 +08:00
lishuang e15bd00524 Refine the README.md file. 2020-07-12 23:08:06 +08:00
lishuang de1e2dbcbb Update the frontend resources. 2020-07-12 22:11:48 +08:00
lishuang 7b24f1dedf Add the recycle bin note. 2020-07-12 21:19:45 +08:00
lishuang ce94a35ed7 Add the recovery files. 2020-07-12 21:17:58 +08:00
lishuang 8a0c66ceff Add the recovery feature. 2020-07-12 21:03:01 +08:00
lishuang a92e172d26 Fix the soft delete bug. 2020-07-12 20:52:20 +08:00
lishuang a7bcc4d4fb Finish the clean expired deleted files feature. 2020-07-12 20:42:01 +08:00
lishuang 19cfd3daf4 Add the field deletedKeepDays. 2020-07-12 17:55:40 +08:00
lishuang b82bac40fc Add the field deletedKeepDays. 2020-07-12 17:53:33 +08:00
lishuang 21d61d9cd2 Fix the delete . 2020-07-12 17:47:07 +08:00
lishuang 76e7359c69 Add the deleted time. 2020-07-12 17:46:17 +08:00
lishuang 82047f4504 Add the deleted feature. 2020-07-12 17:26:15 +08:00
lishuang c970acbe8b Refine the frontend codes. 2020-07-12 16:43:42 +08:00
lishuang 988d2caced Ready to release 3.1.0 2020-07-12 00:14:22 +08:00
lishuang c5111929a3 Update html resources. 2020-07-12 00:11:30 +08:00
lishuang b6b72e0273 Remove lots of useless files. 2020-07-12 00:05:31 +08:00
lishuang 0d43439200 Add the visit time feature. 2020-07-11 22:29:56 +08:00
lishuang da0e68f95c Finish the details for the scan task. 2020-07-11 21:57:37 +08:00
lishuang fbea823ba1 Fix some bug for scan task. 2020-07-11 21:36:24 +08:00
lishuang 7adf56ce0a Fix some bug in the dashboard etl work. 2020-07-11 21:06:12 +08:00
lishuang 7f394b327b Add the task service for scan task. 2020-07-11 20:46:47 +08:00
lishuang 7fe673068b Finish the delete and sync by physics. 2020-07-11 19:56:13 +08:00
lishuang f16d48b432 Finish the PageHandle for matter. 2020-07-11 17:42:09 +08:00
lishuang 192df21da4 Use the new cron lib. 2020-07-11 16:30:28 +08:00
lishuang 02e0f10016 Migrate guuid. 2020-07-11 15:36:21 +08:00
lishuang 24e8dc4e9f Ready to upgrade the dependencies. 2020-07-11 15:28:12 +08:00
lishuang dbeef1cee4 Add the task service. Ready to tidy the go modules. 2020-07-11 15:25:31 +08:00
lishuang 096eb7c73e Add two preference edit api. 2020-07-11 14:40:03 +08:00
lishuang 69820bfcb9 Fix the share bug. 2020-06-21 21:45:55 +08:00
lishuang 3c3b7c4389 Use new front end assets. 2020-06-21 21:28:20 +08:00
lishuang 822ebf4888 Try to use go build. 2020-06-21 20:41:28 +08:00
lishuang 3b6c43ee23 Add the tank31 schema. 2020-06-21 20:08:06 +08:00
lishuang c711423ef9 Add tank30 schema. 2020-06-21 18:22:00 +08:00
lishuang 948c37c039 Add the tank30 schema. 2020-06-21 18:18:06 +08:00
lishuang 1f8e3cfb7a Finish the version of tank-3.1.0.beta1 2020-06-21 18:12:23 +08:00
lishuang 7b875c81d1 Add the preview config. 2020-06-21 02:41:13 +08:00
lishuang 3fb1d874d5 Finish the delete feature. 2020-06-21 00:04:11 +08:00
lishuang 601c60fca7 Finish the cache refresh things. 2020-06-20 22:17:01 +08:00
lishuang d052f75a1c Move to inner. 2020-06-19 23:17:56 +08:00
lishuang 51c81e19af Fix the move to root dir feature. 2020-06-19 23:15:18 +08:00
lishuang 480cbb73ea Add Info. 2020-06-06 02:49:25 +08:00
lishuang 4a1e4c1d68 Finish the preference. 2020-06-05 21:47:02 +08:00
lishuang 76c763b84d Finish the Lock and Unlock feature for webdav. 2020-05-06 01:10:17 +08:00
lishuang ed0aa017db Refine some capital letters. Finish the Lock method. 2020-05-05 22:29:16 +08:00
lishuang a314d4dc54 Add mysqlCharset prop. Fix some dav bug. 2020-05-05 19:33:22 +08:00
zicla 4bfae38176 Finish the prop set feature. 2020-03-26 02:19:43 +08:00
zicla 1f047e25c7 Refine some webdav methods. 2020-03-26 01:11:16 +08:00
zicla ff81448611 Ready to use x's webdav components. 2020-03-25 01:55:03 +08:00
zicla 83cf140fa1 Add the webdav from x 2020-03-25 01:48:33 +08:00
zicla 8fc1cd0430 Read to finish the webdav's props. 2020-03-16 01:50:09 +08:00
zicla 7ff7907e11 Add new fields into matter. Remove migrate20To30. 2020-03-16 01:44:27 +08:00
zicla 4611defe36 Pass all the move tests. 2020-03-12 01:57:08 +08:00
zicla eb89807cf1 Fix the error of copy. 2020-03-12 01:29:22 +08:00
zicla bea9a0a56d Fix some copy warning. 2020-03-12 00:56:54 +08:00
zicla fc2df7e501 Pass the litmus basic tests. 2020-03-11 02:11:26 +08:00
zicla bab3e80aec Upgrade the dependencies. 2020-03-11 00:33:45 +08:00
zicla a556813b01 Show by type. 2020-02-24 13:28:40 +08:00
zicla e90f922b58 Add a todo item. 2020-02-12 03:22:16 +08:00
zicla 7671564ea3 ADD some todo things. 2020-01-08 16:06:51 +08:00
zicla 402dc5d970 Add a todo list. 2020-01-03 14:36:00 +08:00
zicla 51b0668b5d Update the info for dingding. 2019-12-24 15:00:06 +08:00
zicla 8686551e71 Release 3.0.6 2019-10-13 16:37:20 +08:00
simba 437e2c602a fix: a user register bug 2019-09-26 23:26:34 +08:00
zicla fe00d39bc1 Release docker version. 2019-08-14 02:04:39 +08:00
zicla 5cb7998f12 Fix the Bug of sharing. [#56](https://github.com/eyebluecn/tank/issues/56) 2019-08-13 02:49:38 +08:00
eyeblue 6cec43bee6 Update README.md 2019-07-24 11:11:13 +08:00
zicla 6e81d130ed Release 3.0.4 2019-06-11 01:14:48 +08:00
zicla e8ba2326aa Release 3.0.4 2019-06-11 01:03:40 +08:00
zicla a070df069b Use relative path. 2019-06-11 00:58:43 +08:00
zicla fe133d3ec2 Fix the total size logic check. 2019-06-06 02:32:46 +08:00
zicla ddfeb37114 Add the feature of creating user. 2019-06-04 02:39:44 +08:00
182 changed files with 21481 additions and 5759 deletions
+2
View File
@@ -8,3 +8,5 @@ tmp
tank
tank.exe
# mac
.DS_Store
+167 -6
View File
@@ -12,10 +12,7 @@
3. core/config.go
VERSION = x.x.x
4. tank-front 修改 vuex/index.js
versionName: 'x.x.x'
5. readme.md 修改 eyeblue/tank:x.x.x
4. readme.md 修改 eyeblue/tank:x.x.x
eyeblue/tank:x.x.x
@@ -30,8 +27,8 @@ 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 -d mysql:5.7
docker run --name tank -p 6010:6010 --link dockermysql:mysql -v ~/data/dockermatter:/data/matter -d 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 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
```
@@ -50,6 +47,170 @@ c. 在github上发布新版本。
3.更新tank-doc 下载内容
## useful commands
go get xxx/xxx
go mod tidy
tank-4.1.1 2024-10-6
1. 修复已知问题
tank-4.1.0 2024-7-27
1. 删除用户后,空间一并删除。 #222
2. 增加批量绑定空间成员功能。 #227
3. 共享空间增加回收站逻辑。 #232
4. 修复用户修改空间单位问题。 #233 #253
5. 增强搜索功能,会进行dfs深度优先搜索。 #239
1. When delete user, it's space will be deleted #222
2. Batch creating space member #227
3. Add feature of recycle bin for space #232
4. Fix issue of changing unit #233 #253
5. Enhance the search ability, using dfs #239
tank-4.0.4 2024-4-29
1. 修复已知问题
tank-4.0.3 2024-3-26
1. 修复已知问题
tank-4.0.2 2023-11-10
1. 修复BUG https://github.com/eyebluecn/tank/issues/229
2. 新增了分享提取码快速提取
3. 分享文件默认按照创建时间倒序排列。
1. Fix BUG https://github.com/eyebluecn/tank/issues/229
2. Fast share using code.
3. Share list order by create time desc.
tank-4.0.1 2023-09-09
1.修复一些文件扫描的bug https://github.com/eyebluecn/tank/issues/221 https://github.com/eyebluecn/tank/issues/220
1.Fix scan bug. https://github.com/eyebluecn/tank/issues/221 https://github.com/eyebluecn/tank/issues/220
tank-4.0.0 2023-08-13
1.增加空间概念,可以多人共同维护一个共享空间中的文件 #201
2.新增粘贴上传文件功能 #188
3.文件大小单位选择体验优化 #179
4.支持使用url的方式抓取文件
5.一些UI优化
1.Add space, supports multi users maintaining a shared space. #201
2.Add the feature of uploading by pasting files. #188
3.Human readable file size unit. #179
4.Add the feature of uploading by url.
6.Some user experience enhancement.
tank-4.0.0.beta1 2023-07-22
1. Shared space
2. Copy and paste upload
3. Crawl upload
4. Space size selection control upgrade
5. Some style modifications
1. 共享空间
2. 文件复制粘贴上传
3. 文件抓取上传
4. 空间大小选择控件升级
5. 一些样式修改
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.2 2021-01-02
1. Add scan manually once feature
2. Add disable recycle bin feature
3. WebDAV use hard delete now
4. Support Chinese Username
5. Normal user cannot change itself space limit
6. Support the order sort by filename, size and update time
7. Hide the side menu on phone by default
8. Friendly hint for large file upload.
9. Cancel during uploading.
1. 添加了手动扫描一次的功能
2. 添加了禁用回收站功能
3. WebDAV中的删除采用硬删除
4. 支持中文的用户名
5. 普通用户不能再修改自己的空间限制
6. 文件支持按照名称排序,按照大小排序,按照修改日期排序
7. 手机端默认隐藏左边菜单
8. 大文件上传友好性提示
9. 可以取消文件上传
tank-3.1.1 2020-09-08
1. Add upload folder feature.
2. Fix the share auth bug.
1. 添加了文件夹上传功能
2. 修复了分享时需要登陆的问题
tank-3.1.0
1. Reconstruct frontend by typescript+react+antd.
2. Enhance the webdav ability.
3. Add charset in mysql config.
4. Add preview_config.
5. Add delete user feature.
6. Add Scan config.
7. Add recycle bin feature.
1. 前后进行了一次完全的重构。 采用Typescript+React+Antd
2. 增强了WebDav的能力,现在能够适配更多的WebDav客户端了
3. 数据库配置项中添加了编码支持,可以支持emoji了
4. 添加了预览引擎配置,用户可以使用自己的引擎来预览特定格式文件
5. 添加了删除用户的功能,删除用户后会清空用户所有的文件和痕迹
6. 添加了扫描功能,可以定时同步物理文件到蓝眼云盘中
7. 增加回收站功能
2019-10-13
tank-3.0.6
1. Fix the Bug of limit size.
2. Add the drag feature for uploading files.
3. Fix the page bug of list.
2019-08-13
tank-3.0.5
1. Fix the Bug of sharing. [#56](https://github.com/eyebluecn/tank/issues/56)
2019-06-11
tank-3.0.4
1. Use relative assets in tank-front.
2. Fix the total size check bug.
3. Add feature. Creating user.
2019-05-31
tank-3.0.3
1. Add default utf8 charset when creating tables.
+8 -4
View File
@@ -1,5 +1,5 @@
# use golang 1.12
FROM golang:1.12
# use golang 1.22.5
FROM golang:1.22.5
# maintainer. Author's name and email.
MAINTAINER eyeblue "eyebluecn@126.com"
@@ -14,10 +14,14 @@ COPY . /data
VOLUME /data/build/matter
# proxy
ENV GOPROXY=https://athens.azurefd.net
ENV GOPROXY=https://goproxy.cn
# Handle time-zone
ENV TZ=Asia/Shanghai
RUN apt-get install -y tzdata
# prepare the config file
RUN go build -mod=readonly \
RUN go build \
&& cp -r /data/tank /data/build
# use 6010 as default.
+39 -22
View File
@@ -1,12 +1,25 @@
[![蓝眼云盘logo](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/logo.png)](https://github.com/eyebluecn/tank)
[![蓝眼云盘logo](./build/doc/img/logo.png)](https://github.com/eyebluecn/tank)
[English Version](./README_EN.md)
[English Version](https://tank-doc.eyeblue.cn/en)
# 蓝眼云盘(3.0.3)
# 蓝眼云盘(4.1.2)
[在线Demo](https://tanker.eyeblue.cn) (体验账号: demo 密码:123456)
[在线Demo](https://tank.eyeblue.cn) (体验账号: demo 密码:123456)
蓝眼云盘是蓝眼开源系列代表作品之一,致力于打造精致,优雅,简约的云盘。核心功能如下:
1. 文件列表
2. 文件/文件夹上传 + 拖拽上传
3. 共享空间
3. 文件分享
4. 文件监控统计
5. 回收站
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/)
[更多内容请移步至文档](https://tank-doc.eyeblue.cn/)
### 软件截图
@@ -18,27 +31,22 @@
![](./build/doc/img/tank2.png)
![](./build/doc/img/tank3.png)
![](./build/doc/img/tank4.png)
#### 手机端截图
![](./build/doc/img/mobile.png)
#### [安装文档](https://tank-doc.eyeblue.cn/zh/basic/install.html)
## [安装文档](https://tank-doc.eyeblue.cn/basic/install.html)
### 相关文档
[蓝眼云盘后端api](https://github.com/eyebluecn/tank/blob/master/build/doc/api_zh.md)
[蓝眼云盘编程接口](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md)
[快速使用Let's Encrypt开启个人网站的https](https://blog.eyeblue.cn/home/article/9f580b3f-5679-4a9d-be6f-4d9f0dd417af)
[Docker 化你的开源项目](https://blog.eyeblue.cn/home/article/510f9316-9ca1-40fe-b1b3-5285505a527d)
### 快速运行
安装依赖
```shell
go mod tidy
```
运行main文件即可:
```shell
./main.go
```
### Contribution
@@ -46,9 +54,18 @@
如果您也想参与进来,请尽情的fork, star, post issue, pull requests
当然你可以加入钉钉群一起直接交流
当然你可以加入钉钉群(一群已满员)一起直接交流,在钉钉群中可以获取最新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)
### License
-134
View File
@@ -1,134 +0,0 @@
[![蓝眼云盘logo](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/logo.png)](https://github.com/eyebluecn/tank)
[中文版](./README_EN.md)
# Eyeblue Cloud Disk(2.0.0)
[Online Demo](https://tank.eyeblue.cn) (demo@tank.eyeblue.cn 123456)
![](https://tank.eyeblue.cn/api/alien/download/df372827-ba56-415e-42d1-0e3a34fdb2a1/github20x20.png "github20x20.png") [tank backend](https://github.com/eyebluecn/tank)
![](https://tank.eyeblue.cn/api/alien/download/df372827-ba56-415e-42d1-0e3a34fdb2a1/github20x20.png "github20x20.png") [tank-front frontend](https://github.com/eyebluecn/tank-front)
### Description
Eyeblue Cloud Disk is one of [Eyeblue Softwares](https://github.com/eyebluecn), and it is the basic software for other eyeblue softwares.Eyeblue Cloud Disk has the following features.
**1. Easy to use**
- Docker available
- [Install package](https://github.com/eyebluecn/tank/releases) is about 10M. Cross platform.
- Unpack the install zip, and run it with one command.
- Installation Guide
- Dashboard to view UV and PV.
- Preview usual files (doc,ppt,xls,pdf,mp3,mp4,jpg,png)
**2. Core features all in readiness**
- Manage your files on cloud.
- Responsive on PC and mobile.
- Normal user and administrator
**3. Custom Api supported**
- Support [Custom Api](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md)
- Manage files by api.
If this project is helpful for you, star ⭐ it.
### Screen Shot
#### PC
![](./build/doc/img/tank0.png)
![](./build/doc/img/tank1.png)
![](./build/doc/img/tank2.png)
![](./build/doc/img/tank3.png)
![](./build/doc/img/tank4.png)
#### Mobile
![](./build/doc/img/mobile.png)
### Installation by Docker
##### a) Run
```
docker run --name tank -p 6010:6010 -d eyeblue/tank:2.0.0
```
If you'd like to start you mysql by docker, use the following command.
```
docker run --name mysql4tank -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=tank -e MYSQL_USER=tank -e MYSQL_PASSWORD=tank123 -v ~/data/mysqldemo1:/var/lib/mysql -d mysql:5.7
```
##### b) Validation
Open http://127.0.0.1:6010 it succeed if you see the installation guide.
### Installation by installation package (windows/linux almost the same)
##### a) Prepare
1. [Mysql](https://www.mysql.com/downloads/) (Use utf8 charset)
2. [Here](https://github.com/eyebluecn/tank/releases) download installation package.
3. Unzip on server
##### b) Run
- Double click `tank.exe` on windows
- Run the following command on linux
```
cd ApplicationDirectory
./tank
```
If you'd like to run in daemon mode.
```shell
# Run the application
cd ApplicationDirectory/service
./startup.sh
# Stop the application
cd ApplicationDirectory/service
./shutdown.sh
```
##### c) Validation
Open http://127.0.0.1:6010 it succeed if you see the installation guide.
### Reference
[api](https://github.com/eyebluecn/tank/blob/master/build/doc/api_zh.md)
[Custom API](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md)
### Contribution
Thanks these authors [@zicla](https://github.com/zicla),[@seaheart](https://github.com/seaheart),[@yemuhe](https://github.com/yemuhe),[@hxsherry](https://github.com/hxsherry)
You can join us by scanning the following qcode.
![](./build/doc/img/dingding.jpg)
### License
[MIT](http://opensource.org/licenses/MIT)
Copyright (c) 2017-present, eyeblue.cn
+16
View File
@@ -0,0 +1,16 @@
# 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.
-13
View File
@@ -1,13 +0,0 @@
# Eyeblue Tank
> The document is comming...
go build -mod=readonly
### Program Arguments
-mode=mirror -username=admin -password=123456 -src=/Users/fusu/d/temp -dest=/morning
-3
View File
@@ -1,3 +0,0 @@
# 蓝眼云盘
> 详细文档正在撰写中,敬请期待...
-132
View File
@@ -1,132 +0,0 @@
# 蓝眼云盘编程接口
- 蓝眼云盘提供了[编程接口](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md),实现了云存储(如:[七牛云](https://www.qiniu.com),[阿里云OSS](https://www.aliyun.com/product/oss))的核心功能,可以使用编程接口上传文件,作为其他网站、系统、app的资源存储器。可以在下载图片时对图片做缩放裁剪处理,可以有效地节省客户端流量。
- 蓝眼系列开源软件之二的[《蓝眼博客》](https://github.com/eyebluecn/blog)正是使用蓝眼博客作为第三方资源存储器。蓝眼博客中的所有图片,附件均是存储在蓝眼云盘中。
所有的编程接口均定义在`alien_controller`中,主要包括以下几个接口:
`/api/alien/fetch/upload/token` 获取上传token
`/api/alien/fetch/download/token` 获取下载token
`/api/alien/confirm` 来蓝眼云盘确认文件
`/api/alien/upload` 使用form表单上传文件
`/api/alien/download/{uuid}/{filename}` 下载文件
### 上传时序图
![上传时序图](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/upload-time-line.png)
### 下载时序图
![下载时序图](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/download-time-line.png)
### 接口详情
#### /api/alien/fetch/upload/token
功能:一个蓝眼云盘受信任的用户请求一个`UploadToken`,用于给另一个用户向蓝眼云盘上传文件。
一般的使用场景是`应用服务器`向`蓝眼云盘`请求`UploadToken`,然后将此`UploadToken`交由`浏览器`去向`蓝眼云盘`上传文件。
参数 | 类型 | 描述
--------- | ---- | -----------
email | `string` | 【必填】邮箱,用于确定请求者身份
password | `string` | 【必填】密码,用于确定请求者身份
filename | `string` | 【必填】即将上传的文件名,不能包含以下特殊符号:`< > \| * ? / \`
expire | `int` | 【选填】UploadToken过期时间,单位:s。默认 86400s 即24h
privacy | `bool` | 【必填】文件的共有性。`true`表示文件私有,下载时必须要DownloadToken. `false`表示文件公有,任何人可以通过下载链接直接下载
size | `int` | 【必填】文件的大小。单位:byte
dir | `string` | 【必填】文件存放的路径。不能为空,必须以`/`开头,不能出现连续的`//`,不能包含以下特殊符号:`< > \| * ? \`。举例:`/app/blog/20180101121212001`
#### /api/alien/upload
功能:浏览器拿着`UploadToken`通过FormData向蓝眼云盘上传文件。
一般的使用场景是`应用服务器`向`蓝眼云盘`请求`UploadToken`,然后将此`UploadToken`交由`浏览器`去向`蓝眼云盘`上传文件。由于在请求`UploadToken`的时候已经传入了文件元信息,因此这里的文件信息必须要和`/api/alien/fetch/upload/token`传入的参数信息一致。
参数 | 类型 | 描述
--------- | ---- | -----------
uploadTokenUuid | `string` | 【必填】uploadToken标识,`/api/alien/fetch/upload/token`请求返回对象中的`uuid`
file | `file` | 【必填】文件,在浏览器中是通过`<input type="file" name="file"/>`来选择的
#### /api/alien/confirm
功能:`应用服务器`向蓝眼云盘确认某个文件是否确实已经上传好了。
参数 | 类型 | 描述
--------- | ---- | -----------
email | `string` | 【必填】邮箱,用于确定请求者身份
password | `string` | 【必填】密码,用于确定请求者身份
matterUuid | `string` | 【必填】浏览器上传完毕后,蓝眼云盘返回给浏览器的`uuid`
#### /api/alien/fetch/download/token
功能:一个蓝眼云盘受信任的用户请求一个`DownloadToken`,用于给另一个用户下载蓝眼云盘上的私有文件。
一般的使用场景是`应用服务器`向`蓝眼云盘`请求`DownloadToken`,然后将此`DownloadToken`交由`浏览器`去向`蓝眼云盘`下载文件。
参数 | 类型 | 描述
--------- | ---- | -----------
email | `string` | 【必填】邮箱,用于确定请求者身份
password | `string` | 【必填】密码,用于确定请求者身份
matterUuid | `string` | 【必填】文件uuid,要想下载的文件`uuid`
expire | `int` | 【选填】UploadToken过期时间,单位:s。默认 86400s 即24h
#### /api/alien/download/{uuid}/{filename}
功能:在浏览器中下载文件
这个接口既可以下载公有文件,又可以下载私有文件。同时对于图片文件还可以做裁剪缩放等操作。
参数 | 类型 | 描述
--------- | ---- | -----------
uuid | `string` | 【必填】文件的uuid,该参数放在url的路径中
filename | `string` | 【必填】文件的名称,该参数放在url的路径中
downloadTokenUuid | `string` | 【选填】download的uuid,如果是私有文件该参数必须,公有文件无需填写。
该接口同时还可以对图片进行缩放预处理
> 图片缩放支持的格式有:".jpg", ".jpeg", ".png", ".tif", ".tiff", ".bmp", ".gif"
##### 额外参数
| 参数 | 类型 | 描述 | 取值范围 |
| ------------ | ---- | ------------ | ------------ |
| imageProcess | `string` | 指定图片处理的方式,对于图片缩放固定为`resize` | 固定为`resize` |
| imageResizeM | `string` | 指定图片缩放的策略,有三种策略,`fit` 表示固定一边,另一边按比例缩放;`fill`表示先将图片延伸出指定W与H的矩形框外,然后进行居中裁剪;`fixed`表示直接按照指定的W和H缩放图片,这种方式可能导致图片变形 | [`fit`,`fill`,`fixed`] 不填默认`fit` |
| imageResizeW | `int` | 指定的宽度,对于`fit`可以不指定 | 1 ~ 4096 |
| imageResizeH | `int` | 指定的高度,对于`fit`可以不指定 | 1 ~ 4096 |
##### 示例
原图:
![将宽度指定为200,高度等比例缩放](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg)
1. 将宽度指定为200,高度等比例缩放
![将宽度指定为200,高度等比例缩放](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeW=200)
[http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeW=200](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeW=200)
2. 将高度指定为200,宽度等比例缩放
![将高度指定为200,宽度等比例缩放](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeH=200)
[http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeH=200](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fit&imageResizeH=200)
3. 图片自动填充在200*200的大小中 (这种情况用得最多)
![图片自动填充在200*200的大小中](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fill&imageResizeW=200&imageResizeH=200)
[http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fill&imageResizeW=200&imageResizeH=200](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fill&imageResizeW=200&imageResizeH=200)
4. 图片固定大小200*200 (一般会导致变形)
![图片自动填充在200*200的大小中](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fixed&imageResizeW=200&imageResizeH=200)
[http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fixed&imageResizeW=200&imageResizeH=200](http://tank.eyeblue.cn/api/alien/download/3f4b3090-e688-4d63-7705-93a120690505/horse.jpg?imageProcess=resize&imageResizeM=fixed&imageResizeW=200&imageResizeH=200)
-798
View File
@@ -1,798 +0,0 @@
# 蓝眼云盘api接口
## 一、实体
在详细介绍各controller中的接口前,有必要先介绍蓝眼云盘中的各实体,所有的实体基类均为`Base`
#### Base
`Base`定义如下,所有会在数据库中持久化的实体均会继承`Base`,`Controller`在返回实体给前端时,会将字段和值序列化成json字符串,其中键就和每个实体字段后面的`json`标签一致,下文也会有详细例子介绍
```
type Base struct {
//唯一标识
Uuid string `gorm:"primary_key" json:"uuid"`
//排序用的字段,一般是时间戳来表示序号先后
Sort int64 `json:"sort"`
//修改时间
ModifyTime time.Time `json:"modifyTime"`
//创建时间
CreateTime time.Time `json:"createTime"`
}
```
#### Preference
`Preference`是整个网站的偏好设置,网站的名称,logo,favicon,版权,备案号等信息均由这个实体负责。定义如下:
```
type Preference struct {
//继承Base,也就是说Base中的Uuid,Sort,ModifyTime,CreateTime这里也会有
Base
//网站名称
Name string `json:"name"`
//网站的logo url
LogoUrl string `json:"logoUrl"`
//网站的favicon.ico url
FaviconUrl string `json:"faviconUrl"`
//网站下方第一行信息,一般是版权信息
FooterLine1 string `json:"footerLine1"`
//网站下方的第二行信息,一般是本案信息
FooterLine2 string `json:"footerLine2"`
//当前运行的蓝眼博客版本,这个字段不可修改,每次发版时硬编码
Version string `json:"version"`
}
```
#### Matter
`Matter`是代表文件(文件夹是一种特殊的文件),为了和系统的`file`重复,这里使用`matter`,这个实体是蓝眼云盘最重要的实体:
```
type Matter struct {
//继承Base,也就是说Base中的Uuid,Sort,ModifyTime,CreateTime这里也会有
Base
//所在的文件夹的uuid,如果在根目录下,这个字段为 root
Puuid string `json:"puuid"`
//创建这个文件的用户uuid
UserUuid string `json:"userUuid"`
//该文件是否是文件夹
Dir bool `json:"dir"`
//该文件是否是应用文件,比如用户上传的头像这个字段就为true. 一般上传的文件就为false
Alien bool `json:"alien"`
//文件名,带后缀名。例如:avatar.jpg
Name string `json:"name"`
//文件的md5值,目前该功能尚未实现,作为保留字段
Md5 string `json:"md5"`
//文件大小,单位 byte。比如某个文件1M大,那么这里就为: 1048576
Size int64 `json:"size"`
//文件是否为私有,如果true则该文件只能作者或超级管理员可以下载,如果false所有人均可以通过下载链接下载。
Privacy bool `json:"privacy"`
//文件在磁盘中的路径,前端无需关心这个字段。但是后端在寻找文件时这个字段非常关键。
Path string `json:"path"`
//该文件的父级matter,该字段不会持久化到数据集,属于获取matter详情时临时组装出来的。
Parent *Matter `gorm:"-" json:"parent"`
}
```
#### User
`User`是代表用户:
```
type User struct {
//继承Base,也就是说Base中的Uuid,Sort,ModifyTime,CreateTime这里也会有
Base
//角色,有以下枚举值:GUEST(游客,不会持久化到数据库),USER(普通用户),ADMINISTRATOR(超级管理员)
Role string `json:"role"`
//用户名,在Matter的path字段中很有用。
Username string `json:"username"`
//密码,默认不会返回给前端
Password string `json:"-"`
//邮箱,作为登录时的账户
Email string `json:"email"`
//手机
Phone string `json:"phone"`
//性别,有以下枚举值:MALE(男性),FEMALE(女性),UNKNOWN(未知)
Gender string `json:"gender"`
//城市
City string `json:"city"`
//头像Url
AvatarUrl string `json:"avatarUrl"`
//上次登录时的ip
LastIp string `json:"lastIp"`
//上次登录的时间
LastTime time.Time `json:"lastTime"`
//该用户允许上传的单文件最大大小
SizeLimit int64 `json:"sizeLimit"`
//状态,有以下枚举值:OK(正常),DISABLED(被禁用)
Status string `json:"status"`
}
```
### UploadToken
用于给陌生人上传的token
```
type UploadToken struct {
//继承Base,也就是说Base中的Uuid,Sort,ModifyTime,CreateTime这里也会有
Base
//颁发该token的用户,系统中任何用户都能颁发token
UserUuid string `json:"userUuid"`
//使用这个token上传文件就必须上传在这个文件夹下
FolderUuid string `json:"folderUuid"`
//陌生人上传好了的文件uuid
MatterUuid string `json:"matterUuid"`
//过期时间
ExpireTime time.Time `json:"expireTime"`
//使用这个token上传文件就必须是这个文件名
Filename string `json:"filename"`
//使用这个token上传文件就必须是这个公私有性
Privacy bool `json:"privacy"`
//使用这个token上传文件就必须这个大小
Size int64 `json:"size"`
//使用这个token上传文件陌生人的ip
Ip string `json:"ip"`
}
```
### DownloadToken
用于给陌生人下载的token,一个matter如果Privacy=true,那么就意味着只有自己或者超级管理员可以下载,如果让某些自己信任的用户也能下载,那么就需要生成`DownloadToken`给这些用户来下载。
```
type DownloadToken struct {
//继承Base,也就是说Base中的Uuid,Sort,ModifyTime,CreateTime这里也会有
Base
//颁发该token的用户
UserUuid string `json:"userUuid"`
//该token只能下载这个文件
MatterUuid string `json:"matterUuid"`
//有效期截止
ExpireTime time.Time `json:"expireTime"`
//下载者的ip
Ip string `json:"ip"`
}
```
### Pager
在前端请求一个列表时,通常返回的都是一个`Pager`,`Pager`中就是装的各个实体的列表。
```
type Pager struct {
//当前页数,0基
Page int `json:"page"`
//每页的大小
PageSize int `json:"pageSize"`
//总的条目数
TotalItems int `json:"totalItems"`
//总的页数
TotalPages int `json:"totalPages"`
//实体的数组
Data interface{} `json:"data"`
}
```
### WebResult
`WebResult`并不是会持久化到数据库中实体,`WebResult`是在`controller`返回数据给前端时包装的一层,有了`WebResult`后每个接口返回的数据会更加统一,方便了前端的统一处理。
```
type WebResult struct {
//状态码,具体每个码的意义参考下文
Code int `json:"code"`
//一句话描述请求结果,通常会是出错时指明出错原因,或者修改权限等小操作时提示的`操作成功`
Msg string `json:"msg"`
//内容可能是一个实体,也可能是一个 Pager.
Data interface{} `json:"data"`
}
```
状态码对应关系如下:
```
const (
//正常
RESULT_CODE_OK = 200
//未登录
RESULT_CODE_LOGIN = -400
//没有权限
RESULT_CODE_UNAUTHORIZED = -401
//请求错误
RESULT_CODE_BAD_REQUEST = -402
//没有找到
RESULT_CODE_NOT_FOUND = -404
//登录过期
RESULT_CODE_LOGIN_EXPIRED = -405
//该登录用户不是有效用户
RESULT_CODE_LOGIN_INVALID = -406
//提交的表单验证不通过
RESULT_CODE_FORM_INVALID = -410
//请求太频繁
RESULT_CODE_FREQUENCY = -420
//服务器出错。
RESULT_CODE_SERVER_ERROR = -500
//远程服务不可用
RESULT_CODE_NOT_AVAILABLE = -501
//并发异常
RESULT_CODE_CONCURRENCY = -511
//远程微服务没有找到
RESULT_CODE_SERVICE_NOT_FOUND = -600
//远程微服务连接超时
RESULT_CODE_SERVICE_TIME_OUT = -610
//通用的异常
RESULT_CODE_UTIL_EXCEPTION = -700
)
```
## 二、返回规范
蓝眼云盘采用前后端分离的模式,前端调用后端接口时,url均以`/api`开头,返回均是json字符串。
- 返回的json字符串的key均为小写开头的驼峰法,具体参考实体类中`json`标签
- 返回的时间格式均为 `YYYY-MM-dd HH:mm:ss`(例如:2018-01-06 17:57:00)
返回内容均是由`WebResult`进行包装,因此具有高度的统一性,在这里我们约定一些说法,后面介绍`Controller`时便不再赘述。
1. 返回一个`XX`实体
指的是`WebResult`的`Code=200`, `Data=一个XX实体对象`。
例:返回一个User,则前端会收到以下json字符串:
```
{
"code": 200,
"msg": "",
"data": {
"uuid": "eed2c66d-1de6-47ff-645e-b67beaa10365",
"sort": 1514803034507,
"modifyTime": "2018-01-06 18:00:58",
"createTime": "2018-01-01 18:37:15",
"role": "USER",
"username": "demo",
"email": "demo@tank.eyeblue.cn",
"phone": "",
"gender": "UNKNOWN",
"city": "",
"avatarUrl": "/api/alien/download/ea490cb6-368e-436d-71c0-fcfb08854c80/1180472.png",
"lastIp": "124.78.220.82",
"lastTime": "2018-01-06 18:00:58",
"sizeLimit": 1048576,
"status": "OK"
}
}
```
2. 返回`XX`的`Pager`
指的是`WebResult`的`Code=200`, `Data=XX的Pager`。
例:返回`User`的`Pager`,则前端会收到以下json字符串:
```
{
"code": 200,
"msg": "",
"data": {
"page": 0,
"pageSize": 10,
"totalItems": 2,
"totalPages": 1,
"data": [
{
"uuid": "6a661938-8289-4957-4096-5a1b584bf371",
"sort": 1515057859613,
"modifyTime": "2018-01-04 17:26:01",
"createTime": "2018-01-04 17:24:20",
"role": "ADMINISTRATOR",
"username": "simba",
"email": "y******5@163.com",
"phone": "",
"gender": "MALE",
"city": "",
"avatarUrl": "/api/alien/download/d1e453cb-3170-4bdb-73f2-fa0372ee017b/1180480.png",
"lastIp": "180.173.103.207",
"lastTime": "2018-01-04 17:26:01",
"sizeLimit": -1,
"status": "OK"
},
{
"uuid": "e59be6a3-f806-463e-553a-4c5892eedf78",
"sort": 1514881002975,
"modifyTime": "2018-01-02 16:16:43",
"createTime": "2018-01-02 16:16:43",
"role": "USER",
"username": "blog_dev",
"email": "b*****@tank.eyeblue.cn",
"phone": "",
"gender": "MALE",
"city": "",
"avatarUrl": "/api/alien/download/fdca6eee-d009-4eb3-5ad4-15ba3701cb2e/jump.jpg",
"lastIp": "",
"lastTime": "2018-01-02 16:16:43",
"sizeLimit": 1048576,
"status": "OK"
}
]
}
}
```
3. 返回错误信息:yyy
指的是`WebResult`的`Code=-400`, `Msg=yyy`。(这里的Code具体值参考上文的code表)
例:返回错误信息:"【新建文件夹】已经存在了,请使用其他名称。",则前端会收到以下json字符串:
```
{
"code": -700,
"msg": "【新建文件夹】已经存在了,请使用其他名称。",
"data": null
}
```
4. 返回成功信息:zzz
指的是`WebResult`的`Code=200`, `Msg=zzz`。(这里的Code具体值参考上文的code表)
例:返回成功信息:"删除成功。",则前端会收到以下json字符串:
```
{
"code": 200,
"msg": "删除成功。",
"data": null
}
```
## 三、接口
蓝眼云盘所有的接口均定义在`controller`中,总共定义了以下`controller`:
名称 | 所在文件 | 描述
--------- | ---- | -----------
PreferenceController | `preference_controller.go` | 网站标题,logo,版权说明等信息的增删改查
MatterController | `matter_controller.go` | 站内创建文件夹,上传文件,删除文件,修改权限等
UserController | `user_controller.go` | 登录,管理操作站内用户
AlienController | `alien_controller.go` | 第三方授权上传,下载,预处理
每个接口都有不同的访问级别,系统中定义了三种访问级别,分别是:
`游客` < `注册用户` < `管理员`
### PreferenceController
该Controller负责网站中的偏好设置,主要操作`Preference`实体
----------
#### /api/preference/fetch
**功能**:读取网站偏好设置,网站名称,logo,版权,备案信息均从此接口读取。
**访问级别**:`游客`,`注册用户`,`管理员`
**请求参数**:无
**返回**: 一个`Preference`实体
----------
#### /api/preference/edit
**功能**:编辑网站偏好设置,修改网站名称,logo,版权,备案信息。
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
name | `string` | 必填 | 网站名称
logoUrl | `string` | 选填 | 网站logoUrl,如果不填默认使用蓝眼云盘logo
faviconUrl | `string` | 选填 | 网站faviconUrl,如果不填默认使用蓝眼云盘favicon.ico
footerLine1 | `string` | 选填 | 网站版权所有信息
footerLine2 | `string` | 选填 | 网站备案信息
**返回**: 一个`Preference`实体
----------
### MatterController
该Controller负责站内创建文件夹,上传文件,删除文件,修改权限等,主要操作`Matter`实体
----------
#### /api/matter/create/directory
**功能**:创建文件夹
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
puuid | `string` | 必填 | 准备创建的目录所在的目录,如果在根目录下创建传`root`
name | `string` | 必填 | 文件夹名称, 不能包含以下特殊符号:`< > \| * ? / \`
**返回**: 新建的这个文件夹的`Matter`实体
----------
#### /api/matter/upload
**功能**:上传文件
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
userUuid | `string` | 选填 | 该文件的归属人,如果不填则使用当前登录的用户uuid;如果是管理员要给用户A上传文件,那么这里应该填A的uuid.
alien | `bool` | 选填 | 是否是应用数据,true表示应用数据,这时会自动放置在`应用数据`这个文件夹下,比如上传头像。false表示非应用数据,这时`puuid`字段为必填
puuid | `bool` | 选填 | 文件上传到哪个目录下。 如果`alien`=false,这个字段必填。
privacy | `bool` | 选填 | 文件的私有性,默认`false`
file | `file` | 必填 | 文件,在浏览器中是通过`<input type="file" name="file"/>`来选择的
**返回**: 刚上传的这个文件的`Matter`实体
----------
#### /api/matter/delete
**功能**:删除文件或者文件夹
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 待删除的文件或文件夹的uuid
**返回**: 成功信息“删除成功”
----------
#### /api/matter/delete/batch
**功能**:批量删除文件或文件夹
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuids | `string` | 必填 | 待删除的文件或文件夹的uuids,用逗号(,)分隔。
**返回**: 成功信息“删除成功”
----------
#### /api/matter/rename
**功能**:重命名文件或文件夹
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 文件的uuid
name | `string` | 必填 | 新名字,不能包含以下特殊符号:`< > \| * ? / \`
**返回**: 刚重命名的这个文件的`Matter`实体
----------
#### /api/matter/change/privacy
**功能**:改变文件的公私有属性
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 文件的uuid
privacy | `bool` | 选填 | 文件的私有性,默认`false`
**返回**: 成功信息“设置成功”
----------
#### /api/matter/move
**功能**:将一个文件夹或者文件移入到另一个文件夹下。
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
srcUuids | `string` | 必填 | 待移动的文件或文件夹的uuids,用逗号(,)分隔。
destUuid | `string` | 必填 | 目标文件夹,根目录用`root`
**返回**: 成功信息“设置成功”
----------
#### /api/matter/detail
**功能**:产看文件详情
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 该文件的uuid。
destUuid | `string` | 必填 | 目标文件夹,根目录用`root`
**返回**: 这个文件的`Matter`实体
----------
#### /api/matter/page
**功能**:按照分页的方式获取某个文件夹下文件和子文件夹的列表
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
puuid | `string` | 选填 | 文件夹uuid,如果根目录填`root`
page | `int` | 选填 | 当前页数,0基,默认0
pageSize | `int` | 选填 | 每页条目数,默认200
userUuid | `string` | 选填 | 筛选文件拥有者,对于普通用户使用当前登录的用户uuid.
name | `string` | 选填 | 模糊筛选文件名
dir | `bool` | 选填 | 筛选是否为文件夹
orderDir | `DESC`或`ASC` | 选填 | 按文件夹排序,`DESC`降序排,`ASC`升序排
orderCreateTime | `DESC`或`ASC` | 选填 | 按创建时间排序,`DESC`降序排,`ASC`升序排
orderSize | `DESC`或`ASC` | 选填 | 按文件大小排序,`DESC`降序排,`ASC`升序排
orderName | `DESC`或`ASC` | 选填 | 按名称排序,`DESC`降序排,`ASC`升序排
extensions | `string` | 选填 | 按文件后缀名筛选,逗号(,)分隔。例:`jpg,png,pdf`
**返回**: `Matter`的`Pager`
----------
#### /api/alien/download/{uuid}/{filename}
这个接口的定义在在`AlienController`中的,具体使用请参考[蓝眼云盘编程接口](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md) 这里只做简单的下载使用。
**功能**:下载文件。
**访问级别**:`游客`,`注册用户`,`管理员`
**请求参数**: 均是放置在url中
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 要下载的文件uuid
filename | `string` | 必填 | 要下载的文件名
**返回**: 二进制的文件
----------
### UserController
该Controller负责站内创建文件夹,上传文件,删除文件,修改权限等,主要操作`Matter`实体
----------
#### /api/user/create
**功能**:创建用户
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
username | `string` | 必填 | 用户名,且只能包含字母,数字和'_'
password | `string` | 必填 | 密码,密码长度至少为6位
email | `string` | 必填 | 邮箱,作为用户登录的凭证
avatarUrl | `string` | 选填 | 头像
phone | `string` | 选填 | 电话
gender | `string` | 选填 | 性别
role | `string` | 选填 | 角色
city | `string` | 选填 | 城市
sizeLimit | `string` | 选填 | 用户上传单文件限制,单位byte. 如果负数表示无限制。
**返回**: 新建的`User`实体
----------
#### /api/user/edit
**功能**:编辑用户
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 待编辑的用户uuid
avatarUrl | `string` | 选填 | 头像
phone | `string` | 选填 | 电话
gender | `string` | 选填 | 性别
role | `string` | 选填 | 角色
city | `string` | 选填 | 城市
sizeLimit | `string` | 选填 | 用户上传单文件限制,单位byte. 如果负数表示无限制。
**返回**: 编辑的`User`实体
----------
#### /api/user/change/password
**功能**:用户修改密码
**访问级别**:`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
oldPassword | `string` | 必填 | 旧密码
newPassword | `string` | 必填 | 新密码
**返回**: 修改密码的`User`实体
----------
#### /api/user/change/password
**功能**:管理员重置用户密码
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
userUuid | `string` | 必填 | 待重置密码的用户uuid
password | `string` | 必填 | 密码
**返回**: 修改密码的`User`实体
----------
#### /api/user/login
**功能**:登录
**访问级别**:`游客`,`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
email | `string` | 必填 | 邮箱
password | `string` | 必填 | 密码
**返回**: 当前登录的`User`实体
----------
#### /api/user/logout
**功能**:登录
**访问级别**:`注册用户`,`管理员`
**请求参数**:无
**返回**: 成功信息"退出成功!"
----------
#### /api/user/detail
**功能**:查看用户详情
**访问级别**:`游客`,`注册用户`,`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 待查看的用户uuid
**返回**: `User`实体
----------
#### /api/user/page
**功能**:查看用户列表
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
page | `int` | 选填 | 当前页数,0基,默认0
pageSize | `int` | 选填 | 每页条目数,默认200
username | `string` | 选填 | 模糊筛选用户名
email | `string` | 选填 | 模糊筛选邮箱
phone | `string` | 选填 | 模糊筛选电话
orderLastTime | `DESC`或`ASC` | 选填 | 按上次登录时间排序,`DESC`降序排,`ASC`升序排
orderCreateTime | `DESC`或`ASC` | 选填 | 按创建时间排序,`DESC`降序排,`ASC`升序排
**返回**: `User`实体的`Pager`
----------
#### /api/user/disable
**功能**:禁用用户
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 待操作的用户
**返回**: 被操作的用户`User`实体
----------
#### /api/user/enable
**功能**:启用用户
**访问级别**:`管理员`
**请求参数**:
名称 | 类型 | 必填性 | 描述
--------- | ---- | ---- | -----------
uuid | `string` | 必填 | 待操作的用户
**返回**: 被操作的用户`User`实体
----------
### AlienController
这个Controller主要暴露给第三方使用,详情请参考:[蓝眼云盘编程接口](https://github.com/eyebluecn/tank/blob/master/build/doc/alien_zh.md)
-14
View File
@@ -1,14 +0,0 @@
# Package dependency
```
main
├── bin
├── pkg
├── src
│   ├── github.com
│   ├── golang.org
│   ├── tank
│   │   ├── build
│   │   │   ├── conf
│   │   │   ├── doc
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

+193
View File
@@ -0,0 +1,193 @@
CREATE TABLE `tank31_bridge` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`share_uuid` char(36) DEFAULT NULL,
`matter_uuid` char(36) DEFAULT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_dashboard` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`invoke_num` bigint(20) NOT NULL,
`total_invoke_num` bigint(20) NOT NULL DEFAULT '0',
`uv` bigint(20) NOT NULL DEFAULT '0',
`total_uv` bigint(20) NOT NULL DEFAULT '0',
`matter_num` bigint(20) NOT NULL DEFAULT '0',
`total_matter_num` bigint(20) NOT NULL DEFAULT '0',
`file_size` bigint(20) NOT NULL DEFAULT '0',
`total_file_size` bigint(20) NOT NULL DEFAULT '0',
`avg_cost` bigint(20) NOT NULL DEFAULT '0',
`dt` varchar(45) NOT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`),
KEY `idx_dt` (`dt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_download_token` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`user_uuid` char(36) NOT NULL,
`matter_uuid` char(36) NOT NULL,
`expire_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`ip` varchar(128) NOT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`),
KEY `idx_mu` (`matter_uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_footprint` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`user_uuid` char(36) DEFAULT NULL,
`ip` varchar(128) NOT NULL,
`host` varchar(45) NOT NULL,
`uri` varchar(255) NOT NULL,
`params` text,
`cost` bigint(20) NOT NULL DEFAULT '0',
`success` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_image_cache` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`name` varchar(255) NOT NULL,
`user_uuid` char(36) DEFAULT NULL,
`username` varchar(45) NOT NULL,
`matter_uuid` char(36) DEFAULT NULL,
`matter_name` varchar(255) NOT NULL,
`mode` varchar(512) DEFAULT NULL,
`md5` varchar(45) DEFAULT NULL,
`size` bigint(20) NOT NULL DEFAULT '0',
`path` varchar(512) DEFAULT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`),
KEY `idx_mu` (`matter_uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_matter` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`puuid` char(36) DEFAULT NULL,
`user_uuid` char(36) DEFAULT NULL,
`username` varchar(45) NOT NULL,
`dir` tinyint(1) NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`md5` varchar(45) DEFAULT NULL,
`size` bigint(20) NOT NULL DEFAULT '0',
`privacy` tinyint(1) NOT NULL DEFAULT '0',
`path` varchar(1024) DEFAULT NULL,
`times` bigint(20) NOT NULL DEFAULT '0',
`prop` varchar(1024) NOT NULL DEFAULT '{}',
`visit_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
`delete_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`),
KEY `idx_puuid` (`puuid`),
KEY `idx_uu` (`user_uuid`),
KEY `idx_del` (`deleted`),
KEY `idx_delt` (`delete_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_preference` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`name` varchar(45) DEFAULT NULL,
`logo_url` varchar(255) DEFAULT NULL,
`favicon_url` varchar(255) DEFAULT NULL,
`copyright` varchar(1024) DEFAULT NULL,
`record` varchar(1024) DEFAULT NULL,
`download_dir_max_size` bigint(20) NOT NULL DEFAULT '-1',
`download_dir_max_num` bigint(20) NOT NULL DEFAULT '-1',
`default_total_size_limit` bigint(20) NOT NULL DEFAULT '-1',
`allow_register` tinyint(1) NOT NULL DEFAULT '0',
`preview_config` text,
`scan_config` text,
`deleted_keep_days` bigint(20) NOT NULL DEFAULT '7',
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_session` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`user_uuid` char(36) DEFAULT NULL,
`ip` varchar(128) NOT NULL,
`expire_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_share` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`name` varchar(255) DEFAULT NULL,
`share_type` varchar(45) DEFAULT NULL,
`username` varchar(45) DEFAULT NULL,
`user_uuid` char(36) DEFAULT NULL,
`download_times` bigint(20) NOT NULL DEFAULT '0',
`code` varchar(45) NOT NULL,
`expire_infinity` tinyint(1) NOT NULL DEFAULT '0',
`expire_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_upload_token` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`user_uuid` char(36) NOT NULL,
`folder_uuid` char(36) NOT NULL,
`matter_uuid` char(36) NOT NULL,
`expire_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`filename` varchar(255) NOT NULL,
`privacy` tinyint(1) NOT NULL DEFAULT '0',
`size` bigint(20) NOT NULL DEFAULT '0',
`ip` varchar(128) NOT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tank31_user` (
`uuid` char(36) NOT NULL DEFAULT '',
`sort` bigint(20) NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`role` varchar(45) DEFAULT NULL,
`username` varchar(45) NOT NULL,
`password` varchar(255) DEFAULT NULL,
`avatar_url` varchar(255) DEFAULT NULL,
`last_ip` varchar(128) DEFAULT NULL,
`last_time` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00',
`size_limit` bigint(20) NOT NULL DEFAULT '-1',
`total_size_limit` bigint(20) NOT NULL DEFAULT '-1',
`total_size` bigint(20) NOT NULL DEFAULT '0',
`status` varchar(45) DEFAULT NULL,
PRIMARY KEY (`uuid`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-267
View File
@@ -1,267 +0,0 @@
#### PROPFIND 列出目录情况
request method
```
PROPFIND
```
request header
```
Authorization=Basic YWRtaW46YWRtaW4=
Content-Type=text/xml
Accept-Encoding=gzip
Depth=infinity
```
request body
```
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:resourcetype />
<D:getcontentlength />
<D:creationdate />
<D:getlastmodified />
</D:prop>
</D:propfind>
```
response body
```
<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/api/dav/</D:href>
<D:propstat>
<D:prop>
<D:displayname>dav</D:displayname>
<D:getlastmodified>Tue, 16 Apr 2019 17:50:59 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/api/</D:href>
<D:propstat>
<D:prop>
<D:displayname>api</D:displayname>
<D:getlastmodified>Tue, 16 Apr 2019 17:51:03 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/api/dav/</D:href>
<D:propstat>
<D:prop>
<D:displayname>dav</D:displayname>
<D:getlastmodified>Tue, 16 Apr 2019 17:51:38 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/api/dav/body.txt</D:href>
<D:propstat>
<D:prop>
<D:displayname>body.txt</D:displayname>
<D:getlastmodified>Tue, 16 Apr 2019 17:51:38 GMT</D:getlastmodified>
<D:getcontenttype>text/plain; charset=utf-8</D:getcontenttype>
<D:getetag>"159605ccc1d0f3c410"</D:getetag>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:resourcetype></D:resourcetype>
<D:getcontentlength>16</D:getcontentlength>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/api/dav/cat.txt</D:href>
<D:propstat>
<D:prop>
<D:resourcetype></D:resourcetype>
<D:getcontentlength>24</D:getcontentlength>
<D:getlastmodified>Tue, 16 Apr 2019 17:51:19 GMT</D:getlastmodified>
<D:getcontenttype>text/plain; charset=utf-8</D:getcontenttype>
<D:getetag>"159605c862b0d64c18"</D:getetag>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:displayname>cat.txt</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/cat/</D:href>
<D:propstat>
<D:prop>
<D:getlastmodified>Sat, 13 Apr 2019 16:55:54 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:displayname>cat</D:displayname>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/cat/dog/</D:href>
<D:propstat>
<D:prop>
<D:getlastmodified>Sat, 13 Apr 2019 16:55:58 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:displayname>dog</D:displayname>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/cat/dog/pig/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype>
<D:collection xmlns:D="DAV:"/>
</D:resourcetype>
<D:getlastmodified>Sat, 13 Apr 2019 16:56:08 GMT</D:getlastmodified>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:displayname>pig</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/cat/dog/pig/hi.txt</D:href>
<D:propstat>
<D:prop>
<D:getlastmodified>Sat, 13 Apr 2019 16:56:08 GMT</D:getlastmodified>
<D:getcontenttype>text/plain; charset=utf-8</D:getcontenttype>
<D:getetag>"15951707dc1116d87"</D:getetag>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:displayname>hi.txt</D:displayname>
<D:resourcetype></D:resourcetype>
<D:getcontentlength>7</D:getcontentlength>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/api/dav/morning.txt</D:href>
<D:propstat>
<D:prop>
<D:resourcetype></D:resourcetype>
<D:getcontentlength>13</D:getcontentlength>
<D:displayname>morning.txt</D:displayname>
<D:getlastmodified>Sat, 13 Apr 2019 16:52:08 GMT</D:getlastmodified>
<D:getcontenttype>text/plain; charset=utf-8</D:getcontenttype>
<D:getetag>"159516cfe790beecd"</D:getetag>
<D:supportedlock>
<D:lockentry xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
```
+27
View File
@@ -0,0 +1,27 @@
{
"files": {
"main.css": "/static/css/main.8f121d4f.css",
"main.js": "/static/js/main.e27b1761.js",
"static/media/logo.png": "/static/media/logo.847e54ef7fb4b744fad4.png",
"static/media/empty.svg": "/static/media/empty.087b383305fa7993cbf2fd9ccfd2cdaf.svg",
"static/media/psd.svg": "/static/media/psd.d0769f3468941f83b2cd1491e6ac7d69.svg",
"static/media/xls.svg": "/static/media/xls.7a882f471ff07b1015705abf4945d6a3.svg",
"static/media/ppt.svg": "/static/media/ppt.b987e0e201d3a6ebb0f83c5444521626.svg",
"static/media/doc.svg": "/static/media/doc.bc5d5331ff681915068a120f067a9dec.svg",
"static/media/pdf.svg": "/static/media/pdf.c92b8a844f37db16d4a72bf62a73138c.svg",
"static/media/video.svg": "/static/media/video.a1b07956cad84a3efc508d024286b30f.svg",
"static/media/file.svg": "/static/media/file.9f6f3fda1dd60a03fe595532e845852c.svg",
"static/media/text.svg": "/static/media/text.8aeb382b647dad745f0e9c2f11c349d2.svg",
"static/media/audio.svg": "/static/media/audio.0d111f7f828e8ea78c83b47d23e771a2.svg",
"static/media/image.svg": "/static/media/image.333c8c7c7df48b383c852de5ce99c33c.svg",
"static/media/folder.svg": "/static/media/folder.fce5913565dc18a92c7bbbe19ba6c4d0.svg",
"static/media/archive.svg": "/static/media/archive.982c48675c38139800a2f45d7c86a661.svg",
"index.html": "/index.html",
"main.8f121d4f.css.map": "/static/css/main.8f121d4f.css.map",
"main.e27b1761.js.map": "/static/js/main.e27b1761.js.map"
},
"entrypoints": [
"static/css/main.8f121d4f.css",
"static/js/main.e27b1761.js"
]
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 828 B

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

-1
View File
@@ -1 +0,0 @@
<svg width="264" height="88" viewBox="0 0 264 88" xmlns="http://www.w3.org/2000/svg"><title>default-skin 2</title><g fill="none" fill-rule="evenodd"><g><path d="M67.002 59.5v3.768c-6.307.84-9.184 5.75-10.002 9.732 2.22-2.83 5.564-5.098 10.002-5.098V71.5L73 65.585 67.002 59.5z" id="Shape" fill="#fff"/><g fill="#fff"><path d="M13 29v-5h2v3h3v2h-5zM13 15h5v2h-3v3h-2v-5zM31 15v5h-2v-3h-3v-2h5zM31 29h-5v-2h3v-3h2v5z" id="Shape"/></g><g fill="#fff"><path d="M62 24v5h-2v-3h-3v-2h5zM62 20h-5v-2h3v-3h2v5zM70 20v-5h2v3h3v2h-5zM70 24h5v2h-3v3h-2v-5z"/></g><path d="M20.586 66l-5.656-5.656 1.414-1.414L22 64.586l5.656-5.656 1.414 1.414L23.414 66l5.656 5.656-1.414 1.414L22 67.414l-5.656 5.656-1.414-1.414L20.586 66z" fill="#fff"/><path d="M111.785 65.03L110 63.5l3-3.5h-10v-2h10l-3-3.5 1.785-1.468L117 59l-5.215 6.03z" fill="#fff"/><path d="M152.215 65.03L154 63.5l-3-3.5h10v-2h-10l3-3.5-1.785-1.468L147 59l5.215 6.03z" fill="#fff"/><g><path id="Rectangle-11" fill="#fff" d="M160.957 28.543l-3.25-3.25-1.413 1.414 3.25 3.25z"/><path d="M152.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" id="Oval-1" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M150 21h5v1h-5z"/></g><g><path d="M116.957 28.543l-1.414 1.414-3.25-3.25 1.414-1.414 3.25 3.25z" fill="#fff"/><path d="M108.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M106 21h5v1h-5z"/><path fill="#fff" d="M109.043 19.008l-.085 5-1-.017.085-5z"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 1.4 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 943 B

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 1.0 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 2.5 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 3.2 KiB

-1
View File
@@ -1 +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="1544085034574" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1828" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M0 512A512 512 0 1 0 512 0 512 512 0 0 0 0 512" fill="#36D49F" p-id="1829"></path><path d="M450.37037 552.580741l-115.105185-87.798519-50.820741 39.822222L483.365926 701.62963C517.499259 616.296296 625.777778 449.232593 758.518519 330.714074L746.382222 303.407407a1264.071111 1264.071111 0 0 0-296.011852 249.173334" fill="#FFFFFF" p-id="1830"></path></svg>

Before

Width:  |  Height:  |  Size: 743 B

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-1
View File
@@ -1 +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" 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>

Before

Width:  |  Height:  |  Size: 2.5 KiB

+1 -1
View File
@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>EyeblueTank</title><link href=/css/app.b8a22cc6.css rel=preload as=style><link href=/css/chunk-vendors.cb22afd2.css rel=preload as=style><link href=/js/app.ec9d36fc.js rel=preload as=script><link href=/js/chunk-vendors.220ccae9.js rel=preload as=script><link href=/css/chunk-vendors.cb22afd2.css rel=stylesheet><link href=/css/app.b8a22cc6.css rel=stylesheet></head><body><noscript><strong>We're sorry but tank-front-tmp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.220ccae9.js></script><script src=/js/app.ec9d36fc.js></script></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><script defer="defer" src="/static/js/main.e27b1761.js"></script><link href="/static/css/main.8f121d4f.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run EyeblueTank.</noscript><div id="root"></div></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
@@ -0,0 +1,62 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/*! VelocityJS.org (1.5.2). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */
/*! 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
* scheduler.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
*
* 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-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
* react.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.
*/
//! moment.js
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
<?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>

After

Width:  |  Height:  |  Size: 855 B

@@ -0,0 +1,14 @@
<?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>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,12 @@
<?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>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,20 @@
<?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>

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,19 @@
<?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>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,10 @@
<?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>

After

Width:  |  Height:  |  Size: 949 B

@@ -0,0 +1,16 @@
<?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>

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,13 @@
<?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>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,18 @@
<?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>

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1,16 @@
<?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>

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -0,0 +1,10 @@
<?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>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,23 @@
<?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>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,17 @@
<?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>

After

Width:  |  Height:  |  Size: 2.6 KiB

+2 -2
View File
@@ -11,10 +11,10 @@
@REM prepare the variables.
@REM version name
SET VERSION_NAME=tank-3.0.3
SET VERSION_NAME=tank-4.1.2
ECHO VERSION_NAME: %VERSION_NAME%
@REM golang proxy
SET GOPROXY=https://athens.azurefd.net
SET GOPROXY=https://goproxy.cn
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
+5 -4
View File
@@ -1,4 +1,5 @@
#!/bin/bash
set -e
###########################################################################
#
@@ -9,10 +10,10 @@
#prepare the variables.
# version name
VERSION_NAME=tank-3.0.3
VERSION_NAME=tank-4.1.2
echo "VERSION_NAME: ${VERSION_NAME}"
# golang proxy
GOPROXY=https://athens.azurefd.net
GOPROXY=https://goproxy.cn
echo "GOPROXY: ${GOPROXY}"
# eg. amd64
GOARCH=$(go env GOARCH)
@@ -47,8 +48,8 @@ echo "DIST_PATH: ${DIST_PATH}"
cd ${PROJECT_DIR}
echo "go build -mod=readonly"
go build -mod=readonly
echo "go build"
go build
# if a directory
if [[ -d COMPONENT_DIR ]] ; then
+1 -1
View File
@@ -8,7 +8,7 @@ EXE_PATH=$TANK_DIR/tank
if [ -f "$EXE_PATH" ]; then
nohup $EXE_PATH >/dev/null 2>&1 &
echo 'Start tank successfully! http://127.0.0.1:6010'
echo 'Start tank successfully! Default value http://127.0.0.1:6010'
else
echo 'Cannot find $EXE_PATH.'
exit 1
+2 -2
View File
@@ -6,10 +6,10 @@ After=network.target
[Service]
Type=simple
DynamicUser=yes
#DynamicUser=yes
ExecStart=/data/program/tank/tank
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
+12 -4
View File
@@ -1,5 +1,7 @@
package core
import "gorm.io/gorm/schema"
const (
//authentication key of cookie
COOKIE_AUTH_KEY = "_ak"
@@ -9,19 +11,25 @@ const (
DEFAULT_SERVER_PORT = 6010
//db table's prefix. tank30_ means current version is tank:3.0.x
TABLE_PREFIX = "tank30_"
//db table's prefix. tank41_ means current version is tank:4.1.x
TABLE_PREFIX = "tank41_"
VERSION = "3.0.3"
VERSION = "4.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
//when installed by user. Write configs to tank.json
FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string)
FinishInstall(dbType string, 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"
"github.com/jinzhu/gorm"
"gorm.io/gorm"
"net/http"
)
+47 -30
View File
@@ -12,14 +12,16 @@ import (
type AlienController struct {
BaseController
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
matterDao *MatterDao
matterService *MatterService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
alienService *AlienService
shareService *ShareService
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
matterDao *MatterDao
spaceDao *SpaceDao
matterService *MatterService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
alienService *AlienService
shareService *ShareService
spaceMemberService *SpaceMemberService
}
func (this *AlienController) Init() {
@@ -40,6 +42,11 @@ 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
@@ -64,6 +71,11 @@ 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) {
@@ -80,7 +92,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
@@ -108,7 +120,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")
@@ -151,7 +163,8 @@ func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, reques
}
user := this.checkUser(request)
dirMatter := this.matterService.CreateDirectories(request, user, dirPath)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
dirMatter := this.matterService.CreateDirectories(request, user, space, dirPath)
uploadToken := &UploadToken{
UserUuid: user.Uuid,
@@ -170,7 +183,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")
@@ -188,7 +201,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)
@@ -216,6 +229,7 @@ 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)
@@ -228,9 +242,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, user)
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, space)
matter := this.matterService.Upload(request, file, user, dirMatter, uploadToken.Filename, uploadToken.Privacy)
matter := this.matterService.Upload(request, file, handler, user, space, dirMatter, uploadToken.Filename, uploadToken.Privacy)
//expire the upload token.
uploadToken.ExpireTime = time.Now()
@@ -239,7 +253,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.
@@ -263,10 +277,11 @@ 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, user)
dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, space)
matter := this.matterService.AtomicCrawl(request, url, uploadToken.Filename, user, dirMatter, uploadToken.Privacy)
matter := this.matterService.AtomicCrawl(request, url, uploadToken.Filename, user, space, dirMatter, uploadToken.Privacy)
//expire the upload token.
uploadToken.ExpireTime = time.Now()
@@ -275,7 +290,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")
@@ -291,14 +306,15 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht
}
user := this.checkUser(request)
dirMatter := this.matterService.CreateDirectories(request, user, dirPath)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
dirMatter := this.matterService.CreateDirectories(request, user, space, dirPath)
matter := this.matterService.AtomicCrawl(request, url, filename, user, dirMatter, privacy)
matter := this.matterService.AtomicCrawl(request, url, filename, user, space, 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")
@@ -311,8 +327,9 @@ func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, requ
user := this.checkUser(request)
matter := this.matterDao.CheckByUuid(matterUuid)
if matter.UserUuid != user.Uuid {
panic(result.BadRequest("matter not belong to you"))
canRead := this.spaceMemberService.canRead(user, matter.SpaceUuid)
if !canRead {
panic(result.BadRequest("no auth to visit this file."))
}
var expireTime time.Time
@@ -338,14 +355,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) {
this.alienService.PreviewOrDownload(writer, request, uuid, filename, false)
matter := this.alienService.ValidMatter(writer, request, uuid, filename)
this.alienService.PreviewOrDownload(writer, request, matter, false)
}
//download a file.
// download a file.
func (this *AlienController) Download(writer http.ResponseWriter, request *http.Request, uuid string, filename string) {
this.alienService.PreviewOrDownload(writer, request, uuid, filename, true)
matter := this.alienService.ValidMatter(writer, request, uuid, filename)
this.alienService.PreviewOrDownload(writer, request, matter, true)
}
+31 -15
View File
@@ -8,7 +8,7 @@ import (
"time"
)
//@Service
// @Service
type AlienService struct {
BaseBean
matterDao *MatterDao
@@ -19,6 +19,7 @@ type AlienService struct {
shareService *ShareService
imageCacheDao *ImageCacheDao
imageCacheService *ImageCacheService
spaceService *SpaceService
}
func (this *AlienService) Init() {
@@ -63,14 +64,18 @@ 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
}
}
func (this *AlienService) PreviewOrDownload(
// check whether the request params ok.
func (this *AlienService) ValidMatter(
writer http.ResponseWriter,
request *http.Request,
uuid string,
filename string,
withContentDisposition bool) {
filename string) *Matter {
matter := this.matterDao.CheckByUuid(uuid)
@@ -94,8 +99,10 @@ func (this *AlienService) PreviewOrDownload(
}
tokenUser := this.userDao.CheckByUuid(downloadToken.UserUuid)
if matter.UserUuid != tokenUser.Uuid {
panic(result.UNAUTHORIZED)
if matter.SpaceUuid != tokenUser.SpaceUuid {
//whether user has the space's read auth.
this.spaceService.CheckReadableByUuid(request, tokenUser, matter.SpaceUuid)
}
//TODO: expire the download token. If download by chunk, do this later.
@@ -104,18 +111,28 @@ func (this *AlienService) PreviewOrDownload(
} else {
//whether this is myself's matter.
operator := this.findUser(request)
if operator == nil {
panic(result.BadRequest("no auth"))
}
//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)
if matter.SpaceUuid != operator.SpaceUuid {
//whether user has the space's read auth.
this.spaceService.CheckReadableByUuid(request, operator, matter.SpaceUuid)
}
}
}
return matter
}
func (this *AlienService) PreviewOrDownload(
writer http.ResponseWriter,
request *http.Request,
matter *Matter,
withContentDisposition bool,
) {
//download directory
if matter.Dir {
@@ -135,7 +152,7 @@ func (this *AlienService) PreviewOrDownload(
}
//download the cache image file.
this.matterService.DownloadFile(writer, request, GetUserCacheRootDir(imageCache.Username)+imageCache.Path, imageCache.Name, withContentDisposition)
this.matterService.DownloadFile(writer, request, GetSpaceCacheRootDir(imageCache.Username)+imageCache.Path, imageCache.Name, withContentDisposition)
} else {
this.matterService.DownloadFile(writer, request, matter.AbsolutePath(), matter.Name, withContentDisposition)
@@ -145,7 +162,6 @@ func (this *AlienService) PreviewOrDownload(
//async increase the download times.
go core.RunWithRecovery(func() {
this.matterDao.TimesIncrement(uuid)
this.matterDao.TimesIncrement(matter.Uuid)
})
}
+61 -6
View File
@@ -13,8 +13,10 @@ import (
type BaseController struct {
BaseBean
userDao *UserDao
sessionDao *SessionDao
userDao *UserDao
spaceDao *SpaceDao
spaceService *SpaceService
sessionDao *SessionDao
}
func (this *BaseController) Init() {
@@ -26,6 +28,16 @@ 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
@@ -38,12 +50,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) {
@@ -87,7 +99,50 @@ func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *htt
}
}
//response a success result. 1.string 2. WebResult 3.nil pointer 4.any type
// 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
func (this *BaseController) Success(data interface{}) *result.WebResult {
var webResult *result.WebResult = nil
if value, ok := data.(string); ok {
@@ -106,7 +161,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)
}
+3 -19
View File
@@ -2,7 +2,6 @@ package rest
import (
"math"
"time"
)
const (
@@ -11,26 +10,11 @@ const (
DIRECTION_ASC = "ASC"
DIRECTION_DESC = "DESC"
EMPTY_JSON_MAP = "{}"
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"`
+12 -5
View File
@@ -4,9 +4,8 @@ import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/jinzhu/gorm"
"github.com/nu7hatch/gouuid"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/gorm"
"time"
)
@@ -59,7 +58,7 @@ func (this *BridgeDao) CheckByShareUuidAndMatterUuid(shareUuid string, matterUui
}
//get pager
func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray []builder.OrderPair) *Pager {
func (this *BridgeDao) PlainPage(page int, pageSize int, shareUuid string, sortArray []builder.OrderPair) (int, []*Bridge) {
var wp = &builder.WherePair{}
@@ -70,13 +69,21 @@ func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray
var conditionDB *gorm.DB
conditionDB = core.CONTEXT.GetDB().Model(&Bridge{}).Where(wp.Query, wp.Args...)
count := 0
var count int64 = 0
db := conditionDB.Count(&count)
this.PanicError(db.Error)
var bridges []*Bridge
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&bridges)
this.PanicError(db.Error)
return int(count), bridges
}
//get pager
func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray []builder.OrderPair) *Pager {
count, bridges := this.PlainPage(page, pageSize, shareUuid, sortArray)
pager := NewPager(page, pageSize, count, bridges)
return pager
+7 -10
View File
@@ -1,18 +1,15 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
)
import "time"
/**
* the link table for Share and Matter.
*/
type Bridge struct {
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"
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)"`
}
+7
View File
@@ -34,6 +34,7 @@ func (this *DashboardController) RegisterRoutes() map[string]func(writer http.Re
routeMap["/api/dashboard/page"] = this.Wrap(this.Page, USER_ROLE_ADMINISTRATOR)
routeMap["/api/dashboard/active/ip/top10"] = this.Wrap(this.ActiveIpTop10, USER_ROLE_ADMINISTRATOR)
routeMap["/api/dashboard/etl"] = this.Wrap(this.Etl, USER_ROLE_ADMINISTRATOR)
return routeMap
}
@@ -89,3 +90,9 @@ func (this *DashboardController) ActiveIpTop10(writer http.ResponseWriter, reque
list := this.dashboardDao.ActiveIpTop10()
return this.Success(list)
}
func (this *DashboardController) Etl(writer http.ResponseWriter, request *http.Request) *result.WebResult {
this.dashboardService.Etl()
return this.Success("OK")
}
+4 -4
View File
@@ -3,8 +3,8 @@ package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/builder"
"github.com/jinzhu/gorm"
"github.com/nu7hatch/gouuid"
"github.com/eyebluecn/tank/code/tool/uuid"
"gorm.io/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...)
count := 0
var count int64 = 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, count, dashboards)
pager := NewPager(page, pageSize, int(count), dashboards)
return pager
}
+15 -17
View File
@@ -1,27 +1,25 @@
package rest
import "github.com/eyebluecn/tank/code/core"
import "time"
/**
* application's dashboard.
*/
type Dashboard struct {
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"
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_dashboard_dt"` //date. index should unique globally for sqlite.
}
/**
+16 -18
View File
@@ -3,7 +3,6 @@ package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/robfig/cron"
"time"
)
@@ -49,25 +48,24 @@ func (this *DashboardService) Init() {
func (this *DashboardService) Bootstrap() {
this.logger.Info("[cron job] Everyday 00:05 ETL dashboard data.")
expression := "0 5 0 * * ?"
cronJob := cron.New()
err := cronJob.AddFunc(expression, this.etl)
core.PanicError(err)
cronJob.Start()
this.logger.Info("Immediately ETL dashboard data.")
//do the etl method now.
go core.RunWithRecovery(this.etl)
go core.RunWithRecovery(this.Etl)
}
func (this *DashboardService) Etl() {
this.etlOneDay(util.Yesterday())
this.etlOneDay(time.Now())
}
// handle the dashboard data.
func (this *DashboardService) etl() {
func (this *DashboardService) etlOneDay(thenTime time.Time) {
this.logger.Info("ETL dashboard data.")
startTime := util.FirstSecondOfDay(util.Yesterday())
endTime := util.LastSecondOfDay(util.Yesterday())
startTime := util.FirstSecondOfDay(thenTime)
endTime := util.LastSecondOfDay(thenTime)
dt := util.ConvertTimeToDateString(startTime)
now := time.Now()
longTimeAgo := time.Now()
longTimeAgo = longTimeAgo.AddDate(-20, 0, 0)
@@ -81,19 +79,19 @@ func (this *DashboardService) etl() {
}
invokeNum := this.footprintDao.CountBetweenTime(startTime, endTime)
totalInvokeNum := this.footprintDao.CountBetweenTime(longTimeAgo, endTime)
totalInvokeNum := this.footprintDao.CountBetweenTime(longTimeAgo, now)
uv := this.footprintDao.UvBetweenTime(startTime, endTime)
totalUv := this.footprintDao.UvBetweenTime(longTimeAgo, endTime)
totalUv := this.footprintDao.UvBetweenTime(longTimeAgo, now)
matterNum := this.matterDao.CountBetweenTime(startTime, endTime)
totalMatterNum := this.matterDao.CountBetweenTime(longTimeAgo, endTime)
totalMatterNum := this.matterDao.CountBetweenTime(longTimeAgo, now)
matterSize := this.matterDao.SizeBetweenTime(startTime, endTime)
totalMatterSize := this.matterDao.SizeBetweenTime(longTimeAgo, endTime)
totalMatterSize := this.matterDao.SizeBetweenTime(longTimeAgo, now)
cacheSize := this.imageCacheDao.SizeBetweenTime(startTime, endTime)
totalCacheSize := this.imageCacheDao.SizeBetweenTime(longTimeAgo, endTime)
totalCacheSize := this.imageCacheDao.SizeBetweenTime(longTimeAgo, now)
avgCost := this.footprintDao.AvgCostBetweenTime(startTime, endTime)
+19 -5
View File
@@ -18,13 +18,14 @@ import (
* WebDav document
* https://tools.ietf.org/html/rfc4918
* http://www.webdav.org/specs/rfc4918.html
*
* test machine: http://www.webdav.org/neon/litmus/
*/
type DavController struct {
BaseController
uploadTokenDao *UploadTokenDao
downloadTokenDao *DownloadTokenDao
spaceDao *SpaceDao
matterDao *MatterDao
matterService *MatterService
imageCacheDao *ImageCacheDao
@@ -50,6 +51,11 @@ 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
@@ -71,7 +77,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()
@@ -100,7 +106,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
@@ -111,10 +117,16 @@ 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
}
@@ -145,7 +157,7 @@ func (this *DavController) debug(writer http.ResponseWriter, request *http.Reque
bodyBytes, err := ioutil.ReadAll(request.Body)
if err != nil {
fmt.Println("读取body时出错" + err.Error())
fmt.Println("occur error when reading body: " + err.Error())
}
fmt.Println(string(bodyBytes))
@@ -162,10 +174,12 @@ func (this *DavController) debug(writer http.ResponseWriter, request *http.Reque
func (this *DavController) Index(writer http.ResponseWriter, request *http.Request, subPath string) {
//when debugging. open it.
//this.debug(writer, request, subPath)
user := this.CheckCurrentUser(writer, request)
space := this.spaceDao.CheckByUuid(user.SpaceUuid)
this.davService.HandleDav(writer, request, user, subPath)
this.davService.HandleDav(writer, request, user, space, 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(user *User, matter *Matter) string
findFn func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, matter *Matter) string {
return strconv.FormatInt(matter.Size, 10)
},
dir: false,
},
{Space: "DAV:", Local: "getlastmodified"}: {
findFn: func(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, 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(user *User, matter *Matter) string {
findFn: func(space *Space, matter *Matter) string {
var size int64 = 0
if user.TotalSizeLimit >= 0 {
if user.TotalSizeLimit-user.TotalSize > 0 {
size = user.TotalSizeLimit - user.TotalSize
if space.TotalSizeLimit >= 0 {
if space.TotalSizeLimit-space.TotalSize > 0 {
size = space.TotalSizeLimit - space.TotalSize
} else {
size = 0
}
@@ -118,8 +118,8 @@ var LivePropMap = map[xml.Name]LiveProp{
dir: true,
},
{Space: "DAV:", Local: "quota-used-bytes"}: {
findFn: func(user *User, matter *Matter) string {
return fmt.Sprintf(`%d`, user.TotalSize)
findFn: func(space *Space, matter *Matter) string {
return fmt.Sprintf(`%d`, space.TotalSize)
},
dir: true,
},
+475 -72
View File
@@ -7,11 +7,14 @@ import (
"github.com/eyebluecn/tank/code/tool/dav/xml"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/eyebluecn/tank/code/tool/util"
"github.com/eyebluecn/tank/code/tool/webdav"
"io/ioutil"
"net/http"
"net/url"
"path"
"regexp"
"strings"
"time"
)
/**
@@ -26,6 +29,7 @@ type DavService struct {
BaseBean
matterDao *MatterDao
matterService *MatterService
lockSystem webdav.LockSystem
}
func (this *DavService) Init() {
@@ -41,9 +45,11 @@ func (this *DavService) Init() {
this.matterService = b
}
// init the webdav lock system.
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
@@ -82,36 +88,63 @@ func (this *DavService) makePropstatResponse(href string, pstats []dav.Propstat)
return &resp
}
//fetch a matter's []dav.Propstat
func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNames []xml.Name) []dav.Propstat {
// fetch a matter's []dav.Propstat
func (this *DavService) PropstatsFromXmlNames(user *User, space *Space, matter *Matter, xmlNames []xml.Name) []dav.Propstat {
propstats := make([]dav.Propstat, 0)
var properties []dav.Property
var okProperties []dav.Property
var notFoundProperties []dav.Property
for _, xmlName := range xmlNames {
//TODO: deadprops not implement yet.
// 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(user, matter)
innerXML := liveProp.findFn(space, matter)
properties = append(properties, dav.Property{
okProperties = append(okProperties, dav.Property{
XMLName: xmlName,
InnerXML: []byte(innerXML),
})
} else {
this.logger.Info("%s %s cannot finish.", matter.Path, xmlName.Local)
this.logger.Info("handle props %s %s.", matter.Path, xmlName.Local)
propMap := matter.FetchPropMap()
if value, isPresent := propMap[xmlName.Local]; isPresent {
okProperties = append(okProperties, dav.Property{
XMLName: xmlName,
InnerXML: []byte(value),
})
} else {
//only accept Space not null.
if xmlName.Space != "" {
//collect not found props
notFoundProperties = append(notFoundProperties, dav.Property{
XMLName: xmlName,
InnerXML: []byte(""),
})
}
}
}
}
if len(properties) == 0 {
if len(okProperties) == 0 && len(notFoundProperties) == 0 {
panic(result.BadRequest("cannot parse request properties"))
}
okPropstat := dav.Propstat{Status: http.StatusOK, Props: properties}
if len(okProperties) != 0 {
okPropstat := dav.Propstat{Status: http.StatusOK, Props: okProperties}
propstats = append(propstats, okPropstat)
}
propstats = append(propstats, okPropstat)
if len(notFoundProperties) != 0 {
notFoundPropstat := dav.Propstat{Status: http.StatusNotFound, Props: notFoundProperties}
propstats = append(propstats, notFoundPropstat)
}
return propstats
@@ -129,7 +162,7 @@ func (this *DavService) AllPropXmlNames(matter *Matter) []xml.Name {
return pnames
}
func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Propfind) []dav.Propstat {
func (this *DavService) Propstats(user *User, space *Space, matter *Matter, propfind *dav.Propfind) []dav.Propstat {
propstats := make([]dav.Propstat, 0)
if propfind.Propname != nil {
@@ -139,34 +172,35 @@ func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Prop
//TODO: if include other things. add to it.
xmlNames := this.AllPropXmlNames(matter)
propstats = this.PropstatsFromXmlNames(user, matter, xmlNames)
propstats = this.PropstatsFromXmlNames(user, space, matter, xmlNames)
} else {
propstats = this.PropstatsFromXmlNames(user, matter, propfind.Prop)
propstats = this.PropstatsFromXmlNames(user, space, matter, propfind.Prop)
}
return propstats
}
//list the directory.
func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// list the directory.
func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("PROPFIND %s\n", subPath)
// read depth
depth := this.ParseDepth(request)
propfind := dav.ReadPropfind(request.Body)
//find the matter, if subPath is null, means the root directory.
matter := this.matterDao.CheckWithRootByPath(subPath, user)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
var matters []*Matter
if depth == 0 {
matters = []*Matter{matter}
} else {
// len(matters) == 0 means empty directory
matters = this.matterDao.FindByPuuidAndUserUuid(matter.Uuid, user.Uuid, nil)
matters = this.matterDao.FindByPuuidAndUserUuidAndDeleted(matter.Uuid, user.Uuid, FALSE, nil)
//add this matter to head.
matters = append([]*Matter{matter}, matters...)
@@ -179,7 +213,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
fmt.Printf("handle Matter %s\n", matter.Path)
propstats := this.Propstats(user, matter, propfind)
propstats := this.Propstats(user, space, matter, propfind)
visitPath := fmt.Sprintf("%s%s", WEBDAV_PREFIX, matter.Path)
response := this.makePropstatResponse(visitPath, propstats)
@@ -194,16 +228,84 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
}
//handle download
func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// 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)
// handle the lock feature.
reqPath, status, err := this.stripPrefix(request.URL.Path)
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
release, status, err := this.confirmLocks(request, reqPath, "")
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
if release != nil {
defer release()
}
matter := this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath)
patches, status, err := webdav.ReadProppatch(request.Body)
this.PanicError(err)
fmt.Printf("status:%v\n", status)
//prepare a multiStatusWriter.
multiStatusWriter := &dav.MultiStatusWriter{Writer: writer}
propstats := make([]dav.Propstat, 0)
propMap := matter.FetchPropMap()
for _, patch := range patches {
propStat := dav.Propstat{Status: http.StatusOK}
if patch.Remove {
if len(patch.Props) > 0 {
property := patch.Props[0]
if _, isPresent := propMap[property.XMLName.Local]; isPresent {
//delete the prop.
delete(propMap, property.XMLName.Local)
}
}
} else {
for _, prop := range patch.Props {
propMap[prop.XMLName.Local] = string(prop.InnerXML)
propStat.Props = append(propStat.Props, dav.Property{XMLName: xml.Name{Space: prop.XMLName.Space, Local: prop.XMLName.Local}})
}
}
propstats = append(propstats, propStat)
}
matter.SetPropMap(propMap)
// update the matter
this.matterDao.Save(matter)
visitPath := fmt.Sprintf("%s%s", WEBDAV_PREFIX, matter.Path)
response := this.makePropstatResponse(visitPath, propstats)
err1 := multiStatusWriter.Write(response)
this.PanicError(err1)
err2 := multiStatusWriter.Close()
this.PanicError(err2)
}
// handle download
func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("GET %s\n", subPath)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
//if this is a Directory, it means Propfind
if matter.Dir {
this.HandlePropfind(writer, request, user, subPath)
this.HandlePropfind(writer, request, user, space, subPath)
return
}
@@ -212,56 +314,115 @@ func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *h
}
//upload a file
func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// upload a file
func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("PUT %s\n", subPath)
// handle the lock feature.
reqPath, status, err := this.stripPrefix(request.URL.Path)
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
release, status, err := this.confirmLocks(request, reqPath, "")
if err != nil {
//if status == http.StatusLocked {
// status = http.StatusPreconditionFailed
//}
panic(result.StatusCodeWebResult(status, err.Error()))
}
if release != nil {
defer release()
}
filename := util.GetFilenameOfPath(subPath)
dirPath := util.GetDirOfPath(subPath)
dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user)
dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user, space)
//if exist delete it.
srcMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, subPath)
if srcMatter != nil {
this.matterService.AtomicDelete(request, srcMatter, user)
this.matterService.AtomicDelete(request, srcMatter, user, space)
}
this.matterService.Upload(request, request.Body, user, dirMatter, filename, true)
this.matterService.Upload(request, request.Body, nil, user, space, dirMatter, filename, true)
//set the status code 201
writer.WriteHeader(http.StatusCreated)
}
//delete file
func (this *DavService) HandleDelete(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// delete file
func (this *DavService) HandleDelete(w http.ResponseWriter, r *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("DELETE %s\n", subPath)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
reqPath, status, err := this.stripPrefix(r.URL.Path)
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
release, status, err := this.confirmLocks(r, reqPath, "")
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
if release != nil {
defer release()
}
this.matterService.AtomicDelete(request, matter, user)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
this.matterService.AtomicDelete(r, matter, user, space)
}
//crate a directory
func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// crate a directory
func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("MKCOL %s\n", subPath)
//the body of MKCOL request MUST be empty. (RFC2518:8.3.1)
bodyBytes, err := ioutil.ReadAll(request.Body)
if err != nil {
fmt.Println("occur error when reading body: " + err.Error())
} else {
if len(bodyBytes) != 0 {
//throw conflict error
panic(result.CustomWebResult(result.UNSUPPORTED_MEDIA_TYPE, fmt.Sprintf("%s MKCOL should NO body", subPath)))
}
}
thisDirName := util.GetFilenameOfPath(subPath)
dirPath := util.GetDirOfPath(subPath)
dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user)
dirMatter := this.matterDao.FindWithRootByPath(dirPath, user, space)
if dirMatter == nil {
//throw conflict error
panic(result.CustomWebResult(result.CONFLICT, fmt.Sprintf("%s not exist", dirPath)))
}
this.matterService.AtomicCreateDirectory(request, dirMatter, thisDirName, user)
//check whether col exists. (RFC2518:8.3.1)
dbMatter := this.matterDao.FindBySpaceNameAndPuuidAndDirAndName(space.Name, 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)
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)
}
//cors options
func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
// cors options
func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("OPTIONS %s\n", subPath)
matter := this.matterDao.CheckWithRootByPath(subPath, user)
matter := this.matterDao.CheckWithRootByPath(subPath, user, space)
allow := "OPTIONS, LOCK, PUT, MKCOL"
if matter.Dir {
@@ -278,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, subPath string) (
user *User, space *Space, subPath string) (
srcMatter *Matter,
destDirMatter *Matter,
srcDirPath string,
@@ -345,106 +506,348 @@ func (this *DavService) prepareMoveCopy(
}
//source matter
srcMatter = this.matterDao.CheckWithRootByPath(subPath, user)
srcMatter = this.matterDao.CheckWithRootByPath(subPath, user, space)
//if source matter is root.
if srcMatter.Uuid == MATTER_ROOT {
panic(result.BadRequest("you cannot move the root directory"))
}
destDirMatter = this.matterDao.CheckWithRootByPath(destinationDirPath, user)
destDirMatter = this.matterDao.FindWithRootByPath(destinationDirPath, user, space)
if destDirMatter == nil {
//throw conflict error
panic(result.CustomWebResult(result.CONFLICT, fmt.Sprintf("%s not exist", destinationDirPath)))
}
return srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite
}
//move or rename.
func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// move or rename.
func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("MOVE %s\n", subPath)
srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath)
// handle the lock feature.
reqPath, status, err := this.stripPrefix(request.URL.Path)
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
release, status, err := this.confirmLocks(request, reqPath, "")
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
if release != nil {
defer release()
}
srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, space, subPath)
//move to the new directory
if destinationDirPath == srcDirPath {
//if destination path not change. it means rename.
this.matterService.AtomicRename(request, srcMatter, destinationName, user)
this.matterService.AtomicRename(request, srcMatter, destinationName, overwrite, user, space)
} else {
this.matterService.AtomicMove(request, srcMatter, destDirMatter, overwrite, user)
this.matterService.AtomicMove(request, srcMatter, destDirMatter, overwrite, user, space)
}
this.logger.Info("finish moving %s => %s", subPath, destDirMatter.Path)
if overwrite {
//overwrite old. set the status code 204
writer.WriteHeader(http.StatusNoContent)
} else {
//copy new. set the status code 201
writer.WriteHeader(http.StatusCreated)
}
}
//copy file/directory
func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// copy file/directory
func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
fmt.Printf("COPY %s\n", subPath)
srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath)
srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, space, subPath)
// handle the lock feature.
release, status, err := this.confirmLocks(request, destDirMatter.Path+"/"+destinationName, "")
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
if release != nil {
defer release()
}
//copy to the new directory
this.matterService.AtomicCopy(request, srcMatter, destDirMatter, destinationName, overwrite, user)
this.matterService.AtomicCopy(request, srcMatter, destDirMatter, destinationName, overwrite, user, space)
this.logger.Info("finish copying %s => %s", subPath, destDirMatter.Path)
if overwrite {
//overwrite old. set the status code 204
writer.WriteHeader(http.StatusNoContent)
} else {
//copy new. set the status code 201
writer.WriteHeader(http.StatusCreated)
}
}
//lock.
func (this *DavService) HandleLock(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
panic(result.BadRequest("not support LOCK yet."))
func (h *DavService) stripPrefix(p string) (string, int, error) {
if r := strings.TrimPrefix(p, WEBDAV_PREFIX); len(r) < len(p) {
return r, http.StatusOK, nil
}
return p, http.StatusNotFound, webdav.ErrPrefixMismatch
}
//unlock
func (this *DavService) HandleUnlock(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
panic(result.BadRequest("not support UNLOCK yet."))
func (h *DavService) lock(now time.Time, root string) (token string, status int, err error) {
token, err = h.lockSystem.Create(now, webdav.LockDetails{
Root: root,
Duration: webdav.InfiniteTimeout,
ZeroDepth: true,
})
if err != nil {
if err == webdav.ErrLocked {
return "", webdav.StatusLocked, err
}
return "", http.StatusInternalServerError, err
}
return token, 0, nil
}
//change the file's property
func (this *DavService) HandleProppatch(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
func (h *DavService) confirmLocks(r *http.Request, src, dst string) (release func(), status int, err error) {
hdr := r.Header.Get("If")
if hdr == "" {
// An empty If header means that the client hasn't previously created locks.
// Even if this client doesn't care about locks, we still need to check that
// the resources aren't locked by another client, so we create temporary
// locks that would conflict with another client's locks. These temporary
// locks are unlocked at the end of the HTTP request.
now, srcToken, dstToken := time.Now(), "", ""
if src != "" {
srcToken, status, err = h.lock(now, src)
if err != nil {
return nil, status, err
}
}
if dst != "" {
dstToken, status, err = h.lock(now, dst)
if err != nil {
if srcToken != "" {
h.lockSystem.Unlock(now, srcToken)
}
return nil, status, err
}
}
panic(result.BadRequest("not support PROPPATCH yet."))
return func() {
if dstToken != "" {
h.lockSystem.Unlock(now, dstToken)
}
if srcToken != "" {
h.lockSystem.Unlock(now, srcToken)
}
}, 0, nil
}
ih, ok := webdav.ParseIfHeader(hdr)
if !ok {
return nil, http.StatusBadRequest, webdav.ErrInvalidIfHeader
}
// ih is a disjunction (OR) of ifLists, so any IfList will do.
for _, l := range ih.Lists {
lsrc := l.ResourceTag
if lsrc == "" {
lsrc = src
} else {
u, err := url.Parse(lsrc)
if err != nil {
continue
}
if u.Host != r.Host {
continue
}
lsrc, status, err = h.stripPrefix(u.Path)
if err != nil {
return nil, status, err
}
}
release, err = h.lockSystem.Confirm(time.Now(), lsrc, dst, l.Conditions...)
if err == webdav.ErrConfirmationFailed {
continue
}
if err != nil {
return nil, http.StatusInternalServerError, err
}
return release, 0, nil
}
// Section 10.4.1 says that "If this header is evaluated and all state lists
// fail, then the request must fail with a 412 (Precondition Failed) status."
// We follow the spec even though the cond_put_corrupt_token test case from
// the litmus test warns on seeing a 412 instead of a 423 (Locked).
return nil, http.StatusLocked, webdav.ErrLocked
}
//hanle all the request.
func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
// lock.
func (this *DavService) HandleLock(w http.ResponseWriter, r *http.Request, user *User, subPath string) {
duration, err := webdav.ParseTimeout(r.Header.Get("Timeout"))
if err != nil {
panic(result.BadRequest(err.Error()))
}
li, status, err := webdav.ReadLockInfo(r.Body)
if err != nil {
panic(result.BadRequest(fmt.Sprintf("error:%s, status=%d", err.Error(), status)))
}
token, ld, now, created := "", webdav.LockDetails{}, time.Now(), false
if li == (webdav.LockInfo{}) {
// An empty LockInfo means to refresh the lock.
ih, ok := webdav.ParseIfHeader(r.Header.Get("If"))
if !ok {
panic(result.BadRequest(webdav.ErrInvalidIfHeader.Error()))
}
if len(ih.Lists) == 1 && len(ih.Lists[0].Conditions) == 1 {
token = ih.Lists[0].Conditions[0].Token
}
if token == "" {
panic(result.BadRequest(webdav.ErrInvalidLockToken.Error()))
}
ld, err = this.lockSystem.Refresh(now, token, duration)
if err != nil {
if err == webdav.ErrNoSuchLock {
panic(result.StatusCodeWebResult(http.StatusPreconditionFailed, err.Error()))
}
panic(result.StatusCodeWebResult(http.StatusInternalServerError, err.Error()))
}
} else {
// Section 9.10.3 says that "If no Depth header is submitted on a LOCK request,
// then the request MUST act as if a "Depth:infinity" had been submitted."
depth := webdav.InfiniteDepth
if hdr := r.Header.Get("Depth"); hdr != "" {
depth = webdav.ParseDepth(hdr)
if depth != 0 && depth != webdav.InfiniteDepth {
// Section 9.10.3 says that "Values other than 0 or infinity must not be
// used with the Depth header on a LOCK method".
panic(result.StatusCodeWebResult(http.StatusBadRequest, webdav.ErrInvalidDepth.Error()))
}
}
reqPath, status, err := this.stripPrefix(r.URL.Path)
if err != nil {
panic(result.StatusCodeWebResult(status, err.Error()))
}
ld = webdav.LockDetails{
Root: reqPath,
Duration: duration,
OwnerXML: li.Owner.InnerXML,
ZeroDepth: depth == 0,
}
token, err = this.lockSystem.Create(now, ld)
if err != nil {
if err == webdav.ErrLocked {
panic(result.StatusCodeWebResult(http.StatusLocked, err.Error()))
}
panic(result.StatusCodeWebResult(http.StatusInternalServerError, err.Error()))
}
defer func() {
//when error occur, rollback.
//this.lockSystem.Unlock(now, token)
}()
// Create the resource if it didn't previously exist.
// ctx := r.Context()
//if _, err := this.FileSystem.Stat(ctx, subPath); err != nil {
// f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
// if err != nil {
// // TODO: detect missing intermediate dirs and return http.StatusConflict?
// return http.StatusInternalServerError, err
// }
// f.Close()
// created = true
//}
// http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the
// Lock-Token value is a Coded-URL. We add angle brackets.
w.Header().Set("Lock-Token", "<"+token+">")
}
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
if created {
// This is "w.WriteHeader(http.StatusCreated)" and not "return
// http.StatusCreated, nil" because we write our own (XML) response to w
// and Handler.ServeHTTP would otherwise write "Created".
w.WriteHeader(http.StatusCreated)
}
_, _ = webdav.WriteLockInfo(w, token, ld)
}
// 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
// Lock-Token value is a Coded-URL. We strip its angle brackets.
t := r.Header.Get("Lock-Token")
if len(t) < 2 || t[0] != '<' || t[len(t)-1] != '>' {
panic(result.StatusCodeWebResult(http.StatusBadRequest, webdav.ErrInvalidLockToken.Error()))
}
t = t[1 : len(t)-1]
switch err := this.lockSystem.Unlock(time.Now(), t); err {
case nil:
panic(result.StatusCodeWebResult(http.StatusNoContent, ""))
case webdav.ErrForbidden:
panic(result.StatusCodeWebResult(http.StatusForbidden, err.Error()))
case webdav.ErrLocked:
panic(result.StatusCodeWebResult(http.StatusLocked, err.Error()))
case webdav.ErrNoSuchLock:
panic(result.StatusCodeWebResult(http.StatusConflict, err.Error()))
default:
panic(result.StatusCodeWebResult(http.StatusInternalServerError, err.Error()))
}
}
// hanle all the request.
func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Request, user *User, space *Space, subPath string) {
method := request.Method
if method == "OPTIONS" {
//cors option
this.HandleOptions(writer, request, user, subPath)
this.HandleOptions(writer, request, user, space, subPath)
} else if method == "GET" || method == "HEAD" || method == "POST" {
//get the detail of file. download
this.HandleGetHeadPost(writer, request, user, subPath)
this.HandleGetHeadPost(writer, request, user, space, subPath)
} else if method == "DELETE" {
//delete file
this.HandleDelete(writer, request, user, subPath)
this.HandleDelete(writer, request, user, space, subPath)
} else if method == "PUT" {
//upload file
this.HandlePut(writer, request, user, subPath)
this.HandlePut(writer, request, user, space, subPath)
} else if method == "MKCOL" {
//crate directory
this.HandleMkcol(writer, request, user, subPath)
this.HandleMkcol(writer, request, user, space, subPath)
} else if method == "COPY" {
//copy file/directory
this.HandleCopy(writer, request, user, subPath)
this.HandleCopy(writer, request, user, space, subPath)
} else if method == "MOVE" {
//move/rename a file or directory
this.HandleMove(writer, request, user, subPath)
this.HandleMove(writer, request, user, space, subPath)
} else if method == "LOCK" {
@@ -459,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, subPath)
this.HandlePropfind(writer, request, user, space, subPath)
} else if method == "PROPPATCH" {
+8 -1
View File
@@ -3,7 +3,7 @@ package rest
import (
"github.com/eyebluecn/tank/code/core"
"github.com/eyebluecn/tank/code/tool/result"
"github.com/nu7hatch/gouuid"
"github.com/eyebluecn/tank/code/tool/uuid"
"time"
)
@@ -58,6 +58,13 @@ func (this *DownloadTokenDao) Save(downloadToken *DownloadToken) *DownloadToken
return downloadToken
}
func (this *DownloadTokenDao) DeleteByUserUuid(userUuid string) {
db := core.CONTEXT.GetDB().Where("user_uuid = ?", userUuid).Delete(DownloadToken{})
this.PanicError(db.Error)
}
func (this *DownloadTokenDao) Cleanup() {
this.logger.Info("[DownloadTokenDao] clean up. Delete all DownloadToken")
db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(DownloadToken{})
+5 -7
View File
@@ -1,18 +1,16 @@
package rest
import (
"github.com/eyebluecn/tank/code/core"
"time"
)
type DownloadToken struct {
Base
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) not null"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null;index:idx_mu"`
MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null;index:idx_download_token_mu"` //index should unique globally for sqlite
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"
}

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