// URL: /admin/node/new // 新建节点 func adminNewNodeHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin?next=/node/new", http.StatusFound) return } if !user.IsSuperuser { message(w, r, "没有权限", "你没有新建节点的权限", "error") return } form := wtforms.NewForm( wtforms.NewTextField("id", "ID", "", &wtforms.Required{}), wtforms.NewTextField("name", "名称", "", &wtforms.Required{}), wtforms.NewTextArea("description", "描述", "", &wtforms.Required{}), ) if r.Method == "POST" { if form.Validate(r) { c := db.C("nodes") node := Node{} err := c.Find(bson.M{"id": form.Value("id")}).One(&node) if err == nil { form.AddError("id", "该ID已经存在") renderTemplate(w, r, "node/new.html", map[string]interface{}{"form": form, "adminNav": ADMIN_NAV}) return } err = c.Find(bson.M{"name": form.Value("name")}).One(&node) if err == nil { form.AddError("name", "该名称已经存在") renderTemplate(w, r, "node/new.html", map[string]interface{}{"form": form, "adminNav": ADMIN_NAV}) return } Id_ := bson.NewObjectId() err = c.Insert(&Node{ Id_: Id_, Id: form.Value("id"), Name: form.Value("name"), Description: form.Value("description")}) if err != nil { panic(err) } http.Redirect(w, r, "/admin/node/new", http.StatusFound) } } renderTemplate(w, r, "node/new.html", map[string]interface{}{"form": form, "adminNav": ADMIN_NAV}) }
// URL: /site/new // 提交站点 func newSiteHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } var categories []SiteCategory c := db.C("sitecategories") c.Find(nil).All(&categories) var choices []wtforms.Choice for _, category := range categories { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewTextField("name", "网站名称", "", wtforms.Required{}), wtforms.NewTextField("url", "地址", "", wtforms.Required{}, wtforms.URL{}), wtforms.NewTextArea("description", "描述", ""), wtforms.NewSelectField("category", "分类", choices, "", wtforms.Required{}), ) if r.Method == "POST" { if !form.Validate(r) { renderTemplate(w, r, "site/form.html", map[string]interface{}{"form": form, "action": "/site/new", "title": "新建"}) return } var site Site c = db.C("sites") err := c.Find(bson.M{"url": form.Value("url")}).One(&site) if err == nil { form.AddError("url", "该站点已经有了") renderTemplate(w, r, "site/form.html", map[string]interface{}{"form": form, "action": "/site/new", "title": "新建"}) return } Id_ := bson.NewObjectId() c = db.C("sites") c.Insert(&Site{ Id_: Id_, Name: form.Value("name"), Url: form.Value("url"), Description: form.Value("description"), CategoryId: bson.ObjectIdHex(form.Value("category")), UserId: user.Id_, }) http.Redirect(w, r, "/sites#site-"+Id_.Hex(), http.StatusFound) return } renderTemplate(w, r, "site/form.html", map[string]interface{}{"form": form, "action": "/site/new", "title": "新建"}) }
// URL: /package/new // 新建第三方包 func newPackageHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } var categories []PackageCategory c := db.C("packagecategories") c.Find(nil).All(&categories) var choices []wtforms.Choice for _, category := range categories { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewHiddenField("html", ""), wtforms.NewTextField("name", "名称", "", wtforms.Required{}), wtforms.NewSelectField("category_id", "分类", choices, ""), wtforms.NewTextField("url", "网址", "", wtforms.Required{}, wtforms.URL{}), wtforms.NewTextArea("description", "描述", "", wtforms.Required{}), ) if r.Method == "POST" && form.Validate(r) { c = db.C("packages") id := bson.NewObjectId() categoryId := bson.ObjectIdHex(form.Value("category_id")) c.Insert(&Package{ Id_: id, UserId: user.Id_, CategoryId: categoryId, Name: form.Value("name"), Url: form.Value("url"), Markdown: form.Value("description"), Html: template.HTML(form.Value("html")), CreatedAt: time.Now(), }) c = db.C("packagecategories") // 增加数量 c.Update(bson.M{"_id": categoryId}, bson.M{"$inc": bson.M{"packagecount": 1}}) http.Redirect(w, r, "/p/"+id.Hex(), http.StatusFound) return } renderTemplate(w, r, "package/form.html", map[string]interface{}{"form": form, "title": "提交第三方包", "action": "/package/new"}) }
// URL: /admin/package_category/new // 新建包分类 func adminNewPackageCategoryHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin?next=/admin/site_category/new", http.StatusFound) return } if !user.IsSuperuser { message(w, r, "没有权限", "你没有新建包分类的权限", "error") return } form := wtforms.NewForm( wtforms.NewTextField("id", "ID", "", wtforms.Required{}), wtforms.NewTextField("name", "名称", "", wtforms.Required{}), ) if r.Method == "POST" { if !form.Validate(r) { renderTemplate(w, r, "admin/new_package_category.html", map[string]interface{}{"adminNav": ADMIN_NAV, "form": form}) return } c := db.C("packagecategories") var category PackageCategory err := c.Find(bson.M{"name": form.Value("name")}).One(&category) if err == nil { form.AddError("name", "该名称已经有了") renderTemplate(w, r, "admin/new_package_category.html", map[string]interface{}{"adminNav": ADMIN_NAV, "form": form}) return } err = c.Insert(&PackageCategory{ Id_: bson.NewObjectId(), Id: form.Value("id"), Name: form.Value("name"), }) if err != nil { panic(err) } http.Redirect(w, r, "/admin/package_category/new", http.StatusFound) } renderTemplate(w, r, "admin/new_package_category.html", map[string]interface{}{"adminNav": ADMIN_NAV, "form": form}) }
// URL: /signin // 处理用户登录,如果登录成功,设置Cookie func signinHandler(w http.ResponseWriter, r *http.Request) { next := r.FormValue("next") form := wtforms.NewForm( wtforms.NewHiddenField("next", next), wtforms.NewTextField("username", "用户名", "", &wtforms.Required{}), wtforms.NewPasswordField("password", "密码", &wtforms.Required{}), ) if r.Method == "POST" { if form.Validate(r) { c := db.C("users") user := User{} err := c.Find(bson.M{"username": form.Value("username")}).One(&user) if err != nil { form.AddError("username", "该用户不存在") renderTemplate(w, r, "account/signin.html", map[string]interface{}{"form": form}) return } if !user.IsActive { form.AddError("username", "邮箱没有经过验证,如果没有收到邮件,请联系管理员") renderTemplate(w, r, "account/signin.html", map[string]interface{}{"form": form}) return } if user.Password != encryptPassword(form.Value("password")) { form.AddError("password", "密码和用户名不匹配") renderTemplate(w, r, "account/signin.html", map[string]interface{}{"form": form}) return } session, _ := store.Get(r, "user") session.Values["username"] = user.Username session.Save(r, w) if form.Value("next") == "" { http.Redirect(w, r, "/", http.StatusFound) } else { http.Redirect(w, r, next, http.StatusFound) } return } } renderTemplate(w, r, "account/signin.html", map[string]interface{}{"form": form}) }
// URL /profile // 用户设置页面,显示用户设置,用户头像,密码修改 func profileHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin?next=/profile", http.StatusFound) return } profileForm := wtforms.NewForm( wtforms.NewTextField("email", "电子邮件", user.Email, wtforms.Email{}), wtforms.NewTextField("website", "个人网站", user.Website), wtforms.NewTextField("location", "所在地", user.Location), wtforms.NewTextField("tagline", "签名", user.Tagline), wtforms.NewTextArea("bio", "个人简介", user.Bio), ) if r.Method == "POST" { if profileForm.Validate(r) { c := db.C("users") c.Update(bson.M{"_id": user.Id_}, bson.M{"$set": bson.M{"website": profileForm.Value("website"), "location": profileForm.Value("location"), "tagline": profileForm.Value("tagline"), "bio": profileForm.Value("bio"), }}) http.Redirect(w, r, "/profile", http.StatusFound) return } } changePasswordForm := wtforms.NewForm( wtforms.NewPasswordField("current_password", "当前密码"), wtforms.NewPasswordField("new_password", "新密码"), wtforms.NewPasswordField("confirm_password", "新密码确认"), ) renderTemplate(w, r, "account/profile.html", map[string]interface{}{"user": user, "profileForm": profileForm, "changePasswordForm": changePasswordForm}) }
// URL: /forgot_password // 忘记密码,输入用户名和邮箱,如果匹配,发出邮件 func forgotPasswordHandler(w http.ResponseWriter, r *http.Request) { form := wtforms.NewForm( wtforms.NewTextField("username", "用户名", "", wtforms.Required{}), wtforms.NewTextField("email", "电子邮件", "", wtforms.Email{}), ) if r.Method == "POST" { if form.Validate(r) { var user User c := db.C("users") err := c.Find(bson.M{"username": form.Value("username")}).One(&user) if err != nil { form.AddError("username", "没有该用户") } else if user.Email != form.Value("email") { form.AddError("username", "用户名和邮件不匹配") } else { message2 := `Hi %s, 我们的系统收到一个请求,说你希望通过电子邮件重新设置你在 Golang中国 的密码。你可以点击下面的链接开始重设密码: %s/reset/%s 如果这个请求不是由你发起的,那没问题,你不用担心,你可以安全地忽略这封邮件。 如果你有任何疑问,可以回复这封邮件向我提问。` code := uuid() c.Update(bson.M{"_id": user.Id_}, bson.M{"$set": bson.M{"resetcode": code}}) message2 = fmt.Sprintf(message2, user.Username, config["host"], code) sendMail("[Golang中国]重设密码", message2, []string{user.Email}) message(w, r, "通过电子邮件重设密码", "一封包含了重设密码指令的邮件已经发送到你的注册邮箱,按照邮件中的提示,即可重设你的密码。", "success") return } } } renderTemplate(w, r, "account/forgot_password.html", map[string]interface{}{"form": form}) }
// URL: /signup // 处理用户注册,要求输入用户名,密码和邮箱 func signupHandler(w http.ResponseWriter, r *http.Request) { form := wtforms.NewForm( wtforms.NewTextField("username", "用户名", "", wtforms.Required{}, wtforms.Regexp{Expr: `^[a-zA-Z0-9_]{3,16}$`, Message: "请使用a-z, A-Z, 0-9以及下划线, 长度3-16之间"}), wtforms.NewPasswordField("password", "密码", wtforms.Required{}), wtforms.NewTextField("email", "电子邮件", "", wtforms.Required{}, wtforms.Email{}), ) if r.Method == "POST" { if form.Validate(r) { c := db.C("users") result := User{} // 检查用户名 err := c.Find(bson.M{"username": form.Value("username")}).One(&result) if err == nil { form.AddError("username", "该用户名已经被注册") renderTemplate(w, r, "account/signup.html", map[string]interface{}{"form": form}) return } // 检查邮箱 err = c.Find(bson.M{"email": form.Value("email")}).One(&result) if err == nil { form.AddError("email", "电子邮件地址已经被注册") renderTemplate(w, r, "account/signup.html", map[string]interface{}{"form": form}) return } c2 := db.C("status") var status Status c2.Find(nil).One(&status) id := bson.NewObjectId() validateCode := uuid() index := status.UserIndex + 1 err = c.Insert(&User{ Id_: id, Username: form.Value("username"), Password: encryptPassword(form.Value("password")), Email: form.Value("email"), ValidateCode: validateCode, IsActive: true, JoinedAt: time.Now(), Index: index, }) if err != nil { panic(err) } c2.Update(bson.M{"_id": status.Id_}, bson.M{"$inc": bson.M{"userindex": 1}}) // 发送邮件 /* subject := "欢迎加入Golang 中国" message2 := `欢迎加入Golang 中国。请访问下面地址激活你的帐户。 <a href="%s/activate/%s">%s/activate/%s</a> 如果你没有注册,请忽略这封邮件。 ©2012 Golang 中国` message2 = fmt.Sprintf(message2, config["host"], validateCode, config["host"], validateCode) sendMail(subject, message2, []string{form.Value("email")}) message(w, r, "注册成功", "请查看你的邮箱进行验证,如果收件箱没有,请查看垃圾邮件,如果还没有,请给[email protected]发邮件,告知你的用户名。", "success") */ message(w, r, "注册成功", fmt.Sprintf(`感谢您的注册,您已经成为Golang中国第 <strong>%d</strong>位用户,<a href="/signin">登录</a>。`, index), "success") return } } renderTemplate(w, r, "account/signup.html", map[string]interface{}{"form": form}) }
// URL: /package/{packageId}/edit // 编辑第三方包 func editPackageHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } vars := mux.Vars(r) packageId := vars["packageId"] package_ := Package{} c := db.C("packages") err := c.Find(bson.M{"_id": bson.ObjectIdHex(packageId)}).One(&package_) if err != nil { message(w, r, "没有该包", "没有该包", "error") return } if !package_.CanEdit(user.Username) { message(w, r, "没有权限", "你没有权限编辑该包", "error") return } var categories []PackageCategory c = db.C("packagecategories") c.Find(nil).All(&categories) var choices []wtforms.Choice for _, category := range categories { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewHiddenField("html", string(package_.Html)), wtforms.NewTextField("name", "名称", package_.Name, wtforms.Required{}), wtforms.NewSelectField("category_id", "分类", choices, package_.CategoryId.Hex()), wtforms.NewTextField("url", "网址", package_.Url, wtforms.Required{}, wtforms.URL{}), wtforms.NewTextArea("description", "描述", package_.Markdown, wtforms.Required{}), ) if r.Method == "POST" && form.Validate(r) { c = db.C("packages") categoryId := bson.ObjectIdHex(form.Value("category_id")) c.Update(bson.M{"_id": package_.Id_}, bson.M{"$set": bson.M{ "categoryid": categoryId, "name": form.Value("name"), "url": form.Value("url"), "markdown": form.Value("description"), "html": template.HTML(form.Value("html")), }}) c = db.C("packagecategories") if categoryId != package_.CategoryId { // 减少原来类别的包数量 c.Update(bson.M{"_id": package_.CategoryId}, bson.M{"$inc": bson.M{"packagecount": -1}}) // 增加新类别的包数量 c.Update(bson.M{"_id": categoryId}, bson.M{"$inc": bson.M{"packagecount": 1}}) } http.Redirect(w, r, "/p/"+package_.Id_.Hex(), http.StatusFound) return } renderTemplate(w, r, "package/form.html", map[string]interface{}{"form": form, "title": "编辑第三方包", "action": "/p/" + packageId + "/edit"}) }
// URL: /article/new // 新建文章 func newArticleHandler(w http.ResponseWriter, r *http.Request) { if _, ok := currentUser(r); !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } var categories []ArticleCategory c := db.C("articlecategories") c.Find(nil).All(&categories) var choices []wtforms.Choice for _, category := range categories { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewHiddenField("html", ""), wtforms.NewTextField("title", "标题", "", wtforms.Required{}), wtforms.NewTextArea("content", "内容", "", wtforms.Required{}), wtforms.NewTextField("original_source", "原始出处", "", wtforms.Required{}), wtforms.NewTextField("original_url", "原始链接", "", wtforms.URL{}), wtforms.NewSelectField("category", "分类", choices, ""), ) if r.Method == "POST" && form.Validate(r) { session, _ := store.Get(r, "user") username, _ := session.Values["username"] username = username.(string) user := User{} c = db.C("users") c.Find(bson.M{"username": username}).One(&user) c = db.C("articles") Id_ := bson.NewObjectId() html := form.Value("html") html = strings.Replace(html, "<pre>", `<pre class="prettyprint linenums">`, -1) categoryId := bson.ObjectIdHex(form.Value("category")) err := c.Insert(&Article{ Id_: Id_, CategoryId: categoryId, UserId: user.Id_, Title: form.Value("title"), Markdown: form.Value("content"), Html: template.HTML(html), OriginalSource: form.Value("original_source"), OriginalUrl: form.Value("original_url"), CreatedAt: time.Now(), }) if err != nil { panic(err) } http.Redirect(w, r, "/a/"+Id_.Hex(), http.StatusFound) return } renderTemplate(w, r, "article/form.html", map[string]interface{}{"form": form, "title": "新建", "action": "/article/new"}) }
// URL: /a/{articleId}/edit // 编辑主题 func editArticleHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } articleId := mux.Vars(r)["articleId"] c := db.C("articles") var article Article err := c.Find(bson.M{"_id": bson.ObjectIdHex(articleId)}).One(&article) if err != nil { message(w, r, "没有该文章", "没有该文章,不能编辑", "error") return } if !article.CanEdit(user.Username) { message(w, r, "没用该权限", "对不起,你没有权限编辑该文章", "error") return } var categorys []ArticleCategory c = db.C("articlecategories") c.Find(nil).All(&categorys) var choices []wtforms.Choice for _, category := range categorys { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewHiddenField("html", ""), wtforms.NewTextField("title", "标题", article.Title, wtforms.Required{}), wtforms.NewTextArea("content", "内容", article.Markdown, wtforms.Required{}), wtforms.NewTextField("original_source", "原始出处", article.OriginalSource, wtforms.Required{}), wtforms.NewTextField("original_url", "原始链接", article.OriginalUrl, wtforms.URL{}), wtforms.NewSelectField("category", "分类", choices, article.CategoryId.Hex()), ) content := article.Markdown html := article.Html if r.Method == "POST" { if form.Validate(r) { html := form.Value("html") html = strings.Replace(html, "<pre>", `<pre class="prettyprint linenums">`, -1) categoryId := bson.ObjectIdHex(form.Value("category")) c = db.C("articles") c.Update(bson.M{"_id": article.Id_}, bson.M{"$set": bson.M{ "categoryid": categoryId, "title": form.Value("title"), "originalsource": form.Value("original_source"), "originalurl": form.Value("original_url"), "markdown": form.Value("content"), "html": template.HTML(html), }}) http.Redirect(w, r, "/a/"+article.Id_.Hex(), http.StatusFound) return } content = form.Value("content") html = template.HTML(form.Value("html")) } renderTemplate(w, r, "article/form.html", map[string]interface{}{"form": form, "title": "编辑", "action": "/a/" + articleId + "/edit", "html": html, "content": content}) }
// URL: /site/{siteId}/edit // 修改提交过的站点信息,提交者自己或者管理员可以修改 func editSiteHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } siteId := mux.Vars(r)["siteId"] var site Site c := db.C("sites") err := c.Find(bson.M{"_id": bson.ObjectIdHex(siteId)}).One(&site) if err != nil { message(w, r, "错误的连接", "错误的连接", "error") return } if !site.CanEdit(user.Username) { message(w, r, "没有权限", "你没有权限可以修改站点", "error") return } var categories []SiteCategory c = db.C("sitecategories") c.Find(nil).All(&categories) var choices []wtforms.Choice for _, category := range categories { choices = append(choices, wtforms.Choice{Value: category.Id_.Hex(), Label: category.Name}) } form := wtforms.NewForm( wtforms.NewTextField("name", "网站名称", site.Name, wtforms.Required{}), wtforms.NewTextField("url", "地址", site.Url, wtforms.Required{}, wtforms.URL{}), wtforms.NewTextArea("description", "描述", site.Description), wtforms.NewSelectField("category", "分类", choices, site.CategoryId.Hex(), wtforms.Required{}), ) if r.Method == "POST" && form.Validate(r) { // 检查是否用重复 var site2 Site c = db.C("sites") err := c.Find(bson.M{"url": form.Value("url"), "_id": bson.M{"$ne": site.Id_}}).One(&site2) if err == nil { form.AddError("url", "该站点已经有了") renderTemplate(w, r, "site/form.html", map[string]interface{}{"form": form, "action": "/site/" + siteId + "/edit", "title": "编辑"}) return } c.Update(bson.M{"_id": site.Id_}, bson.M{"$set": bson.M{ "name": form.Value("name"), "url": form.Value("url"), "description": form.Value("description"), "categoryid": bson.ObjectIdHex(form.Value("category")), }, }) http.Redirect(w, r, "/sites#site-"+site.Id_.Hex(), http.StatusFound) return } renderTemplate(w, r, "site/form.html", map[string]interface{}{"form": form, "action": "/site/" + siteId + "/edit", "title": "编辑"}) }