func ListHandler(ctx *app.Context) { var groups []*packageGroup dctx := getEnvironment(ctx) for _, gr := range appDocGroups(ctx) { var groupPackages []*doc.Package for _, v := range gr.Packages { pkgs, err := dctx.ImportPackages(packageDir(dctx, v)) if err != nil { log.Errorf("error importing %s: %s", v, err) continue } groupPackages = append(groupPackages, pkgs...) } if len(groupPackages) > 0 { groups = append(groups, &packageGroup{ Title: gr.Title, Packages: groupPackages, }) } } if len(groups) == 0 { ctx.NotFound("no packages to list") return } title := "Package Index" data := map[string]interface{}{ "Header": title, "Title": title, "Groups": groups, } ctx.MustExecute(PackagesTemplateName, data) }
func serveFile(ctx *app.Context, path string) { f, err := os.Open(path) if err != nil { ctx.NotFound("") return } defer f.Close() var modtime time.Time if fi, err := f.Stat(); err == nil { modtime = fi.ModTime() } http.ServeContent(ctx, ctx.R, filepath.Base(path), modtime, f) }
func jsSignUpHandler(ctx *app.Context) { d := data(ctx) if !d.allowRegistration() { ctx.NotFound("") return } user, _ := newEmptyUser(ctx) form := SignUpForm(ctx, user) if form.Submitted() && form.IsValid() { saveNewUser(ctx, user) writeJSONEncoded(ctx, user) return } FormErrors(ctx, form) }
func jsSignInHandler(ctx *app.Context) { d := data(ctx) if !d.allowDirectSignIn() { ctx.NotFound("") return } signIn := SignIn{} form := form.New(ctx, &signIn) if form.Submitted() && form.IsValid() { user := reflect.ValueOf(signIn.User) ctx.MustSignIn(asGondolaUser(user)) writeJSONEncoded(ctx, user) return } FormErrors(ctx, form) }
func ArticleHandler(ctx *app.Context) { slug := ctx.IndexValue(0) var art *article.Article articles := getArticles(ctx) for _, v := range articles { if v.Slug() == slug { art = v break } } if art == nil { for _, v := range articles { for _, s := range v.AllSlugs() { if s == slug { ctx.MustRedirectReverse(true, ctx.HandlerName(), s) return } } } ctx.NotFound("article not found") return } fs := vfs.Memory() filename := path.Base(art.Filename) if filename == "" { filename = "article.html" } if err := vfs.WriteFile(fs, filename, art.Text, 0644); err != nil { panic(err) } log.Debugf("loading article %s", articleId(art)) tmpl, err := app.LoadTemplate(ctx.App(), fs, nil, filename) if err != nil { panic(err) } var buf bytes.Buffer if err := tmpl.ExecuteTo(&buf, ctx, nil); err != nil { panic(err) } body := buf.String() data := map[string]interface{}{ "Article": art, "Title": art.Title(), "Body": template.HTML(body), } ctx.MustExecute("article.html", data) }
func ResetHandler(ctx *app.Context) { d := data(ctx) if !d.allowDirectSignIn() { ctx.NotFound("") return } payload := ctx.FormValue("p") var valid bool var expired bool var f *form.Form var user reflect.Value var err error var done bool if payload != "" { user, err = decodeResetPayload(ctx, payload) if err == nil && user.IsValid() { valid = true } else { if err == errResetExpired { expired = true } } } if valid { passwordForm := &PasswordForm{User: user} f = form.New(ctx, passwordForm) if f.Submitted() && f.IsValid() { ctx.Orm().MustSave(user.Interface()) ctx.MustSignIn(asGondolaUser(user)) done = true } } data := map[string]interface{}{ "Valid": valid, "Expired": expired, "Done": done, "User": user, "PasswordForm": f, "Payload": payload, } ctx.MustExecute(ResetTemplateName, data) }
func signUpHandler(ctx *app.Context) { d := data(ctx) if !d.allowDirectSignIn() { ctx.NotFound("") return } from := ctx.FormValue(app.SignInFromParameterName) user, _ := newEmptyUser(ctx) form := SignUpForm(ctx, user) if form.Submitted() && form.IsValid() { saveNewUser(ctx, user) ctx.RedirectBack() return } data := map[string]interface{}{ "From": from, "SignUpForm": form, } ctx.MustExecute(SignUpTemplateName, data) }
func forgotHandler(ctx *app.Context) { d := data(ctx) if !d.allowDirectSignIn() { ctx.NotFound("") return } var user User var isEmail bool var sent bool var fields struct { Username string `form:",singleline,label=Username or Email"` ValidateUsername func(*app.Context) error } fields.ValidateUsername = func(c *app.Context) error { username := Normalize(fields.Username) isEmail = strings.Contains(username, "@") var field string if isEmail { field = "User.NormalizedEmail" } else { field = "User.NormalizedUsername" } userVal, userIface := newEmptyUser(ctx) ok := c.Orm().MustOne(orm.Eq(field, username), userIface) if !ok { if isEmail { return i18n.Errorf("address %q does not belong to any registered user", username) } return i18n.Errorf("username %q does not belong to any registered user", username) } user = getUserValue(userVal, "User").(User) if user.Email == "" { return i18n.Errorf("username %q does not have any registered emails", username) } return nil } f := form.New(ctx, &fields) if f.Submitted() && f.IsValid() { se, err := ctx.App().EncryptSigner(Salt) if err != nil { panic(err) } values := make(url.Values) values.Add("u", strconv.FormatInt(user.Id(), 36)) values.Add("t", strconv.FormatInt(time.Now().Unix(), 36)) values.Add("n", stringutil.Random(64)) payload := values.Encode() p, err := se.EncryptSign([]byte(payload)) if err != nil { panic(err) } abs := ctx.URL() reset := fmt.Sprintf("%s://%s%s?p=%s", abs.Scheme, abs.Host, ctx.MustReverse(ResetHandlerName), p) data := map[string]interface{}{ "URL": reset, } from := mail.DefaultFrom() if from == "" { from = fmt.Sprintf("no-reply@%s", abs.Host) } msg := &mail.Message{ To: user.Email, From: from, Subject: fmt.Sprintf(ctx.T("Reset your %s password"), d.opts.SiteName), } ctx.MustSendMail("reset_password.txt", data, msg) sent = true } data := map[string]interface{}{ "ForgotForm": f, "IsEmail": isEmail, "Sent": sent, "User": user, } ctx.MustExecute(ForgotTemplateName, data) }
func SourceHandler(ctx *app.Context) { dctx := doc.GetEnvironment(ctx.App()) rel := ctx.IndexValue(0) p := dctx.FromSlash(rel) pDir := dctx.Dir(p) if pDir == "." { pDir = p } else { } dir := packageDir(dctx, pDir) filePath := dir if pDir+dctx.Separator != p && pDir != p { filePath = dctx.Join(dir, dctx.Base(p)) } log.Debugf("Loading source from %s", filePath) var breadcrumbs []*breadcrumb for ii := 0; ii < len(rel); { var end int slash := strings.IndexByte(rel[ii:], '/') if slash < 0 { end = len(rel) } else { end = ii + slash } breadcrumbs = append(breadcrumbs, &breadcrumb{ Title: rel[ii:end], Href: ctx.MustReverse(SourceHandlerName, rel[:end]), }) ii = end + 1 } var tmpl string var title string var files []string var code template.HTML var lines []int if dctx.IsDir(filePath) { if rel != "" && rel[len(rel)-1] != '/' { ctx.MustRedirectReverse(true, SourceHandlerName, rel+"/") return } contents, err := dctx.ReadDir(filePath) if err != nil { panic(err) } for _, v := range contents { if n := v.Name(); len(n) > 0 && n[0] != '.' { files = append(files, n) } } title = "Directory " + dctx.Base(rel) tmpl = "dir.html" } else { f, err := dctx.OpenFile(filePath) if err != nil { ctx.NotFound("File not found") return } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { panic(err) } contentType := http.DetectContentType(contents) if !strings.HasPrefix(contentType, "text") { ctx.Header().Set("Content-Type", contentType) switch contentType { case "image/gif", "image/png", "image/jpeg": default: ctx.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s;", dctx.Base(rel))) } ctx.Write(contents) return } title = "File " + dctx.Base(rel) var buf bytes.Buffer buf.WriteString("<span id=\"line-1\">") last := 0 line := 1 for ii, v := range contents { if v == '\n' { buf.WriteString(html.Escape(string(contents[last:ii]))) lines = append(lines, line) last = ii line++ buf.WriteString(fmt.Sprintf("</span><span id=\"line-%d\">", line)) } } buf.Write(contents[last:]) buf.WriteString("</span>") code = template.HTML(buf.String()) tmpl = "source.html" } data := map[string]interface{}{ "Title": rel, "Header": title, "Breadcrumbs": breadcrumbs, "Files": files, "Code": code, "Lines": lines, "Padding": math.Ceil(math.Log10(float64(len(lines)+1))) + 0.1, "Highlighter": highlighters[path.Ext(rel)], } ctx.MustExecute(tmpl, data) }