Compare commits

...

236 Commits

Author SHA1 Message Date
lealife
340df9ce16 release 2.6.1 for bind all ip 2018-03-08 11:21:05 +08:00
lealife
eaa15d2905 listen on all ip addresses 2018-03-08 10:49:55 +08:00
lealife
29413c0e52 debug 2017-12-01 10:52:48 +08:00
lealife
347e79610e add vendor agtorre/gocolorize 2017-12-01 10:52:41 +08:00
lealife
c084792d32 prepare to release 2.6 2017-12-01 10:25:24 +08:00
lealife
d77e636e53 remove unused 2017-12-01 10:25:08 +08:00
lealife
4729252c63 vendor 2017-11-30 20:18:21 +08:00
lealife
6cbb82a927 cmd 2017-11-30 20:15:28 +08:00
lealife
bba9030f14 cmd 2017-11-30 20:11:10 +08:00
lealife
7cf6dbbe38 remove 2017-11-30 19:57:47 +08:00
lealife
00993e7fe1 Merge branch 'go-vendor-v2' 2017-11-30 19:55:54 +08:00
lealife
0fb92efbf3 go vendor 2017-11-30 19:55:33 +08:00
lealife
2856da6888 update travis 2017-11-30 19:14:42 +08:00
life
c01a6dc9e9 Merge pull request #687 from wangduanduan/master
修改网页端博客文档导航无效的bug
2017-11-30 18:54:36 +08:00
lealife
845c96cd48 update travis 2017-11-30 18:50:44 +08:00
lealife
094d18be46 remove deprecated log 2017-11-30 18:46:30 +08:00
lealife
c6937fd184 Compatible with revel 0.18 2017-11-30 18:10:59 +08:00
lealife
430744a324 build 2017-11-30 12:23:30 +08:00
lealife
98c1589a1a search replace tinymce 2017-11-30 12:23:30 +08:00
wang duanduan
d81bb8c893 修改网页端博客文档导航无效的bug 2017-11-10 13:38:33 +08:00
life
21b774143b Merge pull request #641 from jjchern/patch-1
Fix a few typos in readme
2017-08-09 11:11:03 +08:00
jjchern
3925adc3f2 Fix a few typos in readme 2017-08-01 12:58:19 -05:00
lealife
371f5e23c3 realease 2017-07-27 20:25:54 +08:00
lealife
825fda5544 windows export pdf 2017-07-27 20:00:53 +08:00
lealife
6ede5c1559 for release 2017-07-27 15:31:52 +08:00
lealife
1ff90dacde Fix windows export pdf
https://github.com/leanote/leanote/issues/514
2017-07-27 15:08:34 +08:00
lealife
2654b684df upgrade revel to 0.16 2017-06-21 18:24:42 +08:00
life
d424395d85 Update .travis.yml 2017-06-21 18:09:53 +08:00
life
54810b3458 Merge pull request #628 from samtux/master
Translation to Spanish
2017-06-21 17:57:56 +08:00
Samuel Mesa
1cf66ad6c0 Translation to Spanish 2017-06-19 21:10:49 -05:00
lealife
6dc334ca51 Chrome 58 cannot select image 2017-05-19 11:50:50 +08:00
life
f9b4ead6be Merge pull request #590 from sundev126/patch-1
修复arm 32下/adminUser/index假死的bug
2017-04-16 21:36:13 +08:00
lealife
3bf6703929 blog paging configuration 2017-04-16 15:27:35 +08:00
Sunpy
ec657b9dcb 修复arm 32下/adminUser/index假死的bug
如果pageSize为0,则计算页数的时候会造成浮点数除0.0,由于浮点数除0得到的结果是`+Inf`,转换为整数后的结果是`2,147,483,647`,所以在渲染page.html模板时需要很长时间。
2017-04-13 18:00:42 +08:00
lealife
4ffd048b2a Form submission canceled because the form is not connected 2017-04-12 15:58:55 +08:00
lealife
6af19670da Upgrade revel from 0.13 to 0.14
https://github.com/revel/revel/releases/tag/v0.14.0
2017-04-08 18:55:42 +08:00
lealife
721e375d76 mind map 2017-03-07 13:38:04 +08:00
lealife
41f95cf0e5 2.4 released 2017-02-20 13:57:24 +08:00
lealife
ba411ef580 2.4 released 2017-02-20 13:51:07 +08:00
lealife
9dcf0ed53e delete unused 2017-02-20 13:48:26 +08:00
lealife
d5d853ffd3 Support note list view and sorter 2017-02-18 20:01:43 +08:00
lealife
ae29119664 set session.expires to 3h 2017-02-18 20:01:26 +08:00
lealife
ad644258f5 Support for leanote-chrome plugin 2017-02-18 20:01:14 +08:00
lealife
8c98f4da5c markdown remove smartypants; support table align 2017-02-09 11:39:30 +08:00
lealife
e2585bf695 2.3 released 2017-01-23 22:41:31 +08:00
lealife
3b9bc687c4 theme 2017-01-23 18:26:56 +08:00
lealife
2db182db1b 2.3 released 2017-01-23 17:43:41 +08:00
lealife
f3e1eb6c3f Add leaui mind map plugin 2017-01-23 17:43:13 +08:00
lealife
956e1ba2bb fix upload image error [api] 2017-01-23 17:42:38 +08:00
lealife
f294fa4124 fix cannot add deleted tags 2017-01-23 17:42:21 +08:00
lealife
cabf89f9b8 like bug 2017-01-23 17:42:04 +08:00
lealife
d183cd5a77 https://github.com/leanote/leanote/issues/513 2017-01-16 11:49:30 +08:00
lealife
000dfea92d 2.2.2 2017-01-07 15:55:31 +08:00
lealife
a53398ebb4 Fix export note image to pdf error 2017-01-07 15:53:22 +08:00
lealife
b23592229a update travis 2016-12-31 12:16:17 +08:00
lealife
584bde247e fix search deleted note 2016-12-31 12:10:27 +08:00
lealife
6774392807 2.2.1 2016-12-28 11:19:09 +08:00
lealife
964cf1a750 fix issue can't sync images on markdown notes 2016-12-28 10:27:08 +08:00
lealife
52128e6453 update qq groups 2016-12-26 15:45:48 +08:00
lealife
032470c3df v 2.2 2016-12-24 15:47:57 +08:00
lealife
a8dd578624 relative image url/fix conflict when upload attachment again 2016-12-24 15:16:23 +08:00
lealife
f49624d3eb Support send email with ssl 2016-10-29 16:38:13 +08:00
lealife
816af11db2 防止Unzip文件恶意攻击 2016-10-27 16:37:12 +08:00
lealife
eda03f0aa4 防止用"../../来获取其它文件" 2016-10-27 15:40:17 +08:00
lealife
6a06511405 防止用"../../来获取其它文件" 2016-10-27 15:09:10 +08:00
lealife
15d8ebdc0f New Chrome, Chinese input problem
https://github.com/leanote/leanote/issues/42
2016-09-24 10:44:10 +08:00
life
5dc929c4c0 Merge pull request #408 from zhang-yuan/master
Translation fixed
2016-08-26 09:55:50 +08:00
life
a4d6a99fee Merge pull request #409 from alexsourcerer/patch-9
Update album.conf  (fr-fr)
2016-08-26 09:54:59 +08:00
life
15d3b847cb Merge pull request #411 from alexsourcerer/patch-11
Update member.conf (fr-fr)
2016-08-26 09:54:49 +08:00
life
065ac99942 Merge pull request #412 from alexsourcerer/patch-12
Update msg.conf (fr-fr)
2016-08-26 09:54:33 +08:00
life
08ec359b93 Merge pull request #413 from alexsourcerer/patch-13
Update tinymce_editor.conf (fr-fr)
2016-08-26 09:54:03 +08:00
life
2f81c04f41 Merge pull request #378 from lucienevans/master
auto number in MathJax (just blog)
2016-08-26 09:52:23 +08:00
life
e8bff79425 Merge pull request #410 from alexsourcerer/patch-10
Update markdown.conf
2016-08-26 09:49:45 +08:00
alexsourcerer
4ca8e8cd83 Update tinymce_editor.conf
translation created & completed!
2016-08-23 12:41:32 +02:00
alexsourcerer
c0cc08a3c2 Update msg.conf
translation updated!
2016-08-23 12:04:53 +02:00
alexsourcerer
d32a6dd277 Update member.conf
updated translation to french
2016-08-23 11:57:22 +02:00
alexsourcerer
8bacc15309 Update markdown.conf
translated to french
2016-08-23 11:46:26 +02:00
alexsourcerer
8a3f24b9c6 Update album.conf
translated to french
2016-08-23 11:37:16 +02:00
haha
2a7d1fe7b5 Add translation 2016-08-23 14:09:53 +08:00
haha
9a05ffcd8f 翻译问题 2016-08-23 12:11:41 +08:00
lealife
aa95e680f9 travis use go 1.4 2016-08-23 11:06:50 +08:00
life
874ab69c34 Merge pull request #406 from Xunius/patch-2
add vim and emacs modes to features
2016-08-23 10:33:13 +08:00
Xunius
d43f5fd7ab add vim and emacs modes to features 2016-08-22 17:44:39 +08:00
life
6a048f0d9a Merge pull request #403 from Xunius/patch-1
rephrased English n Chinese, fixed links to docs.
2016-08-22 17:23:21 +08:00
Xunius
cb3681f651 rephrased English n Chinese, fixed links to docs.
Fixed grammar errors in English and polished the wordings.
Changed order at one place to make the Doc part appear before develop.
Added links to installation tutorials
2016-08-19 19:12:30 +08:00
life
dfd7159401 Merge pull request #361 from gaoyifan/patch-1
fix spelling mistake in README.md
2016-07-22 10:36:10 +08:00
lucien
929ec975da auto number in MathJax 2016-06-21 23:35:49 +08:00
life
e826dc7b93 Merge pull request #374 from mhoffmann75/german_transl
add complete german translation
2016-06-10 17:12:21 +08:00
Martin Hoffmann
629a49e54b add complete german translation
- modify app/views/home/header.html to know de-de messages folder
- create messages/de-de folder with all german language files (album, blog, ...)
- create public/js/i18n/blog.de-de.js and ms.de-de.js files
- add public/tinymce/langs/de-de.js from tinymce project

Thanks to Marc Manthey (macbroadcast) who is the original author of the german translation for the leanote 1.x project (https://github.com/macbroadcast/leanote). I took his work as starting point for my complete german translation on leanote 2.0.
2016-06-10 09:46:31 +02:00
lealife
6ebedf94f0 app.conf 2016-05-25 17:33:38 +08:00
lealife
a07bb25128 remove unused codes and add site'url configuration on admin 2016-05-25 16:05:47 +08:00
lealife
a007b89ebb v2.0 2016-05-25 14:46:40 +08:00
lealife
cc4b003503 markdown vim cursor fixed 2016-05-25 09:51:53 +08:00
lealife
091922175a box leanote logo 2016-05-22 16:12:51 +08:00
lealife
371c93912d build 2016-05-22 10:36:36 +08:00
lealife
27221acda7 new logo 2016-05-22 10:34:40 +08:00
lealife
5db724e80b new logo 2016-05-21 23:05:50 +08:00
Yifan Gao
14265d9de4 fix spelling mistake in README.md 2016-05-18 10:26:24 +08:00
lealife
5c9e95ed60 build 2016-04-16 14:53:30 +08:00
lealife
2fc97ed42d markdown editor prettify add linenums 2016-04-16 14:51:54 +08:00
lealife
45cca30cec lea++ -> Explore 2016-04-16 12:09:48 +08:00
lealife
31167b6aaf recount tags 2016-04-16 11:58:39 +08:00
lealife
139906b9d6 recount tags when public note 2016-04-16 11:31:27 +08:00
lealife
a9d49369e2 upgrade markdown mathjax 2016-04-12 22:02:36 +08:00
life
303e0da5c0 Update README.md 2016-04-09 10:12:46 +08:00
life
ff5523bfaa Merge pull request #340 from eric2100/patch-15
Update blog.conf
2016-04-08 17:07:20 +08:00
Tsunghan,Tsai
063dd0140d Update blog.conf
部分口語修改
2016-04-08 12:31:41 +08:00
life
c52d388d5d Merge pull request #337 from eric2100/patch-14
Update msg.conf
2016-04-07 17:31:04 +08:00
eric2100
18bcdb48af Update msg.conf 2016-04-07 12:29:03 +08:00
life
db8f132507 Merge pull request #333 from eric2100/patch-9
Update blog.conf
2016-04-05 10:14:31 +08:00
life
439d5212b0 Merge pull request #334 from eric2100/patch-10
Update markdown.conf
2016-04-05 10:13:40 +08:00
life
88e2320027 Merge pull request #335 from eric2100/patch-11
Update member.conf
2016-04-05 10:13:09 +08:00
life
659a4e590a Merge pull request #336 from eric2100/patch-12
Update tinymce_editor.conf
2016-04-05 10:12:19 +08:00
eric2100
ab7f2386e0 Update tinymce_editor.conf 2016-04-05 00:24:21 +08:00
eric2100
ec82ff18f2 Update member.conf 2016-04-05 00:16:00 +08:00
eric2100
f3f00626e6 Update markdown.conf 2016-04-05 00:03:27 +08:00
eric2100
80fbb56426 Update blog.conf 2016-04-05 00:01:46 +08:00
life
a5c952882f Merge pull request #332 from eric2100/patch-8
Update album.conf
2016-04-03 21:30:30 +08:00
eric2100
973b452a7e Update album.conf 2016-04-02 21:12:30 +08:00
lealife
25bcd21ea9 overwrite revel.Message 2016-03-19 23:00:41 +08:00
lealife
09de5e1e83 Gulp js i18n generator 2016-03-19 15:46:41 +08:00
lealife
15b0ef21ff restructure messages 2016-03-19 15:37:36 +08:00
lealife
9cf9ded855 remove config langs. Gulp will get all langs by messages/ 2016-03-19 15:17:15 +08:00
lealife
7af433ebaf build 2016-03-19 14:36:47 +08:00
lealife
67b608b324 set langs to config and modify gulp build to support langs 2016-03-19 14:30:07 +08:00
lealife
2aa3f5a654 support 中文繁体 2016-03-19 14:05:09 +08:00
lealife
f5538218bd remove baidu statistics Code
https://github.com/leanote/leanote/issues/318
2016-03-04 22:23:53 +08:00
lealife
0e3bdd177c md resize when toggle 2016-02-27 15:30:01 +08:00
lealife
12520cc09d mathjax 2.6.1 2016-02-27 14:20:31 +08:00
life
cb67892124 Merge pull request #309 from alexsourcerer/patch-8
Update msg.fr
2016-02-18 14:55:17 +08:00
alexsourcerer
45c09c9a26 Update msg.fr
I updated the msg.fr file (note that the website isn't it french at all anymore for french users)
2016-02-03 23:10:50 +01:00
lealife
20951ea2dd build release 2015-12-25 23:59:57 +08:00
lealife
530f2368da v1.4.2 released 2015-12-25 23:45:38 +08:00
lealife
e685a99628 member css for multi lang 2015-12-25 23:45:19 +08:00
lealife
bfc5acc3ee 1.4.2 released 2015-12-25 11:50:34 +08:00
lealife
551e3d965e markdown todo-list style 2015-12-25 11:50:34 +08:00
lealife
7c479b5595 fix ace editor hide the last line part section text 2015-12-25 11:50:34 +08:00
lealife
b135f9717f fix gen desc 2015-12-25 11:50:34 +08:00
lealife
08ae37cae0 markdown add todo-list feature 2015-12-25 11:50:34 +08:00
Yingbo CUI
315a7bbe62 Update README.md 2015-12-24 16:47:31 +08:00
life
e173b18ddc Merge pull request #285 from eurafa/master
Portuguese (Brazil) language added
2015-12-17 10:29:10 +08:00
Rafael Andrade de Oliveira
dcc25df679 Chinese translations 2015-12-13 09:09:02 -02:00
Rafael Andrade de Oliveira
c561dec14c Portuguese (Brazil) language added 2015-12-13 09:03:50 -02:00
lealife
43e8f2e701 markdown editor inited 2015-12-06 15:48:05 +08:00
lealife
dd9952c453 fix export pdf error 2015-12-04 17:50:14 +08:00
lealife
19517dd634 fix export pdf error 2015-12-04 17:37:57 +08:00
lealife
a5b006aae7 添加全局 toggle modify with readonly; 发布1.4.1 2015-12-02 20:56:03 +08:00
lealife
90bd07cdcc * markdown v2, 修复笔记内容覆盖 2015-12-02 20:55:34 +08:00
lealife
92576e9239 arm run script 2015-11-29 13:05:26 +08:00
lealife
c58e6874c2 paste image 名称是untitled 2015-11-28 21:47:50 +08:00
lealife
cfebf00cf1 i18n js 2015-11-28 21:32:21 +08:00
lealife
19be0990da 注销后不再保存笔记 2015-11-28 21:31:56 +08:00
lealife
3f27e4b0d4 Failed to generate name for field. Make sure the field name is valid #201 2015-11-28 21:26:29 +08:00
lealife
4710fb6686 i18n 2015-11-28 18:57:58 +08:00
lealife
28324c0178 release v1.4 2015-11-28 18:00:45 +08:00
lealife
f270ade8d7 1.4 2015-11-28 17:58:42 +08:00
lealife
3b3e665a9f paste image 2015-11-28 17:58:38 +08:00
lealife
bfa85e2d34 Merge branch 'feature-v1.4' 2015-11-28 16:45:59 +08:00
lealife
fcf270a521 reinit undo when toggle file 2015-11-28 16:44:59 +08:00
lealife
eba113c73c dev tinymce 2015-11-28 16:40:50 +08:00
lealife
41f63156ea tinymce 不打包 2015-11-28 16:32:29 +08:00
lealife
f54fe397c3 member view 2015-11-28 16:12:27 +08:00
lealife
6f157289d3 update member css 2015-11-28 16:09:33 +08:00
lealife
65792d020c move tinymce theme to /public/css/tinymce 2015-11-28 16:07:17 +08:00
lealife
926882dce6 build js 2015-11-28 15:56:25 +08:00
lealife
f834f469fc update gulp build for i18n 2015-11-28 15:55:58 +08:00
lealife
06d42c36f0 i18n 2015-11-28 15:46:56 +08:00
lealife
17d513a9de fix note-dev 2015-11-28 15:42:39 +08:00
lealife
8cc00c1f66 format date config; for update note's date 2015-11-28 15:38:43 +08:00
lealife
cb433d9392 theme; split by files 2015-11-28 15:36:12 +08:00
lealife
86ca1efd11 tinymce theme 2015-11-28 15:35:26 +08:00
lealife
263f978c54 import theme 2015-11-28 15:33:49 +08:00
lealife
c8af7eda5d hide note and editor when search 2015-11-28 15:33:42 +08:00
lealife
3724811802 set md column width 2015-11-28 15:33:30 +08:00
lealife
10ff48267f clear undo 2015-11-28 15:33:13 +08:00
lealife
cd0913aec0 paste for markdown v2 2015-11-28 15:33:06 +08:00
lealife
f8d4c2ef20 markdown editor v2 2015-11-28 15:32:56 +08:00
lealife
f16b5e816e Leanote upperCase 2015-11-28 15:23:33 +08:00
lealife
9a9968760a note i18n 2015-11-28 15:19:50 +08:00
lealife
b1f36dfbf1 member i18n 2015-11-28 15:17:36 +08:00
lealife
bc0e09f222 file upload path 统一化 GetRandomFilePath 2015-11-28 14:44:07 +08:00
lealife
0dab71e72b delete unused 2015-11-28 14:35:46 +08:00
lealife
10f23c19ab group i18n, pwd 重置密码优化 2015-11-28 14:28:51 +08:00
lealife
bba57ea302 configservice 2015-11-28 14:25:45 +08:00
lealife
f052117989 删除笔记时删除历史 2015-11-28 14:22:10 +08:00
lealife
df4ec53647 api fixContent优化; exportPDF优化 2015-11-28 14:21:23 +08:00
lealife
a7eaf6114a urlTitle 优化, 减少生成次数, 避免使用id作为urlTitle 2015-11-28 14:16:10 +08:00
lealife
b25bf0e16c util 时间判断 2015-11-28 13:49:00 +08:00
lealife
d13447e6d0 controller 支持传递时间 2015-11-28 13:47:59 +08:00
lealife
6a1e84da0c noteService支持传时间添加/更新笔记 2015-11-28 13:43:37 +08:00
lealife
51aeb7d46e build support linux-arm 2015-11-23 10:39:01 +08:00
lealife
2dbd025768 album js build 2015-11-22 23:26:59 +08:00
lealife
d52d80d529 plugins compress 2015-11-22 23:18:07 +08:00
lealife
2000bc585b markdown editor v2 paste images 2015-11-22 23:01:30 +08:00
lealife
8301a1e515 js 优化
* 标题按tab切换到内容
* 左侧最小化用css控制
* resize markdown editor v2
* Ace剪切导致行数减少
* 删除不要的代码
2015-11-22 22:58:38 +08:00
lealife
bee65eb36d markdown editor v2 editor mode i18n 2015-11-22 22:46:27 +08:00
lealife
78199583b0 mv dist -> md 2015-11-22 22:46:00 +08:00
lealife
28d5678349 remove unused files 2015-11-22 22:41:07 +08:00
lealife
e97c468f6e gulp markdown v2 builder 2015-11-22 22:39:16 +08:00
lealife
5d18554542 tinymce build 2015-11-22 22:39:04 +08:00
lealife
3ff0a9e09c markdown editor v2 libs 2015-11-22 22:36:53 +08:00
lealife
6a753682b7 markdown editor v2 2015-11-22 22:33:07 +08:00
lealife
ce491e62c3 insert image i18n 2015-11-22 22:28:51 +08:00
lealife
e4b847b731 undo md 2015-11-22 22:21:59 +08:00
lealife
a12b285a35 tinymce leanote code plugin i18n 2015-11-22 22:21:38 +08:00
lealife
7f0ada8016 update readme 2015-11-18 23:45:20 +08:00
lealife
bac5ab4d79 update readme 2015-11-18 23:43:19 +08:00
life
b362406819 Merge pull request #261 from alexsourcerer/patch-7
Update msg.fr
2015-11-18 13:13:54 +08:00
alexsourcerer
9e2edbb987 Update msg.fr 2015-11-16 21:56:12 +01:00
lealife
7809d00787 fmt all go file 2015-11-13 17:58:41 +08:00
lealife
cba69444a8 v1.3.1 released 2015-10-30 14:44:57 +08:00
lealife
5e02816c09 v1.3.1 release 2015-10-30 14:41:01 +08:00
lealife
20b085aeae Markdown编辑器中文回车有时不换行 #249 2015-10-30 14:12:32 +08:00
lealife
0f5e683a4f Markdown 笔记无法分辨 hyperlink #240 2015-10-30 14:09:35 +08:00
lealife
e134ca7244 个个中心美化 2015-10-30 14:07:42 +08:00
lealife
6818574605 删除leaui不要文件; file/outputImage 变成 api/file/getImage 2015-10-30 14:05:51 +08:00
lealife
6eea03f81e 自动保存优化, 时间缩短成10s
https://github.com/leanote/leanote/issues/243
2015-10-30 14:02:28 +08:00
lealife
1242834b7f 增加修改与只读的快捷键 ctrl/cmd + e
https://github.com/leanote/leanote/issues/241
2015-10-30 13:57:28 +08:00
lealife
1844513f08 mac下cmd+shift+c 不能调出toggle code
https://github.com/leanote/leanote/issues/248
2015-10-30 13:52:50 +08:00
lealife
b0be7a14d2 ctrl+v 复制图片, 有时不显示, 但上传了
https://github.com/leanote/leanote/issues/227
2015-10-30 13:48:54 +08:00
lealife
7e17c68dba update readme 2015-10-27 23:44:53 +08:00
lealife
6259f15ffa update readme 2015-10-27 23:42:19 +08:00
lealife
f65d027a0d update readme 2015-10-27 23:25:17 +08:00
lealife
e9e2ca50ee update readme 2015-10-27 23:19:56 +08:00
lealife
a64ef8517e update readme 2015-10-27 23:17:15 +08:00
lealife
c9bda60554 v1.3 release 2015-10-27 23:14:02 +08:00
lealife
c3478520c0 batch release 2015-10-27 23:08:00 +08:00
lealife
8346ffe915 batch release
https://github.com/leanote/leanote/issues/238
2015-10-27 23:07:49 +08:00
lealife
f49b046601 Merge branch 'feature-batch' 2015-10-27 23:06:51 +08:00
lealife
263c03291e batch ok 2015-10-27 23:04:39 +08:00
lealife
29244c247e lit indent 2015-10-20 09:28:03 +08:00
lealife
320de8637f v1.2 update initial db data 2015-10-18 20:34:44 +08:00
lealife
33bc6bf84b v1.2 update initial data 2015-10-18 20:34:31 +08:00
lealife
0cd2c42b68 v1.2 release 2015-10-18 00:16:54 +08:00
lealife
1716acf9e0 release v1.2 for export pdf 2015-10-17 23:46:09 +08:00
lealife
45477119d4 Merge branch 'feature-pdf' 2015-10-17 23:23:36 +08:00
2137 changed files with 323172 additions and 42219 deletions

1
.gitignore vendored
View File

@@ -7,7 +7,6 @@ bin/release
bin/test.sh
bin/tmp
bin/test
bin/src
public/upload
app/routes/routes.go
app/tmp/main.go

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>leanote-public</name>
<comment>leanote, your own cloud note!</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.googlecode.goclipse.goBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>goclipse.goNature</nature>
</natures>
</projectDescription>

View File

@@ -1,5 +1,5 @@
language: go
go: 1.3
go: 1.7
services:
- mongodb # 2.4.12
@@ -16,9 +16,7 @@ install:
script:
- mongo --version
- mongorestore -h localhost -d leanote --directoryperdb ./mongodb_backup/leanote_install_data/
- go test github.com/leanote/leanote/app/tests
- mongorestore -h localhost -d leanote --dir ./mongodb_backup/leanote_install_data/
# gen tmp/main.go, routes/routes.go
- go run app/cmd/main.go
@@ -34,4 +32,4 @@ script:
- curl http://localhost:9000/demo
# - revel build github.com/leanote/leanote tmp
# OK
# OK

View File

@@ -15,18 +15,20 @@ var base = leanoteBase + '/public'; // public base
var noteDev = leanoteBase + '/app/views/note/note-dev.html';
var noteProBase = leanoteBase + '/app/views/note';
var messagesPath = leanoteBase + 'messages';
// 合并Js, 这些js都是不怎么修改, 且是依赖
// 840kb, 非常耗时!!
gulp.task('concatDepJs', function() {
var jss = [
'js/jquery-1.9.0.min.js',
'js/jquery.ztree.all-3.5-min.js',
'tinymce/tinymce.full.min.js', // 使用打成的包, 加载速度快
// 'tinymce/tinymce.full.min.js', // 使用打成的包, 加载速度快
// 'libs/ace/ace.js',
'js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js',
'js/contextmenu/jquery.contextmenu-min.js',
'js/bootstrap-min.js',
'js/object_id-min.js',
'js/object_id.js',
];
for(var i in jss) {
@@ -62,11 +64,39 @@ gulp.task('concatAppJs', function() {
.pipe(gulp.dest(base + '/js'));
});
// plugins压缩
gulp.task('plugins', function() {
// gulp.src(base + '/js/plugins/libs/*.js')
// .pipe(uglify()) // 压缩
// // .pipe(concat('main.min.js'))
// .pipe(gulp.dest(base + '/js/plugins/libs-min'));
// 所有js合并成一个
var jss = [
'note_info',
'tips',
'history',
'attachment_upload',
'editor_drop_paste',
'main'
];
for(var i in jss) {
jss[i] = base + '/js/plugins/' + jss[i] + '.js';
}
jss.push(base + '/js/plugins/libs-min/fileupload.js');
return gulp.src(jss)
.pipe(uglify()) // 压缩
.pipe(concat('main.min.js'))
.pipe(gulp.dest(base + '/js/plugins'));
});
// 合并requirejs和markdown为一个文件
gulp.task('concatMarkdownJs', function() {
var jss = [
'js/require.js',
'dist/main.min.js',
'md/main.min.js',
];
for(var i in jss) {
@@ -80,6 +110,24 @@ gulp.task('concatMarkdownJs', function() {
.pipe(gulp.dest(base + '/js'));
});
// / 合并requirejs和markdown为一个文件
gulp.task('concatMarkdownJsV2', function() {
var jss = [
'js/require.js',
'md/main-v2.min.js',
];
for(var i in jss) {
jss[i] = base + '/' + jss[i];
}
return gulp
.src(jss)
.pipe(uglify()) // 压缩
.pipe(concat('markdown-v2.min.js'))
.pipe(gulp.dest(base + '/js'));
});
// note-dev.html -> note.html, 替换css, js
// TODO 加?t=2323232, 强制浏览器更新, 一般只需要把app.min.js上加
gulp.task('devToProHtml', function() {
@@ -88,28 +136,40 @@ gulp.task('devToProHtml', function() {
.pipe(replace(/<!-- dev -->[.\s\S]+?<!-- \/dev -->/g, '')) // 把dev 去掉
.pipe(replace(/<!-- pro_dep_js -->/, '<script src="/js/dep.min.js"></script>')) // 替换
.pipe(replace(/<!-- pro_app_js -->/, '<script src="/js/app.min.js"></script>')) // 替换
.pipe(replace(/<!-- pro_markdown_js -->/, '<script src="/js/markdown.min.js"></script>')) // 替换
// .pipe(replace(/<!-- pro_markdown_js -->/, '<script src="/js/markdown.min.js"></script>')) // 替换
.pipe(replace(/<!-- pro_markdown_js -->/, '<script src="/js/markdown-v2.min.js"></script>')) // 替换
.pipe(replace('/tinymce/tinymce.js', '/tinymce/tinymce.full.min.js')) // 替换
.pipe(replace(/<!-- pro_tinymce_init_js -->/, "var tinyMCEPreInit = {base: '/public/tinymce', suffix: '.min'};")) // 替换
.pipe(replace(/plugins\/main.js/, "plugins/main.min.js")) // 替换
// 连续两个空行换成一个空行, 没用
.pipe(replace(/\n\n/g, '\n'))
.pipe(replace(/\n\n/g, '\n'))
// 连续两个空行换成一个空行
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace(/\r\n\r\n/g, '\r\n'))
.pipe(replace('console.log(o);', ''))
.pipe(replace('console.trace(o);', ''))
// .pipe(minifyHtml()) // 不行, 压缩后golang报错
.pipe(rename('note.html'))
.pipe(gulp.dest(noteProBase));
});
// Get used keys
// 只获取需要js i18n的key
var path = require('path');
gulp.task('i18n', function() {
var keys = {};
var reg = /getMsg\(["']+(.+?)["']+/g;
// {rule: "required", msg: "inputNewPassword"},
var reg2 = /msg: ?"?([0-9a-zA-Z]*)"?/g;
function getKey(data) {
while(ret = reg.exec(data)) {
keys[ret[1]] = 1;
}
while(ret2 = reg2.exec(data)) {
keys[ret2[1]] = 1;
}
}
// 先获取需要的key
function ls(ff) {
@@ -137,14 +197,17 @@ gulp.task('i18n', function() {
ls(base + '/admin');
ls(base + '/blog');
ls(base + '/dist');
ls(base + '/md');
ls(base + '/js');
ls(base + '/album');
ls(base + '/libs');
ls(base + '/member');
ls(base + '/tinymce');
ls(leanoteBase + '/app/views');
console.log('parsed');
var langs = {}; // zh-cn: 1
// msg.zh
function getAllMsgs(fname) {
@@ -169,10 +232,30 @@ gulp.task('i18n', function() {
return msg;
}
// 得到所有的语言的后缀
// 返回{en-us: 1, }
function getAllLangs() {
var langs = {};
var files = fs.readdirSync(messagesPath);
for(fn in files) {
var fname = files[fn];
if (fname.indexOf('-') > 0) {
langs[fname] = 1;
}
}
return langs;
}
// msg.zh, msg.js
function genI18nJsFile(fromFilename, keys) {
var msgs = getAllMsgs(leanoteBase + '/messages/' + fromFilename);
var toFilename = fromFilename + '.js';
function genI18nJsFile(targetFilename, lang, fromFilenames, keys) {
var msgs = {};
fromFilenames.forEach(function (name) {
var tmpMsgs = getAllMsgs(leanoteBase + '/messages/' + lang + '/' + name + '.conf');
for (var i in tmpMsgs) {
msgs[i] = tmpMsgs[i];
}
});
var toMsgs = {};
for (var i in msgs) {
// 只要需要的
@@ -190,18 +273,27 @@ gulp.task('i18n', function() {
'}' +
'return key;' +
'}';
// 写入到文件中
var toFilename = targetFilename + '.' + lang + '.js';
fs.writeFile(base + '/js/i18n/' + toFilename, str);
}
genI18nJsFile('msg.zh', keys);
genI18nJsFile('msg.en', keys);
genI18nJsFile('msg.fr', keys);
genI18nJsFile('blog.zh', keys);
genI18nJsFile('blog.en', keys);
genI18nJsFile('blog.fr', keys);
});
function genTinymceLang(lang) {
var msgs = getAllMsgs(leanoteBase + 'messages/' + lang + '/tinymce_editor.conf');
var str = 'tinymce.addI18n("' + lang + '",' + JSON.stringify(msgs) + ');';
fs.writeFile(base + '/tinymce/langs/' + lang + '.js', str);
}
var langs = getAllLangs();
for (var lang in langs) {
genI18nJsFile('blog', lang, ['blog'], keys);
genI18nJsFile('msg', lang, ['msg', 'member', 'markdown', 'album'], keys);
genTinymceLang(lang);
}
});
// 合并album需要的js
gulp.task('concatAlbumJs', function() {
@@ -236,78 +328,9 @@ gulp.task('concatAlbumJs', function() {
.pipe(gulp.dest(base + '/album/js'));
});
// plugins压缩
gulp.task('plugins', function() {
gulp.src(base + '/js/plugins/libs/*.js')
.pipe(uglify()) // 压缩
// .pipe(concat('main.min.js'))
.pipe(gulp.dest(base + '/js/plugins/libs-min'));
// 所有js合并成一个
var jss = [
'note_info',
'tips',
'history',
'attachment_upload',
'editor_drop_paste',
'main'
];
for(var i in jss) {
jss[i] = base + '/js/plugins/' + jss[i] + '.js';
}
gulp.src(jss)
.pipe(uglify()) // 压缩
.pipe(concat('main.min.js'))
.pipe(gulp.dest(base + '/js/plugins'));
});
// mincss
var minifycss = require('gulp-minify-css');
gulp.task('minifycss', function() {
gulp.src(base + '/css/bootstrap.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css'));
gulp.src(base + '/css/font-awesome-4.2.0/css/font-awesome.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/font-awesome-4.2.0/css'));
gulp.src(base + '/css/zTreeStyle/zTreeStyle.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/zTreeStyle'));
gulp.src(base + '/dist/themes/default.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/dist/themes'));
gulp.src(base + '/js/contextmenu/css/contextmenu.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/js/contextmenu/css'));
// theme
// 用codekit
var as = ['default', 'simple', 'writting', /*'writting-overwrite', */ 'mobile'];
/*
for(var i = 0; i < as.length; ++i) {
gulp.src(base + '/css/theme/' + as[i] + '.css')
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/theme'));
}
*/
});
// tinymce
// !! You must has tinymce_dev on public/
var tinymceBase = base + '/tinymce_dev';
// please set the right path on your own env
var tinymceBase = '/Users/life/leanote/leanote-tools/tinymce_4.1.9_leanote_public';
gulp.task('tinymce', function() {
// 先清理
fs.unlink(tinymceBase + '/js/tinymce/tinymce.dev.js');
@@ -317,7 +340,7 @@ gulp.task('tinymce', function() {
var cp = require('child_process');
var bundleCmd = 'grunt bundle --themes leanote --plugins autolink,link,leaui_image,leaui_mind,lists,hr,paste,searchreplace,leanote_nav,leanote_code,tabfocus,table,directionality,textcolor';
var bundleCmd = 'grunt bundle --themes leanote --plugins autolink,link,leaui_image,leaui_mindmap,lists,hr,paste,searchreplace,leanote_nav,leanote_code,tabfocus,table,directionality,textcolor';
// build
cp.exec('grunt minify', {cwd: tinymceBase}, function(err, stdout, stderr) {
console.log('stdout: ' + stdout);
@@ -340,6 +363,47 @@ gulp.task('concatCss', function() {
.pipe(gulp.dest(markdownMin));
});
gulp.task('concat', ['concatDepJs', 'concatAppJs', 'concatMarkdownJs']);
// mincss
var minifycss = require('gulp-minify-css');
gulp.task('minifycss', function() {
gulp.src(base + '/css/bootstrap.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css'));
gulp.src(base + '/css/font-awesome-4.2.0/css/font-awesome.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/font-awesome-4.2.0/css'));
gulp.src(base + '/css/zTreeStyle/zTreeStyle.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/zTreeStyle'));
gulp.src(base + '/md/themes/default.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/md/themes'));
gulp.src(base + '/js/contextmenu/css/contextmenu.css')
.pipe(rename({suffix: '-min'}))
.pipe(minifycss())
.pipe(gulp.dest(base + '/js/contextmenu/css'));
// theme
// 用codekit
var as = ['default', 'simple', 'writting', /*'writting-overwrite', */ 'mobile'];
/*
for(var i = 0; i < as.length; ++i) {
gulp.src(base + '/css/theme/' + as[i] + '.css')
.pipe(minifycss())
.pipe(gulp.dest(base + '/css/theme'));
}
*/
});
gulp.task('concat', ['concatDepJs', 'concatAppJs', /* 'concatMarkdownJs', */'concatMarkdownJsV2']);
gulp.task('html', ['devToProHtml']);
gulp.task('default', ['concat', 'plugins', 'minifycss', 'i18n', 'concatAlbumJs', 'html']);

190
README.md
View File

@@ -1,74 +1,188 @@
# Leanote
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://travis-ci.org/leanote/leanote.svg)](https://travis-ci.org/leanote/leanote)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## 1. Introduction
Leanote, not just a notepad!
![leanote.png](leanote.png "")
**Some Features**
**Highlighted Features**
* Knowledge: Manage your knowledge in leanote. leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
* Share: Share your knowledge with your friends in leanote. You can invite your friends to join your notepad in the cloud so you can share knowledge.
* Cooperation: Collaborate with friends to improve your skills.
* Blog: Publish your knowledge and make leanote your blog.
* Note-taking made easy: Leanote incorporates a clean and intuitive interface, the `tinymce` rich-text editor and a dedicated *markdown* editor, making your writing/typing more efficient and enjoyable. For more advanced users, we even offer `Vim` and `Emacs` writing modes to help boost your writing speed to another level.
* Knowledge management: The flexible and versatile notebook-note-tagging system of Leanote makes it an ideal tool for knowledge management.
* Sharing: Share your knowledge, thoughts and experiences with friends via Leanote. Invite your friends to join your notepad in the cloud.
* Cooperating: Collaborate with colleagues to improve skills, fertilize ideas and brainstorm on the fly.
* Blogging: Publish your work and make Leanote your personal blog.
## 2. Why we created leanote
To be honest, our inspiration comes from Evernote. We use Evernote to manage our knowledge everyday. But we find that:
* Evernote's editor can't meet our needs, it does not have document navigation, it does not render code properly (as a programmer, syntax highlighted code rendering is a basic need), it cannot resize images and so forth
* We like markdown, but Evernote does not support it.
* We want to share our knowledge, so all of us have our blogs (e.g. on Wordpress) and our Evernote accounts, but why can not those two be one!
**Other Features**
* Markdown syntax support
* Distraction-free writing mode
* `Vim` and `Emacs` editing mode
* Export notes to PDFs
* Batch note operation
* Customizable themes for blogging
## 2. Why we create Leanote
We have been using the popular note-taking software/service `Evernote` as our knowledge management tool on a daily basis. Benefited from and inspired by `Evernote`, we decided to create a brand-new tool that provides everything `Evernote` has to offer, plus a bunch of new features that `Evernote` failed to deliver, such as:
* A more powerful editor: `Evernote`'s editor lacks the functionalities of **document navigation**, **syntax based code rendering** (as a programmer, syntax highlighted code rendering is a necessity), **image resizing** and so forth.
* Everybody loves *markdown*, however `Evernote` simply wouldn't add it despite of years' of requests from users. So we will do the favor and bring a *markdown* enabled editor to you, guess what, it is also rendered in real-time!
* If you a developer and miss the `Vim` or `Emacs` ways of writing, we offer you the choice of `Vim` and `Emacs` editing modes. Equipped with *markdown* syntax for text formatting, you will never need to touch your mouse while writing.
* We love managing knowledge and thoughts as much as sharing them, so everybody has their own note account (`Evernote`, `Onenote`, `Google doc`, `Wiz note` etc.) and social media account (`Facebook`, `Wordpress`, blogs, etc.). But why cant those two be one? Leanote makes this first step to bridge the private note-taking and public knowledge sharing seamlessly.
* A complete and all-platform (sorry Windows phone) covering software suite: that includes Leanote Web & Server (this repository), [Desktop app](https://github.com/leanote/desktop-app), [iOS](https://github.com/leanote/leanote-ios), [Android](https://github.com/leanote/leanote-android). And they are all open source!
* ......
## 3. How to install leanote
## 3. How to get Leanote
More information about how to install leanote please see:
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
The Leanote software suite contains: Leanote Web & Server (this repository), [Desktop app](https://github.com/leanote/desktop-app), [iOS](https://github.com/leanote/leanote-ios), [Android](https://github.com/leanote/leanote-android).
## 4. How to develop leanote
Interested in our product and want to try it out from your web browser? Welcome to sign up on https://leanote.com.
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
Feeling suspicious about how those note-taking companies treat your personal data? You can install Leanote on your server, and use Leanote App (Desktop, iOS, Android) to sync notes with your self-hosted server.
More information about how to install Leanote please see:
* Leanote binary installation tutorial:
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
* [Mac and Linux](https://github.com/leanote/leanote/wiki/leanote-binary-installation-on-Mac-and-Linux-(En))
* Leanote source installation tutorial:
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
* [Mac and Linux](https://github.com/leanote/leanote/wiki/Leanote-source-installation-on-Mac-and-Linux-(En))
## 4. Documentation
Please see [wiki](https://github.com/leanote/leanote/wiki) for detailed instruction on how to install Leanote on various platforms, trouble shooting and configuration explanations.
## 5. Docs
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
## 5. How to develop Leanote
More docs please see [wiki](https://github.com/leanote/leanote/wiki).
If you are a developer yourself and feel like to build on top of Leanote, please refer to [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote).
## 6. Contributors
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
this project. Your help is much appreciated.
## 7.Join us
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
## 6. Contributions
If you find some problems or has some good ideas, please submit [issues](https://github.com/leanote/leanote/issues).
Like or dislike Leanote, please leave your comments and suggestions to help us improve it.
If you encounter any issue, we suggest you first search the issues section to see whether a solution already exists, or open up a new one otherwise.
Wed like to acknowledge the contributions made by our [developers and contributors](https://github.com/leanote/leanote/graphs/contributors) to
this project. Leanote wont exist without your hard work. Your help is much appreciated.
## 7. Join us
Please feel free to fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
If you find any problems or have any good ideas, feature requests, please submit here [issues](https://github.com/leanote/leanote/issues).
You are always welcomed!
## 8. Donation
Support us, [donate us](http://leanote.org/#donate). And thanks [donators](http://leanote.leanote.com/post/leanote-donation-list).
If you like our product, consider supporting us via [donate us](http://leanote.org/#donate).
We acknowledge the donations made by all the [donators](http://leanote.leanote.com/post/leanote-donation-list).
## 9. Related projects
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [Download](http://app.leanote.com)
* [Leanote IOS](https://github.com/leanote/leanote-ios), [Download From App Store](https://itunes.apple.com/en/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/Dminter/leanote-android-client), development phase
* [Leanote iOS](https://github.com/leanote/leanote-ios), [Download From App Store](https://itunes.apple.com/en/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/leanote/leanote-android), development phase
And also, you are welcome to join us.
You are welcome to join us.
## 9. Support & Join us
## 10. Contacts
* Email: leanote@leanote.com
* [Leanote BBS](http://bbs.leanote.com)
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
* QQ Group: 158716820, 256076853
* QQ Groups: 326073529, 256076853, 158716820
-----------------------------------------------------------------------
[中文](README_zh.md)
# Leanote
## 1. 介绍
Leanote, 不只是笔记!
**特性**
* 高效笔记Leanote 有易操作的界面, 包含一款富文本编辑器和Markdown编辑器让您的笔记记录更轻松和高效。对高阶用户我们还提供`Vim``Emacs` 编辑模式,助推你的写作速度更上层楼。
* 知识管理: Leanote 灵活而强大的“笔记本-笔记-标签”系统,让它成为你个人知识管理的利器。
* 分享: 你可以通过Leanote同好友分享知识、想法和经历, 邀请好友加入你的笔记簿,通过云端交流信息。
* 协作: Leanote协助你与同事之间相互协作激荡新思路随时随地头脑风暴。
* 博客: Leanote也可以作为你的个人博客, 把你的知识传播的更远!
**其它特性**
* 支持Markdown编辑
* 写作模式
* `Vim``Emacs` 编辑模式
* 支持PDF导出
* 支持批量操作
* 博客自定义主题, 实现高度定制化
## 2. 为什么我们要创建Leanote?
我们都曾是`Evernote`的忠实粉丝, 一直以来`Evernote`都是我们日常知识管理的有效工具。于是我们决定重新创造一款工具,提供`Evernote`所能提供的功能,同时弥补`Evernote`的不足,比如:
* 功能更强的文本编辑器:`Evernote`的编辑器不能满足我们的需求, 不能实现文档导航、不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放等。
* `Evernote` 不支持所有人都喜爱的markdown语法于是我们为Leanote配备了一款可以实时渲染的markdown编辑器。
* 如果你是一名开发者,觉得手指怀念`Vim``Emacs` 了,那么我们还提供给你`Vim``Emacs` 写作模式,配合*markdown*的格式编辑,写作的时候再也不用去碰鼠标了。
* 知识积累和知识分享同样重要,因此大家都有自己的笔记账号和社交账号。但为什么这两者不能合二为一呢? Leanote 做到了将二者无缝衔接。
* 一套完整的、全平台覆盖的软件套装包括了web、桌面、安卓、IOS设备而且全部开源
* 还有...
## 3. 获取Leanote
Leanote云笔记产品包括: Leanote Web & Server(即本仓库), 桌面客户端, IOS, android. 4端全部开源!
如果想试用我们的产品,欢迎在 https://leanote.com 上注册, Leanote团队为你提供稳定可靠的服务。
担心服务厂商如何处理你的个人数据吗你可以下载Leanote安装在自己的服务器上, 通过Leanote客户端连接与自建服务同步数据。
这里详细整理了Leanote二进版和Leanote开发版的安装教程, 请移步至:
* Leanote二进制详细安装教程:
* [Windows](https://github.com/leanote/leanote/wiki/Leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B---Windows)
* [Mac, Linux](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* Leanote源码详细安装教程:
* [Windows](https://github.com/leanote/leanote/wiki/Leanote-%E6%BA%90%E7%A0%81%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B----Windows)
* [Mac, Linux](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
## 4. 相关文档
更多详细的安装说明、问题处理和配置说明文档,请查看 [wiki](https://github.com/leanote/leanote/wiki)。
## 5. 如何对Leanote进行二次开发
如果您有兴趣基于Leanote二次开发请查看 [How-to-develop-Leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)。
## 6. 贡献者
在此对向Leanote贡献力量的[贡献者们](https://github.com/leanote/leanote/graphs/contributors) 表示感谢。Leanote因有你们而更完美!
## 7. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到Leanote。
有任何问题或建议, 请先搜索[issue](https://github.com/leanote/leanote/issues)区是否已经有解决方法。如果没有欢迎提交新issue。
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善Leanote。
## 8. 捐赠
如果您喜欢我们的产品,请考虑支持我们, [捐赠Leanote](http://leanote.org/#donate)。
感谢[这些捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
## 9. 其它相关项目
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
* [Leanote iOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/leanote/leanote-android), 开发阶段
欢迎加入我们!
## 联系&加入我们
* Email: leanote@leanote.com
* [Leanote 社区](http://bbs.leanote.com)
* [QQ群](http://leanote.leanote.com/post/Leanote-groups)
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)

View File

@@ -1,73 +0,0 @@
# Leanote
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://travis-ci.org/leanote/leanote.svg)](https://travis-ci.org/leanote/leanote)
## 1. 介绍
Leanote, 不只是笔记!
![leanote.png](leanote.png "")
**特性**
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
* 协作: 在分享的同时也可以与好友一起协作知识.
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
## 2. 为什么我们要创建leanote?
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
* 我们是markdown的爱好者, 可是evernote竟然没有.
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
* 还有...
## 3.安装leanote
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
## 4. 如何对leanote进行二次开发
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
## 5 相关文档
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
更多文档请查看 [wiki](https://github.com/leanote/leanote/wiki).
## 6. 贡献者
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
## 7. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
有任何问题或建议, 欢迎提交[issue](https://github.com/leanote/leanote/issues).
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
## 8. 捐赠
支持我们, [捐赠Leanote](http://leanote.org/#donate). 感谢[捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
## 9. 其它相关项目
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
* [Leanote IOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/Dminter/leanote-android-client), 开发阶段
欢迎加入我们!
## 联系&加入我们
* Email: leanote@leanote.com
* [leanote 社区](http://bbs.leanote.com)
* QQ群: 158716820, 256076853
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
----------------------------------------------------------------
[English](README.md)

26
Vendor.md Executable file
View File

@@ -0,0 +1,26 @@
# Vendor
脱离 revel 每次升级不向下兼容 的控制!! 基于revel 0.18
## Install leanote_revel cmd
```
go install github.com/leanote/leanote/cmd/leanote_revel
leanote_revel run github.com/leanote/leanote
````
## build leanote
在当前目录生成了leanote二进制文件
```
go build -o ./leanote github.com/leanote/leanote/app/tmp
```
## 运行leanote
其中-importPath是必须的
```
./leanote -importPath=github.com/leanote/leanote -runMode=prod -port=9000
```

View File

@@ -1,9 +1,9 @@
package main
import (
"github.com/revel/revel"
"github.com/revel/cmd/harness"
"fmt"
"github.com/revel/cmd/harness"
"github.com/revel/revel"
)
func main() {
@@ -15,5 +15,5 @@ func main() {
panic(err)
}
fmt.Println("Ok")
// panicOnError(reverr, "Failed to build")
}
// panicOnError(reverr, "Failed to build")
}

View File

@@ -16,18 +16,18 @@ type Album struct {
// 图片管理, iframe
func (c Album) Index() revel.Result {
c.SetLocale();
c.SetLocale()
return c.RenderTemplate("album/index.html")
}
// all albums by userId
func (c Album) GetAlbums() revel.Result {
re := albumService.GetAlbums(c.GetUserId())
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c Album) DeleteAlbum(albumId string) revel.Result {
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
return c.RenderJson(info.Re{Ok: re, Msg: msg})
return c.RenderJSON(info.Re{Ok: re, Msg: msg})
}
// add album
@@ -40,13 +40,13 @@ func (c Album) AddAlbum(name string) revel.Result {
re := albumService.AddAlbum(album)
if re {
return c.RenderJson(album)
return c.RenderJSON(album)
} else {
return c.RenderJson(false)
return c.RenderJSON(false)
}
}
// update alnum name
func (c Album) UpdateAlbum(albumId, name string) revel.Result {
return c.RenderJson(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
return c.RenderJSON(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
}

View File

@@ -2,18 +2,18 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "encoding/json"
"archive/tar"
"compress/gzip"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"io"
"io/ioutil"
"os"
"strings"
"time"
"io"
"fmt"
"archive/tar"
"compress/gzip"
)
// 附件
@@ -24,65 +24,73 @@ type Attach struct {
// 上传附件
func (c Attach) UploadAttach(noteId string) revel.Result {
re := c.uploadAttach(noteId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c Attach) uploadAttach(noteId string) (re info.Re) {
var fileId = ""
var resultMsg = "error" // 错误信息
var Ok = false
var fileInfo info.Attach
re = info.NewRe()
defer func() {
re.Id = fileId // 只是id, 没有其它信息
re.Msg = resultMsg
re.Ok = Ok
re.Item = fileInfo
}()
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(noteId, c.GetUserId()) {
return re
}
file, handel, err := c.Request.FormFile("file")
if err != nil {
return re
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
var data []byte
c.Params.Bind(&data, "file")
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// return re
// }
// defer file.Close()
// data, err := ioutil.ReadAll(file)
if data == nil || len(data) == 0 {
return re
}
// > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize");
maxFileSize := configService.GetUploadSize("uploadAttachSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
if float64(len(data)) > maxFileSize*float64(1024*1024) {
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
return re
}
// 生成上传路径
filePath := "files/" + c.GetUserId() + "/attachs"
dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755)
// filePath := "files/" + c.GetUserId() + "/attachs"
newGuid := NewGuid()
filePath := "files/" + GetRandomFilePath(c.GetUserId(), newGuid) + "/attachs"
dir := revel.BasePath + "/" + filePath
err := os.MkdirAll(dir, 0755)
if err != nil {
return re
}
handel := c.Params.Files["file"][0]
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename) // .doc
filename = NewGuid() + ext
toPath := dir + "/" + filename;
filename = newGuid + ext
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return re
}
// add File to db
fileType := ""
if ext != "" {
@@ -90,22 +98,22 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
}
filesize := GetFilesize(toPath)
fileInfo = info.Attach{Name: filename,
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
UploadUserId: c.GetObjectUserId(),
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
id := bson.NewObjectId();
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
id := bson.NewObjectId()
fileInfo.AttachId = id
fileId = id.Hex()
Ok, resultMsg = attachService.AddAttach(fileInfo, false)
if resultMsg != "" {
resultMsg = c.Message(resultMsg)
}
fileInfo.Path = ""; // 不要返回
fileInfo.Path = "" // 不要返回
if Ok {
resultMsg = "success"
}
@@ -116,7 +124,7 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
func (c Attach) DeleteAttach(attachId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
return c.RenderJson(re)
return c.RenderJSON(re)
}
// get all attachs by noteId
@@ -124,21 +132,21 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
re := info.NewRe()
re.Ok = true
re.List = attachService.ListAttachs(noteId, c.GetUserId())
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 下载附件
// 权限判断
func (c Attach) Download(attachId string) revel.Result {
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
attach := attachService.GetAttach(attachId, c.GetUserId()) // 得到路径
path := attach.Path
if path == "" {
return c.RenderText("")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
}
func (c Attach) DownloadAll(noteId string) revel.Result {
@@ -151,69 +159,75 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
if attachs == nil || len(attachs) == 0 {
return c.RenderText("")
}
/*
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
*/
filename := note.Title + ".tar.gz"
if note.Title == "" {
filename = "all.tar.gz"
}
dir := revel.BasePath + "/files/attach_all"
if !MkdirAll(dir) {
return c.RenderText("error")
}
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
fw, err := os.Create(dir + "/" + filename)
if err != nil {
return c.RenderText("error")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}

View File

@@ -1,10 +1,11 @@
package controllers
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "strconv"
"github.com/revel/revel"
"strings"
// "strconv"
)
// 用户登录/注销/找回密码
@@ -16,29 +17,29 @@ type Auth struct {
//--------
// 登录
func (c Auth) Login(email, from string) revel.Result {
c.RenderArgs["title"] = c.Message("login")
c.RenderArgs["subTitle"] = c.Message("login")
c.RenderArgs["email"] = email
c.RenderArgs["from"] = from
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
sessionId := c.Session.Id()
c.ViewArgs["title"] = c.Message("login")
c.ViewArgs["subTitle"] = c.Message("login")
c.ViewArgs["email"] = email
c.ViewArgs["from"] = from
c.ViewArgs["openRegister"] = configService.IsOpenRegister()
sessionId := c.Session.ID()
if sessionService.LoginTimesIsOver(sessionId) {
c.RenderArgs["needCaptcha"] = true
c.ViewArgs["needCaptcha"] = true
}
c.SetLocale()
if c.Has("demo") {
c.RenderArgs["demo"] = true
c.RenderArgs["email"] = "demo@leanote.com"
c.ViewArgs["demo"] = true
c.ViewArgs["email"] = "demo@leanote.com"
}
return c.RenderTemplate("home/login.html")
}
// 为了demo和register
func (c Auth) doLogin(email, pwd string) revel.Result {
sessionId := c.Session.Id()
sessionId := c.Session.ID()
var msg = ""
userInfo, err := authService.Login(email, pwd)
@@ -48,15 +49,15 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
} else {
c.SetSession(userInfo)
sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.Re{Ok: true})
}
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
return c.RenderJSON(info.Re{Ok: true})
}
return c.RenderJSON(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
}
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
sessionId := c.Session.Id()
sessionId := c.Session.ID()
var msg = ""
// > 5次需要验证码, 直到登录成功
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
msg = "captchaError"
@@ -66,18 +67,19 @@ func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
sessionService.IncrLoginTimes(sessionId)
} else {
} else {
c.SetSession(userInfo)
sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.Re{Ok: true})
}
return c.RenderJSON(info.Re{Ok: true})
}
}
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
return c.RenderJSON(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
}
// 注销
func (c Auth) Logout() revel.Result {
sessionId := c.Session.Id()
sessionId := c.Session.ID()
sessionService.Clear(sessionId)
c.ClearSession()
return c.Redirect("/login")
@@ -90,8 +92,8 @@ func (c Auth) Demo() revel.Result {
userInfo, err := authService.Login(email, pwd)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
} else {
return c.RenderJSON(info.Re{Ok: false})
} else {
c.SetSession(userInfo)
return c.Redirect("/note")
}
@@ -105,75 +107,81 @@ func (c Auth) Register(from, iu string) revel.Result {
return c.Redirect("/index")
}
c.SetLocale()
c.RenderArgs["from"] = from
c.RenderArgs["iu"] = iu
c.RenderArgs["title"] = c.Message("register")
c.RenderArgs["subTitle"] = c.Message("register")
c.ViewArgs["from"] = from
c.ViewArgs["iu"] = iu
c.ViewArgs["title"] = c.Message("register")
c.ViewArgs["subTitle"] = c.Message("register")
return c.RenderTemplate("home/register.html")
}
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
if !configService.IsOpenRegister() {
return c.Redirect("/index")
}
re := info.NewRe();
re := info.NewRe()
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
email = strings.ToLower(email)
// 注册
re.Ok, re.Msg = authService.Register(email, pwd, iu)
// 注册成功, 则立即登录之
if re.Ok {
c.doLogin(email, pwd)
}
return c.RenderRe(re)
}
//--------
// 找回密码
func (c Auth) FindPassword() revel.Result {
c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword")
c.SetLocale()
c.ViewArgs["title"] = c.Message("findPassword")
c.ViewArgs["subTitle"] = c.Message("findPassword")
return c.RenderTemplate("home/find_password.html")
}
func (c Auth) DoFindPassword(email string) revel.Result {
pwdService.FindPwd(email)
re := info.NewRe()
re.Ok = true
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 点击链接后, 先验证之
func (c Auth) FindPassword2(token string) revel.Result {
c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword")
c.SetLocale()
c.ViewArgs["title"] = c.Message("findPassword")
c.ViewArgs["subTitle"] = c.Message("findPassword")
if token == "" {
return c.RenderTemplate("find_password2_timeout.html")
}
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd)
if !ok {
return c.RenderTemplate("home/find_password2_timeout.html")
}
c.RenderArgs["findPwd"] = findPwd
c.RenderArgs["title"] = c.Message("updatePassword")
c.RenderArgs["subTitle"] = c.Message("updatePassword")
c.ViewArgs["findPwd"] = findPwd
c.ViewArgs["title"] = c.Message("updatePassword")
c.ViewArgs["subTitle"] = c.Message("updatePassword")
return c.RenderTemplate("home/find_password2.html")
}
// 找回密码修改密码
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
re := info.NewRe();
re := info.NewRe()
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
// 修改之

View File

@@ -1,17 +1,18 @@
package controllers
import (
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
"encoding/json"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
"bytes"
"math"
"strconv"
"strings"
"bytes"
)
// 公用Controller, 其它Controller继承它
@@ -19,6 +20,11 @@ type BaseController struct {
*revel.Controller
}
// 覆盖revel.Message
func (c *BaseController) Message(message string, args ...interface{}) (value string) {
return i18n.Message(c.Request.Locale, message, args...)
}
func (c BaseController) GetUserId() string {
if userId, ok := c.Session["UserId"]; ok {
return userId
@@ -56,29 +62,29 @@ func (c BaseController) GetUsername() string {
// 得到用户信息
func (c BaseController) GetUserInfo() info.User {
if userId, ok := c.Session["UserId"]; ok && userId != "" {
return userService.GetUserInfo(userId);
return userService.GetUserInfo(userId)
/*
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
mdEditorWidth, _ := strconv.Atoi(c.Session["MdEditorWidth"])
LogJ(c.Session)
user := info.User{UserId: bson.ObjectIdHex(userId),
Email: c.Session["Email"],
Logo: c.Session["Logo"],
Username: c.Session["Username"],
UsernameRaw: c.Session["UsernameRaw"],
Theme: c.Session["Theme"],
NotebookWidth: notebookWidth,
NoteListWidth: noteListWidth,
MdEditorWidth: mdEditorWidth,
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
mdEditorWidth, _ := strconv.Atoi(c.Session["MdEditorWidth"])
LogJ(c.Session)
user := info.User{UserId: bson.ObjectIdHex(userId),
Email: c.Session["Email"],
Logo: c.Session["Logo"],
Username: c.Session["Username"],
UsernameRaw: c.Session["UsernameRaw"],
Theme: c.Session["Theme"],
NotebookWidth: notebookWidth,
NoteListWidth: noteListWidth,
MdEditorWidth: mdEditorWidth,
}
if c.Session["Verified"] == "1" {
user.Verified = true
}
if c.Session["Verified"] == "1" {
user.Verified = true
}
if c.Session["LeftIsMin"] == "1" {
user.LeftIsMin = true
}
return user
if c.Session["LeftIsMin"] == "1" {
user.LeftIsMin = true
}
return user
*/
}
return info.User{}
@@ -86,7 +92,7 @@ func (c BaseController) GetUserInfo() info.User {
func (c BaseController) GetUserAndBlogUrl() info.UserAndBlogUrl {
if userId, ok := c.Session["UserId"]; ok && userId != "" {
return userService.GetUserAndBlogUrl(userId);
return userService.GetUserAndBlogUrl(userId)
}
return info.UserAndBlogUrl{}
}
@@ -107,16 +113,16 @@ func (c BaseController) SetSession(userInfo info.User) {
c.Session["UsernameRaw"] = userInfo.UsernameRaw
c.Session["Theme"] = userInfo.Theme
c.Session["Logo"] = userInfo.Logo
c.Session["NotebookWidth"] = strconv.Itoa(userInfo.NotebookWidth)
c.Session["NoteListWidth"] = strconv.Itoa(userInfo.NoteListWidth)
if userInfo.Verified {
c.Session["Verified"] = "1"
} else {
c.Session["Verified"] = "0"
}
if userInfo.LeftIsMin {
c.Session["LeftIsMin"] = "1"
} else {
@@ -139,8 +145,8 @@ func (c BaseController) UpdateSession(key, value string) {
// 返回json
func (c BaseController) Json(i interface{}) string {
// b, _ := json.MarshalIndent(i, "", " ")
b, _ := json.Marshal(i)
// b, _ := json.MarshalIndent(i, "", " ")
b, _ := json.Marshal(i)
return string(b)
}
@@ -157,9 +163,9 @@ func (c BaseController) GetPage() int {
// 判断是否含有某参数
func (c BaseController) Has(key string) bool {
if _, ok := c.Params.Values[key]; ok {
return true;
return true
}
return false;
return false
}
/*
@@ -169,42 +175,46 @@ func (c Blog) GetPage(page, count int, list interface{}) info.Page {
*/
func (c BaseController) GetTotalPage(page, count int) int {
return int(math.Ceil(float64(count)/float64(page)))
return int(math.Ceil(float64(count) / float64(page)))
}
//-------------
func (c BaseController) E404() revel.Result {
c.RenderArgs["title"] = "404";
c.ViewArgs["title"] = "404"
return c.NotFound("", nil)
}
// 设置本地
func (c BaseController) SetLocale() string {
locale := string(c.Request.Locale) // zh-CN
// lang := locale
// if strings.Contains(locale, "-") {
// pos := strings.Index(locale, "-")
// lang = locale[0:pos]
// }
// if lang != "zh" && lang != "en" {
// lang = "en"
// }
lang := locale
if strings.Contains(locale, "-") {
pos := strings.Index(locale, "-")
lang = locale[0:pos]
if !i18n.HasLang(locale) {
lang = i18n.GetDefaultLang()
}
if lang != "zh" && lang != "en" {
lang = "en";
}
c.RenderArgs["locale"] = lang;
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
c.RenderArgs["noteUrl"] = configService.GetNoteUrl()
c.ViewArgs["locale"] = lang
c.ViewArgs["siteUrl"] = configService.GetSiteUrl()
c.ViewArgs["blogUrl"] = configService.GetBlogUrl()
c.ViewArgs["leaUrl"] = configService.GetLeaUrl()
c.ViewArgs["noteUrl"] = configService.GetNoteUrl()
return lang
}
// 设置userInfo
func (c BaseController) SetUserInfo() info.User {
userInfo := c.GetUserInfo()
c.RenderArgs["userInfo"] = userInfo
if(userInfo.Username == configService.GetAdminUsername()) {
c.RenderArgs["isAdmin"] = true
c.ViewArgs["userInfo"] = userInfo
if userInfo.Username == configService.GetAdminUsername() {
c.ViewArgs["isAdmin"] = true
}
return userInfo
}
@@ -220,12 +230,12 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
tpl := &revel.RenderTemplateResult{
Template: template,
RenderArgs: c.RenderArgs, // 把args给它
ViewArgs: c.ViewArgs, // 把args给它
}
var buffer bytes.Buffer
tpl.Template.Render(&buffer, c.RenderArgs)
return buffer.String();
tpl.Template.Render(&buffer, c.ViewArgs)
return buffer.String()
}
// json, result
@@ -234,7 +244,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
func (c BaseController) RenderRe(re info.Re) revel.Result {
oldMsg := re.Msg
if re.Msg != "" {
if(strings.Contains(re.Msg, "-")) {
if strings.Contains(re.Msg, "-") {
msgAndValues := strings.Split(re.Msg, "-")
if len(msgAndValues) == 2 {
re.Msg = c.Message(msgAndValues[0], msgAndValues[1])
@@ -253,5 +263,5 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
if strings.HasPrefix(re.Msg, "???") {
re.Msg = oldMsg
}
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -6,7 +6,7 @@ import (
// "encoding/json"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/blog"
"gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/types"
@@ -49,19 +49,19 @@ $.bootstrapJsUrl
func (c Blog) render(templateName string, themePath string) revel.Result {
isPreview := false
if c.RenderArgs["isPreview"] != nil {
themePath2 := c.RenderArgs["themePath"]
if c.ViewArgs["isPreview"] != nil {
themePath2 := c.ViewArgs["themePath"]
if themePath2 == nil {
return c.E404()
}
isPreview = true
themePath = themePath2.(string)
c.setPreviewUrl()
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"];
c.ViewArgs["themeInfo"] = c.ViewArgs["themeInfoPreview"]
}
return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
return blog.RenderTemplate(templateName, c.ViewArgs, revel.BasePath+"/"+themePath, isPreview)
}
// 404
@@ -77,7 +77,7 @@ func (c Blog) e404(themePath string) revel.Result {
// life.leanote.com
// lealife.com
func (c Blog) domain() (ok bool, userBlog info.UserBlog) {
host := c.Request.Request.Host // a.cc.com:9000
host := c.Request.Host // a.cc.com:9000
hostArr := strings.Split(host, ".")
if strings.Contains(host, configService.GetDefaultDomain()) {
// 有二级域名 a.leanoe.com 3个
@@ -113,38 +113,38 @@ func (c Blog) setPreviewUrl() {
themeId := c.Session["themeId"]
theme := themeService.GetTheme(userId, themeId)
siteUrl := configService.GetSiteUrl()
blogUrl := siteUrl + "/preview" // blog.leanote.com
// siteUrl := configService.GetSiteUrl()
blogUrl := "/preview" // blog.leanote.com
indexUrl = blogUrl + "/" + userIdOrEmail
cateUrl = blogUrl + "/cate/" + userIdOrEmail // /notebookId
postUrl = blogUrl + "/post/" + userIdOrEmail // /xxxxx
postUrl = blogUrl + "/post/" + userIdOrEmail // /xxxxx
searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/singleId
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/singleId
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
c.RenderArgs["indexUrl"] = indexUrl
c.RenderArgs["cateUrl"] = cateUrl
c.RenderArgs["postUrl"] = postUrl
c.RenderArgs["searchUrl"] = searchUrl
c.RenderArgs["singleUrl"] = singleUrl // 单页
c.RenderArgs["archiveUrl"] = archiveUrl
c.RenderArgs["archivesUrl"] = archiveUrl // 别名
c.RenderArgs["tagsUrl"] = tagsUrl
c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail
c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"]
c.ViewArgs["indexUrl"] = indexUrl
c.ViewArgs["cateUrl"] = cateUrl
c.ViewArgs["postUrl"] = postUrl
c.ViewArgs["searchUrl"] = searchUrl
c.ViewArgs["singleUrl"] = singleUrl // 单页
c.ViewArgs["archiveUrl"] = archiveUrl
c.ViewArgs["archivesUrl"] = archiveUrl // 别名
c.ViewArgs["tagsUrl"] = tagsUrl
c.ViewArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail
c.ViewArgs["tagUrl"] = c.ViewArgs["tagPostsUrl"]
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
c.RenderArgs["themeBaseUrl"] = "/" + theme.Path
c.ViewArgs["themeBaseUrl"] = "/" + theme.Path
}
// 各种地址设置
func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
// 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com
host := c.Request.Request.Host
var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
// host := c.Request.Request.Host
// var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
// staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com
// life.leanote.com, lealife.com
siteUrl := configService.GetSiteUrl()
@@ -152,36 +152,36 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
// 分类
// 搜索
// 查看
c.RenderArgs["siteUrl"] = siteUrl
c.RenderArgs["indexUrl"] = blogUrls.IndexUrl
c.RenderArgs["cateUrl"] = blogUrls.CateUrl
c.RenderArgs["postUrl"] = blogUrls.PostUrl
c.RenderArgs["searchUrl"] = blogUrls.SearchUrl
c.RenderArgs["singleUrl"] = blogUrls.SingleUrl // 单页
c.RenderArgs["archiveUrl"] = blogUrls.ArchiveUrl
c.RenderArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名
c.RenderArgs["tagsUrl"] = blogUrls.TagsUrl
c.RenderArgs["tagPostsUrl"] = blogUrls.TagPostsUrl
c.RenderArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名
c.ViewArgs["siteUrl"] = siteUrl
c.ViewArgs["indexUrl"] = blogUrls.IndexUrl
c.ViewArgs["cateUrl"] = blogUrls.CateUrl
c.ViewArgs["postUrl"] = blogUrls.PostUrl
c.ViewArgs["searchUrl"] = blogUrls.SearchUrl
c.ViewArgs["singleUrl"] = blogUrls.SingleUrl // 单页
c.ViewArgs["archiveUrl"] = blogUrls.ArchiveUrl
c.ViewArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名
c.ViewArgs["tagsUrl"] = blogUrls.TagsUrl
c.ViewArgs["tagPostsUrl"] = blogUrls.TagPostsUrl
c.ViewArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
c.ViewArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
// 其它static js
c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js"
c.ViewArgs["jQueryUrl"] = "/js/jquery-1.9.0.min.js"
c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js"
c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css"
c.ViewArgs["prettifyJsUrl"] = "/js/google-code-prettify/prettify.js"
c.ViewArgs["prettifyCssUrl"] = "/js/google-code-prettify/prettify.css"
c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js"
c.ViewArgs["blogCommonJsUrl"] = "/public/blog/js/common.js"
c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css"
c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js"
c.ViewArgs["shareCommentCssUrl"] = "/public/blog/css/share_comment.css"
c.ViewArgs["shareCommentJsUrl"] = "/public/blog/js/share_comment.js"
c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css"
c.ViewArgs["fontAwesomeUrl"] = "/css/font-awesome-4.2.0/css/font-awesome.css"
c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css"
c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js"
c.ViewArgs["bootstrapCssUrl"] = "/css/bootstrap.css"
c.ViewArgs["bootstrapJsUrl"] = "/js/bootstrap-min.js"
}
// 笔记本分类
@@ -220,7 +220,7 @@ func (c Blog) getCates(userBlog info.UserBlog) {
}
}
}
// 之后添加没有排序的
for _, n := range notebooks {
id := n.NotebookId.Hex()
@@ -234,19 +234,19 @@ func (c Blog) getCates(userBlog info.UserBlog) {
i++
}
}
// LogJ(">>")
// LogJ(cates)
// LogJ(">>")
// LogJ(cates)
// 建立层级
hasParent := map[string]bool{} // 有父的cate
for _, cate := range cates {
parentCateId := cate.ParentCateId
if parentCateId != "" {
if parentCate, ok := cateMap[parentCateId]; ok {
// Log("________")
// LogJ(parentCate)
// LogJ(cate)
// Log("________")
// LogJ(parentCate)
// LogJ(cate)
if parentCate.Children == nil {
parentCate.Children = []*info.Cate{cate}
} else {
@@ -256,7 +256,7 @@ func (c Blog) getCates(userBlog info.UserBlog) {
}
}
}
// 得到没有父的cate, 作为第一级cate
catesTree := []*info.Cate{}
for _, cate := range cates {
@@ -264,9 +264,9 @@ func (c Blog) getCates(userBlog info.UserBlog) {
catesTree = append(catesTree, cate)
}
}
c.RenderArgs["cates"] = cates
c.RenderArgs["catesTree"] = catesTree
c.ViewArgs["cates"] = cates
c.ViewArgs["catesTree"] = catesTree
}
// 单页
@@ -281,7 +281,7 @@ func (c Blog) getSingles(userId string) {
singles2[i] = map[string]string{"title": page["Title"], "singleId": page["SingleId"]}
}
*/
c.RenderArgs["singles"] = singles
c.ViewArgs["singles"] = singles
}
// $.blog = {userId, title, subTitle, desc, openComment, }
@@ -300,11 +300,11 @@ func (c Blog) setBlog(userBlog info.UserBlog, userInfo info.User) {
"SubDomain": userBlog.SubDomain,
"Domain": userBlog.Domain,
}
c.RenderArgs["blogInfo"] = blogInfo
c.ViewArgs["blogInfo"] = blogInfo
}
func (c Blog) setPaging(pageInfo info.Page) {
c.RenderArgs["paging"] = pageInfo
c.ViewArgs["paging"] = pageInfo
}
// 公共
@@ -315,13 +315,13 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
return false, userBlog
}
}
// c.RenderArgs["userInfo"] = userInfo
// c.ViewArgs["userInfo"] = userInfo
// 最新笔记
_, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc)
c.RenderArgs["recentPosts"] = blogService.FixBlogs(recentBlogs)
c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"]
c.RenderArgs["tags"] = blogService.GetBlogTags(userId)
c.ViewArgs["recentPosts"] = blogService.FixBlogs(recentBlogs)
c.ViewArgs["latestPosts"] = c.ViewArgs["recentPosts"]
c.ViewArgs["tags"] = blogService.GetBlogTags(userId)
// 语言, url地址
c.SetLocale()
@@ -331,7 +331,7 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
userBlog = blogService.GetUserBlog(userId)
}
c.setBlog(userBlog, userInfo)
// c.RenderArgs["userBlog"] = userBlog
// c.ViewArgs["userBlog"] = userBlog
// 分类导航
c.getCates(userBlog)
@@ -342,16 +342,16 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
c.setUrl(userBlog, userInfo)
// 当前分类Id, 全设为""
c.RenderArgs["curCateId"] = ""
c.RenderArgs["curSingleId"] = ""
c.ViewArgs["curCateId"] = ""
c.ViewArgs["curSingleId"] = ""
// 得到主题信息
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
c.RenderArgs["themeInfo"] = themeInfo
// Log(">>")
// Log(userBlog.Style)
// Log(userBlog.ThemeId.Hex())
c.ViewArgs["themeInfo"] = themeInfo
// Log(">>")
// Log(userBlog.Style)
// Log(userBlog.ThemeId.Hex())
return true, userBlog
}
@@ -404,9 +404,9 @@ func (c Blog) Tags(userIdOrEmail string) (re revel.Result) {
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
c.RenderArgs["curIsTags"] = true
c.ViewArgs["curIsTags"] = true
tags := blogService.GetBlogTags(userId)
c.RenderArgs["tags"] = tags
c.ViewArgs["tags"] = tags
return c.render("tags.html", userBlog.ThemePath)
}
@@ -443,15 +443,15 @@ func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) {
tag = userIdOrEmail
}
c.RenderArgs["curIsTagPosts"] = true
c.RenderArgs["curTag"] = tag
c.ViewArgs["curIsTagPosts"] = true
c.ViewArgs["curTag"] = tag
page := c.GetPage()
pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
c.setPaging(pageInfo)
c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
tagPostsUrl := c.RenderArgs["tagPostsUrl"].(string)
c.RenderArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag
c.ViewArgs["posts"] = blogService.FixBlogs(blogs)
tagPostsUrl := c.ViewArgs["tagPostsUrl"].(string)
c.ViewArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag
return c.render("tag_posts.html", userBlog.ThemePath)
}
@@ -490,16 +490,16 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re
}
arcs := blogService.ListBlogsArchive(userId, notebookId, year, month, "PublicTime", false)
c.RenderArgs["archives"] = arcs
c.ViewArgs["archives"] = arcs
c.RenderArgs["curIsArchive"] = true
c.ViewArgs["curIsArchive"] = true
if notebookId != "" {
notebook := notebookService.GetNotebookById(notebookId)
c.RenderArgs["curCateTitle"] = notebook.Title
c.RenderArgs["curCateId"] = notebookId
c.ViewArgs["curCateTitle"] = notebook.Title
c.ViewArgs["curCateId"] = notebookId
}
c.RenderArgs["curYear"] = year
c.RenderArgs["curMonth"] = month
c.ViewArgs["curYear"] = year
c.ViewArgs["curMonth"] = month
return c.render("archive.html", userBlog.ThemePath)
}
@@ -507,6 +507,7 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re
// 进入某个用户的博客
var blogPageSize = 5
var searchBlogPageSize = 30
// 分类 /cate/xxxxxxxx?notebookId=1212
func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
// 自定义域名
@@ -540,15 +541,15 @@ func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
page := c.GetPage()
pageInfo, blogs := blogService.ListBlogs(userId, notebookId2, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
blogs2 := blogService.FixBlogs(blogs)
c.RenderArgs["posts"] = blogs2
c.ViewArgs["posts"] = blogs2
c.setPaging(pageInfo)
c.RenderArgs["curCateTitle"] = notebook.Title
c.RenderArgs["curCateId"] = notebookId2
cateUrl := c.RenderArgs["cateUrl"].(string)
c.RenderArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId
c.RenderArgs["curIsCate"] = true
c.ViewArgs["curCateTitle"] = notebook.Title
c.ViewArgs["curCateId"] = notebookId2
cateUrl := c.ViewArgs["cateUrl"].(string)
c.ViewArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId
c.ViewArgs["curIsCate"] = true
return c.render("cate.html", userBlog.ThemePath)
}
@@ -593,12 +594,12 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
page := c.GetPage()
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
blogs2 := blogService.FixBlogs(blogs)
c.RenderArgs["posts"] = blogs2
c.ViewArgs["posts"] = blogs2
c.setPaging(pageInfo)
c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"]
c.ViewArgs["pagingBaseUrl"] = c.ViewArgs["indexUrl"]
c.RenderArgs["curIsIndex"] = true
c.ViewArgs["curIsIndex"] = true
return c.render("index.html", userBlog.ThemePath)
}
@@ -608,7 +609,7 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
hasDomain, userBlog := c.domain()
defer func() {
if err := recover(); err != nil {
Log(err)
// Log(err)
re = c.e404(userBlog.ThemePath)
}
}()
@@ -630,9 +631,9 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
}
post := blogService.FixBlog(blogInfo)
c.RenderArgs["post"] = post
// c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["curIsPost"] = true
c.ViewArgs["post"] = post
// c.ViewArgs["userInfo"] = userInfo
c.ViewArgs["curIsPost"] = true
// 上一篇, 下一篇
var baseTime interface{}
@@ -648,10 +649,10 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, post.NoteId, baseTime)
if prePost.NoteId != "" {
c.RenderArgs["prePost"] = prePost
c.ViewArgs["prePost"] = prePost
}
if nextPost.NoteId != "" {
c.RenderArgs["nextPost"] = nextPost
c.ViewArgs["nextPost"] = nextPost
}
return c.render("post.html", userBlog.ThemePath)
}
@@ -681,7 +682,7 @@ func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) {
panic("")
}
c.RenderArgs["single"] = map[string]interface{}{
c.ViewArgs["single"] = map[string]interface{}{
"SingleId": single.SingleId.Hex(),
"Title": single.Title,
"UrlTitle": single.UrlTitle,
@@ -689,8 +690,8 @@ func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) {
"CreatedTime": single.CreatedTime,
"UpdatedTime": single.UpdatedTime,
}
c.RenderArgs["curSingleId"] = single.SingleId.Hex()
c.RenderArgs["curIsSingle"] = true
c.ViewArgs["curSingleId"] = single.SingleId.Hex()
c.ViewArgs["curIsSingle"] = true
return c.render("single.html", userBlog.ThemePath)
}
@@ -715,7 +716,7 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) {
} else {
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
}
// c.RenderArgs["userInfo"] = userInfo
// c.ViewArgs["userInfo"] = userInfo
userId = userInfo.UserId.Hex()
var ok = false
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
@@ -726,11 +727,11 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) {
pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
c.setPaging(pageInfo)
c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
c.RenderArgs["keywords"] = keywords
searchUrl, _ := c.RenderArgs["searchUrl"].(string)
c.RenderArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords
c.RenderArgs["curIsSearch"] = true
c.ViewArgs["posts"] = blogService.FixBlogs(blogs)
c.ViewArgs["keywords"] = keywords
searchUrl, _ := c.ViewArgs["searchUrl"].(string)
c.ViewArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords
c.ViewArgs["curIsSearch"] = true
return c.render("search.html", userBlog.ThemePath)
}
@@ -740,7 +741,7 @@ func (c Blog) setRenderUserInfo(userInfo info.User) {
if userInfo.Username == "" {
userInfo.Username = userInfo.Email
}
c.RenderArgs["userInfo"] = userInfo
c.ViewArgs["userInfo"] = userInfo
}
//----------------
@@ -752,7 +753,7 @@ func (c Blog) GetPostStat(noteId string) revel.Result {
re.Ok = true
statInfo := blogService.GetBlogStat(noteId)
re.Item = statInfo
return c.RenderJson(re)
return c.RenderJSON(re)
}
// jsonP
@@ -777,7 +778,7 @@ func (c Blog) GetLikes(noteId string, callback string) revel.Result {
result["hasMoreLikedUser"] = hasMoreLikedUser
re.Item = result
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
userId := c.GetUserId()
@@ -805,13 +806,13 @@ func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
result["comments"] = comments
result["commentUserInfo"] = commentUserInfo
re.Item = result
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
func (c Blog) IncReadNum(noteId string) revel.Result {
re := info.NewRe()
re.Ok = blogService.IncReadNum(noteId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 点赞, 要用jsonp
@@ -819,7 +820,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
re := info.NewRe()
userId := c.GetUserId()
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
func (c Blog) GetComments(noteId string, callback string) revel.Result {
// 评论
@@ -833,26 +834,26 @@ func (c Blog) GetComments(noteId string, callback string) revel.Result {
result["comments"] = comments
result["commentUserInfo"] = commentUserInfo
re.Item = result
if callback != "" {
return c.RenderJsonP(callback, result)
return c.RenderJSONP(callback, result)
}
return c.RenderJson(re)
return c.RenderJSON(re)
}
// jsonp
func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result {
re := info.NewRe()
re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId())
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
// jsonp
func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content)
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
// jsonp
@@ -861,7 +862,7 @@ func (c Blog) LikeComment(commentId string, callback string) revel.Result {
ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId())
re.Ok = ok
re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num}
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}
// 显示分类的最近博客, jsonp
@@ -897,5 +898,5 @@ func (c Blog) ListCateLatest(notebookId, callback string) revel.Result {
re := info.NewRe()
re.Ok = true
re.List = blogs
return c.RenderJsonP(callback, re)
return c.RenderJSONP(callback, re)
}

View File

@@ -2,18 +2,19 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/captcha"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
// "strconv"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
// "strconv"
"net/http"
"io"
)
// 验证码服务
@@ -22,22 +23,24 @@ type Captcha struct {
}
type Ca string
func (r Ca) Apply(req *revel.Request, resp *revel.Response) {
resp.WriteHeader(http.StatusOK, "image/png")
resp.WriteHeader(http.StatusOK, "image/png")
}
func (c Captcha) Get() revel.Result {
c.Response.ContentType = "image/png"
image, str := captcha.Fetch()
image.WriteTo(c.Response.Out)
out := io.Writer(c.Response.GetWriter())
image.WriteTo(out)
sessionId := c.Session["_ID"]
// LogJ(c.Session)
// Log("------")
// Log(str)
// Log(sessionId)
Log("..")
// LogJ(c.Session)
// Log("------")
// Log(str)
// Log(sessionId)
Log("..")
sessionService.SetCaptcha(sessionId, str)
return c.Render()
}
}

View File

@@ -2,15 +2,15 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
// "encoding/json"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/netutil"
"github.com/leanote/leanote/app/info"
"gopkg.in/mgo.v2/bson"
"io/ioutil"
"os"
"fmt"
// "strconv"
// "strconv"
"strings"
)
@@ -22,11 +22,11 @@ type File struct {
// 上传的是博客logo
// TODO logo不要设置权限, 另外的目录
func (c File) UploadBlogLogo() revel.Result {
re := c.uploadImage("blogLogo", "");
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
re := c.uploadImage("blogLogo", "")
c.ViewArgs["fileUrlPath"] = re.Id
c.ViewArgs["resultCode"] = re.Code
c.ViewArgs["resultMsg"] = re.Msg
return c.RenderTemplate("file/blog_logo.html")
}
@@ -34,49 +34,51 @@ func (c File) UploadBlogLogo() revel.Result {
// 拖拉上传, pasteImage
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
func (c File) PasteImage(noteId string) revel.Result {
re := c.uploadImage("pasteImage", "");
userId := c.GetUserId()
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
// 是否是有权限协作的
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
// 复制图片之, 图片复制给noteUserId
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
} else {
// 怎么可能在这个笔记下paste图片呢?
// 正常情况下不会
re := c.uploadImage("pasteImage", "")
if noteId != "" {
userId := c.GetUserId()
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
// 是否是有权限协作的
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
// 复制图片之, 图片复制给noteUserId
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
} else {
// 怎么可能在这个笔记下paste图片呢?
// 正常情况下不会
}
}
}
}
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 头像设置
func (c File) UploadAvatar() revel.Result {
re := c.uploadImage("logo", "");
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
re := c.uploadImage("logo", "")
c.ViewArgs["fileUrlPath"] = re.Id
c.ViewArgs["resultCode"] = re.Code
c.ViewArgs["resultMsg"] = re.Msg
if re.Ok {
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
if re.Ok {
c.UpdateSession("Logo", re.Id);
c.UpdateSession("Logo", re.Id)
}
}
return c.RenderJson(re)
return c.RenderJSON(re)
}
// leaui image plugin upload image
func (c File) UploadImageLeaui(albumId string) revel.Result {
re := c.uploadImage("", albumId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 上传图片, 公用方法
@@ -95,25 +97,42 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
re.Ok = Ok
}()
file, handel, err := c.Request.FormFile("file")
if err != nil {
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// return re
// }
// defer file.Close()
var data []byte
c.Params.Bind(&data, "file")
handel := c.Params.Files["file"][0]
if data == nil || len(data) == 0 {
return re
}
defer file.Close()
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// return re
// }
// defer file.Close()
// data, err := ioutil.ReadAll(file)
// 生成上传路径
newGuid := NewGuid()
userId := c.GetUserId()
if(from == "logo" || from == "blogLogo") {
if from == "logo" || from == "blogLogo" {
fileUrlPath = "public/upload/" + Digest3(userId) + "/" + userId + "/images/logo"
} else {
fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
// fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath = "files/" + GetRandomFilePath(userId, newGuid) + "/images"
}
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
err := os.MkdirAll(dir, 0755)
if err != nil {
return re
}
@@ -122,6 +141,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
var ext string
if from == "pasteImage" {
handel.Filename = c.Message("unTitled")
ext = ".png" // TODO 可能不是png类型
} else {
_, ext = SplitFilename(filename)
@@ -132,11 +152,11 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
}
filename = newGuid + ext
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return re
}
// data, err := ioutil.ReadAll(file)
// if err != nil {
// LogJ(err)
// return re
// }
var maxFileSize float64
if from == "logo" {
@@ -180,8 +200,8 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
id := bson.NewObjectId()
fileInfo.FileId = id
fileId = id.Hex()
if(from == "logo" || from == "blogLogo") {
if from == "logo" || from == "blogLogo" {
fileId = fileUrlPath
}
@@ -197,19 +217,19 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
// get all images by userId with page
func (c File) GetImages(albumId, key string, page int) revel.Result {
re := fileService.ListImagesWithPage(c.GetUserId(), albumId, key, page, 12)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c File) UpdateImageTitle(fileId, title string) revel.Result {
re := info.NewRe()
re.Ok = fileService.UpdateImageTitle(c.GetUserId(), fileId, title)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c File) DeleteImage(fileId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
//-----------
@@ -217,13 +237,13 @@ func (c File) DeleteImage(fileId string) revel.Result {
// 输出image
// 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
path := fileService.GetFile(c.GetUserId(), fileId) // 得到路径
if path == "" {
return c.RenderText("")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderFile(file, revel.Inline) // revel.Attachment
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderFile(file, revel.Inline) // revel.Attachment
}
// 协作时复制图片到owner
@@ -231,7 +251,7 @@ func (c File) OutputImage(noteId, fileId string) revel.Result {
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
re := info.NewRe()
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 复制外网的图片
@@ -242,17 +262,18 @@ func (c File) CopyHttpImage(src string) revel.Result {
// 生成上传路径
newGuid := NewGuid()
userId := c.GetUserId()
fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderJson(re)
return c.RenderJSON(re)
}
filesize, filename, _, ok := netutil.WriteUrl(src, dir)
if !ok {
re.Msg = "copy error"
return c.RenderJson(re)
return c.RenderJSON(re)
}
// File
@@ -265,8 +286,8 @@ func (c File) CopyHttpImage(src string) revel.Result {
fileInfo.FileId = id
re.Id = id.Hex()
// re.Item = fileInfo.Path
// re.Item = fileInfo.Path
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -1,9 +1,9 @@
package controllers
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
)
// 首页
@@ -13,31 +13,32 @@ type Index struct {
}
func (c Index) Default() revel.Result {
if configService.HomePageIsAdminsBlog(){
if configService.HomePageIsAdminsBlog() {
blog := Blog{c.BaseController}
return blog.Index(configService.GetAdminUsername());
return blog.Index(configService.GetAdminUsername())
}
return c.Index()
}
// leanote展示页, 没有登录的, 或已登录明确要进该页的
func (c Index) Index() revel.Result {
c.SetUserInfo()
c.RenderArgs["title"] = "leanote"
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
c.ViewArgs["title"] = "leanote"
c.ViewArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
c.SetLocale()
return c.RenderTemplate("home/index.html");
return c.RenderTemplate("home/index.html")
}
// 建议
func (c Index) Suggestion(addr, suggestion string) revel.Result {
re := info.NewRe()
re.Ok = suggestionService.AddSuggestion(info.Suggestion{Addr: addr, UserId: c.GetObjectUserId(), Suggestion: suggestion})
// 发给我
go func() {
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: " + c.GetUserId() + " <br /> Suggestions: " + suggestion)
}();
return c.RenderJson(re)
}
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: "+c.GetUserId()+" <br /> Suggestions: "+suggestion)
}()
return c.RenderJSON(re)
}

View File

@@ -11,6 +11,6 @@ type NoteContentHistory struct {
// 得到list
func (c NoteContentHistory) ListHistories(noteId string) revel.Result {
histories := noteContentHistoryService.ListHistories(noteId, c.GetUserId())
return c.RenderJson(histories)
}
return c.RenderJSON(histories)
}

View File

@@ -11,9 +11,10 @@ import (
"regexp"
"strings"
"time"
"fmt"
"runtime"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
"fmt"
// "bytes"
// "os"
)
@@ -30,51 +31,51 @@ func (c Note) Index(noteId, online string) revel.Result {
userInfo := c.GetUserAndBlogUrl()
userId := userInfo.UserId.Hex()
// 没有登录
if userId == "" {
return c.Redirect("/login")
}
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
c.ViewArgs["openRegister"] = configService.IsOpenRegister()
// 已登录了, 那么得到所有信息
notebooks := notebookService.GetNotebooks(userId)
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
// 还需要按时间排序(DESC)得到notes
notes := []info.Note{}
noteContent := info.NoteContent{}
if len(notebooks) > 0 {
// noteId是否存在
// 是否传入了正确的noteId
hasRightNoteId := false
if IsObjectId(noteId) {
note := noteService.GetNoteById(noteId)
if note.NoteId != "" {
var noteOwner = note.UserId.Hex()
noteContent = noteService.GetNoteContent(noteId, noteOwner)
hasRightNoteId = true
c.RenderArgs["curNoteId"] = noteId
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
c.ViewArgs["curNoteId"] = noteId
c.ViewArgs["curNotebookId"] = note.NotebookId.Hex()
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
if noteOwner != c.GetUserId() {
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
// 不要获取notebook下的笔记
// 在前端下发请求
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
c.RenderArgs["curSharedUserId"] = noteOwner;
// 没有读写权限
c.ViewArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
c.ViewArgs["curSharedUserId"] = noteOwner
// 没有读写权限
} else {
hasRightNoteId = false
}
} else {
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false);
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false)
// 如果指定了某笔记, 则该笔记放在首位
lenNotes := len(notes)
if lenNotes > 1 {
@@ -84,7 +85,7 @@ func (c Note) Index(noteId, online string) revel.Result {
for _, note := range notes {
if note.NoteId.Hex() != noteId {
if i == lenNotes { // 防止越界
break;
break
}
notes2[i] = note
i++
@@ -94,40 +95,40 @@ func (c Note) Index(noteId, online string) revel.Result {
}
}
}
// 得到最近的笔记
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
c.RenderArgs["latestNotes"] = latestNotes
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
c.ViewArgs["latestNotes"] = latestNotes
}
// 没有传入笔记
// 那么得到最新笔记
if !hasRightNoteId {
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
if len(notes) > 0 {
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
c.ViewArgs["curNoteId"] = notes[0].NoteId.Hex()
}
}
}
// 当然, 还需要得到第一个notes的content
//...
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["notebooks"] = notebooks
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
c.RenderArgs["notes"] = notes
c.RenderArgs["noteContentJson"] = noteContent
c.RenderArgs["noteContent"] = noteContent.Content
c.RenderArgs["tags"] = tagService.GetTags(c.GetUserId())
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
c.ViewArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
c.ViewArgs["userInfo"] = userInfo
c.ViewArgs["notebooks"] = notebooks
c.ViewArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
c.ViewArgs["sharedUserInfos"] = sharedUserInfos
c.ViewArgs["notes"] = notes
c.ViewArgs["noteContentJson"] = noteContent
c.ViewArgs["noteContent"] = noteContent.Content
c.ViewArgs["tags"] = tagService.GetTags(c.GetUserId())
c.ViewArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
// return c.RenderTemplate("note/note.html")
if isDev, _ := revel.Config.Bool("mode.dev"); isDev && online == "" {
@@ -142,145 +143,171 @@ func (c Note) Index(noteId, online string) revel.Result {
// 否则, 转向登录页面
func (c Note) ListNotes(notebookId string) revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(notes)
return c.RenderJSON(notes)
}
// 得到trash
func (c Note) ListTrashNotes() revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(notes)
return c.RenderJSON(notes)
}
// 得到note和内容
func (c Note) GetNoteAndContent(noteId string) revel.Result {
return c.RenderJson(noteService.GetNoteAndContent(noteId, c.GetUserId()))
return c.RenderJSON(noteService.GetNoteAndContent(noteId, c.GetUserId()))
}
func (c Note) GetNoteAndContentBySrc(src string) revel.Result {
noteId, noteAndContent := noteService.GetNoteAndContentBySrc(src, c.GetUserId())
ret := info.Re{}
if noteId != "" {
ret.Ok = true
ret.Item = noteAndContent
}
return c.RenderJSON(ret)
}
// 得到内容
func (c Note) GetNoteContent(noteId string) revel.Result {
noteContent := noteService.GetNoteContent(noteId, c.GetUserId())
return c.RenderJson(noteContent)
return c.RenderJSON(noteContent)
}
// 更新note或content
// 肯定会传userId(谁的), NoteId
// 会传Title, Content, Tags, 一种或几种
type NoteOrContent struct {
NotebookId string
NoteId string
UserId string
Title string
Desc string
ImgSrc string
Tags string
Content string
Abstract string
IsNew bool
IsMarkdown bool
FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
}
// 这里不能用json, 要用post
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result {
// 新添加note
if noteOrContent.IsNew {
userId := c.GetObjectUserId();
// myUserId := userId
userId := c.GetObjectUserId()
// myUserId := userId
// 为共享新建?
if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
}
note := info.Note{UserId: userId,
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
Title: noteOrContent.Title,
Tags: strings.Split(noteOrContent.Tags, ","),
Desc: noteOrContent.Desc,
ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
note := info.Note{UserId: userId,
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
Title: noteOrContent.Title,
Src: noteOrContent.Src, // 来源
Tags: strings.Split(noteOrContent.Tags, ","),
Desc: noteOrContent.Desc,
ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown,
};
noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract};
}
noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract}
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
return c.RenderJson(note)
return c.RenderJSON(note)
}
noteUpdate := bson.M{}
needUpdateNote := false
// Desc前台传来
if c.Has("Desc") {
needUpdateNote = true
noteUpdate["Desc"] = noteOrContent.Desc;
noteUpdate["Desc"] = noteOrContent.Desc
}
if c.Has("ImgSrc") {
needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc;
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
}
if c.Has("Title") {
needUpdateNote = true
noteUpdate["Title"] = noteOrContent.Title;
noteUpdate["Title"] = noteOrContent.Title
}
if c.Has("Tags") {
needUpdateNote = true
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",");
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",")
}
// web端不控制
if needUpdateNote {
noteService.UpdateNote(c.GetUserId(),
if needUpdateNote {
noteService.UpdateNote(c.GetUserId(),
noteOrContent.NoteId, noteUpdate, -1)
}
//-------------
afterContentUsn := 0
contentOk := false
contentMsg := ""
// afterContentUsn := 0
// contentOk := false
// contentMsg := ""
if c.Has("Content") {
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.GetUserId(),
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, -1)
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
// contentOk, contentMsg, afterContentUsn =
noteService.UpdateNoteContent(c.GetUserId(),
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract,
needUpdateNote, -1, time.Now())
}
Log(afterContentUsn)
Log(contentOk)
Log(contentMsg)
return c.RenderJson(true)
// Log("usn", "afterContentUsn", afterContentUsn + "")
// Log(contentOk)
// Log(contentMsg)
return c.RenderJSON(true)
}
// 删除note/ 删除别人共享给我的笔记
// userId 是note.UserId
func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
if(!isShared) {
return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result {
if !isShared {
for _, noteId := range noteIds {
trashService.DeleteNote(noteId, c.GetUserId())
}
return c.RenderJSON(true)
}
return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
for _, noteId := range noteIds {
trashService.DeleteSharedNote(noteId, c.GetUserId())
}
return c.RenderJSON(true)
}
// 删除trash
// 删除trash, 已弃用, 用DeleteNote
func (c Note) DeleteTrash(noteId string) revel.Result {
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()));
return c.RenderJSON(trashService.DeleteTrash(noteId, c.GetUserId()))
}
// 移动note
func (c Note) MoveNote(noteId, notebookId string) revel.Result {
return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result {
userId := c.GetUserId()
for _, noteId := range noteIds {
noteService.MoveNote(noteId, notebookId, userId)
}
return c.RenderJSON(true)
}
// 复制note
func (c Note) CopyNote(noteId, notebookId string) revel.Result {
return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds))
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopyNote(noteId, notebookId, userId)
}
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJSON(re)
}
// 复制别人共享的笔记给我
func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result {
return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds))
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopySharedNote(noteId, notebookId, fromUserId, userId)
}
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJSON(re)
}
//------------
@@ -288,12 +315,13 @@ func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result
// 通过title搜索
func (c Note) SearchNote(key string) revel.Result {
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
return c.RenderJson(blogs)
return c.RenderJSON(blogs)
}
// 通过tags搜索
func (c Note) SearchNoteByTags(tags []string) revel.Result {
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
return c.RenderJson(blogs)
return c.RenderJSON(blogs)
}
// 生成PDF
@@ -301,11 +329,11 @@ func (c Note) ToPdf(noteId, appKey string) revel.Result {
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
appKeyTrue, _ := revel.Config.String("app.secret")
if appKeyTrue != appKey {
return c.RenderText("error")
return c.RenderText("auth error")
}
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
return c.RenderText("error")
return c.RenderText("no note")
}
noteUserId := note.UserId.Hex()
@@ -315,14 +343,16 @@ func (c Note) ToPdf(noteId, appKey string) revel.Result {
//------------------
// 将content的图片转换为base64
contentStr := content.Content
siteUrlPattern := configService.GetSiteUrl()
if strings.Contains(siteUrlPattern, "https") {
siteUrlPattern = strings.Replace(siteUrlPattern, "https", "https*", 1)
} else {
siteUrlPattern = strings.Replace(siteUrlPattern, "http", "https*", 1)
}
siteUrlPattern = "(?:" + siteUrlPattern + ")*"
regImage, _ := regexp.Compile(`<img .*?(src=('|")` + siteUrlPattern + `/(file/outputImage|api/file/getImage)\?fileId=([a-z0-9A-Z]{24})("|'))`)
findsImage := regImage.FindAllStringSubmatch(contentStr, -1) // 查找所有的
@@ -369,11 +399,11 @@ func (c Note) ToPdf(noteId, appKey string) revel.Result {
} else {
note.Tags = nil
}
c.RenderArgs["blog"] = note
c.RenderArgs["content"] = contentStr
c.RenderArgs["userInfo"] = userInfo
c.ViewArgs["blog"] = note
c.ViewArgs["content"] = contentStr
c.ViewArgs["userInfo"] = userInfo
userBlog := blogService.GetUserBlog(noteUserId)
c.RenderArgs["userBlog"] = userBlog
c.ViewArgs["userBlog"] = userBlog
return c.RenderTemplate("file/pdf.html")
}
@@ -394,13 +424,13 @@ func (c Note) ExportPdf(noteId string) revel.Result {
// 是否是有权限协作的
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
re.Msg = "No Perm"
return c.RenderText("error")
return c.RenderText("No Perm")
}
}
// path 判断是否需要重新生成之
guid := NewGuid()
fileUrlPath := "files/" + Digest3(noteUserId) + "/" + noteUserId + "/" + Digest2(guid) + "/images/pdf"
fileUrlPath := "files/export_pdf"
dir := revel.BasePath + "/" + fileUrlPath
if !MkdirAll(dir) {
return c.RenderText("error, no dir")
@@ -413,12 +443,16 @@ func (c Note) ExportPdf(noteId string) revel.Result {
if appKey == "" {
appKey, _ = revel.Config.String("app.secret")
}
// 生成之
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
// 默认路径
if binPath == "" {
binPath = "/usr/local/bin/wkhtmltopdf"
if runtime.GOOS == "windows" {
binPath = `C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe`
} else {
binPath = "/usr/local/bin/wkhtmltopdf"
}
}
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
@@ -428,13 +462,29 @@ func (c Note) ExportPdf(noteId string) revel.Result {
// http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html
// wkhtmltopdf参数大全
var cc string
// var cc []string
var ccWindows []string
if note.IsMarkdown {
cc = binPath + " --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
cc = binPath + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
// cc = []string{binPath, "--lowquality", "--window-status", "done", "\"" + url + "\"", "\"" + path + "\""}
ccWindows = []string{"/C", binPath, "--lowquality", "--window-status", "done", url, path}
} else {
cc = binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
cc = binPath + " --lowquality \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
// cc = []string{binPath, "--lowquality", "\"" + url + "\"", "\"" + path + "\""}
ccWindows = []string{"/C", binPath, "--lowquality", url, path}
}
cmd := exec.Command("/bin/sh", "-c", cc)
var cmd *exec.Cmd
// fmt.Println("-------1", runtime.GOOS, ccWindows)
if runtime.GOOS == "windows" {
fmt.Println(ccWindows)
// cmd = exec.Command("cmd", ccWindows...)
cmd = exec.Command(ccWindows[1], ccWindows[2:]...)
} else {
fmt.Println(cc)
cmd = exec.Command("/bin/sh", "-c", cc)
}
_, err := cmd.Output()
if err != nil {
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
@@ -456,7 +506,9 @@ func (c Note) ExportPdf(noteId string) revel.Result {
}
// 设置/取消Blog; 置顶
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
return c.RenderJson(re)
func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
for _, noteId := range noteIds {
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
}
return c.RenderJSON(true)
}

View File

@@ -1,12 +1,12 @@
package controllers
import (
"github.com/revel/revel"
"encoding/json"
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
type Notebook struct {
@@ -14,65 +14,67 @@ type Notebook struct {
}
func (c Notebook) Index(notebook info.Notebook, i int, name string) revel.Result {
return c.RenderJson(notebook)
return c.RenderJSON(notebook)
}
// 得到用户的所有笔记本
func (c Notebook) GetNotebooks() revel.Result {
re := notebookService.GetNotebooks(c.GetUserId())
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
re, msg := notebookService.DeleteNotebook(c.GetUserId(), notebookId)
return c.RenderJson(info.Re{Ok: re, Msg: msg})
return c.RenderJSON(info.Re{Ok: re, Msg: msg})
}
// 添加notebook
func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.Result {
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
Title: title,
Seq: -1,
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
Title: title,
Seq: -1,
UserId: c.GetObjectUserId()}
if(parentNotebookId != "") {
if parentNotebookId != "" {
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
}
re, notebook := notebookService.AddNotebook(notebook)
if(re) {
return c.RenderJson(notebook)
if re {
return c.RenderJSON(notebook)
} else {
return c.RenderJson(false)
return c.RenderJSON(false)
}
}
// 修改标题
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
return c.RenderJSON(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
}
// 排序
// 无用
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
}
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
// return c.RenderJSON(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
// }
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
type DragNotebooksInfo struct {
CurNotebookId string
CurNotebookId string
ParentNotebookId string
Siblings []string
Siblings []string
}
// 传过来的data是JSON.stringfy数据
func (c Notebook) DragNotebooks(data string) revel.Result {
info := DragNotebooksInfo{}
json.Unmarshal([]byte(data), &info)
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
return c.RenderJSON(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
}
// 设置notebook <-> blog
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -2,13 +2,13 @@ package controllers
import (
"github.com/revel/revel"
// "strings"
// "time"
// "strings"
// "time"
// "encoding/json"
// "github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/lea/blog"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/lea/blog"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "math"
@@ -23,7 +23,7 @@ type Preview struct {
// 得到要预览的主题绝对路径
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
if themeId != "" {
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了, 待优化, 有时会取不到
} else {
themeId = c.Session["themeId"] // 直接从session中获取
}
@@ -31,11 +31,11 @@ func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
return false
}
theme := themeService.GetTheme(c.GetUserId(), themeId)
c.RenderArgs["isPreview"] = true
c.RenderArgs["themeId"] = themeId
c.RenderArgs["themeInfoPreview"] = theme.Info
c.RenderArgs["themePath"] = theme.Path
c.ViewArgs["isPreview"] = true
c.ViewArgs["themeId"] = themeId
c.ViewArgs["themeInfoPreview"] = theme.Info
c.ViewArgs["themePath"] = theme.Path
if theme.Path == "" {
return false
}
@@ -47,7 +47,7 @@ func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
return c.E404()
}
return c.Blog.Index(c.GetUserId())
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
// return blog.RenderTemplate("index.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(themeId))
}
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
@@ -61,43 +61,43 @@ func (c Preview) Tags(userIdOrEmail string) revel.Result {
return c.E404()
}
return c.Blog.Tags(c.GetUserId())
// if tag == "" {
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// }
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// if tag == "" {
// return blog.RenderTemplate("tags.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
// }
// return blog.RenderTemplate("tag_posts.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("archive.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Cate(userIdOrEmail, notebookId)
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("cate.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Post(userIdOrEmail, noteId)
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("view.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Single(userIdOrEmail, singleId)
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("single.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Search(c.GetUserId(), keywords)
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
// return blog.RenderTemplate("search.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
}

View File

@@ -2,13 +2,13 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
)
type Share struct {
@@ -19,41 +19,41 @@ type Share struct {
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享
myEmail := c.GetEmail();
myEmail := c.GetEmail()
for _, email := range emails {
if email == "" {
continue;
continue
}
if(myEmail != email) {
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email);
if myEmail != email {
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email)
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else {
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
}
}
}
return c.RenderJson(status)
return c.RenderJSON(status)
}
// 添加共享notebook
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享
myEmail := c.GetEmail();
myEmail := c.GetEmail()
for _, email := range emails {
if email == "" {
continue;
continue
}
if(myEmail != email) {
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email);
if myEmail != email {
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email)
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else {
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
}
}
}
return c.RenderJson(status)
return c.RenderJSON(status)
}
// 得到notes
@@ -62,11 +62,11 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
// 表示是默认笔记本, 不是某个特定notebook的共享
var notes []info.ShareNoteWithPerm
if notebookId == "" {
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false);
return c.RenderJson(notes)
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false)
return c.RenderJSON(notes)
} else {
// 有notebookId的
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false));
return c.RenderJSON(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false))
}
}
@@ -74,7 +74,7 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
// sharedUserId 是谁的笔记
func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
noteContent := shareService.GetShareNoteContent(noteId, c.GetUserId(), sharedUserId)
return c.RenderJson(noteContent)
return c.RenderJSON(noteContent)
}
// 查看note的分享信息
@@ -83,106 +83,110 @@ func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
// 还要查看该note的notebookId分享的信息
func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
note := noteService.GetNote(noteId, c.GetUserId())
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
c.RenderArgs["isNote"] = true
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
c.RenderArgs["title"] = note.Title
c.ViewArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
c.ViewArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
c.ViewArgs["isNote"] = true
c.ViewArgs["noteOrNotebookId"] = note.NoteId.Hex()
c.ViewArgs["title"] = note.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
}
func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
notebook := notebookService.GetNotebook(notebookId, c.GetUserId())
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
c.RenderArgs["isNote"] = false
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
c.RenderArgs["title"] = notebook.Title
c.ViewArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
c.ViewArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
LogJ(c.ViewArgs["noteOrNotebookShareGroupInfos"])
c.ViewArgs["isNote"] = false
c.ViewArgs["noteOrNotebookId"] = notebook.NotebookId.Hex()
c.ViewArgs["title"] = notebook.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
}
//------------
// 改变share note 权限
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId));
return c.RenderJSON(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId))
}
// 改变share notebook 权限
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId));
return c.RenderJSON(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId))
}
//---------------
// 删除share note
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId));
return c.RenderJSON(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId))
}
// 删除share notebook
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId));
return c.RenderJSON(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId))
}
// 删除share note, 被共享方删除
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()));
return c.RenderJSON(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()))
}
// 删除share notebook, 被共享方删除
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()));
return c.RenderJSON(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()))
}
// 删除fromUserId分享给我的所有note, notebook
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
return c.RenderJSON(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()))
}
//-------------
// 用户组
// 将笔记分享给分组
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
re := info.NewRe()
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
return c.RenderJson(re);
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm)
return c.RenderJSON(re)
}
// 删除
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
re := info.NewRe()
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
return c.RenderJson(re);
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId)
return c.RenderJSON(re)
}
// 更新, 也是一样, 先删后加
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
return c.AddShareNoteGroup(noteId, groupId, perm)
}
//------
// 将笔记分享给分组
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
re := info.NewRe()
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
return c.RenderJson(re);
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm)
return c.RenderJSON(re)
}
// 删除
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
re := info.NewRe()
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
return c.RenderJson(re);
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId)
return c.RenderJSON(re)
}
// 更新, 也是一样, 先删后加
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
return c.AddShareNotebookGroup(notebookId, groupId, perm)
}
}

View File

@@ -2,11 +2,11 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// "os/exec"
// "os/exec"
)
type Tag struct {
@@ -18,7 +18,7 @@ func (c Tag) UpdateTag(tag string) revel.Result {
ret := info.NewRe()
ret.Ok = true
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
return c.RenderJson(ret)
return c.RenderJSON(ret)
}
// 删除标签
@@ -26,5 +26,5 @@ func (c Tag) DeleteTag(tag string) revel.Result {
ret := info.Re{}
ret.Ok = true
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
return c.RenderJson(ret)
}
return c.RenderJSON(ret)
}

View File

@@ -2,16 +2,16 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
"strconv"
)
@@ -21,8 +21,8 @@ type User struct {
func (c User) Account(tab int) revel.Result {
userInfo := c.GetUserInfo()
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["tab"] = tab
c.ViewArgs["userInfo"] = userInfo
c.ViewArgs["tab"] = tab
c.SetLocale()
return c.RenderTemplate("user/account.html")
}
@@ -32,18 +32,18 @@ func (c User) UpdateUsername(username string) revel.Result {
re := info.NewRe()
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
re.Msg = "cannotUpdateDemo"
return c.RenderRe(re);
return c.RenderRe(re)
}
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
if(re.Ok) {
if re.Ok {
c.UpdateSession("Username", username)
}
return c.RenderRe(re);
return c.RenderRe(re)
}
// 修改密码
@@ -51,37 +51,37 @@ func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewRe()
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
re.Msg = "cannotUpdateDemo"
return c.RenderRe(re);
return c.RenderRe(re)
}
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
return c.RenderRe(re);
return c.RenderRe(re)
}
// 更新主题
func (c User) UpdateTheme(theme string) revel.Result {
re := info.NewRe();
re := info.NewRe()
re.Ok = userService.UpdateTheme(c.GetUserId(), theme)
if re.Ok {
c.UpdateSession("Theme", theme)
}
return c.RenderJson(re);
return c.RenderJSON(re)
}
// 发送邀请链接
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
re := info.NewRe()
if content == "" || !IsEmail(toEmail) {
return c.RenderJson(re);
return c.RenderJSON(re)
}
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
return c.RenderJson(re);
return c.RenderJSON(re)
}
//---------------------------
@@ -90,82 +90,46 @@ func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
func (c User) ReSendActiveEmail() revel.Result {
re := info.NewRe()
re.Ok = emailService.RegisterSendActiveEmail(c.GetUserInfo(), c.GetEmail())
return c.RenderJson(re)
}
// 修改Email发送激活邮箱
func (c User) updateEmailSendActiveEmail(email, pwd string) revel.Result {
re := info.NewRe()
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re);
}
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re);
}
re.Ok, re.Msg = emailService.UpdateEmailSendActiveEmail(c.GetUserInfo(), email)
return c.RenderRe(re)
return c.RenderJSON(re)
}
// 通过点击链接
// 修改邮箱
func (c User) UpdateEmail(token string) revel.Result {
c.SetUserInfo();
c.SetUserInfo()
ok, msg, email := userService.UpdateEmail(token)
c.RenderArgs["title"] = "验证邮箱"
c.RenderArgs["ok"] = ok
c.RenderArgs["msg"] = msg
c.RenderArgs["email"] = email
c.ViewArgs["title"] = "验证邮箱"
c.ViewArgs["ok"] = ok
c.ViewArgs["msg"] = msg
c.ViewArgs["email"] = email
// 修改session
if ok {
c.UpdateSession("Email", email)
}
return c.RenderTemplate("user/update_email.html")
}
// 注册后激活邮箱
func (c User) ActiveEmail(token string) revel.Result {
c.SetUserInfo();
c.SetUserInfo()
ok, msg, email := userService.ActiveEmail(token)
// 需要修改session
if ok {
c.UpdateSession("Verified", "1");
c.UpdateSession("Verified", "1")
}
c.RenderArgs["title"] = "验证邮箱"
c.RenderArgs["ok"] = ok
c.RenderArgs["msg"] = msg
c.RenderArgs["email"] = email
return c.RenderTemplate("user/active_email.html")
}
//------------
// 第三方账号添加leanote账号
func (c User) AddAccount(email, pwd string) revel.Result {
re := info.NewRe()
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
}
re.Ok, re.Msg = userService.ThirdAddUser(c.GetUserId(), email, pwd)
if re.Ok {
c.UpdateSession("Email", email);
}
return c.RenderRe(re)
c.ViewArgs["title"] = "验证邮箱"
c.ViewArgs["ok"] = ok
c.ViewArgs["msg"] = msg
c.ViewArgs["email"] = email
return c.RenderTemplate("user/active_email.html")
}
//-----------------
@@ -174,23 +138,23 @@ func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int)
re := info.NewRe()
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth)
if re.Ok {
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth));
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth))
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth))
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth))
LogJ(c.Session)
}
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
re := info.NewRe()
re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin)
if re.Ok {
if leftIsMin {
c.UpdateSession("LeftIsMin", "1");
c.UpdateSession("LeftIsMin", "1")
} else {
c.UpdateSession("LeftIsMin", "0");
c.UpdateSession("LeftIsMin", "0")
}
}
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -1,15 +1,15 @@
package admin
import (
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
. "github.com/leanote/leanote/app/lea"
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
@@ -20,34 +20,34 @@ type AdminBaseController struct {
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc;
return sorterField, isAsc
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc;
return sorterField, isAsc
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc;
return sorterField, isAsc
}
}
sorterField = strings.Title(s2[0])
if s2[1] == "up" {
isAsc = true
} else {
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc;
c.ViewArgs["sorter"] = sorter
return sorterField, isAsc
}
func (c AdminBaseController) updateConfig(keys []string) {
@@ -56,4 +56,4 @@ func (c AdminBaseController) updateConfig(keys []string) {
v := c.Params.Values.Get(key)
configService.UpdateGlobalStringConfig(userId, key, v)
}
}
}

View File

@@ -2,7 +2,7 @@ package admin
import (
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
)
@@ -15,16 +15,16 @@ type AdminBlog struct {
// admin 主页
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/blog/list.html");
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"})
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
c.ViewArgs["pageInfo"] = pageInfo
c.ViewArgs["blogs"] = blogs
c.ViewArgs["keywords"] = keywords
return c.RenderTemplate("admin/blog/list.html")
}
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
re := info.NewRe()
re.Ok = blogService.SetRecommend(noteId, recommend);
return c.RenderJson(re)
re.Ok = blogService.SetRecommend(noteId, recommend)
return c.RenderJSON(re)
}

View File

@@ -13,27 +13,27 @@ type Admin struct {
// admin 主页
func (c Admin) Index() revel.Result {
c.SetUserInfo()
c.RenderArgs["title"] = "leanote"
c.ViewArgs["title"] = "leanote"
c.SetLocale()
c.RenderArgs["countUser"] = userService.CountUser()
c.RenderArgs["countNote"] = noteService.CountNote("")
c.RenderArgs["countBlog"] = noteService.CountBlog("")
return c.RenderTemplate("admin/index.html");
c.ViewArgs["countUser"] = userService.CountUser()
c.ViewArgs["countNote"] = noteService.CountNote("")
c.ViewArgs["countBlog"] = noteService.CountBlog("")
return c.RenderTemplate("admin/index.html")
}
// 模板
func (c Admin) T(t string) revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
c.RenderArgs["version"] = configService.GetVersion()
c.ViewArgs["str"] = configService.GlobalStringConfigs
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
c.ViewArgs["map"] = configService.GlobalMapConfigs
c.ViewArgs["arrMap"] = configService.GlobalArrMapConfigs
c.ViewArgs["version"] = configService.GetVersion()
return c.RenderTemplate("admin/" + t + ".html")
}
func (c Admin) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view);
}
return c.RenderTemplate("admin/" + view)
}

View File

@@ -1,14 +1,14 @@
package admin
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"archive/tar"
"compress/gzip"
"github.com/leanote/leanote/app/info"
"archive/tar"
"compress/gzip"
"os"
"io"
"time"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"io"
"os"
"time"
)
// 数据管理, 备份和恢复
@@ -22,93 +22,93 @@ func (c AdminData) Index() revel.Result {
// 逆序之
backups2 := make([]map[string]string, len(backups))
j := 0
for i := len(backups)-1; i >= 0; i-- {
for i := len(backups) - 1; i >= 0; i-- {
backups2[j] = backups[i]
j++
}
c.RenderArgs["backups"] = backups2
return c.RenderTemplate("admin/data/index.html");
c.ViewArgs["backups"] = backups2
return c.RenderTemplate("admin/data/index.html")
}
func (c AdminData) Backup() revel.Result {
re := info.NewRe()
re.Ok, re.Msg = configService.Backup("")
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 还原
func (c AdminData) Restore(createdTime string) revel.Result {
re := info.Re{}
re.Ok, re.Msg = configService.Restore(createdTime)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminData) Delete(createdTime string) revel.Result {
re := info.Re{}
re.Ok, re.Msg = configService.DeleteBackup(createdTime)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminData) UpdateRemark(createdTime, remark string) revel.Result {
re := info.Re{}
re.Ok, re.Msg = configService.UpdateBackupRemark(createdTime, remark)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminData) Download(createdTime string) revel.Result {
backup, ok := configService.GetBackup(createdTime)
if !ok {
return c.RenderText("")
}
dbname, _ := revel.Config.String("db.dbname")
path := backup["path"] + "/" + dbname
allFiles := ListDir(path)
allFiles := ListDir(path)
filename := "backup_" + dbname + "_" + backup["createdTime"] + ".tar.gz"
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, file := range allFiles {
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, file := range allFiles {
fn := path + "/" + file
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = file
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachm
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = file
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachm
}

View File

@@ -1,11 +1,11 @@
package admin
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"strings"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strconv"
"strings"
)
// admin 首页
@@ -23,70 +23,71 @@ func (c AdminEmail) Email() revel.Result {
func (c AdminEmail) Blog() revel.Result {
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html");
c.ViewArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.ViewArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html")
}
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
return c.RenderJson(re)
return c.RenderJSON(re)
}
// demo
// blog标签设置
func (c AdminEmail) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html");
c.ViewArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.ViewArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html")
}
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
return c.RenderJSON(info.Re{Ok: false})
}
if userInfo.UserId == "" {
re.Msg = "The User is Not Exists";
return c.RenderJson(re)
re.Msg = "The User is Not Exists"
return c.RenderJSON(re)
}
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// ToImage
// 长微博的bin路径phantomJs
func (c AdminEmail) ToImage() revel.Result {
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
return c.RenderTemplate("admin/setting/toImage.html");
c.ViewArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
return c.RenderTemplate("admin/setting/toImage.html")
}
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword string) revel.Result {
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emailSSL string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
return c.RenderJson(re)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
return c.RenderJSON(re)
}
func (c AdminEmail) Template() revel.Result {
re := info.NewRe()
keys := []string{"emailTemplateHeader", "emailTemplateFooter",
keys := []string{"emailTemplateHeader", "emailTemplateFooter",
"emailTemplateRegisterSubject",
"emailTemplateRegister",
"emailTemplateFindPasswordSubject",
@@ -98,7 +99,7 @@ func (c AdminEmail) Template() revel.Result {
"emailTemplateCommentSubject",
"emailTemplateComment",
}
userId := c.GetUserId()
for _, key := range keys {
v := c.Params.Values.Get(key)
@@ -107,130 +108,129 @@ func (c AdminEmail) Template() revel.Result {
if !ok {
re.Ok = false
re.Msg = "Error key: " + key + "<br />" + msg
return c.RenderJson(re)
return c.RenderJSON(re)
} else {
configService.UpdateGlobalStringConfig(userId, key, v)
}
}
}
re.Ok = true
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 发送Email
func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
re := info.NewRe()
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
if latestEmailSubject == "" || latestEmailBody == "" {
re.Msg = "subject or body is blank"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
}
sendEmails = strings.Replace(sendEmails, "\r", "", -1)
emails := strings.Split(sendEmails, "\n")
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody);
return c.RenderJson(re)
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody)
return c.RenderJSON(re)
}
// 发送Email
func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
re := info.NewRe()
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
if latestEmailSubject == "" || latestEmailBody == "" {
re.Msg = "subject or body is blank"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
}
emails = strings.Replace(emails, "\r", "", -1)
emailsArr := strings.Split(emails, "\n")
users := userService.ListUserInfosByEmails(emailsArr)
LogJ(emailsArr)
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
return c.RenderJson(re)
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
return c.RenderJSON(re)
}
// send Email dialog
func (c AdminEmail) SendEmailDialog(emails string) revel.Result{
func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
emailsArr := strings.Split(emails, ",")
emailsNl := strings.Join(emailsArr, "\n")
c.RenderArgs["emailsNl"] = emailsNl
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs
return c.RenderTemplate("admin/email/emailDialog.html");
c.ViewArgs["emailsNl"] = emailsNl
c.ViewArgs["str"] = configService.GlobalStringConfigs
c.ViewArgs["map"] = configService.GlobalMapConfigs
return c.RenderTemplate("admin/email/emailDialog.html")
}
func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilterBlackList, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
re := info.NewRe()
c.updateConfig([]string{"userFilterEmail", "userFilterWhiteList", "userFilterBlackList", "latestEmailSubject", "latestEmailBody"})
if latestEmailSubject == "" || latestEmailBody == "" {
re.Msg = "subject or body is blank"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
}
users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified)
if(users == nil || len(users) == 0) {
if users == nil || len(users) == 0 {
re.Ok = false
re.Msg = "no users"
return c.RenderJson(re)
return c.RenderJSON(re)
}
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
if(!re.Ok) {
return c.RenderJson(re)
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
if !re.Ok {
return c.RenderJSON(re)
}
re.Ok = true
re.Msg = "users:" + strconv.Itoa(len(users))
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 删除emails
func (c AdminEmail) DeleteEmails(ids string) revel.Result {
re := info.NewRe()
re.Ok = emailService.DeleteEmails(strings.Split(ids, ","))
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminEmail) List(sorter, keywords string) revel.Result {
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"});
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["emails"] = emails
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/email/list.html");
}
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"})
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords)
c.ViewArgs["pageInfo"] = pageInfo
c.ViewArgs["emails"] = emails
c.ViewArgs["keywords"] = keywords
return c.RenderTemplate("admin/email/list.html")
}

View File

@@ -2,10 +2,10 @@ package admin
import (
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"fmt"
"github.com/leanote/leanote/app/info"
"strings"
"fmt"
)
// admin 首页
@@ -23,90 +23,96 @@ func (c AdminSetting) Email() revel.Result {
func (c AdminSetting) Blog() revel.Result {
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html");
c.ViewArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.ViewArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html")
}
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 共享设置
func (c AdminSetting) ShareNote(registerSharedUserId string,
registerSharedNotebookPerms, registerSharedNotePerms []int,
func (c AdminSetting) ShareNote(registerSharedUserId string,
registerSharedNotebookPerms, registerSharedNotePerms []int,
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds);
return c.RenderJson(re)
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds)
return c.RenderJSON(re)
}
// demo
// blog标签设置
func (c AdminSetting) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html");
c.ViewArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.ViewArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html")
}
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword)
if err != nil {
fmt.Println(err)
return c.RenderJson(info.Re{Ok: false})
return c.RenderJSON(info.Re{Ok: false})
}
if userInfo.UserId == "" {
re.Msg = "The User is Not Exists";
return c.RenderJson(re)
re.Msg = "The User is Not Exists"
return c.RenderJSON(re)
}
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) ExportPdf(path string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl)
return c.RenderJSON(re)
}
// SubDomain
func (c AdminSetting) SubDomain() revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
c.RenderArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
return c.RenderTemplate("admin/setting/subDomain.html");
c.ViewArgs["str"] = configService.GlobalStringConfigs
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
c.ViewArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
c.ViewArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
c.ViewArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
return c.RenderTemplate("admin/setting/subDomain.html")
}
func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, blackSubDomains, allowCustomDomain, blackCustomDomains string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "noteSubDomain", noteSubDomain)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "blogSubDomain", blogSubDomain)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "leaSubDomain", leaSubDomain)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "allowCustomDomain", allowCustomDomain)
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackSubDomains", strings.Split(blackSubDomains, ","))
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackCustomDomains", strings.Split(blackCustomDomains, ","))
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "openRegister", openRegister)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) HomePage(homePage string) revel.Result {
@@ -115,7 +121,7 @@ func (c AdminSetting) HomePage(homePage string) revel.Result {
homePage = ""
}
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
@@ -123,7 +129,7 @@ func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Resu
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
@@ -132,5 +138,5 @@ func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLo
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
return c.RenderJson(re)
}
return c.RenderJSON(re)
}

View File

@@ -2,9 +2,9 @@ package admin
import (
"github.com/revel/revel"
// "encoding/json"
// "encoding/json"
"github.com/leanote/leanote/app/info"
// "io/ioutil"
// "io/ioutil"
)
// Upgrade controller
@@ -14,17 +14,17 @@ type AdminUpgrade struct {
func (c AdminUpgrade) UpgradeBlog() revel.Result {
upgradeService.UpgradeBlog()
return nil;
return nil
}
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
re := info.NewRe()
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
re := info.NewRe()
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
return c.RenderJson(re)
}
return c.RenderJSON(re)
}

View File

@@ -1,9 +1,9 @@
package admin
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
// "time"
"github.com/revel/revel"
// "time"
"github.com/leanote/leanote/app/info"
)
@@ -15,52 +15,53 @@ type AdminUser struct {
// admin 主页
var userPageSize = 10
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
pageNumber := c.GetPage()
if userPageSize == 0 {
if pageSize == 0 {
pageSize = userPageSize
}
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["users"] = users
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/user/list.html");
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"})
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords)
c.ViewArgs["pageInfo"] = pageInfo
c.ViewArgs["users"] = users
c.ViewArgs["keywords"] = keywords
return c.RenderTemplate("admin/user/list.html")
}
func (c AdminUser) Add() revel.Result {
return c.RenderTemplate("admin/user/add.html");
return c.RenderTemplate("admin/user/add.html")
}
// 添加
func (c AdminUser) Register(email, pwd string) revel.Result {
re := info.NewRe();
re := info.NewRe()
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
// 注册
re.Ok, re.Msg = authService.Register(email, pwd, "")
return c.RenderRe(re)
}
// 修改帐户
func (c AdminUser) ResetPwd(userId string) revel.Result {
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
return c.RenderTemplate("admin/user/reset_pwd.html");
c.ViewArgs["userInfo"] = userInfo
return c.RenderTemplate("admin/user/reset_pwd.html")
}
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
re := info.NewRe();
re := info.NewRe()
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
return c.RenderRe(re)
}
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
return c.RenderRe(re)
}
}

View File

@@ -1,11 +1,11 @@
package admin
import (
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "strings"
// "strings"
)
var userService *service.UserService
@@ -19,9 +19,9 @@ var blogService *service.BlogService
var tagService *service.TagService
var pwdService *service.PwdService
var tokenService *service.TokenService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var fileService *service.FileService
var attachService *service.AttachService
var configService *service.ConfigService
@@ -31,31 +31,32 @@ var upgradeService *service.UpgradeService
// 拦截器
// 不需要拦截的url
// Index 除了Note之外都不需要
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
"Login": true,
"DoLogin": true,
"Logout": true,
"Register": true,
"DoRegister": true,
"FindPasswword": true,
"DoFindPassword": true,
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
"Login": true,
"DoLogin": true,
"Logout": true,
"Register": true,
"DoRegister": true,
"FindPasswword": true,
"DoFindPassword": true,
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
"View": true,
"AboutMe": true,
"SearchBlog": true,
},
},
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail":true,
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"ActiveEmail": true,
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
@@ -66,33 +67,33 @@ func needValidate(controller, method string) bool {
return true
} else {
// controller不在这里的, 肯定要验证
return true;
return true
}
}
func AuthInterceptor(c *revel.Controller) revel.Result {
// 全部变成首字大写
/*
var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName)
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName)
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
*/
// 验证是否已登录
// 必须是管理员
if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() {
return nil // 已登录
}
// 没有登录, 判断是否是ajax操作
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
re := info.NewRe()
re.Msg = "NOTLOGIN"
return c.RenderJson(re)
return c.RenderJSON(re)
}
return c.Redirect("/login")
}
@@ -110,7 +111,7 @@ func InitService() {
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService= service.AlbumS
albumService = service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS

View File

@@ -23,17 +23,17 @@ type ApiAuth struct {
// 失败返回 {Ok: false, Msg: ""}
func (c ApiAuth) Login(email, pwd string) revel.Result {
var msg = ""
userInfo, err := authService.Login(email, pwd)
if err == nil {
token := bson.NewObjectId().Hex()
sessionService.SetUserId(token, userInfo.UserId.Hex())
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
return c.RenderJSON(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
} else {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
}
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
return c.RenderJSON(info.ApiRe{Ok: false, Msg: c.Message(msg)})
}
// 注销
@@ -43,7 +43,7 @@ func (c ApiAuth) Logout() revel.Result {
sessionService.Clear(token)
re := info.NewApiRe()
re.Ok = true
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 注册
@@ -53,17 +53,17 @@ func (c ApiAuth) Register(email, pwd string) revel.Result {
re := info.NewApiRe()
if !configService.IsOpenRegister() {
re.Msg = "notOpenRegister" // 未开放注册
return c.RenderJson(re)
return c.RenderJSON(re)
}
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 注册
re.Ok, re.Msg = authService.Register(email, pwd, "")
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -4,11 +4,11 @@ import (
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// "encoding/json"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"os"
// "fmt"
// "fmt"
"io/ioutil"
// "fmt"
// "math"
@@ -43,75 +43,83 @@ func (c ApiBaseContrller) getUserInfo() info.User {
// 上传附件
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
userId := c.getUserId();
userId := c.getUserId()
// 判断是否有权限为笔记添加附件
// 如果笔记还没有添加是不是会有问题
/*
if !shareService.HasUpdateNotePerm(noteId, userId) {
return
}
if !shareService.HasUpdateNotePerm(noteId, userId) {
return
}
*/
file, handel, err := c.Request.FormFile(name)
if err != nil {
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return
var data []byte
c.Params.Bind(&data, name)
handel := c.Params.Files[name][0]
if data == nil || len(data) == 0 {
return
}
// file, handel, err := c.Request.FormFile(name)
// if err != nil {
// return
// }
// defer file.Close()
// data, err := ioutil.ReadAll(file)
// if err != nil {
// return
// }
// > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize");
maxFileSize := configService.GetUploadSize("uploadAttachSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
msg = "fileIsTooLarge"
return
if float64(len(data)) > maxFileSize*float64(1024*1024) {
msg = "fileIsTooLarge"
return
}
// 生成上传路径
newGuid := NewGuid()
filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755)
// filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
filePath := "files/" + GetRandomFilePath(userId, newGuid) + "/attachs"
dir := revel.BasePath + "/" + filePath
err := os.MkdirAll(dir, 0755)
if err != nil {
return
return
}
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename) // .doc
filename = newGuid + ext
toPath := dir + "/" + filename;
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return
return
}
// add File to db
fileType := ""
if ext != "" {
fileType = strings.ToLower(ext[1:])
}
filesize := GetFilesize(toPath)
fileInfo := info.Attach{AttachId: bson.NewObjectId(),
Name: filename,
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
fileInfo := info.Attach{AttachId: bson.NewObjectId(),
Name: filename,
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
UploadUserId: bson.ObjectIdHex(userId),
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
ok, msg = attachService.AddAttach(fileInfo, true)
if !ok {
return
}
id = fileInfo.AttachId.Hex()
return
}
@@ -121,64 +129,72 @@ func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok
if isAttach {
return c.uploadAttach(name, noteId)
}
file, handel, err := c.Request.FormFile(name)
if err != nil {
return
// file, handel, err := c.Request.FormFile(name)
// if err != nil {
// return
// }
// defer file.Close()
var data []byte
c.Params.Bind(&data, name)
handel := c.Params.Files[name][0]
if data == nil || len(data) == 0 {
return
}
defer file.Close()
newGuid := NewGuid()
// 生成上传路径
userId := c.getUserId()
fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err := os.MkdirAll(dir, 0755)
if err != nil {
return
}
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename)
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
msg = "notImage"
return
}
// if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
// msg = "notImage"
// return
// }
filename = newGuid + ext
data, err := ioutil.ReadAll(file)
if err != nil {
return
}
maxFileSize := configService.GetUploadSize("uploadImageSize");
// data, err := ioutil.ReadAll(file)
// if err != nil {
// return
// }
maxFileSize := configService.GetUploadSize("uploadImageSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
// > 2M?
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
if float64(len(data)) > maxFileSize*float64(1024*1024) {
msg = "fileIsTooLarge"
return
}
toPath := dir + "/" + filename;
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return
return
}
// 改变成gif图片
_, toPathGif := TransToGif(toPath, 0, true)
filename = GetFilename(toPathGif)
filesize := GetFilesize(toPathGif)
fileUrlPath += "/" + filename
// File
fileInfo := info.File{FileId: bson.NewObjectId(),
Name: filename,
Name: filename,
Title: handel.Filename,
Path: fileUrlPath,
Size: filesize}
Path: fileUrlPath,
Size: filesize}
ok, msg = fileService.AddImage(fileInfo, "", c.getUserId(), true)
if ok {
id = fileInfo.FileId.Hex()

View File

@@ -3,18 +3,18 @@ package api
import (
"github.com/revel/revel"
// "encoding/json"
// . "github.com/leanote/leanote/app/lea"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/lea/netutil"
// "github.com/leanote/leanote/app/info"
// "io/ioutil"
// "github.com/leanote/leanote/app/info"
// "io/ioutil"
"os"
// "strconv"
"archive/tar"
"compress/gzip"
"io"
"time"
"strings"
"archive/tar"
"compress/gzip"
"time"
)
// 文件操作, 图片, 头像上传, 输出
@@ -30,7 +30,7 @@ func (c ApiFile) CopyImage(userId, fileId, toUserId string) revel.Result {
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// get all images by userId with page
@@ -39,19 +39,19 @@ func (c ApiFile) GetImages(albumId, key string, page int) revel.Result {
re := info.NewRe()
re.Ok = true
re.Item = imagesPage
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
re := info.NewRe()
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c ApiFile) DeleteImage(fileId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
*/
@@ -73,14 +73,14 @@ func (c ApiFile) GetImage(fileId string) revel.Result {
// 下载附件
// [OK]
func (c ApiFile) GetAttach(fileId string) revel.Result {
attach := attachService.GetAttach(fileId, c.getUserId()); // 得到路径
attach := attachService.GetAttach(fileId, c.getUserId()) // 得到路径
path := attach.Path
if path == "" {
return c.RenderText("No Such File")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
}
// 下载所有附件
@@ -95,70 +95,69 @@ func (c ApiFile) GetAllAttachs(noteId string) revel.Result {
if attachs == nil || len(attachs) == 0 {
return c.RenderText("")
}
/*
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
*/
filename := note.Title + ".tar.gz"
if note.Title == "" {
filename = "all.tar.gz"
}
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}

View File

@@ -6,11 +6,11 @@ import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"regexp"
"strings"
"time"
"os/exec"
"os"
"os/exec"
// "strings"
"time"
"regexp"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
@@ -52,27 +52,27 @@ func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
maxEntry = 100
}
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(notes)
return c.RenderJSON(notes)
}
// 得到笔记本下的笔记
// [OK]
func (c ApiNote) GetNotes(notebookId string) revel.Result {
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
re := info.NewApiRe()
re.Msg = "notebookIdInvalid"
return c.RenderJson(re)
return c.RenderJSON(re)
}
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(noteService.ToApiNotes(notes))
return c.RenderJSON(noteService.ToApiNotes(notes))
}
// 得到trash
// [OK]
func (c ApiNote) GetTrashNotes() revel.Result {
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(noteService.ToApiNotes(notes))
return c.RenderJSON(noteService.ToApiNotes(notes))
}
// get Note
@@ -85,7 +85,6 @@ func (c ApiNote) GetTrashNotes() revel.Result {
"Title": "asdfadsf--=",
"Desc": "",
"Tags": [
""
],
"Abstract": "",
"Content": "",
@@ -95,7 +94,7 @@ func (c ApiNote) GetTrashNotes() revel.Result {
"Usn": 8,
"Files": [
{
"FileId": "551975d599c37b970f000002",
"FileId": "551975d599c37b970f000000",
"LocalFileId": "",
"Type": "",
"Title": "",
@@ -103,18 +102,18 @@ func (c ApiNote) GetTrashNotes() revel.Result {
"IsAttach": false
},
{
"FileId": "551975de99c37b970f000003",
"FileId": "551975de99c37b970f000001",
"LocalFileId": "",
"Type": "doc",
"Title": "李铁-简历-ali-print-en.doc",
"Title": "李铁-print-en.doc",
"HasBody": false,
"IsAttach": true
},
{
"FileId": "551975de99c37b970f000004",
"FileId": "551975de99c37b970f000002",
"LocalFileId": "",
"Type": "doc",
"Title": "李铁-简历-ali-print.doc",
"Title": "李铁-print.doc",
"HasBody": false,
"IsAttach": true
}
@@ -125,89 +124,31 @@ func (c ApiNote) GetTrashNotes() revel.Result {
}
*/
func (c ApiNote) GetNote(noteId string) revel.Result {
if !bson.IsObjectIdHex(noteId) {
if !bson.IsObjectIdHex(noteId) {
re := info.NewApiRe()
re.Msg = "noteIdInvalid"
return c.RenderJson(re)
return c.RenderJSON(re)
}
note := noteService.GetNote(noteId, c.getUserId())
if note.NoteId == "" {
re := info.NewApiRe()
re.Msg = "notExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
apiNotes := noteService.ToApiNotes([]info.Note{note})
return c.RenderJson(apiNotes[0])
return c.RenderJSON(apiNotes[0])
}
// 得到note和内容
// [OK]
func (c ApiNote) GetNoteAndContent(noteId string) revel.Result {
noteAndContent := noteService.GetNoteAndContent(noteId, c.getUserId())
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
apiNote := apiNotes[0]
apiNote.Content = noteAndContent.Content
return c.RenderJson(apiNote)
}
// 处理笔记内容数据 http://leanote.com/file/outputImage -> https://leanote.com/api/file/getImage
// 图片, 附件都替换
func (c ApiNote) fixContent(content string) string {
// TODO, 这个url需要从config中取
// baseUrl := "http://leanote.com"
baseUrl := configService.GetSiteUrl()
// baseUrl := "http://localhost:9000"
patterns := []map[string]string{
map[string]string{"src": "src", "middle": "/file/outputImage", "param": "fileId", "to": "getImage?fileId="},
map[string]string{"src": "href", "middle": "/attach/download", "param": "attachId", "to": "getAttach?fileId="},
map[string]string{"src": "href", "middle": "/attach/downloadAll", "param": "noteId", "to": "getAllAttachs?noteId="},
}
for _, eachPattern := range patterns {
// src="http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1"
// href="http://leanote.com/attach/download?attachId=5504243a38f4111dcb00017d"
// href="http://leanote.com/attach/downloadAll?noteId=55041b6a38f4111dcb000159"
regImage, _ := regexp.Compile(eachPattern["src"] + `=('|")`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})("|')`)
findsImage := regImage.FindAllStringSubmatch(content, -1) // 查找所有的
// [[src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "]]
for _, eachFind := range findsImage {
// [src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "]
if len(eachFind) == 4 {
content = strings.Replace(content,
eachFind[0],
eachPattern["src"] + "=\"" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + "\"",
1);
}
}
// markdown处理
// ![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1)
// [selection 2.html](http://leanote.com/attach/download?attachId=5504262638f4111dcb00017f)
// [all.tar.gz](http://leanote.com/attach/downloadAll?noteId=5503b57d59f81b4eb4000000)
pre := "!" // 默认图片
if eachPattern["src"] == "href" { // 是attach
pre = ""
}
regImageMarkdown, _ := regexp.Compile(pre + `\[(.*?)\]\(`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})\)`)
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(content, -1) // 查找所有的
// [[![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1] [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1]]
for _, eachFind := range findsImageMarkdown {
// [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 你好啊, 我很好, 为什么? 5503537b38f4111dcb0000d1]
if len(eachFind) == 3 {
content = strings.Replace(content, eachFind[0], pre + "[" + eachFind[1] + "](" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + ")", 1);
}
}
}
return content
apiNote.Content = noteService.FixContent(noteAndContent.Content, noteAndContent.IsMarkdown)
return c.RenderJSON(apiNote)
}
// content里的image, attach链接是
@@ -218,33 +159,55 @@ func (c ApiNote) fixPostNotecontent(noteOrContent *info.ApiNote) {
if noteOrContent.Content == "" {
return
}
files := noteOrContent.Files
if files != nil && len(files) > 0 {
for _, file := range files {
if file.LocalFileId != "" {
noteOrContent.Content = strings.Replace(noteOrContent.Content, "fileId=" + file.LocalFileId, "fileId=" + file.FileId, -1)
LogJ(file)
if !file.IsAttach {
// <img src="https://"
// ![](http://demo.leanote.top/api/file/getImage?fileId=5863219465b68e4fd5000001)
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getImage\?fileId=`+file.LocalFileId)
// Log(reg)
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getImage?fileId=`+file.FileId)
// // "http://a.com/api/file/getImage?fileId=localId" => /api/file/getImage?fileId=serverId
// noteOrContent.Content = strings.Replace(noteOrContent.Content,
// baseUrl + "/api/file/getImage?fileId="+file.LocalFileId,
// "/api/file/getImage?fileId="+file.FileId, -1)
} else {
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getAttach\?fileId=`+file.LocalFileId)
// Log(reg)
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getAttach?fileId=`+file.FileId)
/*
noteOrContent.Content = strings.Replace(noteOrContent.Content,
baseUrl + "/api/file/getAttach?fileId="+file.LocalFileId,
"/api/file/getAttach?fileId="+file.FileId, -1)
*/
}
}
}
}
}
// 得到内容
// [OK]
func (c ApiNote) GetNoteContent(noteId string) revel.Result {
userId := c.getUserId()
note := noteService.GetNote(noteId, userId)
// re := info.NewRe()
noteContent := noteService.GetNoteContent(noteId, c.getUserId())
noteContent := noteService.GetNoteContent(noteId, userId)
if noteContent.Content != "" {
noteContent.Content = c.fixContent(noteContent.Content)
noteContent.Content = noteService.FixContent(noteContent.Content, note.IsMarkdown)
}
apiNoteContent := info.ApiNoteContent{
NoteId: noteContent.NoteId,
UserId: noteContent.UserId,
NoteId: noteContent.NoteId,
UserId: noteContent.UserId,
Content: noteContent.Content,
}
// re.Item = noteContent
return c.RenderJson(apiNoteContent)
return c.RenderJSON(apiNoteContent)
}
// 添加笔记
@@ -255,12 +218,13 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
myUserId := userId
// 为共享新建?
/*
if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
}
if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
}
*/
// Log(noteOrContent.Title)
// LogJ(noteOrContent)
// LogJ(noteOrContent)
/*
LogJ(c.Params)
for name, _ := range c.Params.Files {
@@ -269,10 +233,10 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
LogJ(file)
}
*/
// return c.RenderJson(re)
// return c.RenderJSON(re)
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
re.Msg = "notebookIdNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
noteId := bson.NewObjectId()
@@ -295,7 +259,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
}
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
if msg != "notImage" {
return c.RenderJson(re)
return c.RenderJSON(re)
}
} else {
// 建立映射
@@ -307,7 +271,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
}
}
} else {
return c.RenderJson(re)
return c.RenderJSON(re)
}
}
}
@@ -315,10 +279,10 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
c.fixPostNotecontent(&noteOrContent)
// Log("Add")
// LogJ(noteOrContent)
// Log("Add")
// LogJ(noteOrContent)
// return c.RenderJson(re)
// return c.RenderJSON(re)
note := info.Note{UserId: userId,
NoteId: noteId,
@@ -326,16 +290,21 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
Title: noteOrContent.Title,
Tags: noteOrContent.Tags,
Desc: noteOrContent.Desc,
// ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown,
AttachNum: attachNum,
// ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown,
AttachNum: attachNum,
CreatedTime: noteOrContent.CreatedTime,
UpdatedTime: noteOrContent.UpdatedTime,
}
noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract}
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract,
CreatedTime: noteOrContent.CreatedTime,
UpdatedTime: noteOrContent.UpdatedTime,
}
// 通过内容得到Desc, abstract
if noteOrContent.Abstract == "" {
@@ -346,10 +315,10 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
}
note = noteService.AddNoteAndContentApi(note, noteContent, myUserId)
if note.NoteId == "" {
re.Ok = false
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 添加需要返回的
@@ -363,7 +332,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
noteOrContent.Content = ""
noteOrContent.Abstract = ""
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
return c.RenderJson(noteOrContent)
return c.RenderJSON(noteOrContent)
}
// 更新笔记
@@ -378,16 +347,16 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
if noteOrContent.NoteId == "" {
re.Msg = "noteIdNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if noteOrContent.Usn <= 0 {
re.Msg = "usnNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
// Log("_____________")
// LogJ(noteOrContent)
// Log("_____________")
// LogJ(noteOrContent)
/*
LogJ(c.Params.Files)
LogJ(c.Request.Header)
@@ -399,25 +368,26 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
note := noteService.GetNote(noteId, userId)
if note.NoteId == "" {
re.Msg = "notExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if note.Usn != noteOrContent.Usn {
re.Msg = "conflict"
Log("conflict")
return c.RenderJson(re)
return c.RenderJSON(re)
}
Log("没有冲突")
// 如果传了files
// TODO 测试
/*
for key, v := range c.Params.Values {
Log(key)
Log(v)
}
for key, v := range c.Params.Values {
Log(key)
Log(v)
}
*/
// Log(c.Has("Files[0]"))
if c.Has("Files[0][LocalFileId]") {
// LogJ(c.Params.Files)
// Log(c.Has("Files[0]"))
if c.Has("Files[0][LocalFileId]") {
// LogJ(c.Params.Files)
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
for i, file := range noteOrContent.Files {
if file.HasBody {
@@ -432,37 +402,38 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
} else {
re.Msg = msg
}
return c.RenderJson(re)
return c.RenderJSON(re)
} else {
// 建立映射
file.FileId = fileId
noteOrContent.Files[i] = file
}
} else {
return c.RenderJson(re)
return c.RenderJSON(re)
}
}
}
}
// Log("after upload")
// LogJ(noteOrContent.Files)
// Log("after upload")
// LogJ(noteOrContent.Files)
}
// 移到外面来, 删除最后一个file时也要处理, 不然总删不掉
// 附件问题, 根据Files, 有些要删除的, 只留下这些
attachService.UpdateOrDeleteAttachApi(noteId, userId, noteOrContent.Files)
// Desc前台传来
if c.Has("Desc") {
needUpdateNote = true
noteUpdate["Desc"] = noteOrContent.Desc
}
/*
if c.Has("ImgSrc") {
needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
}
if c.Has("ImgSrc") {
needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
}
*/
if c.Has("Title") {
needUpdateNote = true
@@ -472,7 +443,7 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
needUpdateNote = true
noteUpdate["IsTrash"] = noteOrContent.IsTrash
}
// 是否是博客
if c.Has("IsBlog") {
needUpdateNote = true
@@ -509,6 +480,8 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
}
}
noteUpdate["UpdatedTime"] = noteOrContent.UpdatedTime
afterNoteUsn := 0
noteOk := false
noteMsg := ""
@@ -517,7 +490,7 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
if !noteOk {
re.Ok = false
re.Msg = noteMsg
return c.RenderJson(re)
return c.RenderJSON(re)
}
}
@@ -532,10 +505,16 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
if noteOrContent.Abstract == "" {
noteOrContent.Abstract = SubStringHTML(noteOrContent.Content, 200, "")
}
// Log("--------> afte fixed")
// Log(noteOrContent.Content)
// Log("--------> afte fixed")
// Log(noteOrContent.Content)
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.getUserId(),
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, noteOrContent.Usn)
noteOrContent.NoteId,
noteOrContent.Content,
noteOrContent.Abstract,
needUpdateNote,
noteOrContent.Usn,
noteOrContent.UpdatedTime)
}
if needUpdateNote {
@@ -549,25 +528,25 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
}
if !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
noteOrContent.Content = ""
noteOrContent.Usn = re.Usn
noteOrContent.UpdatedTime = time.Now()
// Log("after upload")
// LogJ(noteOrContent.Files)
// Log("after upload")
// LogJ(noteOrContent.Files)
noteOrContent.UserId = c.getUserId()
return c.RenderJson(noteOrContent)
return c.RenderJSON(noteOrContent)
}
// 删除trash
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
re := info.NewReUpdate()
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 得到历史列表
@@ -579,25 +558,24 @@ func (c ApiNote) GetHistories(noteId string) revel.Result {
re.Ok = true
re.Item = histories
}
return c.RenderJson(re)
return c.RenderJSON(re)
}
*/
// 0.2 新增
// 导出成PDF
// test localhost:9000/api/note/exportPdf?noteId=554f07bf05fcd15fa9000000&token=562211dc99c37ba6a7000001
func (c ApiNote) ExportPdf(noteId string) revel.Result {
re := info.NewApiRe()
userId := c.getUserId()
if noteId == "" {
re.Msg = "noteNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
re.Msg = "noteNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
noteUserId := note.UserId.Hex()
@@ -606,17 +584,17 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
// 是否是有权限协作的
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
re.Msg = "noteNotExists"
return c.RenderJson(re)
return c.RenderJSON(re)
}
}
// path 判断是否需要重新生成之
guid := NewGuid()
fileUrlPath := "files/" + Digest3(noteUserId) + "/" + noteUserId + "/" + Digest2(guid) + "/images/pdf"
fileUrlPath := "files/export_pdf"
dir := revel.BasePath + "/" + fileUrlPath
if !MkdirAll(dir) {
re.Msg = "noDir"
return c.RenderJson(re)
return c.RenderJSON(re)
}
filename := guid + ".pdf"
path := dir + "/" + filename
@@ -625,7 +603,7 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
if appKey == "" {
appKey, _ = revel.Config.String("app.secret")
}
// 生成之
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
// 默认路径
@@ -635,22 +613,22 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
var cc string
if(note.IsMarkdown) {
cc = binPath + " --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
if note.IsMarkdown {
cc = binPath + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
} else {
cc = binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
cc = binPath + " --lowquality \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
}
cmd := exec.Command("/bin/sh", "-c", cc)
_, err := cmd.Output()
if err != nil {
if err != nil {
re.Msg = "sysError"
return c.RenderJson(re)
return c.RenderJSON(re)
}
file, err := os.Open(path)
if err != nil {
re.Msg = "sysError"
return c.RenderJson(re)
return c.RenderJSON(re)
}
filenameReturn := note.Title
@@ -660,5 +638,5 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
} else {
filenameReturn += ".pdf"
}
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
}

View File

@@ -2,9 +2,9 @@ package api
import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
@@ -30,17 +30,17 @@ func (c ApiNotebook) fixNotebook(notebook *info.Notebook) info.ApiNotebook {
return info.ApiNotebook{}
}
return info.ApiNotebook{
NotebookId : notebook.NotebookId,
UserId : notebook.UserId,
ParentNotebookId : notebook.ParentNotebookId,
Seq : notebook.Seq,
Title : notebook.Title,
UrlTitle : notebook.UrlTitle,
IsBlog : notebook.IsBlog,
CreatedTime : notebook.CreatedTime,
UpdatedTime : notebook.UpdatedTime,
Usn: notebook.Usn,
IsDeleted: notebook.IsDeleted,
NotebookId: notebook.NotebookId,
UserId: notebook.UserId,
ParentNotebookId: notebook.ParentNotebookId,
Seq: notebook.Seq,
Title: notebook.Title,
UrlTitle: notebook.UrlTitle,
IsBlog: notebook.IsBlog,
CreatedTime: notebook.CreatedTime,
UpdatedTime: notebook.UpdatedTime,
Usn: notebook.Usn,
IsDeleted: notebook.IsDeleted,
}
}
@@ -53,7 +53,7 @@ func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
maxEntry = 100
}
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(c.fixNotebooks(notebooks))
return c.RenderJSON(c.fixNotebooks(notebooks))
}
// 得到用户的所有笔记本
@@ -61,7 +61,7 @@ func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
// info.SubNotebooks
func (c ApiNotebook) GetNotebooks() revel.Result {
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
return c.RenderJson(c.fixNotebooks(notebooks))
return c.RenderJSON(c.fixNotebooks(notebooks))
}
// 添加notebook
@@ -77,24 +77,24 @@ func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.
re := info.NewRe()
re.Ok, notebook = notebookService.AddNotebook(notebook)
if !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
return c.RenderJson(c.fixNotebook(&notebook))
return c.RenderJSON(c.fixNotebook(&notebook))
}
// 修改笔记
// [OK]
func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string, seq, usn int) revel.Result {
re := info.NewApiRe()
ok, msg, notebook := notebookService.UpdateNotebookApi(c.getUserId(), notebookId, title, parentNotebookId, seq, usn)
if !ok {
re.Ok = false
re.Msg = msg
return c.RenderJson(re)
return c.RenderJSON(re)
}
LogJ(notebook)
return c.RenderJson(c.fixNotebook(&notebook))
return c.RenderJSON(c.fixNotebook(&notebook))
}
// 删除笔记本
@@ -102,5 +102,5 @@ func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string,
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
re := info.NewApiRe()
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
return c.RenderJson(re)
return c.RenderJSON(re)
}

View File

@@ -3,7 +3,7 @@ package api
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
@@ -23,7 +23,7 @@ func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
maxEntry = 100
}
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(tags)
return c.RenderJSON(tags)
}
// 添加Tag
@@ -44,7 +44,7 @@ func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
*/
func (c ApiTag) AddTag(tag string) revel.Result {
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
return c.RenderJson(ret)
return c.RenderJSON(ret)
}
// 删除标签
@@ -52,5 +52,5 @@ func (c ApiTag) AddTag(tag string) revel.Result {
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
re := info.NewReUpdate()
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
return c.RenderJson(re)
}
return c.RenderJSON(re)
}

View File

@@ -3,15 +3,15 @@ package api
import (
"github.com/revel/revel"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
// "github.com/leanote/leanote/app/types"
"io/ioutil"
"io/ioutil"
// "fmt"
// "math"
"os"
"os"
// "path"
// "strconv"
@@ -28,16 +28,16 @@ func (c ApiUser) Info() revel.Result {
userInfo := c.getUserInfo()
if userInfo.UserId == "" {
return c.RenderJson(re)
return c.RenderJSON(re)
}
apiUser := info.ApiUser{
UserId: userInfo.UserId.Hex(),
UserId: userInfo.UserId.Hex(),
Username: userInfo.Username,
Email: userInfo.Email,
Logo: userInfo.Logo,
Email: userInfo.Email,
Logo: userInfo.Logo,
Verified: userInfo.Verified,
}
return c.RenderJson(apiUser)
return c.RenderJSON(apiUser)
}
// 修改用户名
@@ -46,15 +46,15 @@ func (c ApiUser) UpdateUsername(username string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 修改密码
@@ -63,26 +63,25 @@ func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
return c.RenderJSON(re)
}
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re)
return c.RenderJSON(re)
}
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 获得同步状态
// [OK]
func (c ApiUser) GetSyncState() revel.Result {
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
return c.RenderJson(ret)
return c.RenderJSON(ret)
}
// 头像设置
// 参数file=文件
// 成功返回{Logo: url} 头像新url
@@ -92,11 +91,11 @@ func (c ApiUser) UpdateLogo() revel.Result {
if ok {
ok = userService.UpdateAvatar(c.getUserId(), url)
return c.RenderJson(map[string]string{"Logo": url})
return c.RenderJSON(map[string]string{"Logo": url})
} else {
re := info.NewApiRe()
re.Msg = msg
return c.RenderJson(re)
return c.RenderJSON(re)
}
}
@@ -105,16 +104,23 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
var fileUrlPath = ""
ok = false
file, handel, err := c.Request.FormFile("file")
if err != nil {
var data []byte
c.Params.Bind(&data, "file")
handel := c.Params.Files["file"][0]
if data == nil || len(data) == 0 {
return
}
defer file.Close()
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// return
// }
// defer file.Close()
// 生成上传路径
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
err := os.MkdirAll(dir, 0755)
if err != nil {
return
}
@@ -122,19 +128,19 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
filename := handel.Filename
var ext string
_, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
msg = "notImage"
return
return
}
filename = NewGuid() + ext
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return
}
// data, err := ioutil.ReadAll(file)
// if err != nil {
// LogJ(err)
// return
// }
// > 5M?
if len(data) > 5*1024*1024 {
@@ -148,8 +154,8 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
LogJ(err)
return
}
ok = true
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
return
return
}

View File

@@ -3,7 +3,7 @@ package api
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
)
@@ -46,10 +46,10 @@ const (
// 不需要拦截的url
var commonUrl = map[string]map[string]bool{"ApiAuth": map[string]bool{"Login": true,
"Register": true,
},
},
// 文件的操作也不用登录, userId会从session中获取
"ApiFile": map[string]bool{"GetImage": true,
"GetAttach": true,
"GetAttach": true,
"GetAllAttachs": true,
},
}
@@ -75,7 +75,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
noToken := false
if token == "" {
// 若无, 则取sessionId
token = c.Session.Id()
token = c.Session.ID()
noToken = true
}
c.Session["_token"] = token
@@ -90,15 +90,15 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
if noToken && userId == "" {
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
// 客户端
userId, _ = c.Session["UserId"];
userId, _ = c.Session["UserId"]
}
c.Session["_userId"] = userId
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
if userId != "" {
return nil // 已登录
}
@@ -106,7 +106,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
// 没有登录, 返回错误的信息, 需要登录
re := info.NewApiRe()
re.Msg = "NOTLOGIN"
return c.RenderJson(re)
return c.RenderJSON(re)
}
func init() {

View File

@@ -1,10 +1,10 @@
package controllers
import (
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/blog"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
)
@@ -68,7 +68,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true/*, "DownloadAll": true*/},
"Attach": map[string]bool{"Download": true /*, "DownloadAll": true*/},
}
func needValidate(controller, method string) bool {
@@ -103,7 +103,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
re := info.NewRe()
re.Msg = "NOTLOGIN"
return c.RenderJson(re)
return c.RenderJSON(re)
}
return c.Redirect("/login")

View File

@@ -1,15 +1,15 @@
package member
import (
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
. "github.com/leanote/leanote/app/lea"
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
@@ -20,34 +20,34 @@ type MemberBaseController struct {
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc;
return sorterField, isAsc
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc;
return sorterField, isAsc
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc;
return sorterField, isAsc
}
}
sorterField = strings.Title(s2[0])
if s2[1] == "up" {
isAsc = true
} else {
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc;
c.ViewArgs["sorter"] = sorter
return sorterField, isAsc
}
func (c MemberBaseController) updateConfig(keys []string) {
@@ -56,4 +56,4 @@ func (c MemberBaseController) updateConfig(keys []string) {
v := c.Params.Values.Get(key)
configService.UpdateGlobalStringConfig(userId, key, v)
}
}
}

View File

@@ -21,13 +21,13 @@ type MemberBlog struct {
func (c MemberBlog) common() info.UserBlog {
userId := c.GetUserId()
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
c.ViewArgs["userInfo"] = userInfo
// 得到博客设置信息
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
c.ViewArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
userBlog := blogService.GetUserBlog(userId)
c.RenderArgs["userBlog"] = userBlog
c.ViewArgs["userBlog"] = userBlog
c.SetUserInfo()
c.SetLocale()
@@ -62,7 +62,7 @@ func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string)
} else {
isAsc = false
}
c.RenderArgs["sorter"] = sorter
c.ViewArgs["sorter"] = sorter
return sorterField, isAsc
}
@@ -72,18 +72,20 @@ var userPageSize = 15
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
userId := c.GetUserId()
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
c.ViewArgs["userInfo"] = userInfo
c.RenderArgs["title"] = "Posts"
c.ViewArgs["title"] = c.Message("Posts")
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords
c.ViewArgs["pageInfo"] = pageInfo
c.ViewArgs["blogs"] = blogs
c.ViewArgs["keywords"] = keywords
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
c.RenderArgs["userAndBlog"] = userAndBlog
c.ViewArgs["userAndBlog"] = userAndBlog
c.common()
return c.RenderTemplate("member/blog/list.html")
}
@@ -92,48 +94,48 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 修改笔记的urlTitle
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
c.RenderArgs["title"] = "Update Post Abstract"
c.common()
c.ViewArgs["title"] = c.Message("Update Post Abstract")
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
if !note.Note.IsBlog {
return c.E404()
}
c.RenderArgs["note"] = note
c.RenderArgs["noteId"] = noteId
c.ViewArgs["note"] = note
c.ViewArgs["noteId"] = noteId
return c.RenderTemplate("member/blog/update_abstract.html")
}
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 基本信息设置
func (c MemberBlog) Base() revel.Result {
c.common()
c.RenderArgs["title"] = "Blog Base Info"
c.ViewArgs["title"] = c.Message("Blog Base Info")
return c.RenderTemplate("member/blog/base.html")
}
func (c MemberBlog) Comment() revel.Result {
c.common()
c.RenderArgs["title"] = "Comment"
c.ViewArgs["title"] = c.Message("Comment")
return c.RenderTemplate("member/blog/comment.html")
}
func (c MemberBlog) Paging() revel.Result {
c.common()
c.RenderArgs["title"] = "Paging"
c.ViewArgs["title"] = c.Message("Paging")
return c.RenderTemplate("member/blog/paging.html")
}
func (c MemberBlog) Cate() revel.Result {
userBlog := c.common()
c.RenderArgs["title"] = "Cate"
c.ViewArgs["title"] = c.Message("Category")
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
notebooksMap := map[string]info.Notebook{}
@@ -164,7 +166,7 @@ func (c MemberBlog) Cate() revel.Result {
i++
}
}
c.RenderArgs["notebooks"] = notebooks2
c.ViewArgs["notebooks"] = notebooks2
return c.RenderTemplate("member/blog/cate.html")
}
@@ -173,54 +175,54 @@ func (c MemberBlog) Cate() revel.Result {
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 保存之, 包含增加与保存
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
re := info.NewRe()
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
c.common()
c.RenderArgs["title"] = "Add Single"
c.RenderArgs["singleId"] = singleId
c.ViewArgs["title"] = c.Message("Add Single")
c.ViewArgs["singleId"] = singleId
if singleId != "" {
c.RenderArgs["title"] = "Update Single"
c.RenderArgs["single"] = blogService.GetSingle(singleId)
c.ViewArgs["title"] = c.Message("Update Single")
c.ViewArgs["single"] = blogService.GetSingle(singleId)
}
return c.RenderTemplate("member/blog/add_single.html")
}
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
re := info.NewRe()
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
re := info.NewRe()
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 修改页面标题
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) Single() revel.Result {
c.common()
c.RenderArgs["title"] = "Cate"
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
c.ViewArgs["title"] = c.Message("Single")
c.ViewArgs["singles"] = blogService.GetSingles(c.GetUserId())
return c.RenderTemplate("member/blog/single.html")
}
@@ -229,12 +231,12 @@ func (c MemberBlog) Single() revel.Result {
func (c MemberBlog) Theme() revel.Result {
c.common()
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
c.RenderArgs["activeTheme"] = activeTheme
c.RenderArgs["otherThemes"] = otherThemes
c.ViewArgs["activeTheme"] = activeTheme
c.ViewArgs["otherThemes"] = otherThemes
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
c.ViewArgs["optionThemes"] = themeService.GetDefaultThemes()
c.RenderArgs["title"] = "Theme"
c.ViewArgs["title"] = c.Message("Theme")
return c.RenderTemplate("member/blog/theme.html")
}
@@ -251,11 +253,11 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
}
c.common()
c.RenderArgs["title"] = "Upate Theme"
c.RenderArgs["isNew"] = isNew
c.ViewArgs["title"] = c.Message("Update Theme")
c.ViewArgs["isNew"] = isNew
// 先复制之
c.RenderArgs["themeId"] = themeId
c.ViewArgs["themeId"] = themeId
// 得到脚本目录
userId := c.GetUserId()
@@ -264,7 +266,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
if theme.ThemeId == "" {
return c.E404()
}
c.RenderArgs["theme"] = theme
c.ViewArgs["theme"] = theme
path := revel.BasePath + "/" + theme.Path
@@ -285,7 +287,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
}
}
c.RenderArgs["myTpls"] = myTpls
c.ViewArgs["myTpls"] = myTpls
return c.RenderTemplate("member/blog/update_theme.html")
}
@@ -296,7 +298,7 @@ func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result
re.Ok = true
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
re := info.NewRe()
@@ -307,7 +309,7 @@ func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Re
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
re := info.NewRe()
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
@@ -318,22 +320,22 @@ func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
images := ListDir(path)
re.List = images
re.Ok = true
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
re := info.NewRe()
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
re.Ok = DeleteFile(path)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 上传主题图片
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
re := c.uploadImage(themeId)
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
c.ViewArgs["fileUrlPath"] = re.Id
c.ViewArgs["resultCode"] = re.Code
c.ViewArgs["resultMsg"] = re.Msg
return c.RenderTemplate("file/blog_logo.html")
}
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
@@ -349,14 +351,21 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
re.Ok = Ok
}()
file, handel, err := c.Request.FormFile("file")
if err != nil {
var data []byte
c.Params.Bind(&data, "file")
handel := c.Params.Files["file"][0]
if data == nil || len(data) == 0 {
return re
}
defer file.Close()
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// return re
// }
// defer file.Close()
// 生成上传路径
dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images"
err = os.MkdirAll(dir, 0755)
err := os.MkdirAll(dir, 0755)
if err != nil {
return re
}
@@ -372,11 +381,11 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
}
filename = filename
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return re
}
// data, err := ioutil.ReadAll(file)
// if err != nil {
// LogJ(err)
// return re
// }
// > 2M?
if len(data) > 5*1024*1024 {
@@ -403,21 +412,21 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 删除主题
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 管理员公开主题
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 导出
@@ -439,20 +448,27 @@ func (c MemberBlog) ExportTheme(themeId string) revel.Result {
func (c MemberBlog) ImportTheme() revel.Result {
re := info.NewRe()
file, handel, err := c.Request.FormFile("file")
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
var data []byte
c.Params.Bind(&data, "file")
handel := c.Params.Files["file"][0]
if data == nil || len(data) == 0 {
return c.RenderJSON(re)
}
defer file.Close()
// file, handel, err := c.Request.FormFile("file")
// if err != nil {
// re.Msg = fmt.Sprintf("%v", err)
// return c.RenderJSON(re)
// }
// defer file.Close()
// 生成上传路径
userId := c.GetUserId()
dir := revel.BasePath + "/public/upload/" + userId + "/tmp"
err = os.MkdirAll(dir, 0755)
err := os.MkdirAll(dir, 0755)
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 生成新的文件名
filename := handel.Filename
@@ -461,26 +477,26 @@ func (c MemberBlog) ImportTheme() revel.Result {
_, ext = SplitFilename(filename)
if ext != ".zip" {
re.Msg = "Please upload zip file"
return c.RenderJson(re)
return c.RenderJSON(re)
}
filename = filename
data, err := ioutil.ReadAll(file)
if err != nil {
return c.RenderJson(re)
}
// data, err := ioutil.ReadAll(file)
// if err != nil {
// return c.RenderJSON(re)
// }
// > 10M?
if len(data) > 10*1024*1024 {
re.Msg = "File is big than 10M"
return c.RenderJson(re)
return c.RenderJSON(re)
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 上传好后, 增加之
@@ -492,7 +508,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
return c.RenderJSON(re)
}
// 新建主题
@@ -506,17 +522,17 @@ func (c MemberBlog) NewTheme() revel.Result {
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {

View File

@@ -1,8 +1,8 @@
package member
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
)
// 分组管理
@@ -14,22 +14,22 @@ type MemberGroup struct {
func (c MemberGroup) Index() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "My Group"
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
return c.RenderTemplate("member/group/index.html");
c.ViewArgs["title"] = c.Message("My Group")
c.ViewArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
return c.RenderTemplate("member/group/index.html")
}
// 添加分组
func (c MemberGroup) AddGroup(title string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
re := info.NewRe()
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
return c.RenderJson(re)
return c.RenderJSON(re)
}
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {

View File

@@ -13,25 +13,25 @@ type MemberIndex struct {
// admin 主页
func (c MemberIndex) Index() revel.Result {
c.SetUserInfo()
c.RenderArgs["title"] = "Leanote Member Center"
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
c.ViewArgs["title"] = c.Message("Leanote Member Center")
c.ViewArgs["countNote"] = noteService.CountNote(c.GetUserId())
c.ViewArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
c.SetLocale()
return c.RenderTemplate("member/index.html");
return c.RenderTemplate("member/index.html")
}
// 模板
func (c MemberIndex) T(t string) revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
c.ViewArgs["str"] = configService.GlobalStringConfigs
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
c.ViewArgs["map"] = configService.GlobalMapConfigs
c.ViewArgs["arrMap"] = configService.GlobalArrMapConfigs
return c.RenderTemplate("admin/" + t + ".html")
}
func (c MemberIndex) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view);
}
return c.RenderTemplate("admin/" + view)
}

View File

@@ -13,34 +13,28 @@ type MemberUser struct {
func (c MemberUser) Username() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Username"
return c.RenderTemplate("member/user/username.html");
c.ViewArgs["title"] = c.Message("Username")
return c.RenderTemplate("member/user/username.html")
}
func (c MemberUser) Email() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Email"
return c.RenderTemplate("member/user/email.html");
c.ViewArgs["title"] = c.Message("Email")
return c.RenderTemplate("member/user/email.html")
}
func (c MemberUser) Password() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Password"
return c.RenderTemplate("member/user/password.html");
c.ViewArgs["title"] = c.Message("Password")
return c.RenderTemplate("member/user/password.html")
}
func (c MemberUser) Avatar() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Avatar"
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
return c.RenderTemplate("member/user/avatar.html");
c.ViewArgs["title"] = c.Message("Avatar")
c.ViewArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
return c.RenderTemplate("member/user/avatar.html")
}
func (c MemberUser) AddAccount() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Add Account"
return c.RenderTemplate("member/user/add_account.html");
}

View File

@@ -1,11 +1,11 @@
package member
import (
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "strings"
// "strings"
)
var userService *service.UserService
@@ -20,9 +20,9 @@ var blogService *service.BlogService
var tagService *service.TagService
var pwdService *service.PwdService
var tokenService *service.TokenService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var fileService *service.FileService
var attachService *service.AttachService
var configService *service.ConfigService
@@ -33,31 +33,32 @@ var themeService *service.ThemeService
// 拦截器
// 不需要拦截的url
// Index 除了Note之外都不需要
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
"Login": true,
"DoLogin": true,
"Logout": true,
"Register": true,
"DoRegister": true,
"FindPasswword": true,
"DoFindPassword": true,
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
"Login": true,
"DoLogin": true,
"Logout": true,
"Register": true,
"DoRegister": true,
"FindPasswword": true,
"DoFindPassword": true,
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
"View": true,
"AboutMe": true,
"SearchBlog": true,
},
},
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail":true,
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"ActiveEmail": true,
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
@@ -68,33 +69,33 @@ func needValidate(controller, method string) bool {
return true
} else {
// controller不在这里的, 肯定要验证
return true;
return true
}
}
func AuthInterceptor(c *revel.Controller) revel.Result {
// 全部变成首字大写
/*
var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName)
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName)
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
*/
// 验证是否已登录
// 必须是管理员
if _, ok := c.Session["Username"]; ok {
return nil // 已登录
}
// 没有登录, 判断是否是ajax操作
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
re := info.NewRe()
re.Msg = "NOTLOGIN"
return c.RenderJson(re)
return c.RenderJSON(re)
}
return c.Redirect("/login")
}
@@ -113,7 +114,7 @@ func InitService() {
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService= service.AlbumS
albumService = service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
@@ -131,4 +132,4 @@ func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberGroup{})
revel.OnAppStart(func() {
})
}
}

View File

@@ -1,2 +0,0 @@
包括基本信息设置
博客设置

View File

@@ -2,8 +2,8 @@ package db
import (
"fmt"
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"strings"
@@ -61,7 +61,7 @@ var Sessions *mgo.Collection
func Init(url, dbname string) {
ok := true
config := revel.Config
if url == "" {
if url == "" {
url, ok = config.String("db.url")
if !ok {
url, ok = config.String("db.urlEnv")
@@ -71,7 +71,7 @@ func Init(url, dbname string) {
} else {
Log("get db conf from db.url: " + url)
}
if ok {
// get dbname from urlEnv
urls := strings.Split(url, "/")
@@ -81,7 +81,7 @@ func Init(url, dbname string) {
if dbname == "" {
dbname, _ = config.String("db.dbname")
}
// get db config from host, port, username, password
if !ok {
host, _ := revel.Config.String("db.host")
@@ -124,7 +124,7 @@ func Init(url, dbname string) {
// user
Users = Session.DB(dbname).C("users")
// group
// group
Groups = Session.DB(dbname).C("groups")
GroupUsers = Session.DB(dbname).C("group_users")
@@ -360,15 +360,15 @@ func Err(err error) bool {
// 每个请求之前都要检查!!
func CheckMongoSessionLost() {
// fmt.Println("检查CheckMongoSessionLostErr")
err := Session.Ping()
if err != nil {
Log("Lost connection to db!")
Session.Refresh()
err = Session.Ping()
if err == nil {
Log("Reconnect to db successful.")
} else {
Log("重连失败!!!! 警告")
}
}
err := Session.Ping()
if err != nil {
Log("Lost connection to db!")
Session.Refresh()
err = Session.Ping()
if err == nil {
Log("Reconnect to db successful.")
} else {
Log("重连失败!!!! 警告")
}
}
}

View File

@@ -1,91 +0,0 @@
package main
import (
"fmt"
"os"
"bufio"
"strings"
"encoding/json"
)
// convert revel msg to js msg
var msgBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/messages/"
var targetBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/js/i18n/"
func parse(filename string) {
file, err := os.Open(msgBasePath + filename)
reader := bufio.NewReader(file)
msg := map[string]string{}
if err != nil {
fmt.Println(err)
return
}
for true {
line, _, err := reader.ReadLine()
if err != nil {
break
}
if len(line) == 0 {
continue
}
// 对每一行进行处理
if line[0] == '#' || line[1] == '#' {
continue;
}
lineStr := string(line)
// 找到第一个=位置
pos := strings.Index(lineStr, "=")
if pos < 0 {
continue;
}
key := string(line[0:pos])
value := string(line[pos+1:])
// fmt.Println(lineStr)
// fmt.Println(value)
msg[key] = value
}
// JSON
b, _ := json.Marshal(msg)
str := string(b)
fmt.Println(str);
targetName := targetBasePath + filename + ".js"
file2, err2 := os.OpenFile(targetName, os.O_RDWR|os.O_CREATE, 0644)
if err2 != nil {
file2, err2 = os.Create(targetName)
}
file2.WriteString("var MSG = " + str + ";" + `
function getMsg(key, data) {
var msg = MSG[key]
if(msg) {
if(data) {
if(!isArray(data)) {
data = [data];
}
for(var i = 0; i < data.length; ++i) {
msg = msg.replace("%s", data[i]);
}
}
return msg;
}
return key;
}`)
}
// 生成js的i18n文件
func main() {
parse("msg.en")
parse("msg.zh")
parse("msg.fr")
parse("blog.zh")
parse("blog.en")
parse("blog.fr")
}

View File

@@ -1,20 +1,20 @@
package info
import (
"time"
"gopkg.in/mgo.v2/bson"
"time"
)
//---------
// 数据结构
//---------
type NoteFile struct {
FileId string // 服务器端Id
FileId string // 服务器端Id
LocalFileId string // 客户端Id
Type string // images/png, doc, xls, 根据fileName确定
Title string
HasBody bool // 传过来的值是否要更新内容
IsAttach bool // 是否是附件, 不是附件就是图片
Type string // images/png, doc, xls, 根据fileName确定
Title string
HasBody bool // 传过来的值是否要更新内容
IsAttach bool // 是否是附件, 不是附件就是图片
}
type ApiNote struct {
NoteId string
@@ -22,32 +22,31 @@ type ApiNote struct {
UserId string
Title string
Desc string
// ImgSrc string
// ImgSrc string
Tags []string
Abstract string
Content string
IsMarkdown bool
// FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
IsTrash bool
IsDeleted bool
Usn int
Files []NoteFile
// FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
IsTrash bool
IsDeleted bool
Usn int
Files []NoteFile
CreatedTime time.Time
UpdatedTime time.Time
PublicTime time.Time
PublicTime time.Time
}
// 内容
type ApiNoteContent struct {
NoteId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `bson:"UserId"`
Content string `Content`
Content string `Content`
// CreatedTime time.Time `CreatedTime`
// UpdatedTime time.Time `UpdatedTime`
// CreatedTime time.Time `CreatedTime`
// UpdatedTime time.Time `UpdatedTime`
}
// 转换
@@ -61,11 +60,11 @@ func NoteToApiNote(note Note, files []NoteFile) ApiNote {
//----------
type ApiUser struct {
UserId string
UserId string
Username string
Email string
Email string
Verified bool
Logo string
Logo string
}
//----------
@@ -81,8 +80,8 @@ type ApiNotebook struct {
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
CreatedTime time.Time `CreatedTime,omitempty`
UpdatedTime time.Time `UpdatedTime,omitempty`
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
}
//---------
@@ -91,7 +90,7 @@ type ApiNotebook struct {
// 一般返回
type ApiRe struct {
Ok bool
Ok bool
Msg string
}
@@ -101,19 +100,20 @@ func NewApiRe() ApiRe {
// auth
type AuthOk struct {
Ok bool
Token string
UserId bson.ObjectId
Email string
Ok bool
Token string
UserId bson.ObjectId
Email string
Username string
}
// 供notebook, note, tag更新的返回数据用
type ReUpdate struct {
Ok bool
Ok bool
Msg string
Usn int
}
func NewReUpdate() ReUpdate {
return ReUpdate{Ok: false}
}
}

View File

@@ -7,15 +7,15 @@ import (
// Attach belongs to note
type Attach struct {
AttachId bson.ObjectId `bson:"_id,omitempty"` //
NoteId bson.ObjectId `bson:"NoteId"` //
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
Name string `Name` // file name, md5, such as 13232312.doc
Title string `Title` // raw file name
Size int64 `Size` // file size (byte)
Type string `Type` // file type, "doc" = word
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
CreatedTime time.Time `CreatedTime`
AttachId bson.ObjectId `bson:"_id,omitempty"` //
NoteId bson.ObjectId `bson:"NoteId"` //
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
Name string `Name` // file name, md5, such as 13232312.doc
Title string `Title` // raw file name
Size int64 `Size` // file size (byte)
Type string `Type` // file type, "doc" = word
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
CreatedTime time.Time `CreatedTime`
// FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
}

View File

@@ -7,51 +7,52 @@ import (
// 仅仅为了博客的主题
type BlogInfoCustom struct {
UserId string
Username string
UserLogo string
Title string
SubTitle string
Logo string
UserId string
Username string
UserLogo string
Title string
SubTitle string
Logo string
OpenComment bool
CommentType string
ThemeId string
SubDomain string
Domain string
ThemeId string
SubDomain string
Domain string
}
type Post struct {
NoteId string
Title string
UrlTitle string
ImgSrc string
NoteId string
Title string
UrlTitle string
ImgSrc string
CreatedTime time.Time
UpdatedTime time.Time
PublicTime time.Time
Desc string
Abstract string
Content string
Tags []string
CommentNum int
ReadNum int
LikeNum int
IsMarkdown bool
PublicTime time.Time
Desc string
Abstract string
Content string
Tags []string
CommentNum int
ReadNum int
LikeNum int
IsMarkdown bool
}
// 归档
type ArchiveMonth struct {
Month int
Posts []*Post
}
type Archive struct {
Year int
Year int
MonthAchives []ArchiveMonth
Posts []*Post
Posts []*Post
}
type Cate struct {
CateId string
CateId string
ParentCateId string
Title string
UrlTitle string
Children []*Cate
Title string
UrlTitle string
Children []*Cate
}

View File

@@ -9,17 +9,17 @@ import (
type BlogItem struct {
Note
Abstract string
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
HasMore bool // 是否是否还有
User User // 用户信息
Abstract string
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
HasMore bool // 是否是否还有
User User // 用户信息
}
type UserBlogBase struct {
Logo string `Logo`
Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题
// AboutMe string `AboutMe` // 关于我
// AboutMe string `AboutMe` // 关于我
}
type UserBlogComment struct {
@@ -49,32 +49,32 @@ type UserBlog struct {
Style string `Style` // 风格
Css string `Css` // 自定义css
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
CateIds []string `CateIds,omitempty` // 分类Id, 排序好的
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
PerPageSize int `PerPageSize,omitempty`
SortField string `SortField` // 排序字段
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
PerPageSize int `PerPageSize,omitempty`
SortField string `SortField` // 排序字段
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
SubDomain string `SubDomain` // 二级域名
Domain string `Domain` // 自定义域名
}
// 博客统计信息
type BlogStat struct {
NoteId bson.ObjectId `bson:"_id,omitempty"`
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
NoteId bson.ObjectId `bson:"_id,omitempty"`
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
}
// 单页
type BlogSingle struct {
SingleId bson.ObjectId `bson:"_id,omitempty"`
SingleId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `UserId`
Title string `Title`
UrlTitle string `UrlTitle` // 2014/11/11
@@ -117,12 +117,12 @@ type BlogCommentPublic struct {
}
type BlogUrls struct {
IndexUrl string
CateUrl string
SearchUrl string
SingleUrl string
PostUrl string
ArchiveUrl string
TagsUrl string
IndexUrl string
CateUrl string
SearchUrl string
SingleUrl string
PostUrl string
ArchiveUrl string
TagsUrl string
TagPostsUrl string
}

View File

@@ -10,9 +10,9 @@ type Config struct {
ConfigId bson.ObjectId `bson:"_id"`
UserId bson.ObjectId `UserId`
Key string `Key`
ValueStr string `ValueStr,omitempty` // "1"
ValueArr []string `ValueArr,omitempty` // ["1","b","c"]
ValueMap map[string]string `ValueMap,omitempty` // {"a":"bb", "CC":"xx"}
ValueStr string `ValueStr,omitempty` // "1"
ValueArr []string `ValueArr,omitempty` // ["1","b","c"]
ValueMap map[string]string `ValueMap,omitempty` // {"a":"bb", "CC":"xx"}
ValueArrMap []map[string]string `ValueArrMap,omitempty` // [{"a":"B"}, {}, {}]
IsArr bool `IsArr` // 是否是数组
IsMap bool `IsMap` // 是否是Map

View File

@@ -9,4 +9,4 @@ type NoteImage struct {
NoteImageId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
NoteId bson.ObjectId `bson:"NoteId"` // 笔记
ImageId bson.ObjectId `bson:"ImageId"` // 图片fileId
}
}

View File

@@ -15,6 +15,8 @@ type Note struct {
Title string `Title` // 标题
Desc string `Desc` // 描述, 非html
Src string `Src,omitempty` // 来源, 2016/4/22
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
Tags []string `Tags,omitempty`
@@ -34,15 +36,15 @@ type Note struct {
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
AttachNum int `AttachNum` // 2014/9/21, attachments num
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted` // 删除位
}
@@ -80,3 +82,31 @@ type NoteContentHistory struct {
UserId bson.ObjectId `bson:"UserId"` // 所属者
Histories []EachHistory `Histories`
}
// 为了NoteController接收参数
// 更新note或content
// 肯定会传userId(谁的), NoteId
// 会传Title, Content, Tags, 一种或几种
type NoteOrContent struct {
NotebookId string
NoteId string
UserId string
Title string
Desc string
Src string
ImgSrc string
Tags string
Content string
Abstract string
IsNew bool
IsMarkdown bool
FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
}
// 分开的
type NoteAndContentSep struct {
NoteInfo Note
NoteContentInfo NoteContent
}

View File

@@ -19,9 +19,9 @@ type Notebook struct {
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
CreatedTime time.Time `CreatedTime,omitempty`
UpdatedTime time.Time `UpdatedTime,omitempty`
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
}

View File

@@ -1,18 +1,17 @@
package info
import (
)
import ()
// controller ajax返回
type Re struct {
Ok bool
Ok bool
Code int
Msg string
Id string
Msg string
Id string
List interface{}
Item interface{}
}
func NewRe() Re {
return Re{Ok: false}
}
}

View File

@@ -13,8 +13,8 @@ type Session struct {
LoginTimes int `LoginTimes` // 登录错误时间
Captcha string `Captcha` // 验证码
UserId string `UserId` // API时有值UserId
UserId string `UserId` // API时有值UserId
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空

View File

@@ -18,28 +18,28 @@ type TagNote struct {
// 每个用户一条记录, 存储用户的所有tags
type Tag struct {
UserId bson.ObjectId `bson:"_id"`
Tags []string `Tags`
UserId bson.ObjectId `bson:"_id"`
Tags []string `Tags`
}
// v2 版标签
type NoteTag struct {
TagId bson.ObjectId `bson:"_id"`
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag` // UserId, Tag是唯一索引
Usn int `Usn` // Update Sequence Number
Count int `Count` // 笔记数
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
IsDeleted bool `IsDeleted` // 删除位
TagId bson.ObjectId `bson:"_id"`
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag` // UserId, Tag是唯一索引
Usn int `Usn` // Update Sequence Number
Count int `Count` // 笔记数
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
IsDeleted bool `IsDeleted` // 删除位
}
type TagCount struct {
TagCountId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag`
IsBlog bool `IsBlog` // 是否是博客的tag统计
Count int `Count` // 统计数量
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag`
IsBlog bool `IsBlog` // 是否是博客的tag统计
Count int `Count` // 统计数量
}
/*

View File

@@ -18,7 +18,7 @@ type Theme struct {
Info map[string]interface{} `Info` // 所有信息
IsActive bool `IsActive` // 是否在用
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
CreatedTime time.Time `CreatedTime`

View File

@@ -18,7 +18,7 @@ const (
// 过期时间
const (
PwdOverHours = 2.0
PwdOverHours = 2.0
ActiveEmailOverHours = 48.0
UpdateEmailOverHours = 2.0
)
@@ -29,4 +29,4 @@ type Token struct {
Token string `Token`
Type int `Type`
CreatedTime time.Time `CreatedTime`
}
}

View File

@@ -73,8 +73,8 @@ type UserAccount struct {
// note主页需要
type UserAndBlogUrl struct {
User
BlogUrl string `BlogUrl`
PostUrl string `PostUrl`
BlogUrl string `BlogUrl`
PostUrl string `PostUrl`
}
// 用户与博客信息结合, 公开

View File

@@ -4,14 +4,13 @@ import (
"math"
)
// 分页数据
type Page struct {
CurPage int // 当前页码
TotalPage int // 总页
CurPage int // 当前页码
TotalPage int // 总页
PerPageSize int
Count int // 总记录数
List interface{}
Count int // 总记录数
List interface{}
}
func NewPage(page, perPageSize, count int, list interface{}) Page {

View File

@@ -1,77 +1,79 @@
package app
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/controllers/api"
"github.com/leanote/leanote/app/controllers/admin"
"github.com/leanote/leanote/app/controllers/member"
_ "github.com/leanote/leanote/app/lea/binder"
"github.com/leanote/leanote/app/lea/route"
"reflect"
"encoding/json"
"fmt"
"github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/controllers/admin"
"github.com/leanote/leanote/app/controllers/api"
"github.com/leanote/leanote/app/controllers/member"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
_ "github.com/leanote/leanote/app/lea/binder"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/leanote/leanote/app/lea/route"
"github.com/leanote/leanote/app/service"
"github.com/revel/revel"
"html/template"
"math"
"strings"
"strconv"
"time"
"encoding/json"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
func init() {
// Filters is the default set of global filters.
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
revel.PanicFilter, // Recover from panics and display an error page instead.
route.RouterFilter,
// revel.RouterFilter, // Use the routing table to select the right Action
// AuthFilter, // Invoke the action.
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie.
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
// session.SessionFilter, // leanote session
// session.MSessionFilter, // leanote memcache session
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
revel.I18nFilter, // Resolve the requested language
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
// session.SessionFilter, // leanote session
// session.MSessionFilter, // leanote memcache session
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
// revel.I18nFilter, // Resolve the requested language
i18n.I18nFilter, // Resolve the requested language by leanote
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
}
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
return template.HTML(str)
}
revel.TemplateFuncs["trim"] = func(str string) string {
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
str = strings.Trim(str, "\n")
str = strings.Trim(str, "&nbsp;")
// 以下两个空格不一样
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
return str
}
revel.TemplateFuncs["add"] = func(i int) string {
i = i + 1;
i = i + 1
return fmt.Sprintf("%v", i)
}
revel.TemplateFuncs["sub"] = func(i int) int {
i = i - 1;
i = i - 1
return i
}
// 增加或减少
revel.TemplateFuncs["incr"] = func(n, i int) int {
n = n + i;
n = n + i
return n
}
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
@@ -95,11 +97,11 @@ func init() {
return v.Get("a")
}
revel.TemplateFuncs["json"] = func(i interface{}) string {
b, _ := json.Marshal(i)
b, _ := json.Marshal(i)
return string(b)
}
revel.TemplateFuncs["jsonJs"] = func(i interface{}) template.JS {
b, _ := json.Marshal(i)
b, _ := json.Marshal(i)
return template.JS(string(b))
}
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
@@ -113,10 +115,10 @@ func init() {
t := time.Unix(int64(sec), 0)
return template.HTML(t.Format("2006-01-02 15:04:05"))
}
// interface是否有该字段
revel.TemplateFuncs["has"] = func(i interface{}, key string) bool {
t := reflect.TypeOf(i)
t := reflect.TypeOf(i)
_, ok := t.FieldByName(key)
return ok
}
@@ -127,12 +129,12 @@ func init() {
if tags == nil || len(tags) == 0 {
return ""
}
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
tagStr := ""
lenTags := len(tags)
tagPostUrl, _ := renderArgs["tagPostsUrl"].(string)
for i, tag := range tags {
str := revel.Message(locale, tag)
var classes = "label"
@@ -144,24 +146,24 @@ func init() {
} else {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + "/" + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
var url = tagPostUrl + "/" + tag
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
if i != lenTags-1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
revel.TemplateFuncs["blogTagsForExport"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
tagStr := ""
lenTags := len(tags)
for i, tag := range tags {
str := tag
var classes = "label"
@@ -170,24 +172,32 @@ func init() {
} else {
classes += " label-default"
}
classes += " label-post"
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>";
if i != lenTags - 1 {
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>"
if i != lenTags-1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
revel.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
str, ok := renderArgs[revel.CurrentLocaleViewArg].(string)
if !ok {
return ""
}
return template.HTML(i18n.Message(str, message, args...))
}
// 不用revel的msg
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
str := revel.Message(locale, key)
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
str := i18n.Message(locale, key)
if strings.HasPrefix(str, "???") {
str = key
}
return template.HTML(str);
return template.HTML(str)
}
// lea++
@@ -195,19 +205,19 @@ func init() {
if tags == nil || len(tags) == 0 {
return ""
}
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
tagStr := ""
lenTags := len(tags)
tagPostUrl := "http://lea.leanote.com/"
if typeStr == "recommend" {
tagPostUrl += "?tag=";
tagPostUrl += "?tag="
} else if typeStr == "latest" {
tagPostUrl += "latest?tag=";
tagPostUrl += "latest?tag="
} else {
tagPostUrl += "subscription?tag=";
tagPostUrl += "subscription?tag="
}
for i, tag := range tags {
str := revel.Message(locale, tag)
var classes = "label"
@@ -220,67 +230,67 @@ func init() {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
var url = tagPostUrl + tag
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
if i != lenTags-1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
/*
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
// TODO 这里判断语言, 从语言包中拿
tagMap := map[string]string{"red": "红色", "yellow": "黄色", "blue": "蓝色", "green": "绿色"}
tagStr := ""
lenTags := len(tags)
for i, tag := range tags {
if text, ok := tagMap[tag]; ok {
tagStr += text
} else {
tagStr += tag
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
if i != lenTags - 1 {
tagStr += ","
// TODO 这里判断语言, 从语言包中拿
tagMap := map[string]string{"red": "红色", "yellow": "黄色", "blue": "蓝色", "green": "绿色"}
tagStr := ""
lenTags := len(tags)
for i, tag := range tags {
if text, ok := tagMap[tag]; ok {
tagStr += text
} else {
tagStr += tag
}
if i != lenTags - 1 {
tagStr += ","
}
}
return template.HTML(tagStr)
}
return template.HTML(tagStr)
}
*/
revel.TemplateFuncs["li"] = func(a string) string {
return ""
}
// str连接
revel.TemplateFuncs["urlConcat"] = func(url string, v... interface{}) string {
revel.TemplateFuncs["urlConcat"] = func(url string, v ...interface{}) string {
html := ""
for i := 0; i < len(v); i = i + 2 {
item := v[i]
if i+1 == len(v) {
break;
break
}
value := v[i+1]
if item != nil && value != nil {
keyStr, _ := item.(string)
valueStr, err := value.(string)
if !err {
valueInt, _ := value.(int)
valueStr = strconv.Itoa(valueInt)
}
if keyStr != "" && valueStr != "" {
s := keyStr + "=" + valueStr
if html != "" {
html += "&" + s
} else {
html += s
}
}
}
keyStr, _ := item.(string)
valueStr, err := value.(string)
if !err {
valueInt, _ := value.(int)
valueStr = strconv.Itoa(valueInt)
}
if keyStr != "" && valueStr != "" {
s := keyStr + "=" + valueStr
if html != "" {
html += "&" + s
} else {
html += s
}
}
}
}
if html != "" {
if strings.Index(url, "?") >= 0 {
return url + "&" + html
@@ -290,51 +300,51 @@ func init() {
}
return url
}
revel.TemplateFuncs["urlCond"] = func(url string, sorterI, keyords interface{}) template.HTML {
return ""
}
// http://stackoverflow.com/questions/14226416/go-lang-templates-always-quotes-a-string-and-removes-comments
revel.TemplateFuncs["rawMsg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.JS {
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
str, ok := renderArgs[revel.CurrentLocaleViewArg].(string)
if !ok {
return ""
}
return template.JS(revel.Message(str, message, args...))
}
// 为后台管理sorter th使用
// 必须要返回HTMLAttr, 返回html, golang 会执行安全检查返回ZgotmplZ
// sorterI 可能是nil, 所以用interfalce{}来接收
/*
data-url="/adminUser/index"
data-sorter="email"
class="th-sortable {{if eq .sorter "email-up"}}th-sort-up{{else}}{{if eq .sorter "email-down"}}th-sort-down{{end}}{{end}}"
data-url="/adminUser/index"
data-sorter="email"
class="th-sortable {{if eq .sorter "email-up"}}th-sort-up{{else}}{{if eq .sorter "email-down"}}th-sort-down{{end}}{{end}}"
*/
revel.TemplateFuncs["sorterTh"] = func(url, sorterField string, sorterI interface{}) template.HTMLAttr {
sorter := ""
if sorterI != nil {
sorter, _ = sorterI.(string)
}
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"";
html += " class=\"th-sortable ";
if sorter == sorterField + "-up" {
html += "th-sort-up\"";
} else if(sorter == sorterField + "-down") {
html += "th-sort-down";
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\""
html += " class=\"th-sortable "
if sorter == sorterField+"-up" {
html += "th-sort-up\""
} else if sorter == sorterField+"-down" {
html += "th-sort-down"
}
html += "\"";
html += "\""
return template.HTMLAttr(html)
}
// pagination
revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML {
if count == 0 {
return "";
return ""
}
totalPage := int(math.Ceil(float64(count)/float64(pageSize)))
totalPage := int(math.Ceil(float64(count) / float64(pageSize)))
preClass := ""
prePage := page - 1
if prePage == 0 {
@@ -343,10 +353,10 @@ func init() {
nextClass := ""
nextPage := page + 1
var preUrl, nextUrl string
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
nextUrl = urlBase + "?page=" + strconv.Itoa(nextPage)
// 没有上一页了
if page == 1 {
preClass = "disabled"
@@ -364,49 +374,49 @@ func init() {
// http://play.golang.org/p/snygrVpQva
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
/*
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
switch a1.(type) {
case string:
switch a2.(type) {
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
switch a1.(type) {
case string:
return reflect.ValueOf(a1).String() > reflect.ValueOf(a2).String()
}
case int, int8, int16, int32, int64:
switch a2.(type) {
switch a2.(type) {
case string:
return reflect.ValueOf(a1).String() > reflect.ValueOf(a2).String()
}
case int, int8, int16, int32, int64:
return reflect.ValueOf(a1).Int() > reflect.ValueOf(a2).Int()
}
case uint, uint8, uint16, uint32, uint64:
switch a2.(type) {
switch a2.(type) {
case int, int8, int16, int32, int64:
return reflect.ValueOf(a1).Int() > reflect.ValueOf(a2).Int()
}
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(a1).Uint() > reflect.ValueOf(a2).Uint()
}
case float32, float64:
switch a2.(type) {
switch a2.(type) {
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(a1).Uint() > reflect.ValueOf(a2).Uint()
}
case float32, float64:
return reflect.ValueOf(a1).Float() > reflect.ValueOf(a2).Float()
switch a2.(type) {
case float32, float64:
return reflect.ValueOf(a1).Float() > reflect.ValueOf(a2).Float()
}
}
return false
}
return false
}
*/
/*
{{range $i := N 1 10}}
<div>{{$i}}</div>
{{end}}
*/
{{range $i := N 1 10}}
<div>{{$i}}</div>
{{end}}
*/
revel.TemplateFuncs["N"] = func(start, end int) (stream chan int) {
stream = make(chan int)
go func() {
for i := start; i <= end; i++ {
stream <- i
}
close(stream)
}()
return
stream = make(chan int)
go func() {
for i := start; i <= end; i++ {
stream <- i
}
close(stream)
}()
return
}
// init Email
revel.OnAppStart(func() {
// 数据库

View File

@@ -1,26 +1,34 @@
package lea
import (
"encoding/json"
"github.com/revel/revel"
"fmt"
"encoding/json"
"fmt"
"github.com/revel/revel"
)
func Log(i interface{}) {
revel.INFO.Println(i)
func Log(msg string, i ...interface{}) {
revel.AppLog.Info(msg, i...)
}
func Logf(msg string, i ...interface{}) {
revel.AppLog.Infof(msg, i...)
}
func LogW(msg string, i ...interface{}) {
revel.AppLog.Warn(msg, i...)
}
func LogJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ")
revel.INFO.Println(string(b))
b, _ := json.MarshalIndent(i, "", " ")
revel.AppLog.Info(string(b))
}
// 为test用
func L(i interface{}) {
fmt.Println(i)
fmt.Println(i)
}
func LJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ")
fmt.Println(string(b))
b, _ := json.MarshalIndent(i, "", " ")
fmt.Println(string(b))
}

View File

@@ -1,10 +1,11 @@
package lea
import (
"github.com/revel/revel"
"net/smtp"
"strings"
"github.com/revel/revel"
)
// 发送邮件
var host = "smtp.ym.163.com"
var port = "25"
@@ -12,7 +13,7 @@ var username = "noreply@leanote.com"
var password = "---"
func InitEmail() {
config := revel.Config;
config := revel.Config
host, _ = config.String("email.host")
port, _ = config.String("email.port")
username, _ = config.String("email.username")
@@ -56,28 +57,28 @@ var bodyTpl = `
</body>
</html>
`
func SendEmailOld(to, subject, body string) bool {
hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", username, password, hp[0])
var content_type string
mailtype := "html"
if mailtype == "html" {
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
} else{
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
} else {
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
}
//body = strings.Replace(bodyTpl, "$body", body, 1)
//body = strings.Replace(body, "$title", title, 1)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
send_to := strings.Split(to, ";")
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
if err != nil {
Log(err)
return false
}
return true
@@ -85,5 +86,5 @@ func SendEmailOld(to, subject, body string) bool {
func SendToLeanoteOld(subject, title, body string) {
to := "leanote@leanote.com"
SendEmailOld(to, subject, body);
}
SendEmailOld(to, subject, body)
}

View File

@@ -116,13 +116,13 @@ func CopyDir(source string, dest string) (err error) {
// create sub-directories - recursively
err = CopyDir(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
// fmt.Println(err)
}
} else {
// perform copy
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
// fmt.Println(err)
}
}
}
@@ -183,7 +183,6 @@ func PutFileStrContent(path, content string) bool {
// Log(path)
if err1 != nil {
Log(err1)
return false
}
return true

View File

@@ -16,7 +16,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
transPath = path
wand.Genesis()
defer wand.Terminus()
w := wand.NewMagickWand()
defer w.Destroy()
@@ -24,7 +24,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
fmt.Println(err);
return;
}
width := w.ImageWidth()
height := w.ImageHeight()
if maxWidth != 0 {
@@ -34,14 +34,14 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
width = maxWidth
}
}
w.SetImageFormat("GIF");
if err := paint.Thumbnail(w, width, height); err != nil {
fmt.Println(err);
return;
}
// 判断是否是gif图片, 是就不用转换了
baseName, ext := SplitFilename(path)
var toPath string
@@ -50,19 +50,19 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
} else {
toPath = TransferExt(path, ".gif");
}
if err := w.WriteImage(toPath); err != nil {
fmt.Println(err);
return;
}
if afterDelete {
os.Remove(path)
}
ok = true
transPath = toPath
return
}
@@ -71,7 +71,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
func Reset(path string, maxWidth uint) (ok bool, transPath string){
wand.Genesis()
defer wand.Terminus()
w := wand.NewMagickWand()
defer w.Destroy()
@@ -79,7 +79,7 @@ func Reset(path string, maxWidth uint) (ok bool, transPath string){
fmt.Println(err);
return;
}
width := w.ImageWidth()
height := w.ImageHeight()
if maxWidth != 0 {
@@ -93,20 +93,20 @@ func Reset(path string, maxWidth uint) (ok bool, transPath string){
fmt.Println(err);
return;
}
toPath := TransferExt(path, ".gif");
if err := w.WriteImage(toPath); err != nil {
fmt.Println(err);
return;
}
ok = true
transPath = toPath
return
}
*/
func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPath string) {
return ok, path
}
}

View File

@@ -7,7 +7,7 @@ func ComparePwd(rawPwd, dbPwd string) bool {
if len(dbPwd) == 32 {
return Md5(rawPwd) == dbPwd
}
hex := []byte(dbPwd)
return CompareHash(hex, rawPwd)
}
@@ -19,4 +19,4 @@ func GenPwd(rawPwd string) string {
return ""
}
return string(digest)
}
}

View File

@@ -1,19 +1,19 @@
package lea
import (
"fmt"
"regexp"
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"io"
"gopkg.in/mgo.v2/bson"
"time"
"strings"
"fmt"
"github.com/PuerkitoBio/goquery"
"bytes"
math_rand "math/rand"
"gopkg.in/mgo.v2/bson"
"io"
math_rand "math/rand"
"regexp"
"strings"
"time"
)
// 字符串
@@ -31,14 +31,14 @@ func Digest3(str string) string {
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b % 1000)
return fmt.Sprintf("%d", b%1000)
}
func Digest2(str string) string {
var b rune = 0
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b % 100)
return fmt.Sprintf("%d", b%100)
}
// Guid
@@ -77,7 +77,7 @@ func Substr(str string, start, length int) string {
func substr(str string, start, length int, isRune bool) string {
rs := []rune(str)
rs2 := []byte(str)
rl := len(rs)
if !isRune {
rl = len(rs2)
@@ -161,7 +161,7 @@ func SubStringHTMLToRaw(param string, length int) string {
continue
} else if temp == '>' {
isCode = false
resultRune[n] = ' ';
resultRune[n] = ' '
n++
if n >= length {
@@ -170,7 +170,7 @@ func SubStringHTMLToRaw(param string, length int) string {
continue
}
if !isCode {
resultRune[n] = temp;
resultRune[n] = temp
// s += string(temp)
n++
if n >= length {
@@ -192,13 +192,13 @@ func fixHtml(result string) string {
// 把<div class=xxx的class=xxx去掉
tempResult = ReplaceAll(tempResult, "<(/?[a-zA-Z]+)[^<>]*>", "<$1>")
// 3 只能用正则,+stack来去有结束的
// golang的正则暂不支持back reference, 以后可以用它来去掉重复的标签
p, _ := regexp.Compile("<(/?[a-zA-Z]+)[^<>]*>") // 得到所有的<div>, </div>...
strs := p.FindAllString(tempResult, -1)
// fmt.Println(strs)
// fmt.Println(strs)
stack := make([]string, len(strs))
stackP := -1
for _, each := range strs {
@@ -215,14 +215,14 @@ func fixHtml(result string) string {
// 补全tag
if stackP != -1 {
fmt.Println(stack[0 : stackP+1])
for _, each := range stack[0 : stackP+1] {
if each[1] != '/' {
result += "</" + each[1:]
}
}
}
return result
}
@@ -241,10 +241,10 @@ func SubStringHTML(param string, length int, end string) string {
} else {
// 1
n := 0
var temp rune // 中文问题, 用rune来解决
var temp rune // 中文问题, 用rune来解决
isCode := false //是不是HTML代码
isHTML := false //是不是HTML特殊字符,如&nbsp;
var i = 0;
var i = 0
for ; i < lenStr; i++ {
temp = rStr[i]
if temp == '<' {
@@ -281,11 +281,11 @@ func SubStringHTML(param string, length int, end string) string {
html, _ := dom.Html()
html = strings.Replace(html, "<html><head></head><body>", "", 1)
html = strings.Replace(html, "</body></html>", "", 1)
// TODO 把style="float: left"去掉
return html
// 如果有错误, 则使用自己的方法补全, 有风险
// 如果有错误, 则使用自己的方法补全, 有风险
} else {
return fixHtml(result)
}
@@ -305,7 +305,7 @@ func IsGoodPwd(pwd string) (bool, string) {
// 是否是email
func IsEmail(email string) bool {
if email == "" {
return false;
return false
}
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.|\-]?)*[_a-z\-A-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-zA-Z0-9\-]+\.[0-9a-zA-Z]{2,6}$`, email)
return ok
@@ -314,7 +314,7 @@ func IsEmail(email string) bool {
// 是否只包含数字, 字母 -, _
func IsUsername(username string) bool {
if username == "" {
return false;
return false
}
ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username)
return !ok
@@ -351,15 +351,15 @@ func RandomPwd(num int) string {
chars[j] = byte(i)
j++
}
j--;
j--
str := ""
math_rand.Seed(time.Now().UnixNano())
for i := 0; i < num; i++ {
x := math_rand.Intn(j)
str += string(chars[x])
}
return str
}
@@ -379,14 +379,14 @@ func InArray(arr []string, str string) bool {
func FixFilename(filename string) string {
if filename != "" {
// 把特殊字段给替换掉
// str := `life "%&()+,/:;<>=?@\|`
// str := `life "%&()+,/:;<>=?@\|`
// . == \\.
// $ === \\$
reg, _ := regexp.Compile("\\.|/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
filename = reg.ReplaceAllString(filename, "-")
filename = strings.Trim(filename, "-") // 左右单独的-去掉
// 把空格替换成-
// filename = strings.Replace(filename, " ", "-", -1)
// filename = strings.Replace(filename, " ", "-", -1)
for strings.Index(filename, "--") >= 0 { // 防止出现连续的--
filename = strings.Replace(filename, "--", "-", -1)
}
@@ -394,3 +394,37 @@ func FixFilename(filename string) string {
}
return filename
}
// 是否是合法的时间
// 不是, 0001-01-01T00:00:00Z, 且比今天小
func IsValidTime(t time.Time) bool {
if t.Year() > 20 {
now := time.Now()
if t.Before(now) {
return true
}
}
return false
}
// url传过来的时间没有时区信息, 转到本地时间
func ToLocalTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, time.Local)
}
// 修复传过来的时间, 如果比今天大, 则设为现在
func FixUrlTime(t time.Time) time.Time {
localTime := ToLocalTime(t)
if IsValidTime(localTime) {
return localTime
}
return time.Now()
}
// 得到用户的随机文件路径 3位/userId/2位
func GetRandomFilePath(userId, uuid string) string {
if uuid == "" {
uuid = NewGuid()
}
return Digest3(userId) + "/" + userId + "/" + Digest2(uuid)
}

View File

@@ -2,8 +2,8 @@ package lea
import (
"encoding/json"
"strconv"
"regexp"
"strconv"
)
// 验证
@@ -38,15 +38,15 @@ var rulesStr = `{
`
var rulesMap map[string][]map[string]string
var rules = map[string]func(string, map[string]string)(bool, string) {
"required": func(value string, rule map[string]string)(ok bool, msg string) {
var rules = map[string]func(string, map[string]string) (bool, string){
"required": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
ok = true
return
return
},
"minLength": func(value string, rule map[string]string)(ok bool, msg string) {
"minLength": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
@@ -55,7 +55,7 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
ok = len(value) >= dataI
return
},
"min": func(value string, rule map[string]string)(ok bool, msg string) {
"min": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
@@ -65,8 +65,8 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
ok = vI >= dataI
return
},
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
"sortField": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
@@ -74,22 +74,22 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
ok = InArray(sortFields, value)
return
},
"password": func(value string, rule map[string]string)(ok bool, msg string) {
"password": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
ok = len(value) >= 6
return
},
"email": func(value string, rule map[string]string)(ok bool, msg string) {
"email": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
ok = IsEmail(value)
return
},
"noSpecialChars": func(value string, rule map[string]string)(ok bool, msg string) {
"noSpecialChars": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
@@ -97,8 +97,8 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
return
},
// www.baidu.com
//
"domain": func(value string, rule map[string]string)(ok bool, msg string) {
//
"domain": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
ok = true
return // 可为空
@@ -106,16 +106,16 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
ok2, _ := regexp.MatchString(`[^0-9a-zA-Z_\.\-]`, value)
ok = !ok2
if !ok {
return
return
}
ok = true
return
},
// abcd
"subDomain": func(value string, rule map[string]string)(ok bool, msg string) {
"subDomain": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
ok = true
return // 可为空
return // 可为空
}
if len(value) < 4 {
ok = false
@@ -137,7 +137,7 @@ func InitVd() {
func Vd(name, value string) (ok bool, msg string) {
rs, _ := rulesMap[name]
for _, rule := range rs {
ruleFunc, _ := rules[rule["rule"]]
if ok2, msg2 := ruleFunc(value, rule); !ok2 {
@@ -151,11 +151,11 @@ func Vd(name, value string) (ok bool, msg string) {
if msgData != "" {
msg += "-" + msgData
}
return
return
}
}
ok = true
return
return
}
func Vds(m map[string]string) (ok bool, msg string) {
@@ -166,5 +166,5 @@ func Vds(m map[string]string) (ok bool, msg string) {
}
}
ok = true
return
return
}

View File

@@ -1,12 +1,12 @@
package archive
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path"
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path"
)
// main functions shows how to TarGz a directory/file and
@@ -16,66 +16,66 @@ import (
func main() {
/*
os.Mkdir("/home/ty4z2008/tar", 0777)
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
//targetfile,sourcefile
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(w)
os.Mkdir("/home/ty4z2008/tar", 0777)
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
//targetfile,sourcefile
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(w)
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
os.RemoveAll("/home/ty4z2008/tar")
*/
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
fmt.Println("ok")
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
os.RemoveAll("/home/ty4z2008/tar")
*/
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
fmt.Println("ok")
}
func TarGz(srcDirPath string, destFilePath string) (ok bool) {
defer func() { //必须要先声明defer否则不能捕获到panic异常
defer func() { //必须要先声明defer否则不能捕获到panic异常
if err := recover(); err != nil {
ok = false
}
}()
fw, err := os.Create(destFilePath)
if err != nil {
panic(err)
}
defer fw.Close()
fw, err := os.Create(destFilePath)
// Gzip writer
gw := gzip.NewWriter(fw)
defer gw.Close()
if err != nil {
panic(err)
}
defer fw.Close()
// Tar writer
tw := tar.NewWriter(gw)
defer tw.Close()
// Gzip writer
gw := gzip.NewWriter(fw)
defer gw.Close()
// Check if it's a file or a directory
f, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
fi, err := f.Stat()
if err != nil {
panic(err)
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from directory...")
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
} else {
// handle file directly
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
tarGzFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
return
// Tar writer
tw := tar.NewWriter(gw)
defer tw.Close()
// Check if it's a file or a directory
f, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
fi, err := f.Stat()
if err != nil {
panic(err)
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from directory...")
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
} else {
// handle file directly
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
tarGzFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
return
}
// Deal with directories
@@ -83,148 +83,148 @@ func TarGz(srcDirPath string, destFilePath string) (ok bool) {
// Every recurrence append the base path to the recPath
// recPath is the path inside of tar.gz
func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
// Open source diretory
dir, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
defer dir.Close()
// Open source diretory
dir, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
defer dir.Close()
// Get file info slice
fis, err := dir.Readdir(0)
if err != nil {
panic(err)
}
for _, fi := range fis {
// Append path
curPath := srcDirPath + "/" + fi.Name()
// Check it is directory or file
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
}
// Get file info slice
fis, err := dir.Readdir(0)
if err != nil {
panic(err)
}
for _, fi := range fis {
// Append path
curPath := srcDirPath + "/" + fi.Name()
// Check it is directory or file
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
}
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
}
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
}
}
// Deal with files
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
if fi.IsDir() {
// fmt.Println("??")
// Create tar header
hdr := new(tar.Header)
// if last character of header name is '/' it also can be directory
// but if you don't set Typeflag, error will occur when you untargz
hdr.Name = recPath // + "/"
// fmt.Println(hdr.Name)
hdr.Typeflag = tar.TypeDir
// hdr.Size = 0
//hdr.Mode = 0755 | c_ISDIR
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
if fi.IsDir() {
// fmt.Println("??")
// Create tar header
hdr := new(tar.Header)
// if last character of header name is '/' it also can be directory
// but if you don't set Typeflag, error will occur when you untargz
hdr.Name = recPath // + "/"
// fmt.Println(hdr.Name)
hdr.Typeflag = tar.TypeDir
// hdr.Size = 0
//hdr.Mode = 0755 | c_ISDIR
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
// Write hander
err := tw.WriteHeader(hdr)
if err != nil {
panic(err)
}
} else {
// File reader
fr, err := os.Open(srcFile)
if err != nil {
panic(err)
}
defer fr.Close()
// Write hander
err := tw.WriteHeader(hdr)
if err != nil {
panic(err)
}
} else {
// File reader
fr, err := os.Open(srcFile)
if err != nil {
panic(err)
}
defer fr.Close()
// Create tar header
hdr := new(tar.Header)
hdr.Name = recPath
// fmt.Println(hdr.Name)
hdr.Size = fi.Size()
hdr.Mode = int64(fi.Mode())
hdr.ModTime = fi.ModTime()
// Create tar header
hdr := new(tar.Header)
hdr.Name = recPath
// fmt.Println(hdr.Name)
hdr.Size = fi.Size()
hdr.Mode = int64(fi.Mode())
hdr.ModTime = fi.ModTime()
// Write hander
err = tw.WriteHeader(hdr)
if err != nil {
panic(err)
}
// Write hander
err = tw.WriteHeader(hdr)
if err != nil {
panic(err)
}
// Write file data
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
}
// Write file data
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
}
}
// Ungzip and untar from source file to destination directory
// you need check file exist before you call this function
func UnTarGz(srcFilePath string, destDirPath string) {
// fmt.Println("UnTarGzing " + srcFilePath + "...")
// Create destination directory
os.Mkdir(destDirPath, os.ModePerm)
// fmt.Println("UnTarGzing " + srcFilePath + "...")
// Create destination directory
os.Mkdir(destDirPath, os.ModePerm)
fr, err := os.Open(srcFilePath)
if err != nil {
panic(err)
}
defer fr.Close()
fr, err := os.Open(srcFilePath)
if err != nil {
panic(err)
}
defer fr.Close()
// Gzip reader
gr, err := gzip.NewReader(fr)
if err != nil {
panic(err)
}
defer gr.Close()
// Gzip reader
gr, err := gzip.NewReader(fr)
if err != nil {
panic(err)
}
defer gr.Close()
// Tar reader
tr := tar.NewReader(gr)
// Tar reader
tr := tar.NewReader(gr)
for {
hdr, err := tr.Next()
if err == io.EOF {
// End of tar archive
break
}
//handleError(err)
// fmt.Println("UnTarGzing file..." + hdr.Name)
// Check if it is diretory or file
if hdr.Typeflag != tar.TypeDir {
// Get files from archive
// Create diretory before create file
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
// Write data to file
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
if err != nil {
panic(err)
}
_, err = io.Copy(fw, tr)
if err != nil {
panic(err)
}
}
}
// fmt.Println("Well done!")
for {
hdr, err := tr.Next()
if err == io.EOF {
// End of tar archive
break
}
//handleError(err)
// fmt.Println("UnTarGzing file..." + hdr.Name)
// Check if it is diretory or file
if hdr.Typeflag != tar.TypeDir {
// Get files from archive
// Create diretory before create file
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
// Write data to file
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
if err != nil {
panic(err)
}
_, err = io.Copy(fw, tr)
if err != nil {
panic(err)
}
}
}
// fmt.Println("Well done!")
}
// Copyfile
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}

View File

@@ -1,12 +1,13 @@
package archive
import (
"archive/zip"
"fmt"
"archive/zip"
"fmt"
"io"
"os"
"path"
"strings"
"io"
"os"
"path"
"github.com/leanote/leanote/app/lea"
)
// main functions shows how to TarGz a directory/file and
@@ -15,43 +16,43 @@ import (
// you need check file exist before you call this function
func Zip(srcDirPath string, destFilePath string) (ok bool) {
defer func() { //必须要先声明defer否则不能捕获到panic异常
defer func() { //必须要先声明defer否则不能捕获到panic异常
if err := recover(); err != nil {
ok = false
}
}()
fw, err := os.Create(destFilePath)
if err != nil {
panic(err)
}
defer fw.Close()
fw, err := os.Create(destFilePath)
// Tar writer
tw := zip.NewWriter(fw)
defer tw.Close()
if err != nil {
panic(err)
}
defer fw.Close()
// Check if it's a file or a directory
f, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
fi, err := f.Stat()
if err != nil {
panic(err)
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from directory...")
zipDir(srcDirPath, path.Base(srcDirPath), tw)
} else {
// handle file directly
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
zipFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
return
// Tar writer
tw := zip.NewWriter(fw)
defer tw.Close()
// Check if it's a file or a directory
f, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
fi, err := f.Stat()
if err != nil {
panic(err)
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from directory...")
zipDir(srcDirPath, path.Base(srcDirPath), tw)
} else {
// handle file directly
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
zipFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
return
}
// Deal with directories
@@ -59,69 +60,69 @@ func Zip(srcDirPath string, destFilePath string) (ok bool) {
// Every recurrence append the base path to the recPath
// recPath is the path inside of tar.gz
func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
// Open source diretory
dir, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
defer dir.Close()
// Open source diretory
dir, err := os.Open(srcDirPath)
if err != nil {
panic(err)
}
defer dir.Close()
// Get file info slice
fis, err := dir.Readdir(0)
if err != nil {
panic(err)
}
for _, fi := range fis {
// Append path
curPath := srcDirPath + "/" + fi.Name()
// Check it is directory or file
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
zipDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
}
// Get file info slice
fis, err := dir.Readdir(0)
if err != nil {
panic(err)
}
for _, fi := range fis {
// Append path
curPath := srcDirPath + "/" + fi.Name()
// Check it is directory or file
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
zipDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
}
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
}
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
}
}
// Deal with files
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
if fi.IsDir() {
// fmt.Println("??")
// Create tar header
/*
fh, err := zip.FileInfoHeader(fi)
if err != nil {
panic(err)
}
fh.Name = recPath // + "/"
err = tw.WriteHeader(hdr)
tw.Create(recPath)
*/
} else {
// File reader
fr, err := os.Open(srcFile)
if err != nil {
panic(err)
}
defer fr.Close()
if fi.IsDir() {
// fmt.Println("??")
// Create tar header
/*
fh, err := zip.FileInfoHeader(fi)
if err != nil {
panic(err)
}
fh.Name = recPath // + "/"
err = tw.WriteHeader(hdr)
tw.Create(recPath)
*/
} else {
// File reader
fr, err := os.Open(srcFile)
if err != nil {
panic(err)
}
defer fr.Close()
// Write hander
w, err2 := tw.Create(recPath)
if err2 != nil {
panic(err)
}
// Write file data
_, err = io.Copy(w, fr)
if err != nil {
panic(err)
}
}
// Write hander
w, err2 := tw.Create(recPath)
if err2 != nil {
panic(err)
}
// Write file data
_, err = io.Copy(w, fr)
if err != nil {
panic(err)
}
}
}
// Ungzip and untar from source file to destination directory
@@ -129,33 +130,39 @@ func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
ok = false
msg = ""
defer func() { //必须要先声明defer否则不能捕获到panic异常
defer func() { //必须要先声明defer否则不能捕获到panic异常
if err := recover(); err != nil {
msg = fmt.Sprintf("%v", err)
ok = false
}
}()
os.Mkdir(destDirPath, os.ModePerm)
r, err := zip.OpenReader(srcFilePath);
r, err := zip.OpenReader(srcFilePath)
if err != nil {
panic(err)
}
defer r.Close();
defer r.Close()
for _, f := range r.File {
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
rc, err := f.Open();
if err!=nil {
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
rc, err := f.Open()
if err != nil {
panic(err)
}
// 包含恶意目录
if strings.Contains(f.Name, "../") {
lea.LogW("恶意文件", f.Name);
continue
}
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
paths := strings.Split(f.Name, "/")
prePath := ""
filename := ""
l := len(paths)
// fmt.Println(l)
// fmt.Println(l)
if l > 1 {
// 去掉第1个文件夹
if l == 2 {
@@ -167,26 +174,26 @@ func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
} else {
filename = f.Name
}
// fmt.Println(prePath)
// fmt.Println(prePath)
// 相对于目标文件件下的路径
destPath := destDirPath + "/" + filename
destPath := destDirPath + "/" + filename
if prePath != "" {
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
os.MkdirAll(destDirPath+"/"+prePath, os.ModePerm)
destPath = destDirPath + "/" + prePath + "/" + filename
}
// Write data to file
// fmt.Println(destPath)
fw, _ := os.Create(destPath)
if err != nil {
panic(err)
}
_, err = io.Copy(fw, rc)
if err != nil {
panic(err)
}
// Write data to file
// fmt.Println(destPath)
fw, _ := os.Create(destPath)
if err != nil {
panic(err)
}
_, err = io.Copy(fw, rc)
if err != nil {
panic(err)
}
}
ok = true
return
}
}

View File

@@ -1,10 +1,9 @@
package binder
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/controllers"
// "github.com/leanote/leanote/app/controllers/api"
"github.com/revel/revel"
// "github.com/leanote/leanote/app/controllers/api"
"fmt"
"reflect"
"strings"
@@ -12,7 +11,7 @@ import (
// leanote binder struct
// rewrite revel struct binder
// not need the struct name as prefix,
// not need the struct name as prefix,
// eg:
// type Note struct {Name}
// func (c Controller) List(note Note) revel.Result {}
@@ -34,13 +33,13 @@ var MSSBinder = revel.Binder{
}
return result
},
Unbind: func(output map[string]string, name string, val interface{}) {
mapValue := reflect.ValueOf(val)
for _, key := range mapValue.MapKeys() {
revel.Unbind(output, fmt.Sprintf("%v", key.Interface()),
mapValue.MapIndex(key).Interface())
}
}
},
}
@@ -54,55 +53,56 @@ func nextKey(key string) string {
}
return key[:fieldLen]
}
var leanoteStructBinder = revel.Binder{
// name == "noteOrContent"
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取
fieldValues := make(map[string]reflect.Value)
// fmt.Println(name)
// fmt.Println(name)
// fmt.Println(typ) // api.NoteFiles
// name = files[0], files[1], noteContent
// fmt.Println(params.Values)
// fmt.Println(params.Values)
/*
map[Title:[test1] METHOD:[POST] NotebookId:[54c4f51705fcd14031000002]
files[1][FileId]:[]
controller:[note]
files[1][LocalFileId]:[54c7ae27d98d0329dd000000] files[1][HasBody]:[true] files[0][FileId]:[] files[0][LocalFileId]:[54c7ae855e94ea2dba000000] action:[addNote] Content:[<p>lifedddddd</p><p><img src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" alt="" data-mce-src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" style="display: block; margin-left: auto; margin-right: auto;"></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae27d98d0329dd000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImg?fileId=54c7ae27d98d0329dd000000"></p><p><br></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" style="display: block; margin-left: auto; margin-right: auto;"></p><p><br></p><p><br></p>] IsBlog:[false] token:[user1]
files[0][HasBody]:[true]]
map[Title:[test1] METHOD:[POST] NotebookId:[54c4f51705fcd14031000002]
files[1][FileId]:[]
controller:[note]
files[1][LocalFileId]:[54c7ae27d98d0329dd000000] files[1][HasBody]:[true] files[0][FileId]:[] files[0][LocalFileId]:[54c7ae855e94ea2dba000000] action:[addNote] Content:[<p>lifedddddd</p><p><img src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" alt="" data-mce-src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" style="display: block; margin-left: auto; margin-right: auto;"></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae27d98d0329dd000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImg?fileId=54c7ae27d98d0329dd000000"></p><p><br></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" style="display: block; margin-left: auto; margin-right: auto;"></p><p><br></p><p><br></p>] IsBlog:[false] token:[user1]
files[0][HasBody]:[true]]
*/
nameIsSlice := strings.Contains(name, "[")
// fmt.Println(params.Values["files[1]"])
// fmt.Println(params.Values["Title"])
for key, _ := range params.Values {// Title, Content, Files
// fmt.Println(params.Values["files[1]"])
// fmt.Println(params.Values["Title"])
for key, _ := range params.Values { // Title, Content, Files
// 这里, 如果没有点, 默认就是a.
// life
// fmt.Println("key:" + key); // files[0][LocalFileId]
// fmt.Println("name:" + name); // files[0][LocalFileId]
// fmt.Println("key:" + key); // files[0][LocalFileId]
// fmt.Println("name:" + name); // files[0][LocalFileId]
var suffix string
var noPrefix = false
if nameIsSlice && strings.HasPrefix(key, name) {
suffix = key[len(name)+1:len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
} else if !strings.HasPrefix(key, name + ".") {
suffix = key[len(name)+1 : len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
} else if !strings.HasPrefix(key, name+".") {
noPrefix = true
suffix = key
// continue
// continue
} else {
// Get the name of the struct property.
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
suffix = key[len(name)+1:]
}
// fmt.Println(suffix);
// fmt.Println(suffix);
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
// fmt.Println(fieldName);
// fmt.Println(fieldName);
fieldLen := len(fieldName)
if _, ok := fieldValues[fieldName]; !ok {
// Time to bind this field. Get it and make sure we can set it.
fieldName = strings.Title(fieldName) // 传过来title, 但struct是Title
// fmt.Println("xx: " + fieldName)
// fmt.Println("xx: " + fieldName)
fieldValue := result.FieldByName(fieldName)
// fmt.Println(fieldValue)
// fmt.Println(fieldValue)
if !fieldValue.IsValid() {
continue
}
@@ -111,14 +111,14 @@ files[0][HasBody]:[true]]
}
var boundVal reflect.Value
// 没有name前缀
if(noPrefix) {
if noPrefix {
// life
// fmt.Println("<<")
// fmt.Println(strings.Title(key[:fieldLen]));
// fmt.Println("<<")
// fmt.Println(strings.Title(key[:fieldLen]));
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
} else {
// fmt.Println("final")
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
// fmt.Println("final")
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
if nameIsSlice {
fieldLen += 1
}
@@ -150,7 +150,7 @@ func init() {
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.UserAccount{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteOrContent{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
}
}

View File

@@ -6,8 +6,8 @@ import (
"html/template"
"io/ioutil"
// "os"
"fmt"
"bytes"
"fmt"
"io"
"net/http"
"regexp"
@@ -39,9 +39,9 @@ var CloneTemplate *template.Template
type RenderTemplateResult struct {
Template *template.Template
PathContent map[string]string
RenderArgs map[string]interface{}
IsPreview bool // 是否是预览
ViewArgs map[string]interface{}
IsPreview bool // 是否是预览
CurBlogTpl *BlogTpl
}
@@ -62,7 +62,7 @@ func parseTemplateError(err error) (templateName string, line int, description s
return templateName, line, description
}
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
err := r.Template.Execute(wr, r.RenderArgs)
err := r.Template.Execute(wr, r.ViewArgs)
if err == nil {
return
}
@@ -87,11 +87,11 @@ func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response,
Line: line,
SourceLines: templateContent,
}
// 这里, 错误!!
// 这里应该导向到本主题的错误页面
resp.Status = 500
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
ErrorResult{r.ViewArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
}
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
@@ -104,7 +104,7 @@ func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
chunked := revel.Config.BoolDefault("results.chunked", false)
// If it's a HEAD request, throw away the bytes.
out := io.Writer(resp.Out)
out := io.Writer(resp.GetWriter())
if req.Method == "HEAD" {
out = ioutil.Discard
}
@@ -117,7 +117,7 @@ func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
r.render(req, resp, out) // 这里!!!
return
}
// Render the template into a temporary buffer, to see if there was an error
// rendering the template. If not, then copy it into the response buffer.
// Otherwise, template render errors may result in unpredictable HTML (and
@@ -139,7 +139,7 @@ func Init() {
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
fileStr := string(fileBytes)
path := "blog/" + path
// path := path
// path := path
BlogTplObject.PathContent[path] = fileStr
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
}
@@ -157,12 +157,12 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
// 都不会为空的
if basePath == "" {
path := "blog/" + name
// path := name
// path := name
t := BlogTplObject.Template.Lookup(path)
r = &RenderTemplateResult{
Template: t,
PathContent: BlogTplObject.PathContent, // 为了显示错误
RenderArgs: args, // 把args给它
ViewArgs: args, // 把args给它
}
} else {
// 复制一份
@@ -181,7 +181,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
files := ListDir(basePath)
for _, t := range files {
if !strings.Contains(t, ".html") {
continue;
continue
}
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
if err != nil {
@@ -194,7 +194,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
// 如果本主题下没有, 则用系统的
t := newBlogTplObject.Template.Lookup(name)
if t == nil {
path := "blog/" + name
t = BlogTplObject.Template.Lookup(path)
@@ -202,24 +202,22 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
r = &RenderTemplateResult{
Template: t,
PathContent: newBlogTplObject.PathContent, // 为了显示错误
RenderArgs: args,
CurBlogTpl: newBlogTplObject,
IsPreview: isPreview,
ViewArgs: args,
CurBlogTpl: newBlogTplObject,
IsPreview: isPreview,
}
}
return r
}
////////////////////
//
type ErrorResult struct {
RenderArgs map[string]interface{}
ViewArgs map[string]interface{}
Error error
IsPreview bool
IsPreview bool
CurBlogTpl *BlogTpl
}
@@ -240,7 +238,7 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
var err error
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
err = nil
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
// This func shows a plaintext error message, in case the template rendering
// doesn't work.
@@ -282,19 +280,19 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
panic("no error provided")
}
if r.RenderArgs == nil {
r.RenderArgs = make(map[string]interface{})
if r.ViewArgs == nil {
r.ViewArgs = make(map[string]interface{})
}
r.RenderArgs["Error"] = revelError
r.RenderArgs["Router"] = revel.MainRouter
r.ViewArgs["Error"] = revelError
r.ViewArgs["Router"] = revel.MainRouter
// 不是preview就不要显示错误了
if r.IsPreview {
var b bytes.Buffer
out := io.Writer(resp.Out)
out := io.Writer(resp.GetWriter())
// out = ioutil.Discard
err = tmpl.Execute(&b, r.RenderArgs)
err = tmpl.Execute(&b, r.ViewArgs)
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
b.WriteTo(out)
}
}
}

View File

@@ -1,399 +1,401 @@
package captcha
import (
"image"
"image/color"
"image/png"
"io"
"math/rand"
crand "crypto/rand"
"time"
"strconv"
)
const (
stdWidth = 100
stdHeight = 40
maxSkew = 2
crand "crypto/rand"
"image"
"image/color"
"image/png"
"io"
"math/rand"
"strconv"
"time"
)
const (
fontWidth = 5
fontHeight = 8
blackChar = 1
stdWidth = 100
stdHeight = 40
maxSkew = 2
)
const (
fontWidth = 5
fontHeight = 8
blackChar = 1
)
var font = [][]byte{
{ // 0
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 1
0, 0, 1, 0, 0,
0, 1, 1, 0, 0,
1, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
1, 1, 1, 1, 1,
},
{ // 2
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 1, 1,
0, 1, 1, 0, 0,
1, 0, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 1,
},
{ // 3
1, 1, 1, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
{ // 4
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 1, 1, 1, 1,
0, 0, 0, 1, 0,
0, 0, 0, 1, 0,
0, 0, 0, 1, 0,
},
{ // 5
1, 1, 1, 1, 1,
1, 0, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
{ // 6
0, 0, 1, 1, 1,
0, 1, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 7
1, 1, 1, 1, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
0, 0, 1, 0, 0,
0, 1, 0, 0, 0,
0, 1, 0, 0, 0,
0, 1, 0, 0, 0,
},
{ // 8
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 9
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 0, 0, 1,
0, 1, 1, 1, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
{ // 0
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 1
0, 0, 1, 0, 0,
0, 1, 1, 0, 0,
1, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
1, 1, 1, 1, 1,
},
{ // 2
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 1, 1,
0, 1, 1, 0, 0,
1, 0, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 1,
},
{ // 3
1, 1, 1, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
{ // 4
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 0, 0, 1, 0,
1, 1, 1, 1, 1,
0, 0, 0, 1, 0,
0, 0, 0, 1, 0,
0, 0, 0, 1, 0,
},
{ // 5
1, 1, 1, 1, 1,
1, 0, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 0,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
{ // 6
0, 0, 1, 1, 1,
0, 1, 0, 0, 0,
1, 0, 0, 0, 0,
1, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 7
1, 1, 1, 1, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
0, 0, 1, 0, 0,
0, 1, 0, 0, 0,
0, 1, 0, 0, 0,
0, 1, 0, 0, 0,
},
{ // 8
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
0, 1, 1, 1, 0,
},
{ // 9
0, 1, 1, 1, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 0, 0, 1,
0, 1, 1, 1, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
1, 1, 1, 1, 0,
},
}
type Image struct {
*image.NRGBA
color *color.NRGBA
width int //a digit width
height int //a digit height
dotsize int
*image.NRGBA
color *color.NRGBA
width int //a digit width
height int //a digit height
dotsize int
}
func init(){
rand.Seed(int64(time.Second))
func init() {
rand.Seed(int64(time.Second))
}
func NewImage(digits []byte, width, height int) *Image {
img := new(Image)
r := image.Rect(img.width, img.height, stdWidth, stdHeight)
img.NRGBA = image.NewNRGBA(r)
img.color = &color.NRGBA{
uint8(rand.Intn(129)),
uint8(rand.Intn(129)),
uint8(rand.Intn(129)),
0xFF,
}
// Draw background (10 random circles of random brightness)
img.calculateSizes(width, height, len(digits))
img.fillWithCircles(10, img.dotsize)
maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
maxy := height - img.height - img.dotsize*2
x := rnd(img.dotsize*2, maxx)
y := rnd(img.dotsize*2, maxy)
// Draw digits.
for _, n := range digits {
img.drawDigit(font[n], x, y)
x += img.width + img.dotsize
}
// Draw strike-through line.
// 中间线不要
//img.strikeThrough()
return img
img := new(Image)
r := image.Rect(img.width, img.height, stdWidth, stdHeight)
img.NRGBA = image.NewNRGBA(r)
img.color = &color.NRGBA{
uint8(rand.Intn(129)),
uint8(rand.Intn(129)),
uint8(rand.Intn(129)),
0xFF,
}
// Draw background (10 random circles of random brightness)
img.calculateSizes(width, height, len(digits))
img.fillWithCircles(10, img.dotsize)
maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
maxy := height - img.height - img.dotsize*2
x := rnd(img.dotsize*2, maxx)
y := rnd(img.dotsize*2, maxy)
// Draw digits.
for _, n := range digits {
img.drawDigit(font[n], x, y)
x += img.width + img.dotsize
}
// Draw strike-through line.
// 中间线不要
//img.strikeThrough()
return img
}
func (img *Image) WriteTo(w io.Writer) (int64, error) {
return 0, png.Encode(w, img)
return 0, png.Encode(w, img)
}
func (img *Image) calculateSizes(width, height, ncount int) {
// Goal: fit all digits inside the image.
var border int
if width > height {
border = height / 5
} else {
border = width / 5
}
// Convert everything to floats for calculations.
w := float64(width - border*2) //268
h := float64(height - border*2) //48
// fw takes into account 1-dot spacing between digits.
fw := float64(fontWidth) + 1 //6
fh := float64(fontHeight) //8
nc := float64(ncount) //7
// Calculate the width of a single digit taking into account only the
// width of the image.
nw := w / nc //38
// Calculate the height of a digit from this width.
nh := nw * fh / fw //51
// Digit too high?
if nh > h {
// Fit digits based on height.
nh = h //nh = 44
nw = fw / fh * nh
}
// Calculate dot size.
img.dotsize = int(nh / fh)
// Save everything, making the actual width smaller by 1 dot to account
// for spacing between digits.
img.width = int(nw)
img.height = int(nh) - img.dotsize
// Goal: fit all digits inside the image.
var border int
if width > height {
border = height / 5
} else {
border = width / 5
}
// Convert everything to floats for calculations.
w := float64(width - border*2) //268
h := float64(height - border*2) //48
// fw takes into account 1-dot spacing between digits.
fw := float64(fontWidth) + 1 //6
fh := float64(fontHeight) //8
nc := float64(ncount) //7
// Calculate the width of a single digit taking into account only the
// width of the image.
nw := w / nc //38
// Calculate the height of a digit from this width.
nh := nw * fh / fw //51
// Digit too high?
if nh > h {
// Fit digits based on height.
nh = h //nh = 44
nw = fw / fh * nh
}
// Calculate dot size.
img.dotsize = int(nh / fh)
// Save everything, making the actual width smaller by 1 dot to account
// for spacing between digits.
img.width = int(nw)
img.height = int(nh) - img.dotsize
}
func (img *Image) fillWithCircles(n, maxradius int) {
color := img.color
maxx := img.Bounds().Max.X
maxy := img.Bounds().Max.Y
for i := 0; i < n; i++ {
setRandomBrightness(color, 255)
r := rnd(1, maxradius)
img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
}
color := img.color
maxx := img.Bounds().Max.X
maxy := img.Bounds().Max.Y
for i := 0; i < n; i++ {
setRandomBrightness(color, 255)
r := rnd(1, maxradius)
img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
}
}
func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
for x := fromX; x <= toX; x++ {
img.Set(x, y, color)
}
for x := fromX; x <= toX; x++ {
img.Set(x, y, color)
}
}
func (img *Image) drawCircle(color color.Color, x, y, radius int) {
f := 1 - radius
dfx := 1
dfy := -2 * radius
xx := 0
yy := radius
img.Set(x, y+radius, color)
img.Set(x, y-radius, color)
img.drawHorizLine(color, x-radius, x+radius, y)
for xx < yy {
if f >= 0 {
yy--
dfy += 2
f += dfy
}
xx++
dfx += 2
f += dfx
img.drawHorizLine(color, x-xx, x+xx, y+yy)
img.drawHorizLine(color, x-xx, x+xx, y-yy)
img.drawHorizLine(color, x-yy, x+yy, y+xx)
img.drawHorizLine(color, x-yy, x+yy, y-xx)
}
f := 1 - radius
dfx := 1
dfy := -2 * radius
xx := 0
yy := radius
img.Set(x, y+radius, color)
img.Set(x, y-radius, color)
img.drawHorizLine(color, x-radius, x+radius, y)
for xx < yy {
if f >= 0 {
yy--
dfy += 2
f += dfy
}
xx++
dfx += 2
f += dfx
img.drawHorizLine(color, x-xx, x+xx, y+yy)
img.drawHorizLine(color, x-xx, x+xx, y-yy)
img.drawHorizLine(color, x-yy, x+yy, y+xx)
img.drawHorizLine(color, x-yy, x+yy, y-xx)
}
}
func (img *Image) strikeThrough() {
r := 0
maxx := img.Bounds().Max.X
maxy := img.Bounds().Max.Y
y := rnd(maxy/3, maxy-maxy/3)
for x := 0; x < maxx; x += r {
r = rnd(1, img.dotsize/3)
y += rnd(-img.dotsize/2, img.dotsize/2)
if y <= 0 || y >= maxy {
y = rnd(maxy/3, maxy-maxy/3)
}
img.drawCircle(img.color, x, y, r)
}
r := 0
maxx := img.Bounds().Max.X
maxy := img.Bounds().Max.Y
y := rnd(maxy/3, maxy-maxy/3)
for x := 0; x < maxx; x += r {
r = rnd(1, img.dotsize/3)
y += rnd(-img.dotsize/2, img.dotsize/2)
if y <= 0 || y >= maxy {
y = rnd(maxy/3, maxy-maxy/3)
}
img.drawCircle(img.color, x, y, r)
}
}
func (img *Image) drawDigit(digit []byte, x, y int) {
skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
xs := float64(x)
minr := img.dotsize / 2 // minumum radius
maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
y += rnd(-minr, minr)
for yy := 0; yy < fontHeight; yy++ {
for xx := 0; xx < fontWidth; xx++ {
if digit[yy*fontWidth+xx] != blackChar {
continue
}
// Introduce random variations.
or := rnd(minr, maxr)
ox := x + (xx * img.dotsize) + rnd(0, or/2)
oy := y + (yy * img.dotsize) + rnd(0, or/2)
img.drawCircle(img.color, ox, oy, or)
}
xs += skf
x = int(xs)
}
skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
xs := float64(x)
minr := img.dotsize / 2 // minumum radius
maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
y += rnd(-minr, minr)
for yy := 0; yy < fontHeight; yy++ {
for xx := 0; xx < fontWidth; xx++ {
if digit[yy*fontWidth+xx] != blackChar {
continue
}
// Introduce random variations.
or := rnd(minr, maxr)
ox := x + (xx * img.dotsize) + rnd(0, or/2)
oy := y + (yy * img.dotsize) + rnd(0, or/2)
img.drawCircle(img.color, ox, oy, or)
}
xs += skf
x = int(xs)
}
}
func setRandomBrightness(c *color.NRGBA, max uint8) {
minc := min3(c.R, c.G, c.B)
maxc := max3(c.R, c.G, c.B)
if maxc > max {
return
}
n := rand.Intn(int(max-maxc)) - int(minc)
c.R = uint8(int(c.R) + n)
c.G = uint8(int(c.G) + n)
c.B = uint8(int(c.B) + n)
minc := min3(c.R, c.G, c.B)
maxc := max3(c.R, c.G, c.B)
if maxc > max {
return
}
n := rand.Intn(int(max-maxc)) - int(minc)
c.R = uint8(int(c.R) + n)
c.G = uint8(int(c.G) + n)
c.B = uint8(int(c.B) + n)
}
func min3(x, y, z uint8) (o uint8) {
o = x
if y < o {
o = y
}
if z < o {
o = z
}
return
o = x
if y < o {
o = y
}
if z < o {
o = z
}
return
}
func max3(x, y, z uint8) (o uint8) {
o = x
if y > o {
o = y
}
if z > o {
o = z
}
return
o = x
if y > o {
o = y
}
if z > o {
o = z
}
return
}
// rnd returns a random number in range [from, to].
func rnd(from, to int) int {
//println(to+1-from)
return rand.Intn(to+1-from) + from
//println(to+1-from)
return rand.Intn(to+1-from) + from
}
const (
// Standard length of uniuri string to achive ~95 bits of entropy.
StdLen = 16
// Length of uniurl string to achive ~119 bits of entropy, closest
// to what can be losslessly converted to UUIDv4 (122 bits).
UUIDLen = 20
// Standard length of uniuri string to achive ~95 bits of entropy.
StdLen = 16
// Length of uniurl string to achive ~119 bits of entropy, closest
// to what can be losslessly converted to UUIDv4 (122 bits).
UUIDLen = 20
)
// Standard characters allowed in uniuri string.
var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
// New returns a new random string of the standard length, consisting of
// standard characters.
func New() string {
return NewLenChars(StdLen, StdChars)
return NewLenChars(StdLen, StdChars)
}
// NewLen returns a new random string of the provided length, consisting of
// standard characters.
func NewLen(length int) string {
return NewLenChars(length, StdChars)
return NewLenChars(length, StdChars)
}
// NewLenChars returns a new random string of the provided length, consisting
// of the provided byte slice of allowed characters (maximum 256).
func NewLenChars(length int, chars []byte) string {
b := make([]byte, length)
r := make([]byte, length+(length/4)) // storage for random bytes.
clen := byte(len(chars))
maxrb := byte(256 - (256 % len(chars)))
i := 0
for {
if _, err := io.ReadFull(crand.Reader, r); err != nil {
panic("error reading from random source: " + err.Error())
}
for _, c := range r {
if c >= maxrb {
// Skip this number to avoid modulo bias.
continue
}
b[i] = chars[c%clen]
i++
if i == length {
return string(b)
}
}
}
panic("unreachable")
b := make([]byte, length)
r := make([]byte, length+(length/4)) // storage for random bytes.
clen := byte(len(chars))
maxrb := byte(256 - (256 % len(chars)))
i := 0
for {
if _, err := io.ReadFull(crand.Reader, r); err != nil {
panic("error reading from random source: " + err.Error())
}
for _, c := range r {
if c >= maxrb {
// Skip this number to avoid modulo bias.
continue
}
b[i] = chars[c%clen]
i++
if i == length {
return string(b)
}
}
}
panic("unreachable")
}
func Fetch() (*Image, string) {
d := make([]byte, 4)
s := NewLen(4)
ss := ""
d = []byte(s)
for v := range d {
d[v] %= 10
ss += strconv.FormatInt(int64(d[v]), 32)
}
return NewImage(d, 100, 40), ss
}
d := make([]byte, 4)
s := NewLen(4)
ss := ""
d = []byte(s)
for v := range d {
d[v] %= 10
ss += strconv.FormatInt(int64(d[v]), 32)
}
return NewImage(d, 100, 40), ss
}

View File

@@ -24,29 +24,29 @@ import (
type Html2Image struct {
image *image.RGBA
gc *draw2d.ImageGraphicContext
// 试探
gc2 *draw2d.ImageGraphicContext
width float64 // 图片宽度
height float64
painWidth float64 // 画布宽度
startX float64
x float64
y float64
isFirstP bool // 是否是第一个段落?
// 换行和段落的高度
brY float64
pY float64
// 字体
normalFontFamily draw2d.FontData
boldFontFamily draw2d.FontData
// preTag 之前的标签
preTag *html.Node
}
@@ -58,23 +58,23 @@ func NewHtml2Image() *Html2Image {
i, gc := h.InitGc(h.width, h.height)
h.gc = gc;
h.image = i
// 试探
_, h.gc2 = h.InitGc(h.width, 100)
h.startX = 10
h.startX = 10
// 最初位置
h.x = h.startX
h.y = 80
h.isFirstP = true
h.normalFontFamily = draw2d.FontData{"xihei", 4, draw2d.FontStyleNormal};
h.boldFontFamily = draw2d.FontData{"heiti", 5, draw2d.FontStyleNormal};
h.SetNormalFont()
return h
}
@@ -86,12 +86,12 @@ func (this *Html2Image) InitGc(w, h float64) (* image.RGBA, *draw2d.ImageGraphic
gc.SetFillColor(image.White)
// fill the background
// gc.Clear()
draw2d.SetFontFolder(revel.BasePath + "/public/fonts/weibo")
draw2d.Rect(gc, 0, 0, w, h) // 设置背景
gc.FillStroke()
gc.SetFillColor(image.Black)
// 这个很耗时
// gc.Translate(0, 0)
return i, gc
@@ -101,7 +101,7 @@ func (this *Html2Image) SaveToPngFile(filePath string) bool {
// m := this.image;
m := this.image.SubImage(image.Rect(0, 0, int(this.width), int(this.y + 20)))
// 需要截断之
f, err := os.Create(filePath)
if err != nil {
return false
@@ -124,14 +124,14 @@ func (this *Html2Image) SaveToPngFile(filePath string) bool {
func (this *Html2Image) SetSmallFont() {
this.gc.SetFontData(this.normalFontFamily)
this.gc2.SetFontData(this.normalFontFamily)
this.gc.SetFillColor(color.NRGBA{60, 60, 60, 255})
this.gc.SetFontSize(12)
this.gc2.SetFontSize(12)
this.brY = 16
this.pY = 30
this.painWidth = this.width - 10
}
@@ -139,13 +139,13 @@ func (this *Html2Image) SetNormalFont() {
this.gc.SetFillColor(image.Black)
this.gc.SetFontData(this.normalFontFamily)
this.gc2.SetFontData(this.normalFontFamily)
this.gc.SetFontSize(14)
this.gc2.SetFontSize(14)
this.brY = 20
this.pY = 30
this.painWidth = this.width - 10
}
func (this *Html2Image) SetAColor() {
@@ -155,16 +155,16 @@ func (this *Html2Image) SetAColor() {
// 标题
func (this *Html2Image) SetTitleFont() {
this.gc.SetFillColor(image.Black)
this.gc.SetFontData(this.boldFontFamily)
this.gc2.SetFontData(this.boldFontFamily)
this.gc.SetFontSize(24)
this.gc2.SetFontSize(24)
this.brY = 30
this.pY = 60
this.painWidth = this.width - 100
}
@@ -175,9 +175,9 @@ func (this *Html2Image) SetHeadFont(h string) {
this.gc.SetFontData(this.boldFontFamily)
this.gc2.SetFontData(this.boldFontFamily)
this.painWidth = this.width - 50
if h == "h1" {
this.gc.SetFontSize(20)
this.gc2.SetFontSize(20)
@@ -229,7 +229,7 @@ func (this *Html2Image) IsOver(r []rune) bool {
// 以下的方法可以极大节约时间
// a, b, c, d := this.gc2.GetStringBounds(string(r))
// width2 := c - a + 2
// fmt.Println(width2)
// fmt.Println(c - a)
@@ -268,7 +268,7 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
this.InsertText(text, true, prefix)
return;
}
r := []rune(text)
// 试探吧, 可能需要截取
if !needTest || !this.IsOver(r) {
@@ -316,17 +316,17 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
end = i
}
}
// 这一段写上
// println("------>" + string(r[0:end]))
// 这里, 判断后面一个是否是标点符号
end = this.includePunctuation(r, end)
this.InsertText(string(r[0:end]), false, prefix)
this.NewBr()
// 之后的
this.InsertText(string(r[end:]), true, prefix)
return;
} else {
// 没超出, 不用计算, 但出要看是否是结尾了
@@ -351,17 +351,17 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
end = maxRI + 1
}
}
// 这一段写上
// println("-e----->" + string(r[0:end]))
// 这里, 判断后面一个是否是标点符号
end = this.includePunctuation(r, end)
this.InsertText(string(r[0:end]), false, prefix)
this.NewBr()
// 之后的
this.InsertText(string(r[end:]), true, prefix)
return;
}
}
@@ -376,9 +376,9 @@ func (this *Html2Image) SetBottom(username, url string) {
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
this.gc.SetLineWidth(2)
this.gc.FillStroke()
this.SetSmallFont()
// 左侧写字
this.NewP()
this.InsertText("本文来自 " + username + " 的leanote笔记", true, " ")
@@ -389,11 +389,11 @@ func (this *Html2Image) SetBottom(username, url string) {
siteUrl = "http://leanote.com"
}
this.InsertA(siteUrl + "/blog/" + username, false)
this.setLogo()
// this.painWidth = this.width - 100
// this.NewP()
// this.InsertText("leanote, 不一样的笔记.", false, " ")
// this.InsertText("leanote, 不一样的笔记.", false, " ")
// this.NewBr()
// this.InsertText("在这里你可以管理自己的知识", false, " ")
// this.NewBr()
@@ -401,7 +401,7 @@ func (this *Html2Image) SetBottom(username, url string) {
// this.NewBr()
// this.InsertText("并且还可以将笔记设为博客公开", false, " ")
// this.InsertText(". 赶紧加入吧! leanote.com", false, "")
//
//
// Logo
}
@@ -411,7 +411,7 @@ func (this *Html2Image) setImage(path string, x, y float64) {
return;
panic(err)
}
var m1 image.Image
_, ext := lea.SplitFilename(path)
if ext == ".png" {
@@ -424,8 +424,8 @@ func (this *Html2Image) setImage(path string, x, y float64) {
if err != nil {
return
panic(err)
}
}
this.gc.Translate(x, y)
this.gc.DrawImage(m1)
this.gc.Translate(-x, -y)
@@ -448,10 +448,10 @@ func (this *Html2Image) InsertA(text string, isNormal bool) {
if text == "" {
return
}
this.SetAColor()
this.InsertText(text, true, "")
// 还原
if isNormal {
this.SetNormalFont()
@@ -464,17 +464,17 @@ func (this *Html2Image) InsertA(text string, isNormal bool) {
func (this *Html2Image) InsertTitle(title string) {
oldX := this.x
oldY := this.y - 35
// 插入之
this.SetTitleFont()
this.InsertText(title, true, " ")
// 还原字体大小
this.SetNormalFont()
this.NewBr()
this.gc.MoveTo(oldX, oldY)
this.gc.LineTo(this.x, this.y - 10)
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
@@ -512,7 +512,7 @@ func (this *Html2Image) InsertCode(n *html.Node) {
}
}
this.NewBr()
this.gc.MoveTo(oldX, oldY)
this.gc.LineTo(this.x, this.y - 20)
this.gc.SetStrokeColor(color.NRGBA{0, 200, 0, 255})
@@ -521,14 +521,14 @@ func (this *Html2Image) InsertCode(n *html.Node) {
}
// 插入图片
// 这个path应该是url,
// 这个path应该是url,
// http://abc.com/a.gif 需要先下载
// 或 /upload/a.gif
func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
if path == "" {
return;
}
// 是url, 那么取网络图片之
var ok bool
if strings.HasPrefix(path, "http") || strings.HasPrefix(path, "//") {
@@ -539,7 +539,7 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
} else {
path = revel.BasePath + "/public/" + path
}
// 需要转换, logo不需要转换
if(needTrans) {
painWidth := uint(this.painWidth - 10)
@@ -557,7 +557,7 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
return;
panic(err)
}
var m1 image.Image
_, ext := lea.SplitFilename(path)
if ext == ".png" {
@@ -568,8 +568,8 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
if err != nil {
return
panic(err)
}
}
// 如果之前是p, 那么不要有<br>
if this.preTag.Data != "p" {
this.NewBr()
@@ -580,9 +580,9 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
this.gc.Translate(-this.x, -this.y) // 这个有用些
this.y += float64(m1.Bounds().Dy()) - 20
this.NewP()
os.Remove(path)
// 如果图片是文章第一个的话, 之后的需要p
this.isFirstP = false
}
@@ -605,7 +605,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
this.preTag = n
}
}()
// 标签
if n.Type == html.ElementNode {
if n.Data == "p" {
@@ -616,7 +616,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
}
return;
}
// 也是一个段落, 只是要缩进
if n.Data == "ul" || n.Data == "ol" {
this.NewP()
@@ -637,7 +637,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
} else {
f(c, n, "")
}
if c.Type == html.ElementNode {
if c.Data == "br" || c.Data == "p" {
needPrefix = true
@@ -650,19 +650,19 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
this.NewBr()
return;
}
// 标题
if n.Data == "h1" || n.Data == "h2" || n.Data == "h3" || n.Data == "h4" {
this.InsertHead(n)
return;
}
if n.Data == "pre" {
// 把之后的全拿过来
this.InsertCode(n)
return;
}
// 图片
// 得到src
if n.Data == "img" {
@@ -680,22 +680,22 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
}
return;
}
// 链接
// 如果链接里只有文本, 那么单独处理, 如果还有其它的, 不作链接处理
if n.Data == "a" {
if n.FirstChild == n.LastChild {
this.InsertA(n.FirstChild.Data, true)
return;
}
}
}
// 空行
if n.Data == "br" { // || n.Data == "div"
this.NewBr()
}
}
// 是文本, 输出之
if n.Type == html.TextNode {
data := strings.TrimSpace(n.Data);
@@ -705,36 +705,36 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
}
return;
}
// 其余的
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c, n, prefix)
}
return;
}
f(doc, nil, "")
return true
}
// 主函数
func ToImage(uid, username, noteId, title, htmlStr, toPath string) (ok bool) {
h := NewHtml2Image()
// 标题
h.InsertTitle(title)
// 主体
ok = h.InsertBody(htmlStr)
if(!ok) {
return
}
// 页眉与页脚
h.SetBottom(username, "")
// 保存成png图片
ok = h.SaveToPngFile(toPath)
return
@@ -757,4 +757,4 @@ func TestFillString() {
func ToImage(uid, username, noteId, title, htmlStr, toPath string) (ok bool) {
return false
}
}

View File

@@ -7,4 +7,3 @@ import (
func Html2Image(userInfo info.User, note info.Note, content, toPath string) bool {
return true
}

224
app/lea/i18n/i18n.go Normal file
View File

@@ -0,0 +1,224 @@
package i18n
import (
"fmt"
"github.com/revel/revel"
"github.com/robfig/config"
"os"
"path/filepath"
"regexp"
"strings"
. "github.com/leanote/leanote/app/lea"
)
const (
CurrentLocaleViewArg = "currentLocale" // The key for the current locale render arg value
messageFilesDirectory = "messages"
messageFilePattern = `^\w+\.conf$`
unknownValueFormat = "??? %s ???"
defaultLanguageOption = "i18n.default_language"
localeCookieConfigKey = "i18n.cookie"
)
var (
// All currently loaded message configs.
// en-us, zh-cn, zh-hk ->
messages map[string]*config.Config
)
func GetAllLangMessages() map[string]*config.Config {
return messages
}
func HasLang(lang string) bool {
_, ok := messages[lang]
return ok
}
func GetDefaultLang() string {
lang, _ := revel.Config.String(defaultLanguageOption)
return lang
}
// Return all currently loaded message languages.
func MessageLanguages() []string {
languages := make([]string, len(messages))
i := 0
for language, _ := range messages {
languages[i] = language
i++
}
return languages
}
// Perform a message look-up for the given locale and message using the given arguments.
//
// When either an unknown locale or message is detected, a specially formatted string is returned.
func Message(locale, message string, args ...interface{}) string {
language, region := parseLocale(locale)
langAndRegion := language + "-" + region
// revel.TRACE.Println(langAndRegion + " 怎么回事")
messageConfig, knownLanguage := messages[langAndRegion]
if !knownLanguage {
// revel.TRACE.Printf("Unsupported language for locale '%s' and message '%s', trying default language", locale, message)
if defaultLanguage, found := revel.Config.String(defaultLanguageOption); found {
// revel.TRACE.Printf("Using default language '%s'", defaultLanguage)
messageConfig, knownLanguage = messages[defaultLanguage]
if !knownLanguage {
// WARN.Printf("Unsupported default language for locale '%s' and message '%s'", defaultLanguage, message)
return fmt.Sprintf(unknownValueFormat, message)
}
} else {
// WARN.Printf("Unable to find default language option (%s); messages for unsupported locales will never be translated", defaultLanguageOption)
return fmt.Sprintf(unknownValueFormat, message)
}
}
// This works because unlike the goconfig documentation suggests it will actually
// try to resolve message in DEFAULT if it did not find it in the given section.
value, error := messageConfig.String(region, message)
if error != nil {
// WARN.Printf("Unknown message '%s' for locale '%s'", message, locale)
return fmt.Sprintf(unknownValueFormat, message)
}
if len(args) > 0 {
// revel.TRACE.Printf("Arguments detected, formatting '%s' with %v", value, args)
value = fmt.Sprintf(value, args...)
}
return value
}
func parseLocale(locale string) (language, region string) {
if strings.Contains(locale, "-") {
languageAndRegion := strings.Split(locale, "-")
return languageAndRegion[0], languageAndRegion[1]
}
return locale, ""
}
// Recursively read and cache all available messages from all message files on the given path.
func loadMessages(path string) {
messages = make(map[string]*config.Config)
if error := filepath.Walk(path, loadEachMessageLang); error != nil && !os.IsNotExist(error) {
// ERROR.Println("Error reading messages files:", error)
}
}
// 加载每一个文件夹
func loadEachMessageLang(parentPath string, parentInfo os.FileInfo, osError error) (err error) {
if !parentInfo.IsDir() {
return nil
}
if err := filepath.Walk(parentPath, func(path string, info os.FileInfo, osError error) error {
return loadMessageFile(parentInfo.Name(), path, info, osError)
}); err != nil && !os.IsNotExist(err) {
// ERROR.Println("Error reading messages files:", error)
}
return err
}
// Load a single message file
func loadMessageFile(locale string, path string, info os.FileInfo, osError error) error {
if osError != nil {
return osError
}
if info.IsDir() {
return nil
}
if matched, _ := regexp.MatchString(messageFilePattern, info.Name()); matched {
if config, error := parseMessagesFile(path); error != nil {
return error
} else {
// locale := parseLocaleFromFileName(info.Name())
// revel.TRACE.Print(locale + "----locale")
// If we have already parsed a message file for this locale, merge both
if _, exists := messages[locale]; exists {
messages[locale].Merge(config)
Logf("Successfully merged messages for locale '%s'", locale)
} else {
messages[locale] = config
}
Logf("Successfully loaded messages from file", info.Name())
}
} else {
Logf("Ignoring file %s because it did not have a valid extension", info.Name())
}
return nil
}
func parseMessagesFile(path string) (messageConfig *config.Config, error error) {
messageConfig, error = config.ReadDefault(path)
return
}
func parseLocaleFromFileName(file string) string {
extension := filepath.Ext(file)[1:]
return strings.ToLower(extension)
}
func init() {
revel.OnAppStart(func() {
loadMessages(filepath.Join(revel.BasePath, messageFilesDirectory))
})
}
func I18nFilter(c *revel.Controller, fc []revel.Filter) {
if foundCookie, cookieValue := hasLocaleCookie(c.Request); foundCookie {
// revel.TRACE.Printf("Found locale cookie value: %s", cookieValue)
setCurrentLocaleControllerArguments(c, cookieValue)
} else if foundHeader, headerValue := hasAcceptLanguageHeader(c.Request); foundHeader {
// revel.TRACE.Printf("Found Accept-Language header value: %s", headerValue)
setCurrentLocaleControllerArguments(c, headerValue)
} else {
// revel.TRACE.Println("Unable to find locale in cookie or header, using empty string")
setCurrentLocaleControllerArguments(c, "")
}
fc[0](c, fc[1:])
}
// Set the current locale controller argument (CurrentLocaleControllerArg) with the given locale.
func setCurrentLocaleControllerArguments(c *revel.Controller, locale string) {
c.Request.Locale = locale
c.ViewArgs[CurrentLocaleViewArg] = locale
}
// Determine whether the given request has valid Accept-Language value.
//
// Assumes that the accept languages stored in the request are sorted according to quality, with top
// quality first in the slice.
func hasAcceptLanguageHeader(request *revel.Request) (bool, string) {
if request.AcceptLanguages != nil && len(request.AcceptLanguages) > 0 {
return true, request.AcceptLanguages[0].Language
}
return false, ""
}
// Determine whether the given request has a valid language cookie value.
func hasLocaleCookie(request *revel.Request) (bool, string) {
if request != nil {
name := revel.Config.StringDefault(localeCookieConfigKey, revel.CookiePrefix+"_LANG")
if cookie, error := request.Cookie(name); error == nil {
return true, cookie.GetValue()
} else {
// revel.TRACE.Printf("Unable to read locale cookie with name '%s': %s", name, error.Error())
}
}
return false, ""
}

View File

@@ -1,12 +1,13 @@
package netutil
import (
"strings"
"os"
// "path/filepath"
"strings"
// "path/filepath"
. "github.com/leanote/leanote/app/lea"
"io/ioutil"
"net"
"net/http"
"io/ioutil"
. "github.com/leanote/leanote/app/lea"
)
// net的util
@@ -16,33 +17,33 @@ import (
// 返回文件的完整目录
func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) {
if url == "" {
return;
return
}
content, err := GetContent(url)
if err != nil {
return;
return
}
length = int64(len(content))
// a.html?a=a11&xxx
url = trimQueryParams(url)
_, ext := SplitFilename(url)
if toPath == "" {
toPath = "/tmp"
}
// dir := filepath.Dir(toPath)
// dir := filepath.Dir(toPath)
newFilename = NewGuid() + ext
fullPath := toPath + "/" + newFilename
// 写到文件中
file, err := os.Create(fullPath)
defer file.Close()
if err != nil {
return
defer file.Close()
if err != nil {
return
}
file.Write(content)
path = fullPath
ok = true
return
@@ -52,44 +53,42 @@ func WriteUrl(url string, toPath string) (length int64, newFilename, path string
func GetContent(url string) (content []byte, err error) {
var resp *http.Response
resp, err = http.Get(url)
Log(err)
if(resp != nil && resp.Body != nil) {
if resp != nil && resp.Body != nil {
defer resp.Body.Close()
} else {
}
if resp == nil || resp.Body == nil || err != nil || resp.StatusCode != http.StatusOK {
return
}
var buf []byte
buf, err = ioutil.ReadAll(resp.Body)
if(err != nil) {
Log(err)
if resp == nil || resp.Body == nil || err != nil || resp.StatusCode != http.StatusOK {
return
}
content = buf;
err = nil
return
var buf []byte
buf, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
content = buf
err = nil
return
}
// 将url ?, #后面的字符串去掉
func trimQueryParams(url string) string {
pos := strings.Index(url, "?");
pos := strings.Index(url, "?")
if pos != -1 {
url = Substr(url, 0, pos);
url = Substr(url, 0, pos)
}
pos = strings.Index(url, "#");
pos = strings.Index(url, "#")
if pos != -1 {
url = Substr(url, 0, pos);
url = Substr(url, 0, pos)
}
pos = strings.Index(url, "!");
pos = strings.Index(url, "!")
if pos != -1 {
url = Substr(url, 0, pos);
url = Substr(url, 0, pos)
}
return url;
return url
}
// 通过domain得到ip
@@ -99,4 +98,4 @@ func GetIpFromDomain(domain string) string {
return ip[0].String()
}
return ""
}
}

View File

@@ -1,9 +1,9 @@
package route
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
"net/url"
"strings"
)
@@ -11,53 +11,67 @@ import (
// overwite revel RouterFilter
// /api/user/Info => ApiUser.Info()
var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"}
func RouterFilter(c *revel.Controller, fc []revel.Filter) {
// 补全controller部分
path := c.Request.Request.URL.Path
path := c.Request.URL.Path
// Figure out the Controller/Action
var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)
// var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)
route := revel.MainRouter.Route(c.Request)
if route == nil {
c.Result = c.NotFound("No matching route found: " + c.Request.RequestURI)
c.Result = c.NotFound("No matching route found: " + c.Request.GetRequestURI())
return
}
// Log("---------" + route.Action + " " + path)
// The route may want to explicitly return a 404.
if route.Action == "404" {
c.Result = c.NotFound("(intentionally)")
return
}
//----------
// life start
/*
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
*/
if route.ControllerName != "Static" {
// 检查mongodb 是否lost
db.CheckMongoSessionLost()
// /api/file/getImage -> App\file (/api/file/getImage)
// App\auth
// App\note
// static\static
//
// Log("---------" + route.ControllerName + " " + path)
// api设置
// leanote.com/api/user/get => ApiUser::Get
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
route.ControllerName = "Api" + route.ControllerName
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "App\\api") {
route.ControllerName = "App\\api" + strings.Split(route.ControllerName, "\\")[1]
// route.ControllerName = "App\\apifile"
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "App\\member") {
// member设置
route.ControllerName = "Member" + route.ControllerName
// route.ControllerName = "App\\Member" + route.ControllerName
route.ControllerName = "App\\member" + strings.Split(route.ControllerName, "\\")[1]
}
// end
}
// Set the action.
if err := c.SetAction(route.ControllerName, route.MethodName); err != nil {
c.Result = c.NotFound(err.Error())
@@ -84,4 +98,3 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
fc[0](c, fc[1:])
}

View File

@@ -2,11 +2,11 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"io/ioutil"
"strings"
// "time"
// "time"
)
/*
@@ -31,10 +31,10 @@ import (
*/
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
var jss = []string{"js/jquery-cookie", "js/bootstrap",
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
var jss = []string{"js/jquery-cookie", "js/bootstrap",
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
var cmdPath = "/usr/local/bin/uglifyjs"
@@ -54,26 +54,26 @@ func compressJs(filename string) {
to := base + filename + "-min.js"
cmd := exec.Command(cmdPath, source, "-o", to)
_, err := cmd.CombinedOutput()
fmt.Println(source);
fmt.Println(source)
cmdError(err)
}
func combineJs() {
// 生成一个总文件
cmd := exec.Command("rm", base + "js/all.js")
cmd := exec.Command("rm", base+"js/all.js")
_, err := cmd.CombinedOutput()
cmdError(err)
for _, js := range jss {
to := base + js + "-min.js"
fmt.Println(to)
compressJs(js)
// 每个压缩后的文件放入之
cmd2 := exec.Command("/bin/sh", "-c", "cat " + to + " >> " + base + "js/all.js")
cmd2 := exec.Command("/bin/sh", "-c", "cat "+to+" >> "+base+"js/all.js")
_, err := cmd2.CombinedOutput()
cmdError(err)
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> " + base + "js/all.js")
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> "+base+"js/all.js")
_, err = cmd2.CombinedOutput()
cmdError(err)
}
@@ -82,57 +82,57 @@ func combineJs() {
// 改note-dev->note
func dev() {
// 即替换note.js->note-min.js
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
"tinymce.js": "tinymce.min.js",
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
"note.js": "note-min.js",
"app.js": "app-min.js",
"page.js": "page-min.js",
"common.js": "common-min.js",
"notebook.js": "notebook-min.js",
"share.js": "share-min.js",
"tag.js": "tag-min.js",
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
"editor/editor.js": "editor/editor-min.js",
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
"tinymce.js": "tinymce.min.js",
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
"note.js": "note-min.js",
"app.js": "app-min.js",
"page.js": "page-min.js",
"common.js": "common-min.js",
"notebook.js": "notebook-min.js",
"share.js": "share-min.js",
"tag.js": "tag-min.js",
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
"editor/editor.js": "editor/editor-min.js",
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
"console.log(o);": "",
}
"console.log(o);": "",
}
path := base1 + "/src/views/note/note-dev.html"
target := base1 + "/src/views/note/note.html"
bs, _ := ioutil.ReadFile(path)
content := string(bs)
print(content)
for key, value := range m {
content = strings.Replace(content, key, value, -1)
}
// var time = time.Now().Unix() % 1000
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
// var time = time.Now().Unix() % 1000
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
}
// 压缩js成一块
func tinymce() {
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/bin/sh", "-c", "grunt minify");
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/bin/sh", "-c", "grunt minify")
cmd.Dir = base + "/tinymce_4.1.9"
fmt.Println("正在build tinymce");
fmt.Println("正在build tinymce")
// 必须要先删除
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
cmd2 := exec.Command("/bin/sh", "-c", "rm "+cmd.Dir+"/js/tinymce/tinymce.dev.js")
cmd2.CombinedOutput()
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
cmd2 = exec.Command("/bin/sh", "-c", "rm "+cmd.Dir+"/js/tinymce/tinymce.jquery.dev.js")
c, _ := cmd2.CombinedOutput()
fmt.Println(string(c))
c, _ = cmd.CombinedOutput()
fmt.Println(string(c))
}
@@ -140,19 +140,19 @@ func tinymce() {
func main() {
// 压缩tinymce
// tinymce()
dev();
dev()
// 其它零散的需要压缩的js
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
"js/jquery.ztree.all-3.5",
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
}
}
for _, js := range otherJss {
compressJs(js)
}
// 先压缩后合并
combineJs()

View File

@@ -2,7 +2,7 @@ package service
import (
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"time"
@@ -30,9 +30,9 @@ func (this *AlbumService) GetAlbums(userId string) []info.Album {
// delete album
// presupposition: has no images under this ablum
func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) {
if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId),
if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId),
"UserId": bson.ObjectIdHex(userId),
}) == 0 {
}) == 0 {
return db.DeleteByIdAndUserId(db.Albums, albumId, userId), ""
}
return false, "has images"
@@ -41,4 +41,4 @@ func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) {
// update album name
func (this *AlbumService) UpdateAlbum(albumId, userId, name string) bool {
return db.UpdateByIdAndUserIdField(db.Albums, albumId, userId, "Name", name)
}
}

View File

@@ -20,9 +20,9 @@ type AttachService struct {
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
attach.CreatedTime = time.Now()
ok = db.Insert(db.Attachs, attach)
note := noteService.GetNoteById(attach.NoteId.Hex())
// api调用时, 添加attach之前是没有note的
var userId string
if note.NoteId != "" {
@@ -35,13 +35,13 @@ func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool,
// 更新笔记的attachs num
this.updateNoteAttachNum(attach.NoteId, 1)
}
if !fromApi {
// 增长note's usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
}
return
return
}
// 更新笔记的附件个数
@@ -49,13 +49,13 @@ func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool,
func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int) bool {
num := db.Count(db.Attachs, bson.M{"NoteId": noteId})
/*
note := info.Note{}
note = noteService.GetNoteById(noteId.Hex())
note.AttachNum += addNum
if note.AttachNum < 0 {
note.AttachNum = 0
}
Log(note.AttachNum)
note := info.Note{}
note = noteService.GetNoteById(noteId.Hex())
note.AttachNum += addNum
if note.AttachNum < 0 {
note.AttachNum = 0
}
Log(note.AttachNum)
*/
return db.UpdateByQField(db.Notes, bson.M{"_id": noteId}, "AttachNum", num)
}
@@ -63,18 +63,18 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
// list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs
}
// 笔记是否是自己的
note := noteService.GetNoteByIdAndUserId(noteId, userId)
if note.NoteId == "" {
return attachs
}
// TODO 这里, 优化权限控制
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
@@ -119,16 +119,17 @@ func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
}
// delete attach
// 删除附件为什么要incrNoteUsn ? 因为可能没有内容要修改的
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
if(attach.AttachId != "") {
if attach.AttachId != "" {
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
return false, "No Perm"
}
if db.Delete(db.Attachs, bson.M{"_id": bson.ObjectIdHex(attachId)}) {
this.updateNoteAttachNum(attach.NoteId, -1)
attach.Path = strings.TrimLeft(attach.Path, "/")
@@ -137,7 +138,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size)
// 修改note Usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
return true, "delete file success"
}
return false, "delete file error"

View File

@@ -421,7 +421,7 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
// Log(sortFieldR2)
q = db.Notes.Find(query)
q.Sort(sortFieldR2).Limit(1).One(&note2)
return this.FixNote(note), this.FixNote(note2)
}
@@ -518,7 +518,7 @@ func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
// Logo路径问题, 有些有http: 有些没有
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo
userBlog.Logo = "/" + userBlog.Logo
}
if userBlog.SortField == "" {
@@ -673,19 +673,18 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
noteIdO := bson.ObjectIdHex(noteId)
userIdO := bson.ObjectIdHex(userId)
var n int
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
n = 1
// 添加之
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
isLike = true
} else {
// 已点过, 那么删除之
n = -1
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
isLike = false
}
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
count := db.Count(db.BlogLikes, bson.M{"NoteId": noteIdO})
ok = db.UpdateByQI(db.Notes, bson.M{"_id": noteIdO}, bson.M{"LikeNum": count})
return
}
@@ -919,7 +918,7 @@ func (this *BlogService) UpateCateUrlTitle(userId string, cateId, urlTitle strin
"UrlTitle": "",
})
*/
url = GetUrTitle(userId, urlTitle, "notebook")
url = GetUrTitle(userId, urlTitle, "notebook", cateId)
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{
"UrlTitle": url,
})
@@ -935,7 +934,7 @@ func (this *BlogService) UpateBlogUrlTitle(userId string, noteId, urlTitle strin
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
"UrlTitle": "",
})
url = GetUrTitle(userId, urlTitle, "note")
url = GetUrTitle(userId, urlTitle, "note", noteId)
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
"UrlTitle": url,
})
@@ -1036,7 +1035,7 @@ func (this *BlogService) UpdateSingleUrlTitle(userId, singleId, urlTitle string)
"UrlTitle": "",
})
*/
url = GetUrTitle(userId, urlTitle, "single")
url = GetUrTitle(userId, urlTitle, "single", singleId)
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
"UrlTitle": url,
})
@@ -1070,7 +1069,7 @@ func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content stri
UserId: bson.ObjectIdHex(userId),
Title: title,
Content: content,
UrlTitle: GetUrTitle(userId, title, "single"),
UrlTitle: GetUrTitle(userId, title, "single", singleId),
CreatedTime: time.Now(),
}
page.UpdatedTime = page.CreatedTime
@@ -1108,6 +1107,7 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool
// 得到用户的博客url
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
/*
if userBlog != nil {
if userBlog.Domain != "" && configService.AllowCustomDomain() {
return configService.GetUserUrl(userBlog.Domain)
@@ -1118,12 +1118,15 @@ func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string
username = userBlog.UserId.Hex()
}
}
*/
return configService.GetBlogUrl() + "/" + username
}
// 得到所有url
func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.User) info.BlogUrls {
var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl string
/*
if userBlog.Domain != "" && configService.AllowCustomDomain() { // http://demo.com
// ok
indexUrl = configService.GetUserUrl(userBlog.Domain)
@@ -1144,6 +1147,7 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
tagsUrl = indexUrl + "/tags"
tagPostsUrl = indexUrl + "/tag"
} else {
*/
// ok
blogUrl := configService.GetBlogUrl() // blog.leanote.com
userIdOrEmail := ""
@@ -1162,7 +1166,7 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/username
tagsUrl = blogUrl + "/tags/" + userIdOrEmail
tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/username
}
// }
return info.BlogUrls{
IndexUrl: indexUrl,

View File

@@ -1,32 +1,33 @@
package service
import (
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"github.com/revel/revel"
"time"
"gopkg.in/mgo.v2/bson"
"os"
"os/exec"
"fmt"
"strings"
"strconv"
"strings"
"time"
)
// 配置服务
// 只是全局的, 用户的配置没有
type ConfigService struct {
adminUserId string
siteUrl string
adminUserId string
siteUrl string
adminUsername string
// 全局的
GlobalAllConfigs map[string]interface{}
GlobalAllConfigs map[string]interface{}
GlobalStringConfigs map[string]string
GlobalArrayConfigs map[string][]string
GlobalMapConfigs map[string]map[string]string
GlobalArrayConfigs map[string][]string
GlobalMapConfigs map[string]map[string]string
GlobalArrMapConfigs map[string][]map[string]string
}
// appStart时 将全局的配置从数据库中得到作为全局
func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalAllConfigs = map[string]interface{}{}
@@ -34,22 +35,23 @@ func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalArrayConfigs = map[string][]string{}
this.GlobalMapConfigs = map[string]map[string]string{}
this.GlobalArrMapConfigs = map[string][]map[string]string{}
this.adminUsername, _ = revel.Config.String("adminUsername")
if this.adminUsername == "" {
this.adminUsername = "admin"
}
this.siteUrl, _ = revel.Config.String("site.url")
userInfo := userService.GetUserInfoByAny(this.adminUsername)
if userInfo.UserId == "" {
return false
}
this.adminUserId = userInfo.UserId.Hex()
configs := []info.Config{}
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
// db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
db.ListByQ(db.Configs, bson.M{}, &configs)
for _, config := range configs {
if config.IsArr {
this.GlobalArrayConfigs[config.Key] = config.ValueArr
@@ -65,12 +67,22 @@ func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalAllConfigs[config.Key] = config.ValueStr
}
}
// site URL
if s, ok := this.GlobalStringConfigs["siteUrl"]; !ok || s != "" {
this.GlobalStringConfigs["siteUrl"] = this.siteUrl
}
return true
}
func (this *ConfigService) GetSiteUrl() string {
return this.siteUrl;
s := this.GetGlobalStringConfig("siteUrl")
if s != "" {
return s
}
return this.siteUrl
}
func (this *ConfigService) GetAdminUsername() string {
return this.adminUsername
@@ -84,15 +96,15 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
// 判断是否存在
if _, ok := this.GlobalAllConfigs[key]; !ok {
// 需要添加
config := info.Config{ConfigId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId),
Key: key,
IsArr: isArr,
IsMap: isMap,
IsArrMap: isArrMap,
config := info.Config{ConfigId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId), // 没用
Key: key,
IsArr: isArr,
IsMap: isMap,
IsArrMap: isArrMap,
UpdatedTime: time.Now(),
}
if(isArr) {
if isArr {
v, _ := value.([]string)
config.ValueArr = v
this.GlobalArrayConfigs[key] = v
@@ -113,7 +125,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
} else {
i := bson.M{"UpdatedTime": time.Now()}
this.GlobalAllConfigs[key] = value
if(isArr) {
if isArr {
v, _ := value.([]string)
i["ValueArr"] = v
this.GlobalArrayConfigs[key] = v
@@ -130,7 +142,8 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
i["ValueStr"] = v
this.GlobalStringConfigs[key] = v
}
return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
// return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
return db.UpdateByQMap(db.Configs, bson.M{"Key": key}, i)
}
}
@@ -177,25 +190,26 @@ func (this *ConfigService) GetGlobalArrMapConfig(key string) []map[string]string
func (this *ConfigService) IsOpenRegister() bool {
return this.GetGlobalStringConfig("openRegister") != ""
}
//-------
// 修改共享笔记的配置
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
registerSharedNotebookPerms, registerSharedNotePerms []int,
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
registerSharedNotebookPerms, registerSharedNotePerms []int,
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) (ok bool, msg string) {
defer func() {
defer func() {
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err)
}
}();
}()
// 用户是否存在?
if registerSharedUserId == "" {
ok = true
msg = "share userId is blank, So it share nothing to register"
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
return
return
} else {
user := userService.GetUserInfo(registerSharedUserId)
if user.UserId == "" {
@@ -206,7 +220,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId)
}
}
notebooks := []map[string]string{}
// 共享笔记本
if len(registerSharedNotebookIds) > 0 {
@@ -222,7 +236,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such notebook: " + notebookId
return
} else {
perm := "0";
perm := "0"
if registerSharedNotebookPerms[i] == 1 {
perm = "1"
}
@@ -231,7 +245,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
}
}
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks)
notes := []map[string]string{}
// 共享笔记
if len(registerSharedNoteIds) > 0 {
@@ -247,7 +261,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such note: " + noteId
return
} else {
perm := "0";
perm := "0"
if registerSharedNotePerms[i] == 1 {
perm = "1"
}
@@ -256,7 +270,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
}
}
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
// 复制
noteIds := []string{}
if len(registerCopyNoteIds) > 0 {
@@ -277,7 +291,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
}
}
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds)
ok = true
return
}
@@ -298,7 +312,7 @@ func (this *ConfigService) getBackupDirname() string {
}
func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
binPath := configService.GetGlobalStringConfig("mongodumpPath")
config := revel.Config;
config := revel.Config
dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
@@ -318,20 +332,21 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
msg = fmt.Sprintf("%v", err)
return
}
cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath);
Log(binPath)
b, err := cmd.Output()
if err != nil {
msg = fmt.Sprintf("%v", err)
if err != nil {
msg = fmt.Sprintf("%v", err)
ok = false
Log("error:......")
Log(string(b))
return
}
Log("error:......")
Log(string(b))
return
}
ok = configService.AddBackup(dir, remark)
return ok, msg
return ok, msg
}
// 还原
func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
@@ -339,22 +354,22 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break;
break
}
}
if i == len(backups) {
return false, "Backup Not Found"
}
// 先备份当前
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"] )
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"])
if !ok {
return
}
// mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/
binPath := configService.GetGlobalStringConfig("mongorestorePath")
config := revel.Config;
config := revel.Config
dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
@@ -365,26 +380,26 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
if username != "" {
binPath += " -u " + username + " -p " + password
}
path := backup["path"] + "/" + dbname
// 判断路径是否存在
if !IsDirExists(path) {
return false, path + " Is Not Exists"
}
binPath += " " + path
cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath);
Log(binPath)
b, err := cmd.Output()
if err != nil {
msg = fmt.Sprintf("%v", err)
if err != nil {
msg = fmt.Sprintf("%v", err)
ok = false
Log("error:......")
Log(string(b))
return
}
Log("error:......")
Log(string(b))
return
}
return true, ""
}
func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
@@ -393,22 +408,22 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break;
break
}
}
if i == len(backups) {
return false, "Backup Not Found"
}
// 删除文件夹之
err := os.RemoveAll(backups[i]["path"])
if err != nil {
return false, fmt.Sprintf("%v", err)
}
// 删除之
backups = append(backups[0:i], backups[i+1:]...)
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
return ok, ""
}
@@ -419,14 +434,14 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break;
break
}
}
if i == len(backups) {
return false, "Backup Not Found"
}
backup["remark"] = remark;
backup["remark"] = remark
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
return ok, ""
}
@@ -438,7 +453,7 @@ func (this *ConfigService) GetBackup(createdTime string) (map[string]string, boo
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break;
break
}
}
if i == len(backups) {
@@ -456,15 +471,15 @@ var port string
func init() {
revel.OnAppStart(func() {
/*
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
port = strconv.Itoa(revel.HttpPort)
if port != "80" {
port = ":" + port
} else {
port = "";
}
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
port = strconv.Itoa(revel.HttpPort)
if port != "80" {
port = ":" + port
} else {
port = "";
}
*/
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
if strings.HasPrefix(siteUrl, "http://") {
defaultDomain = siteUrl[len("http://"):]
@@ -472,7 +487,7 @@ func init() {
defaultDomain = siteUrl[len("https://"):]
schema = "https://"
}
// port localhost:9000
ports := strings.Split(defaultDomain, ":")
if len(ports) == 2 {
@@ -487,49 +502,36 @@ func init() {
}
func (this *ConfigService) GetSchema() string {
return schema;
return schema
}
// 默认
func (this *ConfigService) GetDefaultDomain() string {
return defaultDomain
}
// 包含http://
func (this *ConfigService) GetDefaultUrl() string {
return schema + defaultDomain
}
// note
func (this *ConfigService) GetNoteDomain() string {
subDomain := this.GetGlobalStringConfig("noteSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/note"
return "/note"
}
func (this *ConfigService) GetNoteUrl() string {
return schema + this.GetNoteDomain();
return this.GetNoteDomain()
}
// blog
func (this *ConfigService) GetBlogDomain() string {
subDomain := this.GetGlobalStringConfig("blogSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/blog"
return "/blog"
}
func (this *ConfigService) GetBlogUrl() string {
return schema + this.GetBlogDomain();
return this.GetBlogDomain()
}
// lea
func (this *ConfigService) GetLeaDomain() string {
subDomain := this.GetGlobalStringConfig("leaSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/lea"
return "/lea"
}
func (this *ConfigService) GetLeaUrl() string {
return schema + this.GetLeaDomain();
return schema + this.GetLeaDomain()
}
func (this *ConfigService) GetUserUrl(domain string) string {
@@ -543,6 +545,7 @@ func (this *ConfigService) GetUserSubUrl(subDomain string) string {
func (this *ConfigService) AllowCustomDomain() bool {
return configService.GetGlobalStringConfig("allowCustomDomain") != ""
}
// 是否是好的自定义域名
func (this *ConfigService) IsGoodCustomDomain(domain string) bool {
blacks := this.GetGlobalArrayConfig("blackCustomDomains")
@@ -567,20 +570,29 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
// 上传大小
func (this *ConfigService) GetUploadSize(key string) float64 {
f, _ := strconv.ParseFloat(this.GetGlobalStringConfig(key), 64)
return f;
return f
}
func (this *ConfigService) GetInt64(key string) int64 {
f, _ := strconv.ParseInt(this.GetGlobalStringConfig(key), 10, 64)
return f
}
func (this *ConfigService) GetInt32(key string) int32 {
f, _ := strconv.ParseInt(this.GetGlobalStringConfig(key), 10, 32)
return int32(f)
}
func (this *ConfigService) GetUploadSizeLimit() map[string]float64 {
return map[string]float64{
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
"uploadBlogLogoSize":this.GetUploadSize("uploadBlogLogoSize"),
"uploadAttachSize":this.GetUploadSize("uploadAttachSize"),
"uploadAvatarSize":this.GetUploadSize("uploadAvatarSize"),
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
"uploadBlogLogoSize": this.GetUploadSize("uploadBlogLogoSize"),
"uploadAttachSize": this.GetUploadSize("uploadAttachSize"),
"uploadAvatarSize": this.GetUploadSize("uploadAvatarSize"),
}
}
// 为用户得到全局的配置
// NoteController调用
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
uploadSizeConfigs := this.GetUploadSizeLimit();
uploadSizeConfigs := this.GetUploadSizeLimit()
config := map[string]interface{}{}
for k, v := range uploadSizeConfigs {
config[k] = v
@@ -594,5 +606,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
}
func (this *ConfigService) GetVersion() string {
return "1.1"
return "2.6.1"
}

View File

@@ -1,17 +1,19 @@
package service
import (
"github.com/leanote/leanote/app/info"
"crypto/tls"
"net"
"bytes"
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
"strings"
"html/template"
"net/smtp"
"strconv"
"fmt"
"html/template"
"bytes"
"strings"
"time"
)
// 发送邮件
@@ -20,7 +22,7 @@ type EmailService struct {
tpls map[string]*template.Template
}
func NewEmailService() (*EmailService) {
func NewEmailService() *EmailService {
return &EmailService{tpls: map[string]*template.Template{}}
}
@@ -29,42 +31,111 @@ var host = ""
var emailPort = ""
var username = ""
var password = ""
var ssl = false
func InitEmailFromDb() {
host = configService.GetGlobalStringConfig("emailHost")
emailPort = configService.GetGlobalStringConfig("emailPort")
username = configService.GetGlobalStringConfig("emailUsername")
password = configService.GetGlobalStringConfig("emailPassword")
if configService.GetGlobalStringConfig("emailSSL") == "1" {
ssl = true
}
}
//return a smtp client
func dial(addr string) (*smtp.Client, error) {
conn, err := tls.Dial("tcp", addr, nil)
if err != nil {
LogW("Dialing Error:", err)
return nil, err
}
//分解主机端口字符串
host, _, _ := net.SplitHostPort(addr)
return smtp.NewClient(conn, host)
}
func SendEmailWithSSL (auth smtp.Auth, to []string, msg []byte) (err error) {
//create smtp client
c, err := dial(host + ":" + emailPort)
if err != nil {
LogW("Create smpt client error:", err)
return err
}
defer c.Close()
if auth != nil {
if ok, _ := c.Extension("AUTH"); ok {
if err = c.Auth(auth); err != nil {
LogW("Error during AUTH", err)
return err
}
}
}
if err = c.Mail(username); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}
func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string) {
InitEmailFromDb()
if host == "" || emailPort == "" || username == "" || password == "" {
return
return
}
hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", username, password, hp[0])
var content_type string
mailtype := "html"
if mailtype == "html" {
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
} else{
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
} else {
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
}
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
send_to := strings.Split(to, ";")
err := smtp.SendMail(host+":"+emailPort, auth, username, send_to, msg)
var err error
if ssl {
err = SendEmailWithSSL(auth, send_to, msg)
} else {
Log("no ssl")
err = smtp.SendMail(host + ":" + emailPort, auth, username, send_to, msg)
}
if err != nil {
e = fmt.Sprint(err)
return
return
}
ok = true
return
return
}
// AddUser调用
@@ -74,20 +145,20 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
if token == "" {
return false
}
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateRegister");
if(tpl == "") {
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateRegister")
if tpl == "" {
return false
}
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
"user": map[string]interface{}{
"userId": userInfo.UserId.Hex(),
"email": userInfo.Email,
"userId": userInfo.UserId.Hex(),
"email": userInfo.Email,
"username": userInfo.Username,
},
}
@@ -97,7 +168,7 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
if !ok {
return false
}
// 发送邮件
ok, _ = this.SendEmail(email, subject, tpl)
return ok
@@ -113,66 +184,66 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
}
token := tokenService.NewToken(userInfo.UserId.Hex(), email, info.TokenUpdateEmail)
if token == "" {
return
}
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail")
// 发送邮件
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
"newEmail": email,
"user": map[string]interface{}{
"userId": userInfo.UserId.Hex(),
"email": userInfo.Email,
"userId": userInfo.UserId.Hex(),
"email": userInfo.Email,
"username": userInfo.Username,
},
}
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
if !ok {
return
return
}
// 发送邮件
ok, msg = this.SendEmail(email, subject, tpl)
return
}
func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) {
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword")
// 发送邮件
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
if !ok {
return
return
}
// 发送邮件
ok, msg = this.SendEmail(email, subject, tpl)
return
return
}
// 发送邀请链接
func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool {
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateInvite")
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
"content": content,
"content": content,
"user": map[string]interface{}{
"username": userInfo.Username,
"email": userInfo.Email,
"email": userInfo.Email,
},
}
var ok bool
@@ -187,32 +258,32 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str
// 发送评论
func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComment, userId, content string) bool {
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateComment");
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateComment")
// title := "评论提醒"
/*
toUserId := note.UserId.Hex()
// title := "评论提醒"
// 表示回复回复的内容, 那么发送给之前回复的
if comment.CommentId != "" {
toUserId = comment.UserId.Hex()
}
toUserInfo := userService.GetUserInfo(toUserId)
sendUserInfo := userService.GetUserInfo(userId)
subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
if comment.CommentId != "" {
subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
if userId == note.UserId.Hex() {
subject += "(作者)";
toUserId := note.UserId.Hex()
// title := "评论提醒"
// 表示回复回复的内容, 那么发送给之前回复的
if comment.CommentId != "" {
toUserId = comment.UserId.Hex()
}
toUserInfo := userService.GetUserInfo(toUserId)
sendUserInfo := userService.GetUserInfo(userId)
subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
if comment.CommentId != "" {
subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
if userId == note.UserId.Hex() {
subject += "(作者)";
}
subject += " 的评论";
}
subject += " 的评论";
}
*/
toUserId := note.UserId.Hex()
// 表示回复回复的内容, 那么发送给之前回复的
if comment.CommentId != "" {
@@ -220,28 +291,28 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
}
toUserInfo := userService.GetUserInfo(toUserId) // 被评论者
sendUserInfo := userService.GetUserInfo(userId) // 评论者
// {siteUrl} {blogUrl}
// {siteUrl} {blogUrl}
// {blog.id} {blog.title} {blog.url}
// {commentUser.userId} {commentUser.username} {commentUser.email}
// {commentUser.userId} {commentUser.username} {commentUser.email}
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(),
"blog": map[string]string{
"id": note.NoteId.Hex(),
"id": note.NoteId.Hex(),
"title": note.Title,
"url": configService.GetBlogUrl() + "/view/" + note.NoteId.Hex(),
"url": configService.GetBlogUrl() + "/view/" + note.NoteId.Hex(),
},
"commentContent": content,
// 评论者信息
"commentUser": map[string]interface{}{"userId": sendUserInfo.UserId.Hex(),
"username": sendUserInfo.Username,
"email": sendUserInfo.Email,
"commentUser": map[string]interface{}{"userId": sendUserInfo.UserId.Hex(),
"username": sendUserInfo.Username,
"email": sendUserInfo.Email,
"isBlogAuthor": userId == note.UserId.Hex(),
},
// 被评论者信息
"commentedUser": map[string]interface{}{"userId": toUserId,
"username": toUserInfo.Username,
"email": toUserInfo.Email,
"username": toUserInfo.Username,
"email": toUserInfo.Email,
"isBlogAuthor": toUserId == note.UserId.Hex(),
},
}
@@ -251,53 +322,52 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
if !ok {
return false
}
// 发送邮件
ok, _ = this.SendEmail(toUserInfo.Email, subject, tpl)
return ok
}
// 验证模板是否正确
func (this *EmailService) ValidTpl(str string) (ok bool, msg string){
defer func() {
func (this *EmailService) ValidTpl(str string) (ok bool, msg string) {
defer func() {
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err)
}
}();
header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
}()
header := configService.GetGlobalStringConfig("emailTemplateHeader")
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
str = strings.Replace(str, "{{header}}", header, -1)
str = strings.Replace(str, "{{footer}}", footer, -1)
_, err := template.New("tpl name").Parse(str)
if err != nil {
if err != nil {
msg = fmt.Sprint(err)
return
}
ok = true
return
}
ok = true
return
}
// ok, msg, subject, tpl
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template){
defer func() {
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template) {
defer func() {
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err)
}
}();
}()
var err error
var has bool
if tpl, has = this.tpls[str]; !has {
tpl, err = template.New("tpl name").Parse(str)
if err != nil {
tpl, err = template.New("tpl name").Parse(str)
if err != nil {
msg = fmt.Sprint(err)
return
}
this.tpls[str] = tpl
return
}
this.tpls[str] = tpl
}
ok = true
return
@@ -310,67 +380,67 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
defer func() { // 必须要先声明defer否则不能捕获到panic异常
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容
}
}();
}()
var tpl *template.Template
values["siteUrl"] = configService.GetSiteUrl();
values["siteUrl"] = configService.GetSiteUrl()
// subject
if subject != "" {
ok, msg, tpl = this.getTpl(subject)
if(!ok) {
if !ok {
return
}
var buffer bytes.Buffer
err := tpl.Execute(&buffer, values)
if err != nil {
err := tpl.Execute(&buffer, values)
if err != nil {
msg = fmt.Sprint(err)
return
}
o = buffer.String()
} else {
o = ""
}
// content
header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
}
o = buffer.String()
} else {
o = ""
}
// content
header := configService.GetGlobalStringConfig("emailTemplateHeader")
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
body = strings.Replace(body, "{{header}}", header, -1)
body = strings.Replace(body, "{{footer}}", footer, -1)
values["subject"] = o
ok, msg, tpl = this.getTpl(body)
if(!ok) {
if !ok {
return
}
var buffer2 bytes.Buffer
err := tpl.Execute(&buffer2, values)
if err != nil {
err := tpl.Execute(&buffer2, values)
if err != nil {
msg = fmt.Sprint(err)
return
}
b = buffer2.String()
return
}
b = buffer2.String()
return
}
// 发送email给用户
// 需要记录
func (this *EmailService) SendEmailToUsers(users []info.User, subject, body string) (ok bool, msg string) {
if(users == nil || len(users) == 0) {
if users == nil || len(users) == 0 {
msg = "no users"
return
return
}
// 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if(!ok) {
if !ok {
Log(msg)
return
return
}
go func() {
for _, user := range users {
LogJ(user)
@@ -381,8 +451,8 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m)
ok = ok2
msg = msg2
if(ok2) {
sendOk, msg := this.SendEmail(user.Email, subject2, body2);
if ok2 {
sendOk, msg := this.SendEmail(user.Email, subject2, body2)
this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下
// 记录到Email Log
if sendOk {
@@ -395,47 +465,47 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
}
}
}()
return
return
}
func (this *EmailService) SendEmailToEmails(emails []string, subject, body string) (ok bool, msg string) {
if(emails == nil || len(emails) == 0) {
if emails == nil || len(emails) == 0 {
msg = "no emails"
return
return
}
// 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if(!ok) {
if !ok {
Log(msg)
return
return
}
// go func() {
for _, email := range emails {
if email == "" {
continue
}
m := map[string]interface{}{}
m["email"] = email
ok, msg, subject, body = this.renderEmail(subject, body, m)
if(ok) {
sendOk, msg := this.SendEmail(email, subject, body);
this.AddEmailLog(email, subject, body, sendOk, msg)
// 记录到Email Log
if sendOk {
Log("ok " + email)
} else {
Log("no " + email)
}
} else {
Log(msg);
}
// go func() {
for _, email := range emails {
if email == "" {
continue
}
// }()
return
m := map[string]interface{}{}
m["email"] = email
ok, msg, subject, body = this.renderEmail(subject, body, m)
if ok {
sendOk, msg := this.SendEmail(email, subject, body)
this.AddEmailLog(email, subject, body, sendOk, msg)
// 记录到Email Log
if sendOk {
Log("ok " + email)
} else {
Log("no " + email)
}
} else {
Log(msg)
}
}
// }()
return
}
// 添加邮件日志
@@ -443,6 +513,7 @@ func (this *EmailService) AddEmailLog(email, subject, body string, ok bool, msg
log := info.EmailLog{LogId: bson.NewObjectId(), Email: email, Subject: subject, Body: body, Ok: ok, Msg: msg, CreatedTime: time.Now()}
db.Insert(db.EmailLogs, log)
}
// 展示邮件日志
func (this *EmailService) DeleteEmails(ids []string) bool {
@@ -451,7 +522,7 @@ func (this *EmailService) DeleteEmails(ids []string) bool {
idsO[i] = bson.ObjectIdHex(id)
}
db.DeleteAll(db.EmailLogs, bson.M{"_id": bson.M{"$in": idsO}})
return true
}
func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField string, isAsc bool, email string) (page info.Page, emailLogs []info.EmailLog) {
@@ -461,7 +532,7 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
if email != "" {
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
}
q := db.EmailLogs.Find(query);
q := db.EmailLogs.Find(query)
// 总记录数
count, _ := q.Count()
// 列表
@@ -471,4 +542,4 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
All(&emailLogs)
page = info.NewPage(pageNumber, pageSize, count, nil)
return
}
}

View File

@@ -30,7 +30,7 @@ func (this *FileService) AddImage(image info.File, albumId, userId string, needC
image.IsDefaultAlbum = true
}
image.UserId = bson.ObjectIdHex(userId)
ok = db.Insert(db.Files, image)
return
}
@@ -40,28 +40,28 @@ func (this *FileService) AddImage(image info.File, albumId, userId string, needC
func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNumber, pageSize int) info.Page {
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
files := []info.File{}
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
if albumId != "" {
q["AlbumId"] = bson.ObjectIdHex(albumId);
q["AlbumId"] = bson.ObjectIdHex(albumId)
} else {
q["IsDefaultAlbum"] = true
}
if key != "" {
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
}
// LogJ(q)
count := db.Count(db.Files, q);
// LogJ(q)
count := db.Count(db.Files, q)
db.Files.
Find(q).
Sort(sortFieldR).
Skip(skipNum).
Limit(pageSize).
All(&files)
return info.Page{Count: count, List: files}
}
@@ -75,12 +75,12 @@ func (this *FileService) GetAllImageNamesMap(userId string) (m map[string]bool)
q := bson.M{"UserId": bson.ObjectIdHex(userId)}
files := []info.File{}
db.ListByQWithFields(db.Files, q, []string{"Name"}, &files)
m = make(map[string]bool)
if len(files) == 0 {
return
}
for _, file := range files {
m[file.Name] = true
}
@@ -91,8 +91,8 @@ func (this *FileService) GetAllImageNamesMap(userId string) (m map[string]bool)
func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
if(file.FileId != "") {
if file.FileId != "" {
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
// delete image
// TODO
@@ -173,63 +173,63 @@ func (this *FileService) GetFile(userId, fileId string) string {
if fileId == "" {
return ""
}
file := info.File{}
db.Get(db.Files, fileId, &file)
path := file.Path
if path == "" {
return ""
}
// 1. 判断权限
// 是否是我的文件
if userId != "" && file.UserId.Hex() == userId {
return path
}
// 得到使用过该fileId的所有笔记NoteId
// 这些笔记是否有public的, 若有则ok
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
noteIds := noteImageService.GetNoteIds(fileId)
if noteIds != nil && len(noteIds) > 0 {
// 这些笔记是否有public的
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
return path
}
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
for _, noteId := range noteIds {
note := noteService.GetNoteById(noteId.Hex())
if shareService.HasReadPerm(note.UserId.Hex(), userId, noteId.Hex()) {
return path;
}
}
/*
// 若有共享给我的笔记?
// 对该笔记可读?
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
return path
}
// 笔记本是否共享给我?
// 通过笔记得到笔记本
notes := []info.Note{}
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, &notes)
if notes != nil && len(notes) > 0 {
notebookIds := make([]bson.ObjectId, len(notes))
for i := 0; i < len(notes); i++ {
notebookIds[i] = notes[i].NotebookId
}
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
return path
}
}
/*
// 若有共享给我的笔记?
// 对该笔记可读?
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
return path
}
// 笔记本是否共享给我?
// 通过笔记得到笔记本
notes := []info.Note{}
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, &notes)
if notes != nil && len(notes) > 0 {
notebookIds := make([]bson.ObjectId, len(notes))
for i := 0; i < len(notes); i++ {
notebookIds[i] = notes[i].NotebookId
}
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
return path
}
}
*/
}
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
if file.FromFileId != "" {
fromFile := info.File{}
@@ -238,54 +238,56 @@ func (this *FileService) GetFile(userId, fileId string) string {
return fromFile.Path
}
}
return ""
}
// 复制共享的笔记时, 复制其中的图片到我本地
// 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了
file2 := info.File{}
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
if file2.FileId != "" {
return true, file2.FileId.Hex();
return true, file2.FileId.Hex()
}
// 复制之
file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
if file.FileId == "" || file.UserId.Hex() != userId {
return false, ""
}
_, ext := SplitFilename(file.Name)
newFilename := NewGuid() + ext
dir := "files/" + toUserId + "/images"
guid := NewGuid()
newFilename := guid + ext
// TODO 统一目录格式
// dir := "files/" + toUserId + "/images"
dir := "files/" + GetRandomFilePath(toUserId, guid) + "/images"
filePath := dir + "/" + newFilename
err := os.MkdirAll(dir, 0755)
err := os.MkdirAll(revel.BasePath+dir, 0755)
if err != nil {
return false, ""
}
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
_, err = CopyFile(revel.BasePath+"/"+file.Path, revel.BasePath+"/"+filePath)
if err != nil {
Log(err)
return false, ""
}
fileInfo := info.File{Name: newFilename,
Title: file.Title,
Path: filePath,
Size: file.Size,
Title: file.Title,
Path: filePath,
Size: file.Size,
FromFileId: file.FileId}
id := bson.NewObjectId();
id := bson.NewObjectId()
fileInfo.FileId = id
fileId = id.Hex()
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
if Ok {
return Ok, id.Hex()
}
@@ -296,7 +298,7 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
func (this *FileService) IsMyFile(userId, fileId string) bool {
// 如果有问题会panic
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
return false;
return false
}
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
}

View File

@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
// "strings"
// "strings"
)
// 用户组, 用户组用户管理
@@ -16,34 +16,35 @@ type GroupService struct {
// 添加分组
func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
group := info.Group {
GroupId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId),
Title: title,
group := info.Group{
GroupId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId),
Title: title,
CreatedTime: time.Now(),
}
return db.Insert(db.Groups, group), group
}
// 删除分组
// 判断是否有好友
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
/*
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
return false, "groupHasUsers"
}
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
return false, "groupHasUsers"
}
*/
if !this.isMyGroup(userId, groupId) {
return false, "notMyGroup"
}
// 删除分组后, 需要删除所有用户分享到该组的笔记本, 笔记
shareService.DeleteAllShareNotebookGroup(groupId);
shareService.DeleteAllShareNoteGroup(groupId);
shareService.DeleteAllShareNotebookGroup(groupId)
shareService.DeleteAllShareNoteGroup(groupId)
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
}
@@ -53,15 +54,15 @@ func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bo
}
// 得到用户的所有分组(包括下的所有用户)
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
/*
// 得到我的分组
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
*/
func (this *GroupService) GetGroupsAndUsers(userId string) []info.Group {
/*
// 得到我的分组
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
*/
// 我的分组, 及我所属的分组
groups := this.GetGroupsContainOf(userId);
groups := this.GetGroupsContainOf(userId)
// 得到其下的用户
for i, group := range groups {
group.Users = this.GetUsers(group.GroupId.Hex())
@@ -69,8 +70,9 @@ func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
}
return groups
}
// 仅仅得到所有分组
func (this *GroupService) GetGroups(userId string) ([]info.Group) {
func (this *GroupService) GetGroups(userId string) []info.Group {
// 得到分组s
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
@@ -78,24 +80,24 @@ func (this *GroupService) GetGroups(userId string) ([]info.Group) {
}
// 得到我的和我所属组的ids
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) ([]bson.ObjectId) {
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) []bson.ObjectId {
// 所属组
groupIds := this.GetBelongToGroupIds(userId)
m := map[bson.ObjectId]bool{}
for _, groupId := range groupIds {
m[groupId] = true
}
// 我的组
myGroups := this.GetGroups(userId)
for _, group := range myGroups {
if !m[group.GroupId] {
groupIds = append(groupIds, group.GroupId)
}
}
return groupIds
}
@@ -105,28 +107,28 @@ func (this *GroupService) GetGroupsContainOf(userId string) []info.Group {
// 我的组
myGroups := this.GetGroups(userId)
myGroupMap := map[bson.ObjectId]bool{}
for _, group := range myGroups {
myGroupMap[group.GroupId] = true
}
// 所属组
groupIds := this.GetBelongToGroupIds(userId)
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"_id": bson.M{"$in": groupIds}}, &groups)
for _, group := range groups {
if !myGroupMap[group.GroupId] {
myGroups = append(myGroups, group)
}
}
return myGroups
}
// 得到分组, shareService用
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
func (this *GroupService) GetGroup(userId, groupId string) info.Group {
// 得到分组s
group := info.Group{}
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
@@ -134,7 +136,7 @@ func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
}
// 得到某分组下的用户
func (this *GroupService) GetUsers(groupId string) ([]info.User) {
func (this *GroupService) GetUsers(groupId string) []info.User {
// 得到UserIds
groupUsers := []info.GroupUser{}
db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers)
@@ -150,7 +152,7 @@ func (this *GroupService) GetUsers(groupId string) ([]info.User) {
}
// 得到我所属的所有分组ids
func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
func (this *GroupService) GetBelongToGroupIds(userId string) []bson.ObjectId {
// 得到UserIds
groupUsers := []info.GroupUser{}
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
@@ -182,23 +184,23 @@ func (this *GroupService) IsExistsGroupUser(userId, groupId string) (ok bool) {
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
// groupId是否是ownUserId的?
/*
if !this.IsExistsGroupUser(ownUserId, groupId) {
return false, "forbidden"
}
if !this.IsExistsGroupUser(ownUserId, groupId) {
return false, "forbiddenNotMyGroup"
}
*/
if !this.isMyGroup(ownUserId, groupId) {
return false, "forbidden"
return false, "forbiddenNotMyGroup"
}
// 是否已存在
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
return false, "hasUsers"
return false, "userExistsInGroup"
}
return db.Insert(db.GroupUsers, info.GroupUser{
GroupUserId: bson.NewObjectId(),
GroupId: bson.ObjectIdHex(groupId),
UserId: bson.ObjectIdHex(userId),
GroupId: bson.ObjectIdHex(groupId),
UserId: bson.ObjectIdHex(userId),
CreatedTime: time.Now(),
}), ""
}
@@ -207,17 +209,17 @@ func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, m
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
// groupId是否是ownUserId的?
/*
if !this.IsExistsGroupUser(ownUserId, groupId) {
return false, "forbidden"
}
if !this.IsExistsGroupUser(ownUserId, groupId) {
return false, "forbiddenNotMyGroup"
}
*/
if !this.isMyGroup(ownUserId, groupId) {
return false, "forbidden"
return false, "forbiddenNotMyGroup"
}
// 删除该用户分享到本组的笔记本, 笔记
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId);
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId);
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId)
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId)
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
}

View File

@@ -1,11 +1,11 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
// "time"
// "time"
)
// 历史记录
@@ -22,7 +22,7 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
if eachHistory.Content == "" {
return
}
// 先查是否存在历史记录, 没有则添加之
history := info.NoteContentHistory{}
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &history)
@@ -38,8 +38,8 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
}
newHistory := []info.EachHistory{eachHistory}
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
history.Histories = newHistory
history.Histories = newHistory
// 更新之
db.UpdateByIdAndUserId(db.NoteContentHistories, noteId, userId, history)
}
@@ -48,13 +48,13 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
// 新建历史
func (this *NoteContentHistoryService) newHistory(noteId, userId string, eachHistory info.EachHistory) {
history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
Histories: []info.EachHistory{eachHistory},
}
// 保存之
db.Insert(db.NoteContentHistories, history)
db.Insert(db.NoteContentHistories, history)
}
// 列表展示

View File

@@ -1,22 +1,22 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"regexp"
// "time"
// "time"
)
type NoteImageService struct {
}
// 通过id, userId得到noteIds
func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId {
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages)
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages)
if noteImages != nil && len(noteImages) > 0 {
noteIds := make([]bson.ObjectId, len(noteImages))
cnt := len(noteImages)
@@ -25,7 +25,7 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
}
return noteIds
}
return nil
}
@@ -67,23 +67,19 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
}
}
}
return true
}
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
/* 弃用之
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, &noteImages)
if len(noteImages) == 0 {
return content;
}
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
for _, noteImage := range noteImages {
imageId := noteImage.ImageId.Hex()
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
@@ -91,37 +87,61 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
replaceMap[imageId] = newImageId
}
}
if len(replaceMap) > 0 {
// 替换之
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
content = reg.ReplaceAllStringFunc(content, func(each string) string {
// each=outputImage?fileId=541bd2f599c37b4f3r000003
fileId := each[len(each)-24:] // 得到后24位, 也即id
if replaceFileId, ok := replaceMap[fileId]; ok {
*/
// 因为很多图片上传就会删除, 所以直接从内容中查看图片id进行复制
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
content = reg.ReplaceAllStringFunc(content, func(each string) string {
// each = outputImage?fileId=541bd2f599c37b4f3r000003
// each = getImage?fileId=541bd2f599c37b4f3r000003
fileId := each[len(each)-24:] // 得到后24位, 也即id
if _, ok := replaceMap[fileId]; !ok {
if bson.IsObjectIdHex(fileId) {
ok2, newImageId := fileService.CopyImage(fromUserId, fileId, toUserId)
if ok2 {
replaceMap[fileId] = newImageId
} else {
replaceMap[fileId] = ""
}
} else {
replaceMap[fileId] = ""
}
}
replaceFileId := replaceMap[fileId]
if replaceFileId != "" {
if each[0] == 'o' {
return "outputImage?fileId=" + replaceFileId
}
return each
});
}
return content;
return "getImage?fileId=" + replaceFileId
}
return each
})
return content
}
//
//
func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[string][]info.File {
noteNoteImages := []info.NoteImage{}
db.ListByQ(db.NoteImages, bson.M{"NoteId": bson.M{"$in": noteIds}}, &noteNoteImages)
// 得到imageId, 再去files表查所有的Files
imageIds := []bson.ObjectId{}
// 图片1 => N notes
imageIdNotes := map[string][]string{} // imageId => [noteId1, noteId2, ...]
for _, noteImage := range noteNoteImages {
imageId := noteImage.ImageId
imageIds = append(imageIds, imageId)
imageIdHex := imageId.Hex()
noteId := noteImage.NoteId.Hex()
if notes, ok := imageIdNotes[imageIdHex]; ok {
@@ -130,11 +150,11 @@ func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[st
imageIdNotes[imageIdHex] = []string{noteId}
}
}
// 得到所有files
files := []info.File{}
db.ListByQ(db.Files, bson.M{"_id": bson.M{"$in": imageIds}}, &files)
// 建立note->file关联
noteImages := make(map[string][]info.File)
for _, file := range files {

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
package service
import (
// "fmt"
"gopkg.in/mgo.v2/bson"
// "fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"sort"
"time"
"strings"
// "html"
"time"
// "html"
)
// 笔记本
@@ -42,8 +42,8 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
for _, each := range userNotebooks {
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
newNotebooks.NotebookId = each.NotebookId
newNotebooks.Title = each.Title;
// newNotebooks.Title = html.EscapeString(each.Title)
newNotebooks.Title = each.Title
// newNotebooks.Title = html.EscapeString(each.Title)
newNotebooks.Title = strings.Replace(strings.Replace(each.Title, "<script>", "", -1), "</script", "", -1)
newNotebooks.Seq = each.Seq
newNotebooks.UserId = each.UserId
@@ -51,13 +51,13 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
newNotebooks.NumberNotes = each.NumberNotes
newNotebooks.IsTrash = each.IsTrash
newNotebooks.IsBlog = each.IsBlog
// 存地址
userNotebooksMap[each.NotebookId] = &newNotebooks
}
// 第二遍, 追加到父下
// 需要删除的id
needDeleteNotebookId := map[bson.ObjectId]bool{}
for id, each := range userNotebooksMap {
@@ -70,7 +70,7 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
needDeleteNotebookId[id] = true
// delete(userNotebooksMap, id)
} else if noParentDelete {
// 没有父, 且设置了要删除
// 没有父, 且设置了要删除
needDeleteNotebookId[id] = true
// delete(userNotebooksMap, id)
}
@@ -116,9 +116,9 @@ func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOr
}
// 同步的方法
func (this *NotebookService) GeSyncNotebooks(userId string, afterUsn, maxEntry int) ([]info.Notebook) {
func (this *NotebookService) GeSyncNotebooks(userId string, afterUsn, maxEntry int) []info.Notebook {
notebooks := []info.Notebook{}
q := db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
q := db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}})
q.Sort("Usn").Limit(maxEntry).All(&notebooks)
return notebooks
}
@@ -137,7 +137,7 @@ func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
if len(userNotebooks) == 0 {
return nil
}
return ParseAndSortNotebooks(userNotebooks, true, true)
}
@@ -147,18 +147,22 @@ func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.ObjectId) info.SubNotebooks {
userNotebooks := []info.Notebook{}
db.Notebooks.Find(bson.M{"_id": bson.M{"$in": notebookIds}}).All(&userNotebooks)
if len(userNotebooks) == 0 {
return nil
}
return ParseAndSortNotebooks(userNotebooks, false, false)
}
// 添加
// [ok]
func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Notebook) {
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
if notebook.NotebookId == "" {
notebook.NotebookId = bson.NewObjectId()
}
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook", notebook.NotebookId.Hex())
notebook.Usn = userService.IncrUsn(notebook.UserId.Hex())
now := time.Now()
notebook.CreatedTime = now
@@ -169,12 +173,13 @@ func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Not
}
return true, notebook
}
// 更新笔记, api
func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parentNotebookId string, seq, usn int) (bool, string, info.Notebook) {
if notebookId == "" {
return false, "notebookIdNotExists", info.Notebook{}
}
// 先判断usn是否和数据库的一样, 如果不一样, 则冲突, 不保存
notebook := this.GetNotebookById(notebookId)
// 不存在
@@ -183,16 +188,16 @@ func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parent
} else if notebook.Usn != usn {
return false, "conflict", notebook
}
notebook.Usn = userService.IncrUsn(userId);
notebook.Title = title;
updates := bson.M{"Title": title, "Usn": notebook.Usn, "Seq": seq, "UpdatedTime": time.Now()};
if(parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId)) {
updates["ParentNotebookId"] = bson.ObjectIdHex(parentNotebookId);
notebook.Usn = userService.IncrUsn(userId)
notebook.Title = title
updates := bson.M{"Title": title, "Usn": notebook.Usn, "Seq": seq, "UpdatedTime": time.Now()}
if parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId) {
updates["ParentNotebookId"] = bson.ObjectIdHex(parentNotebookId)
} else {
updates["ParentNotebookId"] = "";
updates["ParentNotebookId"] = ""
}
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates);
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
if ok {
return ok, "", this.GetNotebookById(notebookId)
}
@@ -202,7 +207,7 @@ func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parent
// 判断是否是blog
func (this *NotebookService) IsBlog(notebookId string) bool {
notebook := info.Notebook{}
db.GetByQWithFields(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, []string{"IsBlog"}, &notebook);
db.GetByQWithFields(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, []string{"IsBlog"}, &notebook)
return notebook.IsBlog
}
@@ -228,20 +233,20 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin
// 更新notebook
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
needUpdate["UpdatedTime"] = time.Now();
needUpdate["UpdatedTime"] = time.Now()
needUpdate["Usn"] = userService.IncrUsn(userId)
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
}
// ToBlog or Not
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool {
updates := bson.M{"IsBlog": isBlog, "Usn": userService.IncrUsn(userId)}
// 笔记本
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
// 更新笔记
q := bson.M{"UserId": bson.ObjectIdHex(userId),
"NotebookId": bson.ObjectIdHex(notebookId)}
q := bson.M{"UserId": bson.ObjectIdHex(userId),
"NotebookId": bson.ObjectIdHex(notebookId)}
data := bson.M{"IsBlog": isBlog}
if isBlog {
data["PublicTime"] = time.Now()
@@ -251,7 +256,7 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
// usn
data["Usn"] = userService.IncrUsn(userId)
db.UpdateByQMap(db.Notes, q, data)
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
// 先查该notebook下所有notes, 得到id
notes := []info.Note{}
@@ -263,12 +268,12 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
}
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
}
// 重新计算tags
go (func() {
blogService.ReCountBlogTags(userId)
})()
return true
}
@@ -276,18 +281,18 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
// 先查看该notebookId下是否有notes, 没有则删除
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
if db.Count(db.Notebooks, bson.M{
"ParentNotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsDeleted": false,
}) == 0 { // 无
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsTrash": false,
"ParentNotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsDeleted": false,
}) == 0 { // 无
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsTrash": false,
"IsDeleted": false}) == 0 { // 不包含trash
// 不是真删除 1/20, 为了同步笔记本
ok := db.UpdateByQMap(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, bson.M{"IsDeleted": true, "Usn": userService.IncrUsn(userId)})
return ok, ""
// return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
// return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
}
return false, "笔记本下有笔记"
} else {
@@ -321,7 +326,7 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
return false
}
}
return true
}
@@ -329,12 +334,12 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
ok := false
// 如果没parentNotebookId, 则parentNotebookId设空
if(parentNotebookId == "") {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)});
if parentNotebookId == "" {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)})
} else {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": bson.ObjectIdHex(parentNotebookId), "Usn": userService.IncrUsn(userId)});
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": bson.ObjectIdHex(parentNotebookId), "Usn": userService.IncrUsn(userId)})
}
if !ok {
return false
}
@@ -345,7 +350,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
return false
}
}
return true
}
@@ -355,19 +360,19 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
notebookIdO := bson.ObjectIdHex(notebookId)
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false, "IsDeleted": false})
Log(count)
Log(notebookId)
// Log(count)
// Log(notebookId)
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
}
func (this *NotebookService) ReCountAll() {
/*
// 得到所有笔记本
notebooks := []info.Notebook{}
db.ListByQWithFields(db.Notebooks, bson.M{}, []string{"NotebookId"}, &notebooks)
for _, each := range notebooks {
this.ReCountNotebookNumberNotes(each.NotebookId.Hex())
}
// 得到所有笔记本
notebooks := []info.Notebook{}
db.ListByQWithFields(db.Notebooks, bson.M{}, []string{"NotebookId"}, &notebooks)
for _, each := range notebooks {
this.ReCountNotebookNumberNotes(each.NotebookId.Hex())
}
*/
}

View File

@@ -1,10 +1,10 @@
package service
import (
"gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
)
// 找回密码
@@ -14,7 +14,7 @@ var overHours = 2.0 // 小时后过期
type PwdService struct {
}
// 1. 找回密码, 通过email找用户,
// 1. 找回密码, 通过email找用户,
// 用户存在, 生成code
func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
ok = false
@@ -23,38 +23,40 @@ func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
msg = "用户不存在"
return
}
token := tokenService.NewToken(userId, email, info.TokenPwd)
if token == "" {
return false, "db error"
}
// 发送邮件
ok, msg = emailService.FindPwdSendEmail(token, email)
return
}
// 重置密码时
// 修改密码
// 先验证
func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) {
var tokenInfo info.Token
var ok bool
var msg string
// 先验证
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenPwd); !ok {
return ok, msg
}
digest, err := GenerateHash(pwd)
if err != nil {
return false,"GenerateHash error"
passwd := GenPwd(pwd)
if passwd == "" {
return false, "GenerateHash error"
}
passwd := string(digest)
// 修改密码之
ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", passwd)
// 删除token
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
return ok, ""
}
}

View File

@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
// "strings"
// "strings"
)
// Session存储到mongodb中
@@ -14,9 +14,10 @@ type SessionService struct {
}
func (this *SessionService) Update(sessionId, key string, value interface{}) bool {
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now()})
}
// 注销时清空session
func (this *SessionService) Clear(sessionId string) bool {
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
@@ -24,7 +25,7 @@ func (this *SessionService) Clear(sessionId string) bool {
func (this *SessionService) Get(sessionId string) info.Session {
session := info.Session{}
db.GetByQ(db.Sessions, bson.M{"SessionId": sessionId}, &session)
// 如果没有session, 那么插入一条之
if session.Id == "" {
session.Id = bson.NewObjectId()
@@ -33,7 +34,7 @@ func (this *SessionService) Get(sessionId string) info.Session {
session.UpdatedTime = session.CreatedTime
db.Insert(db.Sessions, session)
}
return session
}
@@ -45,14 +46,16 @@ func (this *SessionService) LoginTimesIsOver(sessionId string) bool {
session := this.Get(sessionId)
return session.LoginTimes > 5
}
// 登录成功后清空错误次数
func (this *SessionService) ClearLoginTimes(sessionId string) bool {
return this.Update(sessionId, "LoginTimes", 0)
}
// 增加错误次数
func (this *SessionService) IncrLoginTimes(sessionId string) bool {
session := this.Get(sessionId)
return this.Update(sessionId, "LoginTimes", session.LoginTimes + 1)
return this.Update(sessionId, "LoginTimes", session.LoginTimes+1)
}
//----------
@@ -63,10 +66,10 @@ func (this *SessionService) GetCaptcha(sessionId string) string {
}
func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
this.Get(sessionId)
Log(sessionId)
Log(captcha)
// Log(sessionId)
// Log(captcha)
ok := this.Update(sessionId, "Captcha", captcha)
Log(ok)
// Log(ok)
return ok
}
@@ -75,7 +78,7 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
func (this *SessionService) GetUserId(sessionId string) string {
session := this.Get(sessionId)
// 更新updateTime, 避免过期
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{"UpdatedTime": time.Now()})
return session.UserId
}

View File

@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
"sort"
"time"
)
// 共享Notebook, Note服务
@@ -35,7 +35,7 @@ type ShareService struct {
func (this *ShareService) getOrQ(userId string) bson.M {
// 得到我和和我参与的组织
groupIds := groupService.GetMineAndBelongToGroupIds(userId)
q := bson.M{}
if len(groupIds) > 0 {
orQ := []bson.M{
@@ -45,7 +45,7 @@ func (this *ShareService) getOrQ(userId string) bson.M {
// 不是trash的
q["$or"] = orQ
} else {
q["ToUserId"] = bson.ObjectIdHex(userId);
q["ToUserId"] = bson.ObjectIdHex(userId)
}
return q
}
@@ -53,44 +53,44 @@ func (this *ShareService) getOrQ(userId string) bson.M {
// 得到共享给我的笔记本和用户(谁共享给了我)
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
myUserId := userId
// 得到共享给我的用户s信息
// 得到我参与的组织
q := this.getOrQ(userId)
// 不查hasShareNotes
// 直接查shareNotes, shareNotebooks表得到userId
userIds1 := []bson.ObjectId{}
db.Distinct(db.ShareNotes, q, "UserId", &userIds1)
userIds2 := []bson.ObjectId{}
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
userIds := append(userIds1, userIds2...)
userInfos := userService.GetUserInfosOrderBySeq(userIds);
userInfos := userService.GetUserInfosOrderBySeq(userIds)
// 不要我的id
for i, userInfo := range userInfos {
if userInfo.UserId.Hex() == myUserId {
userInfos = append(userInfos[:i], userInfos[i+1:]...)
break;
break
}
}
//--------------------
// 得到他们共享给我的notebooks
// 这里可能会得到重复的记录
// 权限: 笔记本分享给个人 > 笔记本分享给组织
shareNotebooks := []info.ShareNotebook{}
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shareNotebooks) // 按ToUserId降序排序, 那么有ToUserId的在前面
if len(shareNotebooks) == 0 {
return nil, userInfos
}
shareNotebooksLen := len(shareNotebooks)
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
notebookIds := []bson.ObjectId{}
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
@@ -102,34 +102,34 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
shareNotebooksMap[each.NotebookId] = each
}
}
// 1, 2
subNotebooks := notebookService.GetNotebooksByNotebookIds(notebookIds)
// 填充其它信息变成SubShareNotebooks
subShareNotebooks := this.parseToSubShareNotebooks(&subNotebooks, &shareNotebooksMap)
// 3 按用户进行分组成ShareNotebooksByUser
shareNotebooksByUsersMap := map[bson.ObjectId] []info.ShareNotebooks{}
shareNotebooksByUsersMap := map[bson.ObjectId][]info.ShareNotebooks{}
// 先建立userId => []
for _, eachSub := range subShareNotebooks {
userId := eachSub.Notebook.UserId
// 我自己的, 算了
if userId.Hex() == myUserId {
continue;
continue
}
if _, ok := shareNotebooksByUsersMap[userId]; ok {
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
} else {
shareNotebooksByUsersMap[userId] = []info.ShareNotebooks{eachSub}
}
}
shareNotebooksByUser := info.ShareNotebooksByUser{};
shareNotebooksByUser := info.ShareNotebooksByUser{}
for userId, eachShareNotebooks := range shareNotebooksByUsersMap {
// 4, 按用户排序
shareNotebooksByUser[userId.Hex()] = sortSubShareNotebooks(eachShareNotebooks)
}
return shareNotebooksByUser, userInfos
}
@@ -152,46 +152,46 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
subShareNotebooks := info.SubShareNotebooks{}
for _, each := range *subNotebooks {
shareNotebooks := info.ShareNotebooks{}
shareNotebooks.Notebook = each.Notebook // 基本信息有了
shareNotebooks.Notebook = each.Notebook // 基本信息有了
shareNotebooks.ShareNotebook = (*shareNotebooksMap)[each.NotebookId] // perm有了
// 公用的, 单独赋值
shareNotebooks.Seq = shareNotebooks.ShareNotebook.Seq
shareNotebooks.NotebookId = shareNotebooks.ShareNotebook.NotebookId
// 还有其子, 递归解析之
if each.Subs != nil && len(each.Subs) > 0 {
shareNotebooks.Subs = this.parseToSubShareNotebooks(&each.Subs, shareNotebooksMap)
}
subShareNotebooks = append(subShareNotebooks, shareNotebooks)
}
return subShareNotebooks
}
//-------------
// 得到共享笔记本下的notes
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
page, pageSize int, sortField string, isAsc bool) []info.ShareNoteWithPerm {
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
q := this.getOrQ(myUserId)
q["NotebookId"] = bson.ObjectIdHex(notebookId);
q["UserId"] = bson.ObjectIdHex(sharedUserId);
q["NotebookId"] = bson.ObjectIdHex(notebookId)
q["UserId"] = bson.ObjectIdHex(sharedUserId)
shareNotebook := info.ShareNotebook{}
db.GetByQ(db.ShareNotebooks,
db.GetByQ(db.ShareNotebooks,
q,
&shareNotebook)
if shareNotebook.NotebookId == "" {
return nil
}
perm := shareNotebook.Perm
// 2 得到该notebook下分页显示所有的notes
_, notes := noteService.ListNotes(sharedUserId, notebookId, false, page, pageSize, sortField, isAsc, false);
_, notes := noteService.ListNotes(sharedUserId, notebookId, false, page, pageSize, sortField, isAsc, false)
// 3 添加权限信息
// 3.1 如果该notebook自己有其它权限信息, 比如1, 那么覆盖notebook的权限信息
noteIds := make([]bson.ObjectId, len(notes))
@@ -201,7 +201,7 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
// 笔记的权限
shareNotes := []info.ShareNote{}
delete(q, "NotebookId")
q["NoteId"] = bson.M{"$in": noteIds}
q["NoteId"] = bson.M{"$in": noteIds}
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限
notePerms := map[bson.ObjectId]int{}
for _, each := range shareNotes {
@@ -210,16 +210,16 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
}
}
Log("笔记权限")
LogJ(notePerms);
LogJ(notePerms)
// 3.2 组合
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
for i, each := range notes {
thisPerm := perm;
thisPerm := perm
if selfPerm, ok := notePerms[each.NoteId]; ok {
thisPerm = selfPerm
}
notesWithPerm[i] = info.ShareNoteWithPerm{each, thisPerm}
}
return notesWithPerm
@@ -228,17 +228,17 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
// 得到note的perm信息
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
// shareNotes := []info.ShareNote{}
// db.ListByQ(db.ShareNotes,
// db.ListByQ(db.ShareNotes,
// bson.M{
// "NoteId": bson.M{"$in": noteIds},
// "UserId": bson.ObjectIdHex(sharedUserId),
// "NoteId": bson.M{"$in": noteIds},
// "UserId": bson.ObjectIdHex(sharedUserId),
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
//
//
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
// for _, each := range shareNotes {
// notesPerm[each.NoteId] = each.Perm
// }
//
//
// return notesPerm
//}
@@ -246,26 +246,26 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
// 可以这样! 到时将零散的共享noteId放在用户基本数据中
// 这里不好排序
func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
pageNumber, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
pageNumber, pageSize int, sortField string, isAsc bool) []info.ShareNoteWithPerm {
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
shareNotes := []info.ShareNote{}
q := this.getOrQ(myUserId)
q["UserId"] = bson.ObjectIdHex(sharedUserId);
q["UserId"] = bson.ObjectIdHex(sharedUserId)
db.ShareNotes.
Find(q).
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限
Skip(skipNum).
Limit(pageSize).
All(&shareNotes)
if len(shareNotes) == 0 {
return nil
}
noteIds := make([]bson.ObjectId, len(shareNotes))
for i, each := range shareNotes {
noteIds[i] = each.NoteId
@@ -275,7 +275,7 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
for _, each := range notes {
notesMap[each.NoteId] = each
}
// 将shareNotes与notes结合起来
notesWithPerm := []info.ShareNoteWithPerm{}
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的
@@ -297,8 +297,8 @@ func (this *ShareService) notes2NotesWithPerm(notes []info.Note) {
// [ok]
func (this *ShareService) AddShareNotebook1(shareNotebook info.ShareNotebook) bool {
// 添加一条记录说明两者存在关系
this.AddHasShareNote(shareNotebook.UserId.Hex(), shareNotebook.ToUserId.Hex());
this.AddHasShareNote(shareNotebook.UserId.Hex(), shareNotebook.ToUserId.Hex())
shareNotebook.CreatedTime = time.Now()
return db.Insert(db.ShareNotebooks, shareNotebook)
}
@@ -312,22 +312,22 @@ func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId,
}
return this.AddShareNotebookToUserId(notebookId, perm, userId, toUserId)
}
// 第三方注册时没有email
func (this *ShareService) AddShareNotebookToUserId(notebookId string, perm int, userId, toUserId string) (bool, string, string) {
// 添加一条记录说明两者存在关系
this.AddHasShareNote(userId, toUserId);
this.AddHasShareNote(userId, toUserId)
// 先删除之
db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId),
});
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId),
ToUserId: bson.ObjectIdHex(toUserId),
Perm: perm,
})
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId),
ToUserId: bson.ObjectIdHex(toUserId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotebooks, shareNotebook), "", toUserId
@@ -350,27 +350,26 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
return this.AddShareNoteToUserId(noteId, perm, userId, toUserId)
}
// 第三方测试没有userId
// 第三方测试没有userId
func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId, toUserId string) (bool, string, string) {
// 添加一条记录说明两者存在关系
this.AddHasShareNote(userId, toUserId);
this.AddHasShareNote(userId, toUserId)
// 先删除之
db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId),
});
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
ToUserId: bson.ObjectIdHex(toUserId),
Perm: perm,
})
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
ToUserId: bson.ObjectIdHex(toUserId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotes, shareNote), "", toUserId
}
// updatedUserId是否有查看userId noteId的权限?
// userId是所有者
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
@@ -383,16 +382,16 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool
if notebookId.Hex() == "" {
return false
}
delete(q, "NoteId")
q["NotebookId"] = notebookId
// 判断notebook是否被共享
if !db.Has(db.ShareNotebooks, q) {
return false
} else {
return true
}
} else {
return true
}
} else {
return true
}
@@ -403,20 +402,20 @@ func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bo
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
q["UserId"] = bson.ObjectIdHex(userId)
q["NoteId"] = bson.ObjectIdHex(noteId)
// note的权限
shares := []info.ShareNote{}
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织
for _, share := range shares {
return share.Perm == 1 // 第1个权限最大
}
// notebook的权限
notebookId := noteService.GetNotebookId(noteId)
if notebookId.Hex() == "" {
return false
}
delete(q, "NoteId")
q["NotebookId"] = notebookId
shares2 := []info.ShareNotebook{}
@@ -443,19 +442,20 @@ func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookI
// 共享note, notebook时使用
func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
db.Insert(db.HasShareNotes, info.HasShareNote{UserId: bson.ObjectIdHex(userId), ToUserId: bson.ObjectIdHex(toUserId)})
return true;
return true
}
// userId是否被共享了noteId
func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
}
// noteId的notebook是否共享了给我
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
notebookId := noteService.GetNotebookId(noteId)
if notebookId != "" {
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": notebookId,
"UserId": bson.ObjectIdHex(sharedUserId),
"UserId": bson.ObjectIdHex(sharedUserId),
"ToUserId": bson.ObjectIdHex(myUserId),
})
}
@@ -468,11 +468,12 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
noteContent = info.NoteContent{}
// 是否单独共享了该notebook
// 或者, 其notebook共享了我
// Log(this.HasSharedNote(noteId, myUserId))
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
// Log(this.HasSharedNote(noteId, myUserId))
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
// Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
if this.HasReadPerm(sharedUserId, myUserId, noteId) {
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
db.Get(db.NoteContents, noteId, &noteContent)
} else {
}
@@ -486,16 +487,16 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
// 得到shareNote信息, 得到所有的ToUserId
shareNotes := []info.ShareNote{}
db.ListByQLimit(db.ShareNotes,
db.ListByQLimit(db.ShareNotes,
bson.M{
"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.M{"$exists": false},
}, &shareNotes, 100)
// Log("<<>>>>")
// Log(len(shareNotes))
// Log("<<>>>>")
// Log(len(shareNotes))
if len(shareNotes) == 0 {
return nil
}
@@ -504,45 +505,45 @@ func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.Sh
for _, each := range shareNotes {
shareNotesMap[each.ToUserId] = each
}
toUserIds := make([]bson.ObjectId, len(shareNotes))
for i, eachShareNote := range shareNotes {
toUserIds[i] = eachShareNote.ToUserId
}
note := noteService.GetNote(noteId, userId)
if note.NoteId == "" {
return nil
}
// 查看其notebook的shareNotebooks信息
shareNotebooks := []info.ShareNotebook{}
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": note.NotebookId, "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.M{"$in": toUserIds}},
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": note.NotebookId, "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.M{"$in": toUserIds}},
&shareNotebooks)
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, len(shareNotebooks))
for _, each := range shareNotebooks {
shareNotebooksMap[each.ToUserId] = each
}
// 得到用户信息
userInfos := userService.ListUserInfosByUserIds(toUserIds)
if len(userInfos) == 0 {
return nil
}
shareUserInfos := make([]info.ShareUserInfo, len(userInfos))
for i, userInfo := range userInfos {
_, hasNotebook := shareNotebooksMap[userInfo.UserId]
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
Email: userInfo.Email,
Perm: shareNotesMap[userInfo.UserId].Perm,
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
Email: userInfo.Email,
Perm: shareNotesMap[userInfo.UserId].Perm,
NotebookHasShared: hasNotebook,
}
}
}
return shareUserInfos
}
@@ -551,63 +552,62 @@ func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.Sh
func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) []info.ShareUserInfo {
// notebook的shareNotebooks信息
shareNotebooks := []info.ShareNotebook{}
db.ListByQLimit(db.ShareNotebooks,
db.ListByQLimit(db.ShareNotebooks,
bson.M{
"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.M{"$exists": false},
},
"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.M{"$exists": false},
},
&shareNotebooks, 100)
if len(shareNotebooks) == 0 {
return nil
}
// 得到用户信息
toUserIds := make([]bson.ObjectId, len(shareNotebooks))
for i, each := range shareNotebooks {
toUserIds[i] = each.ToUserId
}
userInfos := userService.ListUserInfosByUserIds(toUserIds)
if len(userInfos) == 0 {
return nil
}
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, len(shareNotebooks))
for _, each := range shareNotebooks {
shareNotebooksMap[each.ToUserId] = each
}
shareUserInfos := make([]info.ShareUserInfo, len(userInfos))
for i, userInfo := range userInfos {
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
Email: userInfo.Email,
Perm: shareNotebooksMap[userInfo.UserId].Perm,
}
Perm: shareNotebooksMap[userInfo.UserId].Perm,
}
}
return shareUserInfos
}
//----------------
// 改变note share权限
func (this *ShareService) UpdateShareNotePerm(noteId string, perm int, userId, toUserId string) bool {
return db.UpdateByQField(db.ShareNotes,
return db.UpdateByQField(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)},
"Perm",
"Perm",
perm,
)
)
}
func (this *ShareService) UpdateShareNotebookPerm(notebookId string, perm int, userId, toUserId string) bool {
return db.UpdateByQField(db.ShareNotebooks,
return db.UpdateByQField(db.ShareNotebooks,
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)},
"Perm",
"Perm",
perm,
)
)
}
//---------------
@@ -622,6 +622,7 @@ func (this *ShareService) DeleteShareNoteAll(noteId string, userId string) bool
return db.DeleteAll(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)})
}
// 删除share notebook
func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserId string) bool {
return db.DeleteAll(db.ShareNotebooks,
@@ -631,20 +632,20 @@ func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserI
// 删除userId分享给toUserId的所有
func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool {
query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)}
db.DeleteAll(db.ShareNotebooks, query);
db.DeleteAll(db.ShareNotes, query);
db.DeleteAll(db.HasShareNotes, query);
db.DeleteAll(db.ShareNotebooks, query)
db.DeleteAll(db.ShareNotes, query)
db.DeleteAll(db.HasShareNotes, query)
return true
}
// 用户userId是否有修改noteId的权限
// 用户userId是否有修改noteId的权限
func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false;
return false
}
note := noteService.GetNoteById(noteId)
LogJ(note);
LogJ(note)
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
@@ -652,20 +653,20 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if this.HasUpdatePerm(noteUserId, userId, noteId) {
return true
} else {
return false;
return false
}
} else {
return true
}
} else {
return false;
return false
}
}
// 用户userId是否有查看noteId的权限
// 用户userId是否有查看noteId的权限
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false;
return false
}
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
@@ -675,13 +676,13 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if this.HasReadPerm(noteUserId, userId, noteId) {
return true
} else {
return false;
return false
}
} else {
return true
}
} else {
return false;
return false
}
}
@@ -691,16 +692,16 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
// 得到笔记分享给的groups
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
groups := groupService.GetGroupsContainOf(userId)
// 得到有分享的分组
shares := []info.ShareNote{}
db.ListByQ(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
db.ListByQ(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
mapShares := map[bson.ObjectId]info.ShareNote{}
for _, share := range shares {
mapShares[share.ToGroupId] = share
mapShares[share.ToGroupId] = share
}
// 所有的groups都有share, 但没有share的group没有shareId
shares2 := make([]info.ShareNote, len(groups))
for i, group := range groups {
@@ -708,26 +709,26 @@ func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.Share
if !ok {
share = info.ShareNote{}
}
share.ToGroup = group;
share.ToGroup = group
shares2[i] = share
}
return shares2
}
// 共享笔记给分组
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
return false
}
// 先删除之
this.DeleteShareNoteGroup(userId, noteId, groupId)
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotes, shareNote)
@@ -736,27 +737,27 @@ func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm
// 删除
func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}
//-------
// 得到笔记本分享给的groups
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
groups := groupService.GetGroupsContainOf(userId)
// 得到有分享的分组
shares := []info.ShareNotebook{}
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
mapShares := map[bson.ObjectId]info.ShareNotebook{}
for _, share := range shares {
mapShares[share.ToGroupId] = share
mapShares[share.ToGroupId] = share
}
LogJ(shares)
// 所有的groups都有share, 但没有share的group没有shareId
shares2 := make([]info.ShareNotebook, len(groups))
for i, group := range groups {
@@ -764,25 +765,26 @@ func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []in
if !ok {
share = info.ShareNotebook{}
}
share.ToGroup = group;
share.ToGroup = group
shares2[i] = share
}
return shares2
}
// 共享笔记给分组
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
return false
}
// 先删除之
this.DeleteShareNotebookGroup(userId, notebookId, groupId)
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotebooks, shareNotebook)
@@ -791,9 +793,9 @@ func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId stri
// 删除
func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}
//--------------------
@@ -803,12 +805,12 @@ func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId s
func (this *ShareService) DeleteAllShareNotebookGroup(groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}
func (this *ShareService) DeleteAllShareNoteGroup(groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}
//--------------------
@@ -817,14 +819,14 @@ func (this *ShareService) DeleteAllShareNoteGroup(groupId string) bool {
func (this *ShareService) DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}
func (this *ShareService) DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{
"UserId": bson.ObjectIdHex(userId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
});
})
}

View File

@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
// "time"
// "sort"
// "time"
// "sort"
)
type SuggestionService struct {
@@ -18,4 +18,4 @@ func (this *SuggestionService) AddSuggestion(suggestion info.Suggestion) bool {
suggestion.Id = bson.NewObjectId()
}
return db.Insert(db.Suggestions, suggestion)
}
}

View File

@@ -1,9 +1,9 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
)
@@ -31,8 +31,8 @@ func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
}
func (this *TagService) AddTags(userId string, tags []string) bool {
for _, tag := range tags {
if !db.Upsert(db.Tags,
bson.M{"_id": bson.ObjectIdHex(userId)},
if !db.Upsert(db.Tags,
bson.M{"_id": bson.ObjectIdHex(userId)},
bson.M{"$addToSet": bson.M{"Tags": tag}}) {
return false
}
@@ -53,18 +53,26 @@ func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
userIdO := bson.ObjectIdHex(userId)
noteTag := info.NoteTag{}
db.GetByQ(db.NoteTags, bson.M{"UserId": userIdO, "Tag": tag}, &noteTag)
// 存在, 则更新之
if noteTag.TagId != "" {
// 统计note数
count := noteService.CountNoteByTag(userId, tag)
noteTag.Count = count
noteTag.UpdatedTime = time.Now()
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
// 之前删除过的, 现在要添加回来了
if noteTag.IsDeleted {
Log("之前删除过的, 现在要添加回来了: " + tag)
noteTag.Usn = userService.IncrUsn(userId)
noteTag.IsDeleted = false
}
db.UpdateByIdAndUserId(db.NoteTags, noteTag.TagId.Hex(), userId, noteTag)
return noteTag
}
// 不存在, 则创建之
noteTag.TagId = bson.NewObjectId()
noteTag.Count = 1
@@ -75,7 +83,7 @@ func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
noteTag.Usn = userService.IncrUsn(userId)
noteTag.IsDeleted = false
db.Insert(db.NoteTags, noteTag)
return noteTag
}
@@ -83,7 +91,7 @@ func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
func (this *TagService) GetTags(userId string) []info.NoteTag {
tags := []info.NoteTag{}
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsDeleted": false}
q := db.NoteTags.Find(query);
q := db.NoteTags.Find(query)
sortFieldR := "-UpdatedTime"
q.Sort(sortFieldR).All(&tags)
return tags
@@ -95,7 +103,7 @@ func (this *TagService) GetTags(userId string) []info.NoteTag {
func (this *TagService) DeleteTag(userId string, tag string) map[string]int {
usn := userService.IncrUsn(userId)
if db.UpdateByQMap(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, bson.M{"Usn": usn, "IsDeleted": true}) {
return noteService.UpdateNoteToDeleteTag(userId, tag);
return noteService.UpdateNoteToDeleteTag(userId, tag)
}
return map[string]int{}
}
@@ -104,7 +112,7 @@ func (this *TagService) DeleteTag(userId string, tag string) map[string]int {
func (this *TagService) DeleteTagApi(userId string, tag string, usn int) (ok bool, msg string, toUsn int) {
noteTag := info.NoteTag{}
db.GetByQ(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, &noteTag)
if noteTag.TagId == "" {
return false, "notExists", 0
}
@@ -124,14 +132,14 @@ func (this *TagService) reCountTagCount(userId string, tags []string) {
return
}
for _, tag := range tags {
this.AddOrUpdateTag(userId, tag);
this.AddOrUpdateTag(userId, tag)
}
}
// 同步用
func (this *TagService) GeSyncTags(userId string, afterUsn, maxEntry int) ([]info.NoteTag) {
func (this *TagService) GeSyncTags(userId string, afterUsn, maxEntry int) []info.NoteTag {
noteTags := []info.NoteTag{}
q := db.NoteTags.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
q := db.NoteTags.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}})
q.Sort("Usn").Limit(maxEntry).All(&noteTags)
return noteTags
}

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