├── .gitignore
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── README.md
├── build.bat
├── conf.json
├── controllers
├── reply
│ └── reply.go
├── sign
│ └── sign.go
├── site
│ └── site.go
├── topic
│ └── topic.go
└── user
│ └── user.go
├── database
└── mysql.go
├── go.mod
├── go.png
├── go.sum
├── main.go
├── mgoModels
├── message.go
├── reply.go
├── topic.go
└── user.go
├── public
├── 19ITP3EmsT.txt
├── github-card.html
├── images
│ ├── cngo.svg
│ ├── cngo2.svg
│ ├── cngo3.svg
│ ├── cngo_icon_32.png
│ ├── cnode_icon_32.png
│ ├── cnode_icon_32.svg
│ ├── cnode_icon_64.png
│ ├── cnode_logo_128.png
│ ├── cnode_logo_32.png
│ ├── cnodejs.svg
│ ├── cnodejs_light.svg
│ ├── digitalocean.png
│ ├── egg-logo.png
│ ├── golangtc-logo.png
│ ├── iojs-logo-w150h50.png
│ ├── iojs-logo.png
│ ├── logo.png
│ ├── logo_bak.png
│ ├── nodejs_black.png
│ ├── phphub-logo.png
│ ├── qiniu.png
│ ├── ruby-china-20150529.png
│ ├── ruby-china-logo2.png
│ ├── search.png
│ ├── ucloud.png
│ └── upyun_logo.png
├── img
│ ├── glyphicons-halflings-white.png
│ └── glyphicons-halflings.png
├── javascripts
│ ├── main.js
│ └── responsive.js
├── libs
│ ├── bootstrap
│ │ ├── css
│ │ │ ├── bootstrap-responsive.css
│ │ │ ├── bootstrap-responsive.min.css
│ │ │ ├── bootstrap.css
│ │ │ └── bootstrap.min.css
│ │ ├── img
│ │ │ ├── glyphicons-halflings-white.png
│ │ │ └── glyphicons-halflings.png
│ │ └── js
│ │ │ ├── bootstrap.js
│ │ │ └── bootstrap.min.js
│ ├── code-prettify
│ │ ├── lang-apollo.js
│ │ ├── lang-clj.js
│ │ ├── lang-css.js
│ │ ├── lang-go.js
│ │ ├── lang-hs.js
│ │ ├── lang-lisp.js
│ │ ├── lang-lua.js
│ │ ├── lang-ml.js
│ │ ├── lang-n.js
│ │ ├── lang-proto.js
│ │ ├── lang-scala.js
│ │ ├── lang-sql.js
│ │ ├── lang-tex.js
│ │ ├── lang-vb.js
│ │ ├── lang-vhdl.js
│ │ ├── lang-wiki.js
│ │ ├── lang-xq.js
│ │ ├── lang-yaml.js
│ │ ├── prettify.css
│ │ └── prettify.js
│ ├── editor
│ │ ├── editor.css
│ │ ├── editor.js
│ │ ├── ext.js
│ │ └── fonts
│ │ │ ├── icomoon.dev.svg
│ │ │ ├── icomoon.eot
│ │ │ ├── icomoon.svg
│ │ │ ├── icomoon.ttf
│ │ │ └── icomoon.woff
│ ├── font-awesome
│ │ ├── css
│ │ │ └── font-awesome.css
│ │ └── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ └── fontawesome-webfont.woff
│ ├── jquery-2.1.0.js
│ ├── jquery-ujs.js
│ ├── jquery.atwho.js
│ ├── jquery.caret.js
│ ├── less.min.js
│ ├── lodash.compat.js
│ ├── markdownit.js
│ ├── qrcode.js
│ └── webuploader
│ │ ├── webuploader.css
│ │ └── webuploader.withoutimage.js
├── stylesheets
│ ├── common.css
│ ├── jquery.atwho.css
│ ├── responsive.css
│ └── style.less
└── upload
│ └── .gitkeep
├── router
└── router.go
├── service
├── cache
│ ├── .DS_Store
│ └── cache.go
└── mail
│ ├── .DS_Store
│ └── mail.go
├── utils
├── dysms.go
└── loadConf.go
└── views
├── about
└── about.html
├── api
└── api.html
├── common
├── _sponsors.html
├── card.html
├── footer.html
├── header.html
├── sidebar.html
└── sidebar2.html
├── edit
└── edit.html
├── getStart
└── getstart.html
├── index
├── abstract.html
├── index.html
├── main.html
└── topic_list.html
├── message
├── message.html
└── message_index.html
├── notify
└── notify.html
├── searchPass
└── search_pass.html
├── setting
└── setting.html
├── showSignUp
└── showsignup.html
├── signIn
└── signin.html
├── signUp
└── signup.html
├── topic
├── edit.html
├── reply.html
└── topicIndex.html
└── user
├── index.html
├── replies.html
├── top100.html
└── topics.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .svn
2 | .DS_Store
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "program": "${fileDirname}",
13 | "env": {},
14 | "args": []
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "go.formatTool": "goimports"
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | 'Software'), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # go_cnode
2 |
3 | #### 项目介绍
4 | http://cnodejs.org/ 是一个用nodejs语言编写的开源论坛
5 | 打算是用golang语言仿写
6 | 项目部署在 http://52.77.218.37:9035/ 账号密码admin
7 | #### 安装
8 | go version 1.12.4
9 | git version 2.19
10 | go版本>1.11
11 | git版本>2.17
12 | 用了go mod 管理依赖
13 | 安装mongodb
14 | 安装redis
15 |
16 | ## 使用
17 |
18 | ### 使用命令行
19 |
20 | ```bash
21 | $ git clone https://github.com/dangyanglim/go_cnode.git
22 | $ cd go_cnode
23 | $ redis-server # 要安装redis
24 | $ mongod --fork --logpath=/data/logs.log # 要安装mongodb
25 | $ go run main.go # 访问 http://localhost:9035
26 | ```
27 | #### 功能介绍
28 | - 邮箱注册/Github第三方注册
29 | - Go 模块管理
30 | - 后台 Gin+mongodb+redis
31 | - 前台 bootstrap+jquery+渲染模板
32 |
33 | 
34 |
35 | ## 目录结构
36 | ```
37 | ├─.vscode
38 | ├─controllers
39 | │ ├─reply
40 | │ ├─sign
41 | │ ├─site
42 | │ └─topic
43 | ├─database
44 | ├─mgoModels
45 | ├─public
46 | │ ├─images
47 | │ ├─img
48 | │ ├─javascripts
49 | │ ├─libs
50 | │ │ ├─bootstrap
51 | │ │ │ ├─css
52 | │ │ │ ├─img
53 | │ │ │ └─js
54 | │ │ ├─code-prettify
55 | │ │ ├─editor
56 | │ │ │ └─fonts
57 | │ │ ├─font-awesome
58 | │ │ │ ├─css
59 | │ │ │ └─fonts
60 | │ │ └─webuploader
61 | │ ├─stylesheets
62 | │ └─upload
63 | ├─router
64 | ├─service
65 | │ ├─cache
66 | │ └─mail
67 | ├─utils
68 | └─views
69 | ├─about
70 | ├─api
71 | ├─common
72 | ├─edit
73 | ├─getStart
74 | ├─index
75 | ├─message
76 | ├─notify
77 | ├─searchPass
78 | ├─setting
79 | ├─showSignUp
80 | ├─signIn
81 | ├─signUp
82 | └─topic
83 |
84 | ```
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | SET CGO_ENABLED=0
2 | SET GOOS=linux
3 | SET GOARCH=amd64
4 | go build -o go_cnode main.go
--------------------------------------------------------------------------------
/conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "mongo_url": "fenghuangyu.cn:27017",
3 | "redis_url": "127.0.0.1:6379",
4 | "port": ":9035",
5 | "smtp_username":"dangyanglim@qq.com",
6 | "smtp_password":"uicmeimalcnybgdj",
7 | "smtp_hostname":"smtp.qq.com",
8 | "smtp_active_Url":"http://fenghuangyu.cn:9035/active_account",
9 | "github_client_id":"bafc506847f325223094",
10 | "github_client_secret":"172d5424cc25be8c8ac8095b40d79fea859588ea",
11 | "github_AuthURL":"https://github.com/login/oauth/authorize?",
12 | "github_UserURL":"https://api.github.com/user?",
13 | "github_TokenURL":"https://github.com/login/oauth/access_token?"
14 | }
--------------------------------------------------------------------------------
/controllers/reply/reply.go:
--------------------------------------------------------------------------------
1 | package reply
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | //"regexp"
7 |
8 | "go_cnode/mgoModels"
9 | //"github.com/dangyanglim/go_cnode/service/mail"
10 | "encoding/json"
11 | "github.com/gin-gonic/gin"
12 | "github.com/tommy351/gin-sessions"
13 | "go_cnode/service/cache"
14 | "regexp"
15 | )
16 |
17 | var userModel = new(models.UserModel)
18 | var topicModel = new(models.TopicModel)
19 | var replyModel = new(models.ReplyModel)
20 | var messageModel = new(models.MessageModel)
21 |
22 | func ShowCreate(c *gin.Context) {
23 | session := sessions.Get(c)
24 | var name string
25 | user := models.User{}
26 | //var err error
27 |
28 | if nil != session.Get("loginname") {
29 | name = session.Get("loginname").(string)
30 | user, _ = userModel.GetUserByName(name)
31 | }
32 | tabs := [3]map[string]string{{"value": "share", "text": "分享"}, {"value": "ask", "text": "问答"}, {"value": "job", "text": "招聘"}}
33 | c.HTML(http.StatusOK, "edit", gin.H{
34 | "user": user,
35 | "tabs": tabs,
36 | "config": gin.H{
37 | "description": "CNode:Node.js专业中文社区",
38 | },
39 | })
40 | }
41 |
42 | func Index(c *gin.Context) {
43 | session := sessions.Get(c)
44 | var name string
45 | var no_reply_topics []models.Topic
46 | type Temp struct {
47 | Topic models.Topic
48 | Author models.User
49 | Replies []models.Reply
50 | RepliyWithAuthors []models.ReplyAndAuthor
51 | }
52 | var temp Temp
53 | user := models.User{}
54 | if nil != session.Get("loginname") {
55 | name = session.Get("loginname").(string)
56 | user, _ = userModel.GetUserByName(name)
57 | }
58 | id := c.Param("id")
59 | topic, author, replies, repliyWithAuthors, _ := topicModel.GetTopicByIdWithReply(id)
60 | temp.Author = author
61 | temp.Topic = topic
62 | temp.Replies = replies
63 | NoOfRepliy := len(replies)
64 | temp.RepliyWithAuthors = repliyWithAuthors
65 | no_reply_topics2, err2 := cache.Get("no_reply_topics")
66 | json.Unmarshal(no_reply_topics2.([]byte), &no_reply_topics)
67 | log.Println("temp")
68 | log.Println(err2)
69 | //log.Println(temp)
70 | if err2 != nil {
71 | no_reply_topics, _ = topicModel.GetTopicNoReply()
72 | no_reply_topics_json, _ := json.Marshal(no_reply_topics)
73 | cache.SetEx("no_reply_topics", no_reply_topics_json)
74 | }
75 | other_topics, _ := topicModel.GetAuthorOtherTopics(author.Id.Hex(), id)
76 | c.HTML(http.StatusOK, "topicIndex", gin.H{
77 | "title": "布局页面",
78 | "user": user,
79 | "topic": temp,
80 | "NoOfRepliy": NoOfRepliy,
81 | "no_reply_topics": no_reply_topics,
82 | "author_other_topics": other_topics,
83 | "config": gin.H{
84 | "description": "CNode:Node.js专业中文社区",
85 | },
86 | })
87 | }
88 | func Create(c *gin.Context) {
89 | session := sessions.Get(c)
90 | var name string
91 | user := models.User{}
92 | if nil != session.Get("loginname") {
93 | name = session.Get("loginname").(string)
94 | user, _ = userModel.GetUserByName(name)
95 | }
96 | id := user.Id.Hex()
97 | log.Println(id)
98 | tab := c.Request.FormValue("tab")
99 | title := c.Request.FormValue("title")
100 | content := c.Request.FormValue("content")
101 | topic, _ := topicModel.NewAndSave(title, tab, id, content)
102 | url := "/topic/" + topic.Id.Hex()
103 | c.Redirect(301, url)
104 | }
105 | func Add(c *gin.Context) {
106 | topic_id := c.Param("topic_id")
107 | r_content := c.Request.FormValue("r_content")
108 | user_id := c.Request.FormValue("user_id")
109 | if user_id==""{
110 | c.HTML(http.StatusOK, "notify", gin.H{
111 | "error": "您还没登录呢",
112 | })
113 | return
114 | }
115 |
116 | topic,_:=topicModel.GetTopicById(topic_id)
117 | reply, _ := replyModel.NewAndSave(r_content, topic_id, user_id, "")
118 | topicModel.UpdateReplyCount(topic_id, reply.Id)
119 | log.Println(r_content)
120 | r, _ := regexp.Compile("@([a-z0-9]+)")
121 | usersArray:=r.FindAllString(r_content, -1)
122 | log.Println(len(usersArray))
123 | var users map[string]int
124 | users=make(map[string]int)
125 | if len(usersArray)>0 {
126 | for _,user:=range usersArray{
127 | user=user[1 : len(user)]
128 | users[user]=1
129 | }
130 | for userName:=range users{
131 | log.Println(userName)
132 | user,_:=userModel.GetUserByName(userName)
133 | log.Println(user)
134 | if user_id!=user.Id.Hex() {
135 | messageModel.SendAtMessage(user.Id.Hex(),user_id,topic_id,reply.Id)
136 | }
137 | }
138 | }
139 | log.Println(users)
140 | if topic.Author_id.Hex()!=user_id {
141 | messageModel.SendReplyMessage(topic.Author_id.Hex(),user_id,topic_id,reply.Id)
142 | }
143 | url := "/topic/" + topic_id
144 | c.Redirect(301, url)
145 | }
146 | func Edit(c *gin.Context) {
147 |
148 | reply_id := c.Param("reply_id")
149 | t_content := c.Request.FormValue("t_content")
150 | user_id := c.Request.FormValue("user_id")
151 | reply, _ := replyModel.GetReplyById(reply_id)
152 |
153 | if reply.Author_id.Hex() != user_id {
154 | c.HTML(http.StatusOK, "notify", gin.H{
155 | "error": "你不能编辑此回复",
156 | })
157 | return
158 | }
159 |
160 | replyModel.Update(t_content, reply_id)
161 |
162 | url := "/topic/" + reply.Topic_id.Hex() + "#" + reply.Id.Hex()
163 | c.Redirect(301, url)
164 | }
165 | func Delete(c *gin.Context) {
166 | log.Print("delete3")
167 | reply_id := c.Param("reply_id")
168 | session := sessions.Get(c)
169 | var name string
170 | user := models.User{}
171 | if nil != session.Get("loginname") {
172 | name = session.Get("loginname").(string)
173 | user, _ = userModel.GetUserByName(name)
174 | }
175 | reply, _ := replyModel.GetReplyById(reply_id)
176 |
177 | var msg struct {
178 | Status string `json:"status"`
179 | }
180 | if reply.Author_id.Hex() != user.Id.Hex() {
181 |
182 | msg.Status = "failed"
183 | c.JSON(http.StatusOK, msg)
184 | return
185 | }
186 |
187 | replyModel.Delete(reply_id)
188 |
189 | msg.Status = "success"
190 | c.JSON(http.StatusOK, msg)
191 | }
192 | func ShowEdit(c *gin.Context) {
193 | reply_id := c.Param("reply_id")
194 | user_id := c.Request.FormValue("user_id")
195 | reply, err := replyModel.GetReplyById(reply_id)
196 |
197 | if err != nil {
198 | c.HTML(http.StatusOK, "notify", gin.H{
199 | "error": "评论不存在",
200 | })
201 | return
202 | }
203 | c.HTML(http.StatusOK, "reply/edit", gin.H{
204 | "reply_id": reply.Id.Hex(),
205 | "content": reply.Content,
206 | "user_id": user_id,
207 | })
208 | }
209 |
--------------------------------------------------------------------------------
/controllers/topic/topic.go:
--------------------------------------------------------------------------------
1 | package topic
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | //"regexp"
7 | //"fmt"
8 | //"os"
9 | //"io"
10 | "go_cnode/mgoModels"
11 | //"github.com/dangyanglim/go_cnode/service/mail"
12 | "encoding/json"
13 | "github.com/gin-gonic/gin"
14 | "github.com/russross/blackfriday"
15 | "github.com/tommy351/gin-sessions"
16 | "go_cnode/service/cache"
17 | "html/template" /* */
18 | "strings"
19 | )
20 |
21 | var userModel = new(models.UserModel)
22 | var topicModel = new(models.TopicModel)
23 |
24 | func ShowCreate(c *gin.Context) {
25 | session := sessions.Get(c)
26 | var name string
27 | user := models.User{}
28 | //var err error
29 |
30 | if nil != session.Get("loginname") {
31 | name = session.Get("loginname").(string)
32 | user, _ = userModel.GetUserByName(name)
33 | }
34 | tabs := [3]map[string]string{{"value": "share", "text": "分享"}, {"value": "ask", "text": "问答"}, {"value": "job", "text": "招聘"}}
35 | c.HTML(http.StatusOK, "edit", gin.H{
36 | "user": user,
37 | "tabs": tabs,
38 | "tab": "share",
39 | "config": gin.H{
40 | "description": "CNode:Node.js专业中文社区",
41 | },
42 | })
43 | }
44 |
45 | func Index(c *gin.Context) {
46 | session := sessions.Get(c)
47 | var name string
48 | var no_reply_topics []models.Topic
49 | type Temp struct {
50 | Topic models.Topic
51 | LinkContent template.HTML
52 | Author models.User
53 | Replies []models.Reply
54 | RepliyWithAuthors []models.ReplyAndAuthor
55 | }
56 | var temp Temp
57 | user := models.User{}
58 | if nil != session.Get("loginname") {
59 | name = session.Get("loginname").(string)
60 | user, _ = userModel.GetUserByName(name)
61 | }
62 | id := c.Param("id")
63 | topic, author, replies, repliyWithAuthors, _ := topicModel.GetTopicByIdWithReply(id)
64 | temp.Author = author
65 | topic.Content = strings.Replace(topic.Content, "\r\n", "
", -1)
66 | //temp.LinkContent=topic.Content
67 | temp.LinkContent = template.HTML(blackfriday.Run([]byte(topic.Content)))
68 | temp.Topic = topic
69 | temp.Replies = replies
70 | NoOfRepliy := len(replies)
71 | temp.RepliyWithAuthors = repliyWithAuthors
72 | no_reply_topics2, err2 := cache.Get("no_reply_topics")
73 | json.Unmarshal(no_reply_topics2.([]byte), &no_reply_topics)
74 |
75 | if err2 != nil {
76 | no_reply_topics, _ = topicModel.GetTopicNoReply()
77 | no_reply_topics_json, _ := json.Marshal(no_reply_topics)
78 | cache.SetEx("no_reply_topics", no_reply_topics_json)
79 | }
80 | topicModel.UpdateVisitCount(id)
81 | other_topics, _ := topicModel.GetAuthorOtherTopics(author.Id.Hex(), id)
82 | c.HTML(http.StatusOK, "topicIndex", gin.H{
83 | "title": "布局页面",
84 | "user": user,
85 | "topic": temp,
86 | "NoOfRepliy": NoOfRepliy,
87 | "no_reply_topics": no_reply_topics,
88 | "author_other_topics": other_topics,
89 | "config": gin.H{
90 | "description": "CNode:Node.js专业中文社区",
91 | },
92 | })
93 | }
94 | func Top(c *gin.Context) {
95 | session := sessions.Get(c)
96 | var name string
97 | user := models.User{}
98 | if nil != session.Get("loginname") {
99 | name = session.Get("loginname").(string)
100 | user, _ = userModel.GetUserByName(name)
101 | }
102 | if user.Name != "admin" {
103 | c.HTML(http.StatusOK, "notify", gin.H{
104 | "error": "没权限",
105 | })
106 | return
107 | }
108 | id := c.Param("id")
109 | topic, err := topicModel.GetTopicById(id)
110 | if err != nil {
111 | c.HTML(http.StatusOK, "notify", gin.H{
112 | "error": "话题不存在",
113 | })
114 | return
115 | }
116 | topicModel.SetTop(id, !topic.Top)
117 | msg := ""
118 | if topic.Top {
119 | msg = "此话题取消置顶成功。"
120 | } else {
121 | msg = "此话题置顶成功。"
122 | }
123 |
124 | c.HTML(http.StatusOK, "notify", gin.H{
125 | "success": msg,
126 | })
127 | }
128 | func Detele(c *gin.Context) {
129 | session := sessions.Get(c)
130 | var name string
131 | user := models.User{}
132 | if nil != session.Get("loginname") {
133 | name = session.Get("loginname").(string)
134 | user, _ = userModel.GetUserByName(name)
135 | }
136 | var msg struct {
137 | Message string `json:"message"`
138 | Success bool `json:"success"`
139 | }
140 | id := c.Param("id")
141 | topic, err := topicModel.GetTopicById(id)
142 |
143 | if err != nil {
144 | msg.Message = "此话题不存在"
145 | msg.Success = false
146 | c.JSON(http.StatusOK, msg)
147 | return
148 | }
149 | if topic.Author_id.Hex() != user.Id.Hex() {
150 | msg.Message = "无权限"
151 | msg.Success = false
152 | c.JSON(http.StatusForbidden, msg)
153 | return
154 | }
155 |
156 | topicModel.Delete(id)
157 | msg.Message = "话题删除成功"
158 | msg.Success = true
159 | c.JSON(http.StatusOK, msg)
160 | }
161 | func ShowEdit(c *gin.Context) {
162 | session := sessions.Get(c)
163 | var name string
164 | user := models.User{}
165 | if nil != session.Get("loginname") {
166 | name = session.Get("loginname").(string)
167 | user, _ = userModel.GetUserByName(name)
168 | }
169 | var msg struct {
170 | Message string `json:"message"`
171 | Success bool `json:"success"`
172 | }
173 | id := c.Param("id")
174 | topic, err := topicModel.GetTopicById(id)
175 |
176 | if err != nil {
177 | msg.Message = "此话题不存在"
178 | msg.Success = false
179 | c.JSON(http.StatusNotFound, msg)
180 | return
181 | }
182 | if topic.Author_id.Hex() != user.Id.Hex() {
183 | msg.Message = "对不起,你不能编辑此话题"
184 | msg.Success = false
185 | c.JSON(http.StatusForbidden, msg)
186 | return
187 | }
188 | tabs := [3]map[string]string{{"value": "share", "text": "分享"}, {"value": "ask", "text": "问答"}, {"value": "job", "text": "招聘"}}
189 | c.HTML(http.StatusOK, "edit", gin.H{
190 | "user": user,
191 | "action": "edit",
192 | "topic_id": topic.Id.Hex(),
193 | "title": topic.Title,
194 | "content": topic.Content,
195 | "tab": topic.Tab,
196 | "tabs": tabs,
197 | "config": gin.H{
198 | "description": "CNode:Node.js专业中文社区",
199 | },
200 | })
201 |
202 | }
203 | func Update(c *gin.Context) {
204 | session := sessions.Get(c)
205 | var name string
206 | user := models.User{}
207 | if nil != session.Get("loginname") {
208 | name = session.Get("loginname").(string)
209 | user, _ = userModel.GetUserByName(name)
210 | }
211 | var msg struct {
212 | Message string `json:"message"`
213 | Success bool `json:"success"`
214 | }
215 | id := c.Param("id")
216 | topic, err := topicModel.GetTopicById(id)
217 |
218 | if err != nil {
219 | msg.Message = "此话题不存在"
220 | msg.Success = false
221 | c.JSON(http.StatusNotFound, msg)
222 | return
223 | }
224 | if topic.Author_id.Hex() != user.Id.Hex() {
225 | msg.Message = "对不起,你不能编辑此话题"
226 | msg.Success = false
227 | c.JSON(http.StatusForbidden, msg)
228 | return
229 | }
230 | tabs := [3]map[string]string{{"value": "share", "text": "分享"}, {"value": "ask", "text": "问答"}, {"value": "job", "text": "招聘"}}
231 | tab := c.Request.FormValue("tab")
232 | title := c.Request.FormValue("title")
233 | content := c.Request.FormValue("content")
234 | // 验证
235 | editError := ""
236 | if title == "" {
237 | editError = "标题不能是空的。"
238 | }
239 | if len(title) < 5 || len(title) > 100 {
240 | editError = "标题字数太多或太少。"
241 | }
242 | if tab == "" {
243 | editError = "必须选择一个版块"
244 | }
245 | if content == "" {
246 | editError = "内容不可为空。"
247 | }
248 | if editError != "" {
249 | c.HTML(http.StatusOK, "edit", gin.H{
250 | "user": user,
251 | "editError": editError,
252 | "action": "edit",
253 | "topic_id": topic.Id.Hex(),
254 | "title": topic.Title,
255 | "content": topic.Content,
256 | "tab": topic.Tab,
257 | "tabs": tabs,
258 | "config": gin.H{
259 | "description": "CNode:Node.js专业中文社区",
260 | },
261 | })
262 | return
263 | }
264 | topic.Title=title
265 | topic.Tab=tab
266 | topic.Content=content
267 | topicModel.Update(topic)
268 | url := "/topic/" + topic.Id.Hex()
269 | c.Redirect(301, url)
270 |
271 | }
272 | func Create(c *gin.Context) {
273 | session := sessions.Get(c)
274 | var name string
275 | user := models.User{}
276 | if nil != session.Get("loginname") {
277 | name = session.Get("loginname").(string)
278 | user, _ = userModel.GetUserByName(name)
279 | }
280 | id := user.Id.Hex()
281 |
282 | tab := c.Request.FormValue("tab")
283 | title := c.Request.FormValue("title")
284 | content := c.Request.FormValue("content")
285 | topic, _ := topicModel.NewAndSave(title, tab, id, content)
286 | url := "/topic/" + topic.Id.Hex()
287 | c.Redirect(301, url)
288 | }
289 |
290 | const (
291 | upload_path string = "./public/upload/"
292 | upload_path2 string = "/public/upload/"
293 | )
294 |
295 | func Upload(c *gin.Context) {
296 | session := sessions.Get(c)
297 | var name string
298 | user := models.User{}
299 | if nil != session.Get("loginname") {
300 | name = session.Get("loginname").(string)
301 | user, _ = userModel.GetUserByName(name)
302 | }
303 |
304 | id := user.Id.Hex()
305 | log.Println(id)
306 | //picName := c.Request.FormValue("name")
307 | file, _ := c.FormFile("file")
308 |
309 | //创建文件
310 | // fW, err := os.Create(upload_path + file.Filename)
311 | // if err != nil {
312 | // fmt.Println("文件创建失败")
313 | // return
314 | // }
315 | // defer fW.Close()
316 | // _, err = io.Copy(fW, file)
317 | // if err != nil {
318 | // fmt.Println("文件保存失败")
319 | // return
320 | // }
321 | c.SaveUploadedFile(file, upload_path+file.Filename)
322 | var msg struct {
323 | Success bool `json:"success"`
324 | Url string `json:"url"`
325 | }
326 | msg.Success = true
327 | msg.Url = upload_path2 + file.Filename
328 | c.JSON(http.StatusOK, msg)
329 |
330 | }
331 |
--------------------------------------------------------------------------------
/controllers/user/user.go:
--------------------------------------------------------------------------------
1 | package user
2 |
3 | import (
4 |
5 | "net/http"
6 | //"regexp"
7 | "log"
8 | "go_cnode/mgoModels"
9 | //"github.com/dangyanglim/go_cnode/service/mail"
10 | "encoding/json"
11 | "github.com/gin-gonic/gin"
12 | "github.com/tommy351/gin-sessions"
13 | "time"
14 | "strconv"
15 | "math"
16 |
17 | )
18 |
19 | var userModel = new(models.UserModel)
20 | var topicModel = new(models.TopicModel)
21 | var replyModel = new(models.ReplyModel)
22 |
23 |
24 | func Index(c *gin.Context) {
25 | session := sessions.Get(c)
26 | var loginname string
27 |
28 | user := models.User{}
29 | if nil != session.Get("loginname") {
30 | loginname = session.Get("loginname").(string)
31 | user, _ = userModel.GetUserByName(loginname)
32 | }
33 | name := c.Param("name")
34 | user, _ = userModel.GetUserByName(name)
35 | _,topics, _ := topicModel.GetAuthorTopics(user.Id.Hex(),5,0)
36 | var recent_topics []map[string]interface{}
37 | json.Unmarshal([]byte(topics), &recent_topics)
38 |
39 | for _, v := range recent_topics {
40 | timeString := v["topic"].(map[string]interface{})["Create_at"].(string)
41 | t, _ := time.Parse("2006-01-02T15:04:05-07:00", timeString)
42 | v["topic"].(map[string]interface{})["Create_at"] = t.Format("2006-01-02 15:04:05")
43 | timeString = v["topic"].(map[string]interface{})["last_reply_at"].(string)
44 | t, _ = time.Parse("2006-01-02T15:04:05-07:00", timeString)
45 | v["topic"].(map[string]interface{})["last_reply_at"] = t.Format("2006-01-02 15:04:05")
46 | if v["reply"].(map[string]interface{})["Author_id"].(string) != "" {
47 | author, _ := userModel.GetUserById(v["reply"].(map[string]interface{})["Author_id"].(string))
48 | j, _ := json.Marshal(author)
49 | m := make(map[string]interface{})
50 | json.Unmarshal(j, &m)
51 | v["reply"].(map[string]interface{})["author"] = m
52 | }
53 | }
54 | topics2, _ := topicModel.GetReplyTopics(user.Id.Hex(),20,0,5)
55 | var recent_replies []map[string]interface{}
56 | json.Unmarshal([]byte(topics2), &recent_replies)
57 | for _, v := range recent_replies {
58 | timeString := v["topic"].(map[string]interface{})["Create_at"].(string)
59 | t, _ := time.Parse("2006-01-02T15:04:05-07:00", timeString)
60 | v["topic"].(map[string]interface{})["Create_at"] = t.Format("2006-01-02 15:04:05")
61 | timeString = v["topic"].(map[string]interface{})["last_reply_at"].(string)
62 | t, _ = time.Parse("2006-01-02T15:04:05-07:00", timeString)
63 | v["topic"].(map[string]interface{})["last_reply_at"] = t.Format("2006-01-02 15:04:05")
64 | if v["reply"].(map[string]interface{})["Author_id"].(string) != "" {
65 | author, _ := userModel.GetUserById(v["reply"].(map[string]interface{})["Author_id"].(string))
66 | j, _ := json.Marshal(author)
67 | m := make(map[string]interface{})
68 | json.Unmarshal(j, &m)
69 | v["reply"].(map[string]interface{})["author"] = m
70 | }
71 | }
72 | c.HTML(http.StatusOK, "userIndex", gin.H{
73 | "recent_topics":recent_topics,
74 | "recent_replies":recent_replies,
75 | "user": user,
76 | })
77 | }
78 | func Topics(c *gin.Context) {
79 | session := sessions.Get(c)
80 | var loginname string
81 | var pageSize = 20
82 |
83 | page := c.Request.FormValue("page")
84 | if page == "" {
85 | page = "1"
86 | }
87 | current_page, _ := strconv.Atoi(page)
88 | user := models.User{}
89 | if nil != session.Get("loginname") {
90 | loginname = session.Get("loginname").(string)
91 | user, _ = userModel.GetUserByName(loginname)
92 | }
93 | name := c.Param("name")
94 | user, _ = userModel.GetUserByName(name)
95 | _,topics, _ := topicModel.GetAuthorTopics(user.Id.Hex(),pageSize,(current_page-1)*pageSize)
96 | var recent_topics []map[string]interface{}
97 | json.Unmarshal([]byte(topics), &recent_topics)
98 |
99 | for _, v := range recent_topics {
100 | timeString := v["topic"].(map[string]interface{})["Create_at"].(string)
101 | t, _ := time.Parse("2006-01-02T15:04:05-07:00", timeString)
102 | v["topic"].(map[string]interface{})["Create_at"] = t.Format("2006-01-02 15:04:05")
103 | timeString = v["topic"].(map[string]interface{})["last_reply_at"].(string)
104 | t, _ = time.Parse("2006-01-02T15:04:05-07:00", timeString)
105 | v["topic"].(map[string]interface{})["last_reply_at"] = t.Format("2006-01-02 15:04:05")
106 | if v["reply"].(map[string]interface{})["Author_id"].(string) != "" {
107 | author, _ := userModel.GetUserById(v["reply"].(map[string]interface{})["Author_id"].(string))
108 | j, _ := json.Marshal(author)
109 | m := make(map[string]interface{})
110 | json.Unmarshal(j, &m)
111 | v["reply"].(map[string]interface{})["author"] = m
112 | }
113 | }
114 | var page_start int
115 | pages, _:= topicModel.GetTopicByAuthorQueryCount(user.Id,"all", false)
116 | pages = int(math.Floor(float64(pages)/float64(pageSize))) + 1
117 | base_url := "?page="
118 | var page_end int
119 |
120 | log.Println(current_page)
121 | if (current_page - 2) > 0 {
122 | page_start = current_page - 2
123 | } else {
124 | page_start = 1
125 | }
126 | if (page_start + 4) > pages {
127 | page_end = pages
128 | } else {
129 | page_end = page_start + 4
130 | }
131 | pagesArray := []int{}
132 | var i int
133 | for i = 1; i < pages+1; i++ {
134 | pagesArray = append(pagesArray, i)
135 | }
136 | //log.Println(recent_topics)
137 | c.HTML(http.StatusOK, "userTopics", gin.H{
138 | "user": user,
139 | "topicss":recent_topics,
140 | "pages": pages,
141 | "page_start": page_start,
142 | "page_end": page_end,
143 | "pagesArray": pagesArray,
144 | "base_url": base_url,
145 | "current_page": current_page,
146 | })
147 |
148 | }
149 | func Replies(c *gin.Context) {
150 | session := sessions.Get(c)
151 | var loginname string
152 | var pageSize = 20
153 |
154 | page := c.Request.FormValue("page")
155 | if page == "" {
156 | page = "1"
157 | }
158 | current_page, _ := strconv.Atoi(page)
159 | user := models.User{}
160 | if nil != session.Get("loginname") {
161 | loginname = session.Get("loginname").(string)
162 | user, _ = userModel.GetUserByName(loginname)
163 | }
164 | name := c.Param("name")
165 | user, _ = userModel.GetUserByName(name)
166 | topics2, _ := topicModel.GetReplyTopics(user.Id.Hex(),pageSize,(current_page-1)*pageSize,pageSize)
167 | var recent_replies []map[string]interface{}
168 | json.Unmarshal([]byte(topics2), &recent_replies)
169 | for _, v := range recent_replies {
170 | timeString := v["topic"].(map[string]interface{})["Create_at"].(string)
171 | t, _ := time.Parse("2006-01-02T15:04:05-07:00", timeString)
172 | v["topic"].(map[string]interface{})["Create_at"] = t.Format("2006-01-02 15:04:05")
173 | timeString = v["topic"].(map[string]interface{})["last_reply_at"].(string)
174 | t, _ = time.Parse("2006-01-02T15:04:05-07:00", timeString)
175 | v["topic"].(map[string]interface{})["last_reply_at"] = t.Format("2006-01-02 15:04:05")
176 | if v["reply"].(map[string]interface{})["Author_id"].(string) != "" {
177 | author, _ := userModel.GetUserById(v["reply"].(map[string]interface{})["Author_id"].(string))
178 | j, _ := json.Marshal(author)
179 | m := make(map[string]interface{})
180 | json.Unmarshal(j, &m)
181 | v["reply"].(map[string]interface{})["author"] = m
182 | }
183 | }
184 |
185 | var page_start int
186 | pages, _:= replyModel.GetReplyByAuthorQueryCount(user.Id)
187 | pages = int(math.Floor(float64(pages)/float64(pageSize))) + 1
188 | base_url := "?page="
189 | var page_end int
190 |
191 | log.Println(current_page)
192 | if (current_page - 2) > 0 {
193 | page_start = current_page - 2
194 | } else {
195 | page_start = 1
196 | }
197 | if (page_start + 4) > pages {
198 | page_end = pages
199 | } else {
200 | page_end = page_start + 4
201 | }
202 | pagesArray := []int{}
203 | var i int
204 | for i = 1; i < pages+1; i++ {
205 | pagesArray = append(pagesArray, i)
206 | }
207 | //log.Println(recent_topics)
208 | c.HTML(http.StatusOK, "userReplies", gin.H{
209 | "user": user,
210 | "topicss":recent_replies,
211 | "pages": pages,
212 | "page_start": page_start,
213 | "page_end": page_end,
214 | "pagesArray": pagesArray,
215 | "base_url": base_url,
216 | "current_page": current_page,
217 | })
218 |
219 | }
220 | func Top100(c *gin.Context) {
221 | session := sessions.Get(c)
222 | var loginname string
223 |
224 | user := models.User{}
225 | if nil != session.Get("loginname") {
226 | loginname = session.Get("loginname").(string)
227 | user, _ = userModel.GetUserByName(loginname)
228 | }
229 | tops, _ := userModel.GetUserTops(100)
230 | c.HTML(http.StatusOK, "userTop100", gin.H{
231 | "user": user,
232 | "users":tops,
233 | })
234 | }
235 |
--------------------------------------------------------------------------------
/database/mysql.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | //"database/sql"
5 | "fmt"
6 | "log"
7 | "github.com/garyburd/redigo/redis"
8 | //_ "github.com/go-sql-driver/mysql"
9 | "gopkg.in/mgo.v2"
10 | //"log"
11 | )
12 |
13 | type MongoLog struct {
14 | }
15 |
16 | func (MongoLog)Output(calldepth int, s string) error {
17 | log.SetFlags(log.Lshortfile)
18 | return log.Output(calldepth,s)
19 | }
20 |
21 | //var SqlDB *sql.DB
22 | var MogSession *mgo.Session
23 | var Redis redis.Conn
24 | var Mgodb *mgo.Database
25 | func init() {
26 | }
27 | //var mgodb *mgo.Database
28 | func Config(mogo_url string,redis_url string) {
29 | var err error
30 | var mgoerr error
31 | // SqlDB, err = sql.Open("mysql", "root@tcp(127.0.0.1:3306)/test?parseTime=true")
32 | // if err != nil {
33 | // log.Fatal(err.Error())
34 | // }
35 | // err = SqlDB.Ping()
36 | // if err != nil {
37 | // log.Fatal(err.Error())
38 | // }
39 | MogSession, mgoerr = mgo.Dial(mogo_url)
40 | if mgoerr != nil {
41 | panic(mgoerr)
42 | }
43 | MogSession.SetMode(mgo.Monotonic, true)
44 | Mgodb=MogSession.DB("egg_cnode")
45 | Redis, err = redis.Dial("tcp", redis_url)
46 | if err != nil {
47 | fmt.Println("Connect to redis error", err)
48 | return
49 | }
50 |
51 |
52 | // defer mogSession.Close()
53 | // session.SetMode(mgo.Monotonic, true)
54 | // mgodb = session.DB("egg_cnode")
55 | // countNum, _ :=mgodb.C("users").Count()
56 | // log.Println(countNum)
57 | mgo.SetDebug(false) // 设置DEBUG模式
58 | //mgo.SetLogger(new(MongoLog)) // 设置日志.
59 | }
60 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module go_cnode
2 |
3 | go 1.12
4 |
5 | replace golang.org/x/net => github.com/golang/net v0.0.0-20190424024845-afe8014c977f
6 |
7 | replace golang.org/x/sync => github.com/golang/sync v0.0.0-20190423024810-112230192c58
8 |
9 | replace golang.org/x/sys => github.com/golang/sys v0.0.0-20190422165155-953cdadca894
10 |
11 | replace golang.org/x/crypto => github.com/golang/crypto v0.0.0-20190422183909-d864b10871cd
12 |
13 | replace golang.org/x/text => github.com/golang/text v0.3.0
14 |
15 | replace google.golang.org/appengine => github.com/golang/appengine v1.5.0
16 |
17 | require (
18 | github.com/garyburd/redigo v1.6.0
19 | github.com/gin-contrib/cors v0.0.0-20190424000812-bd1331c62cae
20 | github.com/gin-gonic/gin v1.3.0
21 | github.com/go-sql-driver/mysql v1.4.1
22 | github.com/gorilla/sessions v1.1.3 // indirect
23 | github.com/russross/blackfriday v2.0.0+incompatible
24 | github.com/satori/go.uuid v1.2.0
25 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
26 | github.com/tommy351/gin-sessions v0.0.0-20150617141853-353060947eb6
27 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
28 | google.golang.org/appengine v1.5.0 // indirect
29 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce
30 | )
31 |
--------------------------------------------------------------------------------
/go.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dangyanglim/go_cnode/9e4d845b743654c54e7abe7bdfaf37b97ed8381f/go.png
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
4 | github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
5 | github.com/gin-contrib/cors v0.0.0-20190424000812-bd1331c62cae h1:sGWKl+Nw64hNtVFaYWM4Gk8LMpK3OQScMlyzFFfbHBk=
6 | github.com/gin-contrib/cors v0.0.0-20190424000812-bd1331c62cae/go.mod h1:pL2kNE+DgDU+eQ+dary5bX0Z6LPP8nR6Mqs1iejILw4=
7 | github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
8 | github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
9 | github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
10 | github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
11 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
12 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
13 | github.com/golang/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
14 | github.com/golang/crypto v0.0.0-20190422183909-d864b10871cd h1:mhLrErKLIynY9Fs2Z/kFJwUzpEZFHltw72hQN1Em5+E=
15 | github.com/golang/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
16 | github.com/golang/net v0.0.0-20190424024845-afe8014c977f h1:8zPcFd05aawb15tchyXnHb0DFfCSMDpq8DPzfBOYt1g=
17 | github.com/golang/net v0.0.0-20190424024845-afe8014c977f/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
18 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
19 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
20 | github.com/golang/sync v0.0.0-20190423024810-112230192c58 h1:FVziwFqxtCKvWuys1e98ng/JsDBTeuqRNI/P2yxNfzI=
21 | github.com/golang/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
22 | github.com/golang/sys v0.0.0-20190422165155-953cdadca894 h1:C9ZDFLCRWOewEpp/wj0dsonEXGfatyyu3Z6rhdD3W5A=
23 | github.com/golang/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
24 | github.com/golang/text v0.3.0/go.mod h1:GUiq9pdJKRKKAZXiVgWFEvocYuREvC14NhI4OPgEjeE=
25 | github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
26 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
27 | github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
28 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
29 | github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
30 | github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
31 | github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
32 | github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
33 | github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
34 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
35 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
36 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
37 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
38 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
39 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
40 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
41 | github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
42 | github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
43 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
44 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
45 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
46 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
47 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
48 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
49 | github.com/tommy351/gin-sessions v0.0.0-20150617141853-353060947eb6 h1:AlxjM5zhlVJhzzCSTrdgHOLagMl8eo2VhvJJKBXihAM=
50 | github.com/tommy351/gin-sessions v0.0.0-20150617141853-353060947eb6/go.mod h1:Z322RVSctbqRYhFCVnLI+hNZUBoAarOPebn/B5XXSJY=
51 | github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
52 | github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
53 | google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
54 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
55 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
56 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
57 | gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
58 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
59 | gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
60 | gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
61 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
62 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
63 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
64 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
65 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | db "go_cnode/database"
5 | "go_cnode/router"
6 | "go_cnode/utils"
7 | //"log"
8 | )
9 |
10 | func main() {
11 | conf := utils.LoadConf()
12 | db.Config(conf.Mongo_url, conf.Redis_url)
13 | //defer db.SqlDB.Close()
14 | defer db.MogSession.Close()
15 | defer db.Redis.Close()
16 |
17 | router := router.InitRouter()
18 |
19 | // config := cors.DefaultConfig()
20 | // config.AllowAllOrigins = true
21 | // config.AllowCredentials = true
22 | // config.AllowMethods = []string{"*"}
23 | // config.AllowHeaders = []string{"*"}
24 | //router.Use(cors.Default())
25 | router.Run(conf.Port)
26 | }
27 |
--------------------------------------------------------------------------------
/mgoModels/message.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | db "go_cnode/database"
5 | "gopkg.in/mgo.v2/bson"
6 | "time"
7 | "log"
8 | )
9 |
10 | //"log"
11 |
12 | type Message struct {
13 | Id bson.ObjectId `bson:"_id"`
14 | Type string `json:"type"`
15 | Master_id bson.ObjectId `json:"master_id" `
16 | Author_id bson.ObjectId `bson:"author_id" `
17 | Topic_id bson.ObjectId `json:"topic_id" `
18 | Reply_id bson.ObjectId `json:"reply_id" `
19 | Has_read bool `json:"has_read"`
20 | Create_at time.Time `bson:"create_at"`
21 | }
22 | type MessageModel struct{}
23 |
24 | func (p *MessageModel) GetMessagesCount(id string) (count int, err error) {
25 | mgodb:=db.Mgodb
26 | objectId := bson.ObjectIdHex(id)
27 | count, err = mgodb.C("messages").Find(bson.M{"master_id": objectId,"has_read": false}).Count()
28 | return count, err
29 | }
30 | func (p *MessageModel) GetMessageById(id string) (message Message, err error) {
31 | mgodb:=db.Mgodb
32 | objectId := bson.ObjectIdHex(id)
33 | err = mgodb.C("messages").Find(bson.M{"_id": objectId}).One(&message)
34 | return message, err
35 | }
36 | func (p *MessageModel) GetMessagesByUserId(id bson.ObjectId) (messages []Message, err error) {
37 | mgodb:=db.Mgodb
38 | err = mgodb.C("messages").Find(bson.M{"master_id": id, "has_read": true}).Sort("-create_at").All(&messages)
39 | return messages, err
40 | }
41 | func (p *MessageModel) GetUnreadMessagesByUserId(id bson.ObjectId) (messages []Message, err error) {
42 | mgodb:=db.Mgodb
43 | err = mgodb.C("messages").Find(bson.M{"master_id": id, "has_read": false}).Sort("-create_at").All(&messages)
44 | return messages, err
45 | }
46 | func (p *MessageModel) UpdateOneMessageToRead(msgId string) (err error) {
47 | mgodb:=db.Mgodb
48 | objectId := bson.ObjectIdHex(msgId)
49 | err = mgodb.C("messages").Update(bson.M{"_id": objectId},
50 | bson.M{
51 | "$set": bson.M{"has_read": true},
52 | })
53 | return err
54 | }
55 | func (p *MessageModel) UpdateMessagesToRead(userId string, messages []Message) (err error) {
56 | mgodb:=db.Mgodb
57 | var ids []bson.ObjectId
58 | for _, message := range messages {
59 | ids = append(ids, message.Id)
60 | }
61 | log.Println(ids)
62 | _,err = mgodb.C("messages").UpdateAll(
63 | bson.M{"master_id": bson.ObjectIdHex(userId),
64 | "_id":bson.M{"$in": ids}},
65 | bson.M{
66 | "$set": bson.M{"has_read": true},
67 | })
68 | return err
69 | }
70 | func (p *MessageModel) SendAtMessage(userId string, authorId string, topicId string, replyId bson.ObjectId) (err error) {
71 | mgodb:=db.Mgodb
72 | message := Message{
73 | Id: bson.NewObjectId(),
74 | Type: "at",
75 | Master_id: bson.ObjectIdHex(userId),
76 | Topic_id: bson.ObjectIdHex(topicId),
77 | Author_id: bson.ObjectIdHex(authorId),
78 | Reply_id: replyId,
79 | Create_at: time.Now(),
80 | }
81 | err = mgodb.C("messages").Insert(&message)
82 | return err
83 | }
84 | func (p *MessageModel) SendReplyMessage(userId string, authorId string, topicId string, replyId bson.ObjectId) (err error) {
85 | //mgodb := db.MogSession.DB("egg_cnode")
86 | mgodb:=db.Mgodb
87 | message := Message{
88 | Id: bson.NewObjectId(),
89 | Type: "reply",
90 | Master_id: bson.ObjectIdHex(userId),
91 | Topic_id: bson.ObjectIdHex(topicId),
92 | Author_id: bson.ObjectIdHex(authorId),
93 | Reply_id: replyId,
94 | Create_at: time.Now(),
95 | }
96 | err = mgodb.C("messages").Insert(&message)
97 | return err
98 | }
99 |
--------------------------------------------------------------------------------
/mgoModels/reply.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | //"log"
5 |
6 | db "go_cnode/database"
7 | "gopkg.in/mgo.v2/bson"
8 | //"encoding/json"
9 | "github.com/russross/blackfriday"
10 | "html/template"
11 | "strings"
12 | "time"
13 | )
14 |
15 | //"log"
16 |
17 | type Reply struct {
18 | Id bson.ObjectId `bson:"_id"`
19 | Topic_id bson.ObjectId `bson:"topic_id"`
20 | Reply_id bson.ObjectId `bson:"reply_id,omitempty"`
21 | Author_id bson.ObjectId `bson:"author_id" `
22 | Create_at time.Time `bson:"create_at"`
23 | Create_at_string string `json:"create_at_string,omitempty"`
24 | Update_at time.Time `bson:"update_at"`
25 | Update_at_string string `json:"update_at_string,omitempty"`
26 | Content string `json:"content"`
27 | Content_is_html bool `json:"content_is_html"`
28 |
29 | Deleted bool `json:"deleted"`
30 | }
31 | type ReplyAndAuthor struct {
32 | Reply Reply
33 | Author User
34 | LinkContent template.HTML
35 | }
36 | type ReplyModel struct{}
37 |
38 | func (p *ReplyModel) GetReplyById(id string) (reply Reply, err error) {
39 | mgodb:=db.Mgodb
40 | objectId := bson.ObjectIdHex(id)
41 | err = mgodb.C("replies").Find(bson.M{"_id": objectId,"deleted":false}).One(&reply)
42 | return reply, err
43 | }
44 | func (p *ReplyModel) GetRepliesByTopicId(id string) (replies []Reply, replyAndAuthor []ReplyAndAuthor, err error) {
45 | mgodb:=db.Mgodb
46 | objectId := bson.ObjectIdHex(id)
47 | err = mgodb.C("replies").Find(bson.M{"topic_id": objectId,"deleted":false}).Sort("_id").All(&replies)
48 | for _, v := range replies {
49 | var temp ReplyAndAuthor
50 | author, _ := userModel.GetUserById(v.Author_id.Hex())
51 | temp.Reply = v
52 | temp.Reply.Create_at_string = v.Create_at.Format("2006-01-02 15:04:05")
53 | temp.Reply.Update_at_string = v.Update_at.Format("2006-01-02 15:04:05")
54 | temp.Reply.Content = strings.Replace(temp.Reply.Content, "\r\n", "
", -1)
55 | temp.LinkContent = template.HTML(blackfriday.Run([]byte(temp.Reply.Content)))
56 | temp.Author = author
57 | replyAndAuthor = append(replyAndAuthor, temp)
58 | }
59 | return replies, replyAndAuthor, err
60 | }
61 | func (p *ReplyModel) NewAndSave(content string, topic_id string, user_id string, reply_id string) (reply Reply, err error) {
62 |
63 | objectId := bson.ObjectIdHex(user_id)
64 | object_topic_id := bson.ObjectIdHex(topic_id)
65 |
66 | reply = Reply{
67 | Id: bson.NewObjectId(),
68 | Topic_id: object_topic_id,
69 | Content: content,
70 | Author_id: objectId,
71 | Create_at: time.Now(),
72 | }
73 | if reply_id != "" {
74 | object_reply_id := bson.ObjectIdHex(reply_id)
75 | reply.Reply_id = object_reply_id
76 | }
77 | mgodb:=db.Mgodb
78 | err = mgodb.C("replies").Insert(&reply)
79 |
80 | return reply, err
81 | }
82 | func (p *ReplyModel) Update(content string, reply_id string) (err error) {
83 |
84 | objectId := bson.ObjectIdHex(reply_id)
85 |
86 | mgodb:=db.Mgodb
87 | err = mgodb.C("replies").Update(bson.M{"_id": objectId},
88 | bson.M{
89 | "$set": bson.M{"update_at": time.Now(), "content": content},
90 | })
91 |
92 | return err
93 | }
94 | func (p *ReplyModel) Delete( reply_id string) (err error) {
95 |
96 | objectId := bson.ObjectIdHex(reply_id)
97 | mgodb:=db.Mgodb
98 | err = mgodb.C("replies").Update(bson.M{"_id": objectId},
99 | bson.M{
100 | "$set": bson.M{"update_at": time.Now(), "deleted": true},
101 | })
102 | return err
103 | }
104 | func (p *ReplyModel) GetReplyByAuthorQueryCount(objectId bson.ObjectId) (count int, err error) {
105 | mgodb:=db.Mgodb
106 |
107 | count, err = mgodb.C("replies").Find(bson.M{"author_id": objectId}).Count()
108 |
109 | return count, err
110 | }
111 |
--------------------------------------------------------------------------------
/mgoModels/topic.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | //"log"
5 | "encoding/json"
6 | db "go_cnode/database"
7 | "gopkg.in/mgo.v2/bson"
8 | "log"
9 | "time"
10 | )
11 |
12 | //"log"
13 |
14 | type Topic struct {
15 | Id bson.ObjectId `bson:"_id"`
16 | Title string `json:"title"`
17 | Content string `json:"content" `
18 | Author_id bson.ObjectId `bson:"author_id" `
19 | Top bool `json:"top" `
20 | Good bool `json:"good" `
21 | Lock bool `json:"lock"`
22 | Reply_count uint `json:"reply_count"`
23 | Visit_count uint `json:"visit_count"`
24 | Collect_count uint `json:"collect_count"`
25 | Create_at time.Time `bson:"create_at"`
26 | Create_at_string string `json:"create_at_string,omitempty"`
27 | Update_at string `json:"update_at"`
28 | Last_reply bson.ObjectId `bson:"last_reply,omitempty"`
29 | Last_reply_at time.Time `json:"last_reply_at,omitempty"`
30 | Content_is_html bool `json:"content_is_html"`
31 | Tab string `json:"tab"`
32 | Deleted bool `json:"deleted"`
33 | }
34 | type TopicModel struct{}
35 |
36 | var userModel = new(UserModel)
37 | var replyModel = new(ReplyModel)
38 | var topicModel = new(TopicModel)
39 |
40 | type TopciAndAuthor struct {
41 | Author User `json:"author"`
42 | Topic Topic `json:"topic"`
43 | Reply Reply `json:"reply"`
44 | }
45 |
46 | func (p *TopicModel) GetTopicByQuery(tab string, good bool, limit int, skip int) (topics []Topic, err error) {
47 | mgodb := db.MogSession.DB("egg_cnode")
48 | if tab == "" || tab == "all" {
49 | err = mgodb.C("topics").Find(bson.M{"good": good,"deleted":false}).Sort("-top", "-create_at").Limit(limit).Skip(skip).All(&topics)
50 | } else {
51 | err = mgodb.C("topics").Find(bson.M{"tab": tab, "good": good,"deleted":false}).Sort("-top", "-create_at").Limit(limit).Skip(skip).All(&topics)
52 | }
53 | //log.Println(topics)
54 | return topics, err
55 | }
56 | func (p *TopicModel) GetTopicBy(tab string, good bool, limit int, skip int) (topics []Topic, topicss []byte, err error) {
57 |
58 | var temps []TopciAndAuthor
59 | mgodb := db.MogSession.DB("egg_cnode")
60 | if tab == "" || tab == "all" {
61 | err = mgodb.C("topics").Find(bson.M{"good": good,"deleted":false}).Sort("-top", "-create_at").Limit(limit).Skip(skip).All(&topics)
62 | } else {
63 | err = mgodb.C("topics").Find(bson.M{"tab": tab, "good": good,"deleted":false}).Sort("-top", "-create_at").Limit(limit).Skip(skip).All(&topics)
64 | }
65 | //log.Println(topics)
66 | for _, v := range topics {
67 | var temp TopciAndAuthor
68 | temp.Topic = v
69 | author, _ := userModel.GetUserById(v.Author_id.Hex())
70 | temp.Author = author
71 | if v.Last_reply.Hex() != "" {
72 | reply, _ := replyModel.GetReplyById(v.Last_reply.Hex())
73 | temp.Reply = reply
74 | }
75 |
76 | temps = append(temps, temp)
77 | }
78 | topicss, _ = json.Marshal(temps)
79 |
80 | return topics, topicss, err
81 | }
82 | func (p *TopicModel) GetTopicByQueryCount(tab string, good bool) (count int, err error) {
83 | mgodb := db.MogSession.DB("egg_cnode")
84 | if tab == "" || tab == "all" {
85 | count, err = mgodb.C("topics").Find(bson.M{"deleted":false}).Count()
86 | } else {
87 | if good == true {
88 | count, err = mgodb.C("topics").Find(bson.M{"good": good,"deleted":false}).Count()
89 | } else {
90 | count, err = mgodb.C("topics").Find(bson.M{"tab": tab,"deleted":false}).Count()
91 | }
92 |
93 | }
94 |
95 | return count, err
96 | }
97 | func (p *TopicModel) GetTopicByAuthorQueryCount(objectId bson.ObjectId, tab string, good bool) (count int, err error) {
98 | mgodb := db.MogSession.DB("egg_cnode")
99 | if tab == "" || tab == "all" {
100 | count, err = mgodb.C("topics").Find(bson.M{"author_id": objectId,"deleted":false}).Count()
101 | } else {
102 | if good == true {
103 | count, err = mgodb.C("topics").Find(bson.M{"author_id": objectId, "good": good,"deleted":false}).Count()
104 | } else {
105 | count, err = mgodb.C("topics").Find(bson.M{"author_id": objectId, "tab": tab,"deleted":false}).Count()
106 | }
107 |
108 | }
109 |
110 | return count, err
111 | }
112 |
113 | // type ReplyAndAuthor struct {
114 | // Author models.User
115 | // Reply models.Reply
116 | // }
117 | func (p *TopicModel) GetTopicById(id string) (topic Topic, err error) {
118 | //mgodb := db.MogSession.DB("egg_cnode")
119 | mgodb:=db.Mgodb
120 | objectId := bson.ObjectIdHex(id)
121 | err = mgodb.C("topics").Find(bson.M{"_id": objectId}).One(&topic)
122 | return topic, err
123 | }
124 | func (p *TopicModel) GetTopicByIdWithReply(id string) (topic Topic, author User, replies []Reply, repliyWithAuthors []ReplyAndAuthor, err error) {
125 | mgodb:=db.Mgodb
126 | objectId := bson.ObjectIdHex(id)
127 |
128 | err = mgodb.C("topics").Find(bson.M{"_id": objectId}).One(&topic)
129 |
130 | author, _ = userModel.GetUserById(topic.Author_id.Hex())
131 | topic.Create_at_string = topic.Create_at.Format("2006-01-02 15:04:05")
132 | replies, repliyWithAuthors, _ = replyModel.GetRepliesByTopicId(topic.Id.Hex())
133 | return topic, author, replies, repliyWithAuthors, err
134 | }
135 | func (p *TopicModel) NewAndSave(title string, tab string, id string, content string) (topic Topic, err error) {
136 |
137 | objectId := bson.ObjectIdHex(id)
138 | topic = Topic{
139 | Id: bson.NewObjectId(),
140 | Title: title,
141 | Content: content,
142 | Tab: tab,
143 | Author_id: objectId,
144 | Create_at: time.Now(),
145 | }
146 | mgodb:=db.Mgodb
147 | err = mgodb.C("topics").Insert(&topic)
148 | log.Println(err)
149 | return topic, err
150 | }
151 | func (p *TopicModel) GetTopicNoReply() (topics []Topic, err error) {
152 | mgodb:=db.Mgodb
153 |
154 | err = mgodb.C("topics").Find(bson.M{"reply_count": 0,"deleted":false}).Sort("-create_at").Limit(5).All(&topics)
155 |
156 | return topics, err
157 | }
158 | func (p *TopicModel) GetAuthorOtherTopics(author_id string, topic_id string) (topics []Topic, err error) {
159 | mgodb:=db.Mgodb
160 | objectId := bson.ObjectIdHex(author_id)
161 | topic_objectId := bson.ObjectIdHex(topic_id)
162 | err = mgodb.C("topics").Find(bson.M{"author_id": objectId,"deleted":false, "_id": bson.M{"$nin": []bson.ObjectId{topic_objectId}}}).Limit(5).Sort("-last_reply_at").All(&topics)
163 | return topics, err
164 | }
165 | func (p *TopicModel) GetAuthorTopics(author_id string, limit int, skip int) (topics []Topic, topicss []byte, err error) {
166 | var temps []TopciAndAuthor
167 | mgodb:=db.Mgodb
168 | objectId := bson.ObjectIdHex(author_id)
169 | err = mgodb.C("topics").Find(bson.M{"author_id": objectId,"deleted":false}).Skip(skip).Limit(limit).Sort("-create_at").All(&topics)
170 | for _, v := range topics {
171 | var temp TopciAndAuthor
172 | temp.Topic = v
173 | author, _ := userModel.GetUserById(v.Author_id.Hex())
174 | temp.Author = author
175 | if v.Last_reply.Hex() != "" {
176 | reply, _ := replyModel.GetReplyById(v.Last_reply.Hex())
177 | temp.Reply = reply
178 | }
179 |
180 | temps = append(temps, temp)
181 | }
182 | topicss, _ = json.Marshal(temps)
183 | return topics, topicss, err
184 | }
185 | func (p *TopicModel) GetReplyTopics(author_id string, limit int, skip int, most int) (topicss []byte, err error) {
186 | var temps []TopciAndAuthor
187 | var replies []Reply
188 | var topic_ids map[bson.ObjectId]int
189 | var topic_id_ints []bson.ObjectId
190 | topic_ids = make(map[bson.ObjectId]int)
191 | mgodb:=db.Mgodb
192 | objectId := bson.ObjectIdHex(author_id)
193 | err = mgodb.C("replies").Find(bson.M{"author_id": objectId,"deleted":false}).Sort("-create_at").Skip(skip).Limit(limit).All(&replies)
194 | for i := 0; i < len(replies); i++ {
195 | if _, ok := topic_ids[replies[i].Topic_id]; ok {
196 | } else {
197 | topic_ids[replies[i].Topic_id] = len(topic_ids) + 1
198 | topic_id_ints = append(topic_id_ints, replies[i].Topic_id)
199 | }
200 | if len(topic_ids) == most {
201 | break
202 | }
203 | }
204 | for j := 0; j < len(topic_id_ints); j++ {
205 | topic, err2 := topicModel.GetTopicById(topic_id_ints[j].Hex())
206 | if err2 == nil && topic.Author_id.Hex() != "" {
207 | var temp TopciAndAuthor
208 | temp.Topic = topic
209 | author, _ := userModel.GetUserById(topic.Author_id.Hex())
210 | temp.Author = author
211 | if topic.Last_reply.Hex() != "" {
212 | reply, _ := replyModel.GetReplyById(topic.Last_reply.Hex())
213 | temp.Reply = reply
214 | }
215 | temps = append(temps, temp)
216 | }
217 | }
218 | topicss, _ = json.Marshal(temps)
219 | return topicss, err
220 | }
221 | func (p *TopicModel) UpdateReplyCount(id string, replyId bson.ObjectId) (err error) {
222 | mgodb:=db.Mgodb
223 | objectId := bson.ObjectIdHex(id)
224 | //objectReplyId := bson.ObjectIdHex(replyId)
225 | err = mgodb.C("topics").Update(bson.M{"_id": objectId},
226 | bson.M{
227 | "$inc": bson.M{"reply_count": 1},
228 | "$set": bson.M{"last_reply_at": time.Now(), "last_reply": replyId},
229 | })
230 | log.Println(err)
231 | return err
232 | }
233 | func (p *TopicModel) UpdateVisitCount(id string) (err error) {
234 | mgodb:=db.Mgodb
235 | objectId := bson.ObjectIdHex(id)
236 |
237 | err = mgodb.C("topics").Update(bson.M{"_id": objectId},
238 | bson.M{
239 | "$inc": bson.M{"visit_count": 1},
240 | })
241 | log.Println(err)
242 | return err
243 | }
244 | func (p *TopicModel) SetTop(id string, value bool) (err error) {
245 | mgodb:=db.Mgodb
246 | objectId := bson.ObjectIdHex(id)
247 |
248 | err = mgodb.C("topics").Update(bson.M{"_id": objectId},
249 | bson.M{
250 | "$set": bson.M{"top": value},
251 | })
252 | log.Println(err)
253 | return err
254 | }
255 | func (p *TopicModel) Delete( id string) (err error) {
256 |
257 | objectId := bson.ObjectIdHex(id)
258 | mgodb:=db.Mgodb
259 | err = mgodb.C("topics").Update(bson.M{"_id": objectId},
260 | bson.M{
261 | "$set": bson.M{"update_at": time.Now(), "deleted": true},
262 | })
263 | return err
264 | }
265 | func (p *TopicModel) Update(topic Topic) (err error) {
266 | mgodb:=db.Mgodb
267 | err = mgodb.C("topics").Update(bson.M{"_id": topic.Id},
268 | bson.M{
269 | "$set": bson.M{"update_at": time.Now(), "title": topic.Title,
270 |
271 | "tab":topic.Tab,"content":topic.Content},
272 | })
273 | log.Println(err)
274 | return err
275 | }
276 |
--------------------------------------------------------------------------------
/mgoModels/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "github.com/satori/go.uuid"
5 | db "go_cnode/database"
6 | "golang.org/x/crypto/bcrypt"
7 | "gopkg.in/mgo.v2/bson"
8 | "log"
9 | "time"
10 | )
11 |
12 | //"log"
13 |
14 | type User struct {
15 | Id bson.ObjectId `bson:"_id"`
16 | Name string `json:"name"`
17 | Loginname string `json:"loginname"`
18 | Pass string `json:"pass,omitempty"`
19 | Email string `json:"email"`
20 | Avatar string `json:"avatar" `
21 | AccessToken string `json:"accessToken"`
22 | Score uint `json:"score"`
23 | Collect_topic_count uint `json:"collect_topic_count"`
24 | Topic_count uint `json:"topic_count"`
25 | Reply_count uint `json:"reply_count"`
26 | Active bool `json:"active"`
27 | Is_block bool `json:"is_block"`
28 | GithubUsername string `json:"githubUsername,omitempty"`
29 | GithubAccessToken string `json:"githubAccessToken,omitempty"`
30 | Messages_count int `json:"messages_count,omitempty"`
31 | GithubId int `json:"githubId,omitempty"`
32 | Url string `json:"url"`
33 | Location string `json:"location"`
34 | Weibo string `json:"weibo"`
35 | Create_at time.Time `bson:"create_at"`
36 | Is_star string `json:"is_star"`
37 | }
38 | type UserModel struct{}
39 | var messageModel = new(MessageModel)
40 | func (p *UserModel) GetUserByGithubId(id int) (user User, err error) {
41 | mgodb := db.MogSession.DB("egg_cnode")
42 | log.Println(id)
43 | err = mgodb.C("users").Find(bson.M{"GithubId": id}).One(&user)
44 | if err==nil{
45 | user.Messages_count,_=messageModel.GetMessagesCount(user.Id.Hex())
46 | }
47 | return user, err
48 | }
49 | func (p *UserModel) GetUserById(id string) (user User, err error) {
50 | mgodb := db.MogSession.DB("egg_cnode")
51 | objectId := bson.ObjectIdHex(id)
52 | err = mgodb.C("users").Find(bson.M{"_id": objectId}).One(&user)
53 | if err==nil{
54 | user.Messages_count,_=messageModel.GetMessagesCount(id)
55 | }
56 | return user, err
57 | }
58 | func (p *UserModel) GetUserTops(limit int) (users []User, err error) {
59 | mgodb := db.MogSession.DB("egg_cnode")
60 | err = mgodb.C("users").Find(bson.M{}).Sort("-score").Limit(limit).All(&users)
61 | return users, err
62 | }
63 | func (p *UserModel) GetUserByName(name string) (user User, err error) {
64 | mgodb := db.MogSession.DB("egg_cnode")
65 | err = mgodb.C("users").Find(bson.M{"name": name}).One(&user)
66 | if err==nil{
67 | user.Messages_count,_=messageModel.GetMessagesCount(user.Id.Hex())
68 | }
69 | return user, err
70 | }
71 | func (p *UserModel) ActiveUserByName(name string) (err error) {
72 | mgodb := db.MogSession.DB("egg_cnode")
73 | err = mgodb.C("users").Update(bson.M{"name": name}, bson.M{"$set": bson.M{"active": true}})
74 | return err
75 | }
76 | func (p *UserModel) GetUserByNameOrEmail(name string, email string) (user User, err error) {
77 | mgodb := db.MogSession.DB("egg_cnode")
78 | err = mgodb.C("users").Find(bson.M{"$or": []bson.M{bson.M{"name": name}, bson.M{"email": email}}}).One(&user)
79 | return user, err
80 | }
81 | func (p *UserModel) NewAndSave(name string, loginname string, email string, pass string, avatar_url string, active bool) (err error) {
82 | hashPass, _ := bcrypt.GenerateFromPassword([]byte(pass), 10)
83 | mgodb := db.MogSession.DB("egg_cnode")
84 | u2 := uuid.NewV4()
85 | user := User{
86 | Id: bson.NewObjectId(),
87 | Name: name,
88 | Loginname: loginname,
89 | Pass: string(hashPass),
90 | Avatar: "http://www.gravatar.com/avatar/81f36fbf3b658c6a2330ca6840f7cb12?size=48",
91 | Email: email,
92 | Active: active,
93 | AccessToken: u2.String(),
94 | Create_at: time.Now(),
95 | }
96 | err = mgodb.C("users").Insert(&user)
97 | log.Println(err)
98 | return err
99 | }
100 | func (p *UserModel) GithubNewAndSave(name string, loginname string, email string, avatar_url string, active bool, githubId int) (temp User, err error) {
101 |
102 | mgodb := db.MogSession.DB("egg_cnode")
103 | u2 := uuid.NewV4()
104 | user := User{
105 | Id: bson.NewObjectId(),
106 | Name: name,
107 | Loginname: loginname,
108 | Avatar: avatar_url,
109 | Email: email,
110 | Active: active,
111 | AccessToken: u2.String(),
112 | GithubId: githubId,
113 | Create_at: time.Now(),
114 | }
115 | err = mgodb.C("users").Insert(&user)
116 | log.Println(err)
117 | return user, err
118 | }
119 |
--------------------------------------------------------------------------------
/public/19ITP3EmsT.txt:
--------------------------------------------------------------------------------
1 | 7a35f0ff6fc19ea2756c83f235c7b2d7
--------------------------------------------------------------------------------
/public/github-card.html:
--------------------------------------------------------------------------------
1 |
您好:" + name + "
" + 90 | "我们收到您在Go_Cnode社区的注册信息,请点击下面的链接来激活帐户:
" + 91 | "激活链接" + 92 | "若您没有在Go_Cnode社区填写过注册信息,说明有人滥用了您的电子邮箱,请删除此邮件,我们对给您造成的打扰感到抱歉。
" + 93 | "Go_Cnode社区 谨上。
" 94 | msg := []byte("To: " + strings.Join(to, ",") + "\r\nFrom: " + nickname + 95 | "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body) 96 | //err := smtp.SendMail("smtp.qq.com:465", auth, user, to, msg) 97 | err := SendMailViaTLS( 98 | conf.Smtp_hostname+":465", 99 | auth, 100 | user, 101 | to, 102 | msg, 103 | ) 104 | if err != nil { 105 | fmt.Printf("send mail error: %v", err) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /utils/dysms.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha1" 6 | "encoding/base64" 7 | "encoding/json" 8 | "errors" 9 | "fmt" 10 | "io/ioutil" 11 | "math/rand" 12 | "net/http" 13 | "net/url" 14 | "sort" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | // SendSmsReply 发送短信返回 20 | type SendSmsReply struct { 21 | Code string `json:"Code,omitempty"` 22 | Message string `json:"Message,omitempty"` 23 | } 24 | 25 | func replace(in string) string { 26 | rep := strings.NewReplacer("+", "%20", "*", "%2A", "%7E", "~") 27 | return rep.Replace(url.QueryEscape(in)) 28 | } 29 | 30 | // SendSms 发送短信 31 | func SendSms(accessKeyID, accessSecret, phoneNumbers, signName, templateParam, templateCode string) error { 32 | paras := map[string]string{ 33 | "SignatureMethod": "HMAC-SHA1", 34 | "SignatureNonce": fmt.Sprintf("%d", rand.Int63()), 35 | "AccessKeyId": accessKeyID, 36 | "SignatureVersion": "1.0", 37 | "Timestamp": time.Now().UTC().Format("2006-01-02T15:04:05Z"), 38 | "Format": "JSON", 39 | 40 | "Action": "SendSms", 41 | "Version": "2017-05-25", 42 | "RegionId": "cn-hangzhou", 43 | "PhoneNumbers": phoneNumbers, 44 | "SignName": signName, 45 | "TemplateParam": templateParam, 46 | "TemplateCode": templateCode, 47 | } 48 | 49 | var keys []string 50 | 51 | for k := range paras { 52 | keys = append(keys, k) 53 | } 54 | 55 | sort.Strings(keys) 56 | 57 | var sortQueryString string 58 | 59 | for _, v := range keys { 60 | sortQueryString = fmt.Sprintf("%s&%s=%s", sortQueryString, replace(v), replace(paras[v])) 61 | } 62 | 63 | stringToSign := fmt.Sprintf("GET&%s&%s", replace("/"), replace(sortQueryString[1:])) 64 | 65 | mac := hmac.New(sha1.New, []byte(fmt.Sprintf("%s&", accessSecret))) 66 | mac.Write([]byte(stringToSign)) 67 | sign := replace(base64.StdEncoding.EncodeToString(mac.Sum(nil))) 68 | 69 | str := fmt.Sprintf("http://dysmsapi.aliyuncs.com/?Signature=%s%s", sign, sortQueryString) 70 | 71 | resp, err := http.Get(str) 72 | if err != nil { 73 | return err 74 | } 75 | defer resp.Body.Close() 76 | body, err := ioutil.ReadAll(resp.Body) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | ssr := &SendSmsReply{} 82 | 83 | if err := json.Unmarshal(body, ssr); err != nil { 84 | return err 85 | } 86 | 87 | if ssr.Code == "SignatureNonceUsed" { 88 | return SendSms(accessKeyID, accessSecret, phoneNumbers, signName, templateParam, templateCode) 89 | } else if ssr.Code != "OK" { 90 | return errors.New(ssr.Code) 91 | } 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /utils/loadConf.go: -------------------------------------------------------------------------------- 1 | package utils 2 | import( 3 | "os" 4 | "encoding/json" 5 | ) 6 | 7 | type configuration struct { 8 | Port string 9 | Mongo_url string 10 | Redis_url string 11 | Smtp_username string 12 | Smtp_password string 13 | Smtp_hostname string 14 | Smtp_active_Url string 15 | Github_client_id string 16 | Github_client_secret string 17 | Github_AuthURL string 18 | Github_UserURL string 19 | Github_TokenURL string 20 | } 21 | func LoadConf() (conf configuration) { 22 | // 打开文件 23 | file, _ := os.Open("conf.json") 24 | 25 | // 关闭文件 26 | defer file.Close() 27 | 28 | //NewDecoder创建一个从file读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。 29 | decoder := json.NewDecoder(file) 30 | 31 | //Decode从输入流读取下一个json编码值并保存在v指向的值里 32 | decoder.Decode(&conf) 33 | return conf 34 | } -------------------------------------------------------------------------------- /views/about/about.html: -------------------------------------------------------------------------------- 1 | {{ define "about" }} 2 | {{ template "common/header" .}} 3 |CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
4 |服务器搭建在
5 |
7 |
9 |
10 | ,存储赞助商为
11 |
13 |
15 |
16 |
新手搭建 Node.js 服务器,推荐使用无需备案的 DigitalOcean(https://www.digitalocean.com/)
18 |