A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

148 lines
4.1 KiB

  1. /*
  2. * Copyright © 2018-2019 A Bunch Tell LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "database/sql"
  13. "encoding/json"
  14. "github.com/writeas/impart"
  15. "github.com/writeas/web-core/log"
  16. "net/http"
  17. )
  18. func handleWebSignup(app *App, w http.ResponseWriter, r *http.Request) error {
  19. reqJSON := IsJSON(r.Header.Get("Content-Type"))
  20. // Get params
  21. var ur userRegistration
  22. if reqJSON {
  23. decoder := json.NewDecoder(r.Body)
  24. err := decoder.Decode(&ur)
  25. if err != nil {
  26. log.Error("Couldn't parse signup JSON request: %v\n", err)
  27. return ErrBadJSON
  28. }
  29. } else {
  30. err := r.ParseForm()
  31. if err != nil {
  32. log.Error("Couldn't parse signup form request: %v\n", err)
  33. return ErrBadFormData
  34. }
  35. err = app.formDecoder.Decode(&ur, r.PostForm)
  36. if err != nil {
  37. log.Error("Couldn't decode signup form request: %v\n", err)
  38. return ErrBadFormData
  39. }
  40. }
  41. ur.Web = true
  42. ur.Normalize = true
  43. to := "/"
  44. if app.cfg.App.SimpleNav {
  45. to = "/new"
  46. }
  47. if ur.InviteCode != "" {
  48. to = "/invite/" + ur.InviteCode
  49. }
  50. _, err := signupWithRegistration(app, ur, w, r)
  51. if err != nil {
  52. if err, ok := err.(impart.HTTPError); ok {
  53. session, _ := app.sessionStore.Get(r, cookieName)
  54. if session != nil {
  55. session.AddFlash(err.Message)
  56. session.Save(r, w)
  57. return impart.HTTPError{http.StatusFound, to}
  58. }
  59. }
  60. return err
  61. }
  62. return impart.HTTPError{http.StatusFound, to}
  63. }
  64. // { "username": "asdf" }
  65. // result: { code: 204 }
  66. func handleUsernameCheck(app *App, w http.ResponseWriter, r *http.Request) error {
  67. reqJSON := IsJSON(r.Header.Get("Content-Type"))
  68. // Get params
  69. var d struct {
  70. Username string `json:"username"`
  71. }
  72. if reqJSON {
  73. decoder := json.NewDecoder(r.Body)
  74. err := decoder.Decode(&d)
  75. if err != nil {
  76. log.Error("Couldn't decode username check: %v\n", err)
  77. return ErrBadFormData
  78. }
  79. } else {
  80. return impart.HTTPError{http.StatusNotAcceptable, "Must be JSON request"}
  81. }
  82. // Check if username is okay
  83. finalUsername := getSlug(d.Username, "")
  84. if finalUsername == "" {
  85. errMsg := "Invalid username"
  86. if d.Username != "" {
  87. // Username was provided, but didn't convert into valid latin characters
  88. errMsg += " - must have at least 2 letters or numbers"
  89. }
  90. return impart.HTTPError{http.StatusBadRequest, errMsg + "."}
  91. }
  92. if app.db.PostIDExists(finalUsername) {
  93. return impart.HTTPError{http.StatusConflict, "Username is already taken."}
  94. }
  95. var un string
  96. err := app.db.QueryRow("SELECT username FROM users WHERE username = ?", finalUsername).Scan(&un)
  97. switch {
  98. case err == sql.ErrNoRows:
  99. return impart.WriteSuccess(w, finalUsername, http.StatusOK)
  100. case err != nil:
  101. log.Error("Couldn't SELECT username: %v", err)
  102. return impart.HTTPError{http.StatusInternalServerError, "We messed up."}
  103. }
  104. // Username was found, so it's taken
  105. return impart.HTTPError{http.StatusConflict, "Username is already taken."}
  106. }
  107. func getValidUsername(app *App, reqName, prevName string) (string, *impart.HTTPError) {
  108. // Check if username is okay
  109. finalUsername := getSlug(reqName, "")
  110. if finalUsername == "" {
  111. errMsg := "Invalid username"
  112. if reqName != "" {
  113. // Username was provided, but didn't convert into valid latin characters
  114. errMsg += " - must have at least 2 letters or numbers"
  115. }
  116. return "", &impart.HTTPError{http.StatusBadRequest, errMsg + "."}
  117. }
  118. if finalUsername == prevName {
  119. return "", &impart.HTTPError{http.StatusNotModified, "Username unchanged."}
  120. }
  121. if app.db.PostIDExists(finalUsername) {
  122. return "", &impart.HTTPError{http.StatusConflict, "Username is already taken."}
  123. }
  124. var un string
  125. err := app.db.QueryRow("SELECT username FROM users WHERE username = ?", finalUsername).Scan(&un)
  126. switch {
  127. case err == sql.ErrNoRows:
  128. return finalUsername, nil
  129. case err != nil:
  130. log.Error("Couldn't SELECT username: %v", err)
  131. return "", &impart.HTTPError{http.StatusInternalServerError, "We messed up."}
  132. }
  133. // Username was found, so it's taken
  134. return "", &impart.HTTPError{http.StatusConflict, "Username is already taken."}
  135. }