mirror of
https://github.com/writefreely/writefreely
synced 2024-11-24 09:33:11 +00:00
Add collection handlers, routes, feeds, sitemaps
This commit is contained in:
parent
af872127c6
commit
ebeacff43c
10 changed files with 1502 additions and 34 deletions
1036
collections.go
1036
collections.go
File diff suppressed because it is too large
Load diff
114
export.go
Normal file
114
export.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
package writefreely
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"github.com/writeas/web-core/log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func exportPostsCSV(u *User, posts *[]PublicPost) []byte {
|
||||
var b bytes.Buffer
|
||||
|
||||
r := [][]string{
|
||||
{"id", "slug", "blog", "url", "created", "title", "body"},
|
||||
}
|
||||
for _, p := range *posts {
|
||||
var blog string
|
||||
if p.Collection != nil {
|
||||
blog = p.Collection.Alias
|
||||
}
|
||||
f := []string{p.ID, p.Slug.String, blog, p.CanonicalURL(), p.Created8601(), p.Title.String, strings.Replace(p.Content, "\n", "\\n", -1)}
|
||||
r = append(r, f)
|
||||
}
|
||||
|
||||
w := csv.NewWriter(&b)
|
||||
w.WriteAll(r) // calls Flush internally
|
||||
if err := w.Error(); err != nil {
|
||||
log.Info("error writing csv:", err)
|
||||
}
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
type exportedTxt struct {
|
||||
Name, Body string
|
||||
Mod time.Time
|
||||
}
|
||||
|
||||
func exportPostsZip(u *User, posts *[]PublicPost) []byte {
|
||||
// Create a buffer to write our archive to.
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
// Create a new zip archive.
|
||||
w := zip.NewWriter(b)
|
||||
|
||||
// Add some files to the archive.
|
||||
var filename string
|
||||
files := []exportedTxt{}
|
||||
for _, p := range *posts {
|
||||
filename = ""
|
||||
if p.Collection != nil {
|
||||
filename += p.Collection.Alias + "/"
|
||||
}
|
||||
if p.Slug.String != "" {
|
||||
filename += p.Slug.String + "_"
|
||||
}
|
||||
filename += p.ID + ".txt"
|
||||
files = append(files, exportedTxt{filename, p.Content, p.Created})
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
head := &zip.FileHeader{Name: file.Name}
|
||||
head.SetModTime(file.Mod)
|
||||
f, err := w.CreateHeader(head)
|
||||
if err != nil {
|
||||
log.Error("export zip header: %v", err)
|
||||
}
|
||||
_, err = f.Write([]byte(file.Body))
|
||||
if err != nil {
|
||||
log.Error("export zip write: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to check the error on Close.
|
||||
err := w.Close()
|
||||
if err != nil {
|
||||
log.Error("export zip close: %v", err)
|
||||
}
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func compileFullExport(app *app, u *User) *ExportUser {
|
||||
exportUser := &ExportUser{
|
||||
User: u,
|
||||
}
|
||||
|
||||
colls, err := app.db.GetCollections(u)
|
||||
if err != nil {
|
||||
log.Error("unable to fetch collections: %v", err)
|
||||
}
|
||||
|
||||
posts, err := app.db.GetAnonymousPosts(u)
|
||||
if err != nil {
|
||||
log.Error("unable to fetch anon posts: %v", err)
|
||||
}
|
||||
exportUser.AnonymousPosts = *posts
|
||||
|
||||
var collObjs []CollectionObj
|
||||
for _, c := range *colls {
|
||||
co := &CollectionObj{Collection: c}
|
||||
co.Posts, err = app.db.GetPosts(&c, 0, true)
|
||||
if err != nil {
|
||||
log.Error("unable to get collection posts: %v", err)
|
||||
}
|
||||
app.db.GetPostsCount(co, true)
|
||||
collObjs = append(collObjs, *co)
|
||||
}
|
||||
exportUser.Collections = &collObjs
|
||||
|
||||
return exportUser
|
||||
}
|
100
feed.go
Normal file
100
feed.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package writefreely
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/gorilla/feeds"
|
||||
"github.com/gorilla/mux"
|
||||
stripmd "github.com/writeas/go-strip-markdown"
|
||||
"github.com/writeas/web-core/log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ViewFeed(app *app, w http.ResponseWriter, req *http.Request) error {
|
||||
alias := collectionAliasFromReq(req)
|
||||
|
||||
// Display collection if this is a collection
|
||||
var c *Collection
|
||||
var err error
|
||||
if app.cfg.App.SingleUser {
|
||||
c, err = app.db.GetCollection(alias)
|
||||
} else {
|
||||
c, err = app.db.GetCollectionByID(1)
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.IsPrivate() || c.IsProtected() {
|
||||
return ErrCollectionNotFound
|
||||
}
|
||||
|
||||
// Fetch extra data about the Collection
|
||||
// TODO: refactor out this logic, shared in collection.go:fetchCollection()
|
||||
coll := &DisplayCollection{CollectionObj: &CollectionObj{Collection: *c}}
|
||||
if c.PublicOwner {
|
||||
u, err := app.db.GetUserByID(coll.OwnerID)
|
||||
if err != nil {
|
||||
// Log the error and just continue
|
||||
log.Error("Error getting user for collection: %v", err)
|
||||
} else {
|
||||
coll.Owner = u
|
||||
}
|
||||
}
|
||||
|
||||
tag := mux.Vars(req)["tag"]
|
||||
if tag != "" {
|
||||
coll.Posts, _ = app.db.GetPostsTagged(c, tag, 1, false)
|
||||
} else {
|
||||
coll.Posts, _ = app.db.GetPosts(c, 1, false)
|
||||
}
|
||||
|
||||
author := ""
|
||||
if coll.Owner != nil {
|
||||
author = coll.Owner.Username
|
||||
}
|
||||
|
||||
collectionTitle := coll.DisplayTitle()
|
||||
if tag != "" {
|
||||
collectionTitle = tag + " — " + collectionTitle
|
||||
}
|
||||
|
||||
baseUrl := coll.CanonicalURL()
|
||||
basePermalinkUrl := baseUrl
|
||||
siteURL := baseUrl
|
||||
if tag != "" {
|
||||
siteURL += "tag:" + tag
|
||||
}
|
||||
|
||||
feed := &Feed{
|
||||
Title: collectionTitle,
|
||||
Link: &Link{Href: siteURL},
|
||||
Description: coll.Description,
|
||||
Author: &Author{author, ""},
|
||||
Created: time.Now(),
|
||||
}
|
||||
|
||||
var title, permalink string
|
||||
for _, p := range *coll.Posts {
|
||||
title = p.PlainDisplayTitle()
|
||||
permalink = fmt.Sprintf("%s%s", baseUrl, p.Slug.String)
|
||||
feed.Items = append(feed.Items, &Item{
|
||||
Id: fmt.Sprintf("%s%s", basePermalinkUrl, p.Slug.String),
|
||||
Title: title,
|
||||
Link: &Link{Href: permalink},
|
||||
Description: "<![CDATA[" + stripmd.Strip(p.Content) + "]]>",
|
||||
Content: applyMarkdown([]byte(p.Content)),
|
||||
Author: &Author{author, ""},
|
||||
Created: p.Created,
|
||||
Updated: p.Updated,
|
||||
})
|
||||
}
|
||||
|
||||
rss, err := feed.ToRss()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprint(w, rss)
|
||||
return nil
|
||||
}
|
8
request.go
Normal file
8
request.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package writefreely
|
||||
|
||||
import "mime"
|
||||
|
||||
func IsJSON(h string) bool {
|
||||
ct, _, _ := mime.ParseMediaType(h)
|
||||
return ct == "application/json"
|
||||
}
|
59
routes.go
59
routes.go
|
@ -35,6 +35,48 @@ func initRoutes(handler *Handler, r *mux.Router, cfg *config.Config, db *datasto
|
|||
write.HandleFunc(nodeinfo.NodeInfoPath, handler.LogHandlerFunc(http.HandlerFunc(ni.NodeInfoDiscover)))
|
||||
write.HandleFunc(niCfg.InfoURL, handler.LogHandlerFunc(http.HandlerFunc(ni.NodeInfo)))
|
||||
|
||||
// Handle logged in user sections
|
||||
me := write.PathPrefix("/me").Subrouter()
|
||||
me.HandleFunc("/", handler.Redirect("/me", UserLevelUser))
|
||||
me.HandleFunc("/c", handler.Redirect("/me/c/", UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/c/", handler.User(viewCollections)).Methods("GET")
|
||||
me.HandleFunc("/c/{collection}", handler.User(viewEditCollection)).Methods("GET")
|
||||
me.HandleFunc("/c/{collection}/stats", handler.User(viewStats)).Methods("GET")
|
||||
me.HandleFunc("/posts", handler.Redirect("/me/posts/", UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/posts/", handler.User(viewArticles)).Methods("GET")
|
||||
me.HandleFunc("/posts/export.csv", handler.Download(viewExportPosts, UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/posts/export.zip", handler.Download(viewExportPosts, UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/posts/export.json", handler.Download(viewExportPosts, UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/export", handler.User(viewExportOptions)).Methods("GET")
|
||||
me.HandleFunc("/export.json", handler.Download(viewExportFull, UserLevelUser)).Methods("GET")
|
||||
me.HandleFunc("/settings", handler.User(viewSettings)).Methods("GET")
|
||||
me.HandleFunc("/logout", handler.Web(viewLogout, UserLevelNone)).Methods("GET")
|
||||
|
||||
write.HandleFunc("/api/me", handler.All(viewMeAPI)).Methods("GET")
|
||||
apiMe := write.PathPrefix("/api/me/").Subrouter()
|
||||
apiMe.HandleFunc("/", handler.All(viewMeAPI)).Methods("GET")
|
||||
apiMe.HandleFunc("/posts", handler.UserAPI(viewMyPostsAPI)).Methods("GET")
|
||||
apiMe.HandleFunc("/collections", handler.UserAPI(viewMyCollectionsAPI)).Methods("GET")
|
||||
apiMe.HandleFunc("/password", handler.All(updatePassphrase)).Methods("POST")
|
||||
apiMe.HandleFunc("/self", handler.All(updateSettings)).Methods("POST")
|
||||
|
||||
// Sign up validation
|
||||
write.HandleFunc("/api/alias", handler.All(handleUsernameCheck)).Methods("POST")
|
||||
|
||||
// Handle collections
|
||||
write.HandleFunc("/api/collections", handler.All(newCollection)).Methods("POST")
|
||||
apiColls := write.PathPrefix("/api/collections/").Subrouter()
|
||||
apiColls.HandleFunc("/{alias:[0-9a-zA-Z\\-]+}", handler.All(fetchCollection)).Methods("GET")
|
||||
apiColls.HandleFunc("/{alias:[0-9a-zA-Z\\-]+}", handler.All(existingCollection)).Methods("POST", "DELETE")
|
||||
apiColls.HandleFunc("/{alias}/posts", handler.All(fetchCollectionPosts)).Methods("GET")
|
||||
apiColls.HandleFunc("/{alias}/posts", handler.All(newPost)).Methods("POST")
|
||||
apiColls.HandleFunc("/{alias}/posts/{post}", handler.All(fetchPost)).Methods("GET")
|
||||
apiColls.HandleFunc("/{alias}/posts/{post:[a-zA-Z0-9]{10}}", handler.All(existingPost)).Methods("POST")
|
||||
apiColls.HandleFunc("/{alias}/posts/{post}/{property}", handler.All(fetchPostProperty)).Methods("GET")
|
||||
apiColls.HandleFunc("/{alias}/collect", handler.All(addPost)).Methods("POST")
|
||||
apiColls.HandleFunc("/{alias}/pin", handler.All(pinPost)).Methods("POST")
|
||||
apiColls.HandleFunc("/{alias}/unpin", handler.All(pinPost)).Methods("POST")
|
||||
|
||||
// Handle posts
|
||||
write.HandleFunc("/api/posts", handler.All(newPost)).Methods("POST")
|
||||
posts := write.PathPrefix("/api/posts/").Subrouter()
|
||||
|
@ -56,9 +98,26 @@ func initRoutes(handler *Handler, r *mux.Router, cfg *config.Config, db *datasto
|
|||
write.HandleFunc("/{action}/meta", handler.Web(handleViewMeta, UserLevelOptional)).Methods("GET")
|
||||
// Collections
|
||||
if cfg.App.SingleUser {
|
||||
RouteCollections(handler, write.PathPrefix("/").Subrouter())
|
||||
} else {
|
||||
write.HandleFunc("/{prefix:[@~$!\\-+]}{collection}", handler.Web(handleViewCollection, UserLevelOptional))
|
||||
write.HandleFunc("/{collection}/", handler.Web(handleViewCollection, UserLevelOptional))
|
||||
RouteCollections(handler, write.PathPrefix("/{prefix:[@~$!\\-+]?}{collection}").Subrouter())
|
||||
// Posts
|
||||
write.HandleFunc("/{post}", handler.Web(handleViewPost, UserLevelOptional))
|
||||
}
|
||||
write.HandleFunc("/", handler.Web(handleViewHome, UserLevelOptional))
|
||||
}
|
||||
|
||||
func RouteCollections(handler *Handler, r *mux.Router) {
|
||||
r.HandleFunc("/page/{page:[0-9]+}", handler.Web(handleViewCollection, UserLevelOptional))
|
||||
r.HandleFunc("/tag:{tag}", handler.Web(handleViewCollectionTag, UserLevelOptional))
|
||||
r.HandleFunc("/tag:{tag}/feed/", handler.Web(ViewFeed, UserLevelOptional))
|
||||
r.HandleFunc("/tags/{tag}", handler.Web(handleViewCollectionTag, UserLevelOptional))
|
||||
r.HandleFunc("/sitemap.xml", handler.All(handleViewSitemap))
|
||||
r.HandleFunc("/feed/", handler.All(ViewFeed))
|
||||
r.HandleFunc("/{slug}", handler.Web(viewCollectionPost, UserLevelOptional))
|
||||
r.HandleFunc("/{slug}/edit", handler.Web(handleViewPad, UserLevelUser))
|
||||
r.HandleFunc("/{slug}/edit/meta", handler.Web(handleViewMeta, UserLevelUser))
|
||||
r.HandleFunc("/{slug}/", handler.Web(handleCollectionPostRedirect, UserLevelOptional)).Methods("GET")
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ const (
|
|||
sessionLength = 180 * day
|
||||
cookieName = "wfu"
|
||||
cookieUserVal = "u"
|
||||
|
||||
blogPassCookieName = "ub"
|
||||
)
|
||||
|
||||
// initSession creates the cookie store. It depends on the keychain already
|
||||
|
|
94
sitemap.go
Normal file
94
sitemap.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package writefreely
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/ikeikeikeike/go-sitemap-generator/stm"
|
||||
"github.com/writeas/web-core/log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func buildSitemap(host, alias string) *stm.Sitemap {
|
||||
sm := stm.NewSitemap()
|
||||
sm.SetDefaultHost(host)
|
||||
if alias != "/" {
|
||||
sm.SetSitemapsPath(alias)
|
||||
}
|
||||
|
||||
sm.Create()
|
||||
|
||||
// Note: Do not call `sm.Finalize()` because it flushes
|
||||
// the underlying datastructure from memory to disk.
|
||||
|
||||
return sm
|
||||
}
|
||||
|
||||
func handleViewSitemap(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
// Determine canonical blog URL
|
||||
alias := vars["collection"]
|
||||
subdomain := vars["subdomain"]
|
||||
isSubdomain := subdomain != ""
|
||||
if isSubdomain {
|
||||
alias = subdomain
|
||||
}
|
||||
|
||||
host := fmt.Sprintf("%s/%s/", app.cfg.App.Host, alias)
|
||||
var c *Collection
|
||||
var err error
|
||||
pre := "/"
|
||||
if app.cfg.App.SingleUser {
|
||||
c, err = app.db.GetCollectionByID(1)
|
||||
} else {
|
||||
c, err = app.db.GetCollection(alias)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !isSubdomain {
|
||||
pre += alias + "/"
|
||||
}
|
||||
host = c.CanonicalURL()
|
||||
|
||||
sm := buildSitemap(host, pre)
|
||||
posts, err := app.db.GetPosts(c, 0, false)
|
||||
if err != nil {
|
||||
log.Error("Error getting posts: %v", err)
|
||||
return err
|
||||
}
|
||||
lastSiteMod := time.Now()
|
||||
for i, p := range *posts {
|
||||
if i == 0 {
|
||||
lastSiteMod = p.Updated
|
||||
}
|
||||
u := stm.URL{
|
||||
"loc": p.Slug.String,
|
||||
"changefreq": "weekly",
|
||||
"mobile": true,
|
||||
"lastmod": p.Updated,
|
||||
}
|
||||
if len(p.Images) > 0 {
|
||||
imgs := []stm.URL{}
|
||||
for _, i := range p.Images {
|
||||
imgs = append(imgs, stm.URL{"loc": i, "title": ""})
|
||||
}
|
||||
u["image"] = imgs
|
||||
}
|
||||
sm.Add(u)
|
||||
}
|
||||
|
||||
// Add top URL
|
||||
sm.Add(stm.URL{
|
||||
"loc": pre,
|
||||
"changefreq": "daily",
|
||||
"priority": "1.0",
|
||||
"lastmod": lastSiteMod,
|
||||
})
|
||||
|
||||
w.Write(sm.XMLContent())
|
||||
|
||||
return nil
|
||||
}
|
|
@ -89,7 +89,6 @@ function unpinPost(e, postID) {
|
|||
// Hide current page
|
||||
var $pinnedNavLink = $header.getElementsByTagName('nav')[0].querySelector('.pinned.selected');
|
||||
$pinnedNavLink.style.display = 'none';
|
||||
try { _paq.push(['trackEvent', 'Post', 'unpin', 'post']); } catch(e) {}
|
||||
};
|
||||
|
||||
var $pinBtn = $header.getElementsByClassName('unpin')[0];
|
||||
|
|
|
@ -365,7 +365,6 @@ H.getEl('set-now').on('click', function(e) {
|
|||
// whatevs
|
||||
}
|
||||
</script>
|
||||
<noscript><p><img src="https://analytics.write.as/piwik.php?idsite=1" style="border:0;" alt="" /></p></noscript>
|
||||
<link href="/css/icons.css" rel="stylesheet">
|
||||
</body>
|
||||
</html>{{end}}
|
||||
|
|
121
unregisteredusers.go
Normal file
121
unregisteredusers.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package writefreely
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"github.com/writeas/impart"
|
||||
"github.com/writeas/web-core/log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func handleWebSignup(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
reqJSON := IsJSON(r.Header.Get("Content-Type"))
|
||||
|
||||
// Get params
|
||||
var ur userRegistration
|
||||
if reqJSON {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&ur)
|
||||
if err != nil {
|
||||
log.Error("Couldn't parse signup JSON request: %v\n", err)
|
||||
return ErrBadJSON
|
||||
}
|
||||
} else {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Error("Couldn't parse signup form request: %v\n", err)
|
||||
return ErrBadFormData
|
||||
}
|
||||
|
||||
err = app.formDecoder.Decode(&ur, r.PostForm)
|
||||
if err != nil {
|
||||
log.Error("Couldn't decode signup form request: %v\n", err)
|
||||
return ErrBadFormData
|
||||
}
|
||||
}
|
||||
ur.Web = true
|
||||
|
||||
_, err := signupWithRegistration(app, ur, w, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return impart.HTTPError{http.StatusFound, "/"}
|
||||
}
|
||||
|
||||
// { "username": "asdf" }
|
||||
// result: { code: 204 }
|
||||
func handleUsernameCheck(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
reqJSON := IsJSON(r.Header.Get("Content-Type"))
|
||||
|
||||
// Get params
|
||||
var d struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
if reqJSON {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&d)
|
||||
if err != nil {
|
||||
log.Error("Couldn't decode username check: %v\n", err)
|
||||
return ErrBadFormData
|
||||
}
|
||||
} else {
|
||||
return impart.HTTPError{http.StatusNotAcceptable, "Must be JSON request"}
|
||||
}
|
||||
|
||||
// Check if username is okay
|
||||
finalUsername := getSlug(d.Username, "")
|
||||
if finalUsername == "" {
|
||||
errMsg := "Invalid username"
|
||||
if d.Username != "" {
|
||||
// Username was provided, but didn't convert into valid latin characters
|
||||
errMsg += " - must have at least 2 letters or numbers"
|
||||
}
|
||||
return impart.HTTPError{http.StatusBadRequest, errMsg + "."}
|
||||
}
|
||||
if app.db.PostIDExists(finalUsername) {
|
||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||
}
|
||||
var un string
|
||||
err := app.db.QueryRow("SELECT username FROM users WHERE username = ?", finalUsername).Scan(&un)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return impart.WriteSuccess(w, finalUsername, http.StatusOK)
|
||||
case err != nil:
|
||||
log.Error("Couldn't SELECT username: %v", err)
|
||||
return impart.HTTPError{http.StatusInternalServerError, "We messed up."}
|
||||
}
|
||||
|
||||
// Username was found, so it's taken
|
||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||
}
|
||||
|
||||
func getValidUsername(app *app, reqName, prevName string) (string, *impart.HTTPError) {
|
||||
// Check if username is okay
|
||||
finalUsername := getSlug(reqName, "")
|
||||
if finalUsername == "" {
|
||||
errMsg := "Invalid username"
|
||||
if reqName != "" {
|
||||
// Username was provided, but didn't convert into valid latin characters
|
||||
errMsg += " - must have at least 2 letters or numbers"
|
||||
}
|
||||
return "", &impart.HTTPError{http.StatusBadRequest, errMsg + "."}
|
||||
}
|
||||
if finalUsername == prevName {
|
||||
return "", &impart.HTTPError{http.StatusNotModified, "Username unchanged."}
|
||||
}
|
||||
if app.db.PostIDExists(finalUsername) {
|
||||
return "", &impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||
}
|
||||
var un string
|
||||
err := app.db.QueryRow("SELECT username FROM users WHERE username = ?", finalUsername).Scan(&un)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return finalUsername, nil
|
||||
case err != nil:
|
||||
log.Error("Couldn't SELECT username: %v", err)
|
||||
return "", &impart.HTTPError{http.StatusInternalServerError, "We messed up."}
|
||||
}
|
||||
|
||||
// Username was found, so it's taken
|
||||
return "", &impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||
}
|
Loading…
Reference in a new issue