Commit ea43034f authored by Lukas Matt's avatar Lukas Matt

Refactor Dispatcher/Receiver jobs

* Add reshare call for post entity
* Add delete post/reshare call
* Add delete comment call
* Add delete like call

related to ganggo/ganggo@4383093ce34acb5335081ecbfdacbc53d3b83525
parent 5bdcda5c
......@@ -31,6 +31,9 @@ const (
ERR_PASSWORD = "Password did not match"
ERR_UNAUTHORIZED = "You are not authenticated"
ERR_SERVER = "Internal server error"
ERR_USER_NOT_FOUND = "User not found"
ERR_POST_NOT_FOUND = "Post not found"
ERR_BAD_REQUEST = "Bad request"
ERR_NOT_FOUND = "Not found"
ERR_NOT_IMPLEMENTED = "Not implemented"
)
......
......@@ -22,6 +22,8 @@ import (
"gopkg.in/ganggo/ganggo.v0/app/models"
"gopkg.in/ganggo/ganggo.v0/app/jobs"
"gopkg.in/ganggo/api.v0/app/helpers"
// XXX only for uuid
uuid "gopkg.in/ganggo/ganggo.v0/app/helpers"
federation "gopkg.in/ganggo/federation.v0"
"strconv"
"net/http"
......@@ -209,16 +211,16 @@ func (c ApiComment) IndexPost() revel.Result {
*/
func (c ApiComment) CreatePost() revel.Result {
var (
comment, fields string
text, fields string
postID uint
post models.Post
)
c.Params.Bind(&comment, "comment")
c.Params.Bind(&text, "comment")
c.Params.Bind(&fields, "fields")
c.Params.Bind(&postID, "id")
if helpers.EmptyString(comment) {
if helpers.EmptyString(text) {
c.Log.Error(TAG, "api", ERR_EMPTY_STRING)
return c.ApiError(http.StatusBadRequest, ERR_EMPTY_STRING)
}
......@@ -228,20 +230,111 @@ func (c ApiComment) CreatePost() revel.Result {
return c.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
guid, err := uuid.Uuid()
if err != nil {
c.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return c.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
entityComment := federation.EntityComment{
Author: c.CurrentUser.Person.Author,
Guid: guid,
ParentGuid: post.Guid,
Text: text,
}
var comment models.Comment
err = comment.Create(&entityComment)
if err != nil {
c.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return c.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
entityComment.CreatedAt = federation.Time{
Time: comment.CreatedAt,
}
dispatcher := jobs.Dispatcher{
User: c.CurrentUser,
ParentPerson: &post.Person,
Message: federation.EntityComment{
ParentGuid: post.Guid,
Text: comment,
},
Model: comment,
Message: entityComment,
}
// XXX
// notify local user about a new comment
//go like.TriggerNotification(parentUser)
// deliver to the network
go dispatcher.Run()
// XXX that should return the comment
return c.RenderJSON(post)
return c.RenderJSON(comment)
}
func (c ApiComment) Delete() revel.Result {
return c.NotFound("Not implemented yet")
/**
* @api {delete} /comments/:guid Delete a comment
* @apiName ApiComment.Delete
* @apiGroup Comments
*
* @apiParam {String} access_token Oauth access token
* @apiParam {String} guid Unique global ID
*
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {}
*
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 BadRequest
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "[...]"
* }
*
*/
func (c ApiComment) Delete(guid string) revel.Result {
var comment models.Comment
commentID, err := strconv.ParseUint(guid, 10, 32);
if err == nil {
err = comment.FindByUserAndID(c.CurrentUser, uint(commentID))
} else {
err = comment.FindByUserAndGuid(c.CurrentUser, guid)
}
if err != nil {
c.Log.Error(TAG, "db", err, "api", ERR_POST_NOT_FOUND)
return c.ApiError(http.StatusNotFound, ERR_POST_NOT_FOUND)
}
if comment.Person.ID == c.CurrentUser.Person.ID {
entity := federation.EntityRetraction{
Author: c.CurrentUser.Person.Author,
TargetGuid: comment.Guid,
TargetType: models.ShareableComment,
}
dispatcher := jobs.Dispatcher{Message: entity}
// NOTE relay to other hosts if we own this entity
// should be done before we start deleting db records
// thats why this call is synchron XXX we should
// change that !
dispatcher.Run()
err = comment.Delete()
if err != nil {
c.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return c.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
} else {
c.Log.Error(TAG, "api", ERR_BAD_REQUEST)
return c.ApiError(http.StatusBadRequest, ERR_BAD_REQUEST)
}
return c.RenderJSON(struct{}{})
}
......@@ -24,6 +24,7 @@ import (
"gopkg.in/ganggo/ganggo.v0/app/helpers"
federation "gopkg.in/ganggo/federation.v0"
"net/http"
"strconv"
)
/**
......@@ -185,7 +186,7 @@ func (l ApiLike) Create() revel.Result {
Positive: positive,
Guid: guid,
Author: l.CurrentUser.Person.Author,
TargetType: models.ShareablePost,
ParentType: models.ShareablePost,
ParentGuid: post.Guid,
}
......@@ -197,25 +198,93 @@ func (l ApiLike) Create() revel.Result {
dispatcher := jobs.Dispatcher{
User: l.CurrentUser,
Model: like,
Message: entityLike,
}
if parentUser, ok := like.ParentIsLocal(); ok {
dispatcher.ParentUser = &parentUser
// XXX
// notify local user about a new comment
go like.TriggerNotification(parentUser)
}
//go like.TriggerNotification(parentUser)
// deliver to the network
go dispatcher.Run()
return l.RenderJSON(like)
}
func (l ApiLike) Show() revel.Result {
return l.NotFound("Not implemented yet")
}
/**
* @api {delete} /likes/:guid Delete a like
* @apiName ApiLike.Delete
* @apiGroup Likes
*
* @apiParam {String} access_token Oauth access token
* @apiParam {String} guid Unique global ID
*
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {}
*
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 BadRequest
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "[...]"
* }
*
*/
func (l ApiLike) Delete(guid string) revel.Result {
var post models.Post
postID, err := strconv.ParseUint(guid, 10, 32);
if err == nil {
err = post.FindByIDAndUser(uint(postID), l.CurrentUser)
} else {
err = post.FindByGuidAndUser(guid, l.CurrentUser)
}
if err != nil {
l.Log.Error(TAG, "db", err, "api", ERR_POST_NOT_FOUND)
return l.ApiError(http.StatusNotFound, ERR_POST_NOT_FOUND)
}
var like models.Like
err = like.FindByUserAndPostID(l.CurrentUser, post.ID)
if err != nil {
l.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return l.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
func (l ApiLike) Delete() revel.Result {
return l.NotFound("Not implemented yet")
if like.PersonID == l.CurrentUser.Person.ID {
entity := federation.EntityRetraction{
Author: l.CurrentUser.Person.Author,
TargetGuid: like.Guid,
TargetType: models.ShareableLike,
}
dispatcher := jobs.Dispatcher{Message: entity}
// NOTE relay to other hosts if we own this entity
// should be done before we start deleting db records
// thats why this call is synchron XXX we should
// change that !
dispatcher.Run()
err = like.Delete()
if err != nil {
l.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return l.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
} else {
l.Log.Error(TAG, "api", ERR_BAD_REQUEST)
return l.ApiError(http.StatusBadRequest, ERR_BAD_REQUEST)
}
return l.RenderJSON(struct{}{})
}
......@@ -195,7 +195,7 @@ func (p ApiPost) Create() revel.Result {
Text: postText,
Author: p.CurrentUser.Person.Author,
Guid: guid,
CreatedAt: time.Now().UTC(),
CreatedAt: federation.Time{Time: time.Now()},
ProviderName: "GangGo",
Public: true,
}
......@@ -205,7 +205,7 @@ func (p ApiPost) Create() revel.Result {
}
// save post locally
err = post.Create(&entity, false)
err = post.Create(&entity)
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return p.ApiError(http.StatusInternalServerError, ERR_SERVER)
......@@ -238,8 +238,8 @@ func (p ApiPost) Create() revel.Result {
dispatcher := jobs.Dispatcher{
User: p.CurrentUser,
AspectID: aspectID,
Message: entity,
Model: post,
}
go dispatcher.Run()
......@@ -314,6 +314,167 @@ func (p ApiPost) Show(guid string) revel.Result {
apiHelpers.SelectStructFields(post, fields))
}
func (p ApiPost) Delete() revel.Result {
return p.NotFound("Not implemented yet")
/**
* @api {delete} /posts/:guid Delete post/reshare
* @apiName ApiPost.Delete
* @apiGroup Posts
*
* @apiParam {String} access_token Oauth access token
* @apiParam {String} guid Unique global ID
*
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {}
*
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 BadRequest
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "[...]"
* }
*
*/
func (p ApiPost) Delete(guid string) revel.Result {
var post models.Post
postID, err := strconv.ParseUint(guid, 10, 32);
if err == nil {
err = post.FindByIDAndUser(uint(postID), p.CurrentUser)
} else {
err = post.FindByGuidAndUser(guid, p.CurrentUser)
}
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_POST_NOT_FOUND)
return p.ApiError(http.StatusNotFound, ERR_POST_NOT_FOUND)
}
if post.Person.ID == p.CurrentUser.Person.ID {
entity := federation.EntityRetraction{
Author: p.CurrentUser.Person.Author,
TargetGuid: post.Guid,
TargetType: models.ShareablePost,
}
dispatcher := jobs.Dispatcher{
User: p.CurrentUser,
Message: entity,
}
// NOTE relay to other hosts if we own this entity
// should be done before we start deleting db records
// thats why this call is synchron XXX we should
// change that !
dispatcher.Run()
err = post.Delete()
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return p.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
} else {
p.Log.Error(TAG, "api", ERR_BAD_REQUEST)
return p.ApiError(http.StatusBadRequest, ERR_BAD_REQUEST)
}
return p.RenderJSON(struct{}{})
}
/**
* @api {post} /posts/:guid/reshare Reshare a post
* @apiName ApiPost.Reshare
* @apiGroup Posts
*
* @apiParam {String} access_token Oauth access token
* @apiParam {String} guid Unique global ID
*
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {}
*
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 BadRequest
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (p ApiPost) Reshare() revel.Result {
var rootPost models.Post
var rootGuid string
p.Params.Bind(&rootGuid, "guid")
postID, err := strconv.ParseUint(rootGuid, 10, 32);
if err == nil {
err = rootPost.FindByIDAndUser(uint(postID), p.CurrentUser)
} else {
err = rootPost.FindByGuidAndUser(rootGuid, p.CurrentUser)
}
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_POST_NOT_FOUND)
return p.ApiError(http.StatusNotFound, ERR_POST_NOT_FOUND)
}
if rootPost.Person.ID == p.CurrentUser.Person.ID {
p.Log.Error(TAG, "api", ERR_BAD_REQUEST)
return p.ApiError(http.StatusBadRequest, ERR_BAD_REQUEST)
}
guid, err := helpers.Uuid()
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return p.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
entity := federation.EntityReshare{
Author: p.CurrentUser.Person.Author,
Guid: guid,
CreatedAt: federation.Time{Time: time.Now()},
RootAuthor: rootPost.Person.Author,
RootGuid: rootPost.Guid,
}
var post models.Post
err = post.Create(&entity)
if err != nil {
p.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return p.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
dispatcher := jobs.Dispatcher{
User: p.CurrentUser,
Model: post,
Message: entity,
}
go dispatcher.Run()
return p.RenderJSON(post)
}
......@@ -7,19 +7,18 @@ GET /api/v0/posts ApiPost.Index
POST /api/v0/posts ApiPost.Create
# both guid and uint are possible here
GET /api/v0/posts/:guid ApiPost.Show
#DELETE /api/v0/posts/:guid ApiPost.Delete
DELETE /api/v0/posts/:guid ApiPost.Delete
POST /api/v0/posts/:guid/reshare ApiPost.Reshare
GET /api/v0/notifications ApiNotification.Index
#POST /api/v0/notifications ApiNotification.Create
#GET /api/v0/notifications/:id ApiNotification.Show
PUT /api/v0/notifications/:id ApiNotification.Update
DELETE /api/v0/posts/:guid/likes ApiLike.Delete
GET /api/v0/posts/:id/likes ApiLike.Index
POST /api/v0/posts/:id/likes/:positive ApiLike.Create
#GET /api/v0/posts/:id/likes/:like_id ApiLike.Show
#DELETE /api/v0/posts/:id/likes/:like_id ApiLike.Delete
GET /api/v0/comments/:id ApiComment.Show
DELETE /api/v0/comments/:guid ApiComment.Delete
GET /api/v0/posts/:id/comments ApiComment.IndexPost
POST /api/v0/posts/:id/comments ApiComment.CreatePost
#GET /api/v0/posts/:id/comments/:comment_id ApiComment.Show
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment