add error codes

This commit is contained in:
Umputun
2019-02-10 17:47:58 -06:00
parent 08ab725b3d
commit 70ef130976
9 changed files with 118 additions and 72 deletions
+15 -14
View File
@@ -55,7 +55,7 @@ func (a *admin) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
err := a.dataService.Delete(locator, id, store.SoftDelete)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete comment")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete comment", rest.ErrInternal)
return
}
a.cache.Flush(cache.Flusher(locator.SiteID).Scopes(locator.SiteID, locator.URL, lastCommentsScope))
@@ -71,7 +71,7 @@ func (a *admin) deleteUserCtrl(w http.ResponseWriter, r *http.Request) {
log.Printf("[INFO] delete all user comments for %s, site %s", userID, siteID)
if err := a.dataService.DeleteUser(siteID, userID); err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete user")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete user", rest.ErrInternal)
return
}
a.cache.Flush(cache.Flusher(siteID).Scopes(userID, siteID, lastCommentsScope))
@@ -88,7 +88,7 @@ func (a *admin) getUserInfoCtrl(w http.ResponseWriter, r *http.Request) {
ucomments, err := a.dataService.User(siteID, userID, 1, 0)
if err != nil || len(ucomments) == 0 {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get user info")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get user info", rest.ErrInternal)
return
}
render.Status(r, http.StatusOK)
@@ -103,7 +103,7 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
claims, err := a.authenticator.TokenService().Parse(token)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't process token")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't process token", rest.ErrActionRejected)
return
}
@@ -111,19 +111,19 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
// deleteme set by deleteMeCtrl, this check just to make sure we not trying to delete with leaked token
if !claims.User.BoolAttr("delete_me") {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("forbidden"), "can't use provided token")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("forbidden"), "can't use provided token", rest.ErrNoAccess)
return
}
if err := a.dataService.DeleteUser(claims.Audience, claims.User.ID); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user", rest.ErrNoAccess)
return
}
if claims.User.Picture != "" && a.authenticator.AvatarProxy() != nil {
avatartStore := a.authenticator.AvatarProxy().Store
if err := avatartStore.Remove(path.Base(claims.User.Picture)); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user's avatar")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user's avatar", rest.ErrInternal)
return
}
}
@@ -147,7 +147,7 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) {
}
if err := a.dataService.SetBlock(siteID, userID, blockStatus, ttl); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set blocking status")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set blocking status", rest.ErrActionRejected)
return
}
a.cache.Flush(cache.Flusher(siteID).Scopes(userID, siteID, lastCommentsScope))
@@ -159,7 +159,7 @@ func (a *admin) blockedUsersCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
users, err := a.dataService.Blocked(siteID)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get blocked users")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get blocked users", rest.ErrSiteNotFound)
return
}
render.JSON(w, r, users)
@@ -178,13 +178,14 @@ func (a *admin) setReadOnlyCtrl(w http.ResponseWriter, r *http.Request) {
// don't allow to reset ro for posts turned to ro by ReadOnlyAge
if !roStatus {
if info, e := a.dataService.Info(locator, a.readOnlyAge); e == nil && isRoByAge(info) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "read-only due the age")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"),
"read-only due the age", rest.ErrActionRejected)
return
}
}
if err := a.dataService.SetReadOnly(locator, roStatus); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set readonly status")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set readonly status", rest.ErrPostNotFound)
return
}
a.cache.Flush(cache.Flusher(locator.SiteID).Scopes(locator.URL, locator.SiteID))
@@ -198,7 +199,7 @@ func (a *admin) setTitleCtrl(w http.ResponseWriter, r *http.Request) {
c, err := a.dataService.SetTitle(locator, id)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't set title")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't set title", rest.ErrInternal)
return
}
log.Printf("[INFO] set comment's title %s to %q", id, c.PostTitle)
@@ -215,7 +216,7 @@ func (a *admin) setVerifyCtrl(w http.ResponseWriter, r *http.Request) {
verifyStatus := r.URL.Query().Get("verified") == "1"
if err := a.dataService.SetVerified(siteID, userID, verifyStatus); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set verify status")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set verify status", rest.ErrActionRejected)
return
}
a.cache.Flush(cache.Flusher(siteID).Scopes(siteID, userID))
@@ -230,7 +231,7 @@ func (a *admin) setPinCtrl(w http.ResponseWriter, r *http.Request) {
pinStatus := r.URL.Query().Get("pin") == "1"
if err := a.dataService.SetPin(locator, commentID, pinStatus); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set pin status")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set pin status", rest.ErrActionRejected)
return
}
a.cache.Flush(cache.Flusher(locator.SiteID).Scopes(locator.URL))
+9 -7
View File
@@ -56,13 +56,14 @@ func (m *Migrator) importCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
if m.isBusy(siteID) {
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"), "import rejected")
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"),
"import rejected", rest.ErrActionRejected)
return
}
tmpfile, err := m.saveTemp(r.Body)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save request to temp file")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save request to temp file", rest.ErrInternal)
return
}
@@ -78,25 +79,26 @@ func (m *Migrator) importFormCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
if m.isBusy(siteID) {
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"), "import rejected")
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"),
"import rejected", rest.ErrActionRejected)
return
}
if err := r.ParseMultipartForm(20 * 1024 * 1024); err != nil { // 20M max memory, if bigger will make a file
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't parse multipart form")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't parse multipart form", rest.ErrDecode)
return
}
file, _, err := r.FormFile("file")
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get import from the request")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get import file from the request", rest.ErrInternal)
return
}
defer func() { _ = file.Close() }()
tmpfile, err := m.saveTemp(file)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save request to temp file")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save request to temp file", rest.ErrInternal)
return
}
@@ -155,7 +157,7 @@ func (m *Migrator) exportCtrl(w http.ResponseWriter, r *http.Request) {
}
if _, err := m.NativeExporter.Export(writer, siteID); err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "export failed")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "export failed", rest.ErrInternal)
return
}
}
+39 -20
View File
@@ -28,7 +28,7 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
comment := store.Comment{}
if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment", rest.ErrDecode)
return
}
@@ -40,36 +40,36 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
comment.Orig = comment.Text // original comment text, prior to md render
if err := s.DataService.ValidateComment(&comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment", rest.ErrCommentValidation)
return
}
comment = s.CommentFormatter.Format(comment)
// check if user blocked
if s.adminService.checkBlocked(comment.Locator.SiteID, comment.User) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked", rest.ErrUserBlocked)
return
}
if s.isReadOnly(comment.Locator) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only", rest.ErrReadOnly)
return
}
id, err := s.DataService.Create(comment)
if err == service.ErrRestrictedWordsFound {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment", rest.ErrCommentValidation)
return
}
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save comment")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't save comment", rest.ErrInternal)
return
}
// DataService modifies comment
finalComment, err := s.DataService.Get(comment.Locator, id)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't load created comment")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't load created comment", rest.ErrInternal)
return
}
s.Cache.Flush(cache.Flusher(comment.Locator.SiteID).
@@ -95,7 +95,7 @@ func (s *Rest) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
}{}
if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &edit); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment", rest.ErrDecode)
return
}
@@ -108,12 +108,13 @@ func (s *Rest) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
var currComment store.Comment
var err error
if currComment, err = s.DataService.Get(locator, id); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comment", rest.ErrCommentNotFound)
return
}
if currComment.User.ID != user.ID {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "can not edit comments for other users")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"),
"can not edit comments for other users", rest.ErrNoAccess)
return
}
@@ -126,11 +127,18 @@ func (s *Rest) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
res, err := s.DataService.EditComment(locator, id, editReq)
if err == service.ErrRestrictedWordsFound {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment", rest.ErrCommentValidation)
return
}
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't update comment")
code := rest.ErrCommentRejected
switch {
case strings.HasPrefix(err.Error(), "too late to edit"):
code = rest.ErrCommentEditExpired
case strings.HasPrefix(err.Error(), "parent comment with reply can't be edited"):
code = rest.ErrCommentEditChanged
}
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't update comment", code)
return
}
@@ -158,19 +166,30 @@ func (s *Rest) voteCtrl(w http.ResponseWriter, r *http.Request) {
vote := r.URL.Query().Get("vote") == "1"
if s.isReadOnly(locator) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only", rest.ErrReadOnly)
return
}
// check if user blocked
if s.adminService.checkBlocked(locator.SiteID, user) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked")
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked", rest.ErrUserBlocked)
return
}
comment, err := s.DataService.Vote(locator, id, user.ID, vote)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't vote for comment")
code := rest.ErrVoteRejected
switch {
case strings.Contains(err.Error(), "can not vote for his own comment"):
code = rest.ErrVoteSelf
case strings.Contains(err.Error(), "already voted for"):
code = rest.ErrVoteDbl
case strings.Contains(err.Error(), "maximum number of votes exceeded for comment"):
code = rest.ErrVoteMax
case strings.Contains(err.Error(), "minimal score reached for comment"):
code = rest.ErrVoteMinScore
}
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't vote for comment", code)
return
}
s.Cache.Flush(cache.Flusher(locator.SiteID).Scopes(locator.URL, comment.User.ID))
@@ -183,7 +202,7 @@ func (s *Rest) userAllDataCtrl(w http.ResponseWriter, r *http.Request) {
user := rest.MustGetUserInfo(r)
userB, err := json.Marshal(&user)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't marshal user info")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't marshal user info", rest.ErrInternal)
return
}
@@ -211,12 +230,12 @@ func (s *Rest) userAllDataCtrl(w http.ResponseWriter, r *http.Request) {
for i := 0; i < 100; i++ {
comments, err := s.DataService.User(siteID, user.ID, 100, i*100)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get user comments")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get user comments", rest.ErrInternal)
return
}
b, err := json.Marshal(comments)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't marshal user comments")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't marshal user comments", rest.ErrInternal)
return
}
@@ -228,7 +247,7 @@ func (s *Rest) userAllDataCtrl(w http.ResponseWriter, r *http.Request) {
merr = multierror.Append(merr, write([]byte(`}`)))
if merr.(*multierror.Error).ErrorOrNil() != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, merr, "can't write user info")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, merr, "can't write user info", rest.ErrInternal)
return
}
@@ -258,7 +277,7 @@ func (s *Rest) deleteMeCtrl(w http.ResponseWriter, r *http.Request) {
tokenStr, err := s.Authenticator.TokenService().Token(claims)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't make token")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't make token", rest.ErrInternal)
return
}
+1 -1
View File
@@ -289,7 +289,7 @@ func TestRest_UpdateNotOwner(t *testing.T) {
body, err := ioutil.ReadAll(b.Body)
assert.Nil(t, err)
assert.Equal(t, 403, b.StatusCode, string(body), "update from non-owner")
assert.Equal(t, `{"details":"can not edit comments for other users","error":"rejected"}`+"\n", string(body))
assert.Equal(t, `{"code":3,"details":"can not edit comments for other users","error":"rejected"}`+"\n", string(body))
client = http.Client{}
req, err = http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id1+
+13 -13
View File
@@ -56,7 +56,7 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comments")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comments", rest.ErrCommentNotFound)
return
}
@@ -69,19 +69,19 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
func (s *Rest) previewCommentCtrl(w http.ResponseWriter, r *http.Request) {
comment := store.Comment{}
if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment", rest.ErrDecode)
return
}
user, err := rest.GetUserInfo(r)
if err != nil { // this not suppose to happen (handled by Auth), just dbl-check
rest.SendErrorJSON(w, r, http.StatusUnauthorized, err, "can't get user info")
rest.SendErrorJSON(w, r, http.StatusUnauthorized, err, "can't get user info", rest.ErrNoAccess)
return
}
comment.User = user
comment.Orig = comment.Text
if err = s.DataService.ValidateComment(&comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment", rest.ErrCommentValidation)
return
}
@@ -104,7 +104,7 @@ func (s *Rest) infoCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get post info")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get post info", rest.ErrPostNotFound)
return
}
@@ -136,7 +136,7 @@ func (s *Rest) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get last comments")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get last comments", rest.ErrInternal)
return
}
@@ -156,7 +156,7 @@ func (s *Rest) commentByIDCtrl(w http.ResponseWriter, r *http.Request) {
comment, err := s.DataService.Get(store.Locator{SiteID: siteID, URL: url}, id)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by id")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by id", rest.ErrCommentNotFound)
return
}
comment = s.adminService.alterComments([]store.Comment{comment}, r)[0]
@@ -202,7 +202,7 @@ func (s *Rest) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by user id")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by user id", rest.ErrCommentNotFound)
return
}
@@ -257,7 +257,7 @@ func (s *Rest) countCtrl(w http.ResponseWriter, r *http.Request) {
locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")}
count, err := s.DataService.Count(locator)
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get count")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get count", rest.ErrPostNotFound)
return
}
render.JSON(w, r, R.JSON{"count": count, "locator": locator})
@@ -268,7 +268,7 @@ func (s *Rest) countMultiCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
posts := []string{}
if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &posts); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get list of posts from request")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get list of posts from request", rest.ErrSiteNotFound)
return
}
@@ -276,7 +276,7 @@ func (s *Rest) countMultiCtrl(w http.ResponseWriter, r *http.Request) {
k := URLKey(r) + strings.Join(posts, ",")
hasher := sha1.New()
if _, err := hasher.Write([]byte(k)); err != nil {
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't make sha1 for list of urls")
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't make sha1 for list of urls", rest.ErrInternal)
return
}
sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
@@ -290,7 +290,7 @@ func (s *Rest) countMultiCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get counts for "+siteID)
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get counts for "+siteID, rest.ErrSiteNotFound)
return
}
@@ -322,7 +322,7 @@ func (s *Rest) listCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get list of comments for "+siteID)
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get list of comments for "+siteID, rest.ErrSiteNotFound)
return
}
+3 -3
View File
@@ -50,7 +50,7 @@ func (s *Rest) rssPostCommentsCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comments")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comments", rest.ErrPostNotFound)
return
}
@@ -83,7 +83,7 @@ func (s *Rest) rssSiteCommentsCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get last comments")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get last comments", rest.ErrSiteNotFound)
return
}
@@ -135,7 +135,7 @@ func (s *Rest) rssRepliesCtrl(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get replies")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get replies", rest.ErrSiteNotFound)
return
}
+30 -6
View File
@@ -9,16 +9,39 @@ import (
"github.com/go-chi/render"
log "github.com/go-pkgz/lgr"
"github.com/go-pkgz/rest"
)
const (
ErrInternal = 0 // any internal error
ErrCommentNotFound = 1 // can't find comment
ErrDecode = 2 // failed to unmarshal incoming request
ErrNoAccess = 3 // rejected by auth
ErrCommentValidation = 4 // validation failed
ErrPostNotFound = 5 // can't find post
ErrSiteNotFound = 6 // can't find site
ErrUserBlocked = 7 // user blocked
ErrReadOnly = 8 // write failed on read only
ErrCommentRejected = 9 // general error on rejected comment change
ErrCommentEditExpired = 10 // too late for edit
ErrCommentEditChanged = 11 // parent commend changed
ErrVoteRejected = 12 // general error on vote rejected
ErrVoteSelf = 13 // vote for own comment
ErrVoteDbl = 14 // already voted for the comment
ErrVoteMax = 15 // too many votes for the comment
ErrVoteMinScore = 16 // min score reached for the comment
ErrActionRejected = 17 // general error for rejected actions
ErrAssetNotFound = 18 // requested file not found
)
// SendErrorJSON makes {error: blah, details: blah} json body and responds with error code
func SendErrorJSON(w http.ResponseWriter, r *http.Request, code int, err error, details string) {
log.Printf("[DEBUG] %s", errDetailsMsg(r, code, err, details))
render.Status(r, code)
render.JSON(w, r, map[string]interface{}{"error": err.Error(), "details": details})
func SendErrorJSON(w http.ResponseWriter, r *http.Request, httpStatusCode int, err error, details string, errCode int) {
log.Printf("[DEBUG] %s", errDetailsMsg(r, httpStatusCode, err, details, errCode))
render.Status(r, httpStatusCode)
render.JSON(w, r, rest.JSON{"error": err.Error(), "details": details, "code": errCode})
}
func errDetailsMsg(r *http.Request, code int, err error, details string) string {
func errDetailsMsg(r *http.Request, httpStatusCode int, err error, details string, errCode int) string {
uinfoStr := ""
if user, e := GetUserInfo(r); e == nil {
uinfoStr = user.Name + "/" + user.ID + " - "
@@ -40,5 +63,6 @@ func errDetailsMsg(r *http.Request, code int, err error, details string) string
if pos := strings.Index(remoteIP, ":"); pos >= 0 {
remoteIP = remoteIP[:pos]
}
return fmt.Sprintf("%s - %v - %d - %s%s - %s%s", details, err, code, uinfoStr, remoteIP, q, srcFileInfo)
return fmt.Sprintf("%s - %v - %d (%d) - %s%s - %s%s",
details, err, httpStatusCode, errCode, uinfoStr, remoteIP, q, srcFileInfo)
}
+6 -6
View File
@@ -17,7 +17,7 @@ func TestSendErrorJSON(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/error" {
t.Log("http err request", r.URL)
SendErrorJSON(w, r, 500, errors.New("error 500"), "error details 123456")
SendErrorJSON(w, r, 500, errors.New("error 500"), "error details 123456", 123)
return
}
w.WriteHeader(404)
@@ -33,7 +33,7 @@ func TestSendErrorJSON(t *testing.T) {
require.Nil(t, err)
assert.Equal(t, 500, resp.StatusCode)
assert.Equal(t, `{"details":"error details 123456","error":"error 500"}`+"\n", string(body))
assert.Equal(t, `{"code":123,"details":"error details 123456","error":"error 500"}`+"\n", string(body))
}
func TestErrorDetailsMsg(t *testing.T) {
@@ -41,8 +41,8 @@ func TestErrorDetailsMsg(t *testing.T) {
req, err := http.NewRequest("GET", "https://example.com/test?k1=v1&k2=v2", nil)
require.Nil(t, err)
req.RemoteAddr = "1.2.3.4"
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456")
assert.Equal(t, "error details 123456 - error 500 - 500 - 1.2.3.4 - https://example.com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:47 rest.TestErrorDetailsMsg]", msg)
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456", 123)
assert.Equal(t, "error details 123456 - error 500 - 500 (123) - 1.2.3.4 - https://example.com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:47 rest.TestErrorDetailsMsg]", msg)
}
callerFn()
}
@@ -53,8 +53,8 @@ func TestErrorDetailsMsgWithUser(t *testing.T) {
req.RemoteAddr = "127.0.0.1:1234"
req = SetUserInfo(req, store.User{Name: "test", ID: "id"})
require.Nil(t, err)
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456")
assert.Equal(t, "error details 123456 - error 500 - 500 - test/id - 127.0.0.1 - https://example.com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:59 rest.TestErrorDetailsMsgWithUser]", msg)
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456", 34567)
assert.Equal(t, "error details 123456 - error 500 - 500 (34567) - test/id - 127.0.0.1 - https://example.com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:59 rest.TestErrorDetailsMsgWithUser]", msg)
}
callerFn()
}
+2 -2
View File
@@ -49,7 +49,7 @@ func (p Image) Routes() chi.Router {
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
src, err := base64.URLEncoding.DecodeString(r.URL.Query().Get("src"))
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't decode image url")
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't decode image url", rest.ErrDecode)
return
}
@@ -73,7 +73,7 @@ func (p Image) Routes() chi.Router {
return e
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get image "+string(src))
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get image "+string(src), rest.ErrAssetNotFound)
return
}
defer func() {