mirror of
https://github.com/diaspora/diaspora.git
synced 2026-01-09 15:18:11 -05:00
seperate interactions from posts
Lazily load post interactions on show page hella refactorz
This commit is contained in:
@@ -7,5 +7,18 @@ app.collections.Comments = Backbone.Collection.extend({
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.post = options.post
|
||||
},
|
||||
|
||||
make : function(text){
|
||||
var self = this
|
||||
|
||||
var comment = new app.models.Comment({text: text })
|
||||
, deferred = comment.save({}, {url : self.url()})
|
||||
|
||||
comment.set({author: app.currentUser.toJSON(), parent: self.post })
|
||||
|
||||
this.add(comment)
|
||||
|
||||
return deferred
|
||||
}
|
||||
});
|
||||
|
||||
4
app/assets/javascripts/app/collections/reshares.js
Normal file
4
app/assets/javascripts/app/collections/reshares.js
Normal file
@@ -0,0 +1,4 @@
|
||||
app.collections.Reshares = Backbone.Collection.extend({
|
||||
model: app.models.Reshare,
|
||||
url : "/reshares"
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
app.models.Participation = Backbone.Model.extend({ });
|
||||
@@ -2,27 +2,27 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
||||
urlRoot : "/posts",
|
||||
|
||||
initialize : function() {
|
||||
this.setupCollections();
|
||||
this.bind("change", this.setupCollections, this)
|
||||
this.interactions = new app.models.Post.Interactions(_.extend({post : this}, this.get("interactions")))
|
||||
this.delegateToInteractions()
|
||||
},
|
||||
|
||||
setupCollections: function() {
|
||||
this.comments = new app.collections.Comments(this.get("comments") || this.get("last_three_comments"), {post : this});
|
||||
this.likes = this.likes || new app.collections.Likes([], {post : this}); // load in the user like initially
|
||||
this.participations = this.participations || new app.collections.Participations([], {post : this}); // load in the user like initially
|
||||
delegateToInteractions : function(){
|
||||
this.comments = this.interactions.comments
|
||||
this.likes = this.interactions.likes
|
||||
|
||||
this.comment = function(){
|
||||
this.interactions.comment.apply(this.interactions, arguments)
|
||||
}
|
||||
},
|
||||
|
||||
setFrameName : function(){
|
||||
var templatePicker = new app.models.Post.TemplatePicker(this)
|
||||
this.set({frame_name : templatePicker.getFrameName()})
|
||||
this.set({frame_name : new app.models.Post.TemplatePicker(this).getFrameName()})
|
||||
},
|
||||
|
||||
interactedAt : function() {
|
||||
return this.timeOf("interacted_at");
|
||||
},
|
||||
|
||||
createReshareUrl : "/reshares",
|
||||
|
||||
reshare : function(){
|
||||
return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")});
|
||||
},
|
||||
@@ -31,15 +31,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
||||
return this.get("author")
|
||||
},
|
||||
|
||||
toggleLike : function() {
|
||||
var userLike = this.get("user_like")
|
||||
if(userLike) {
|
||||
this.unlike()
|
||||
} else {
|
||||
this.like()
|
||||
}
|
||||
},
|
||||
|
||||
toggleFavorite : function(options){
|
||||
this.set({favorite : !this.get("favorite")})
|
||||
|
||||
@@ -47,40 +38,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
||||
if(options.save){ this.save() }
|
||||
},
|
||||
|
||||
like : function() {
|
||||
var self = this;
|
||||
this.likes.create({}, {success : function(resp){
|
||||
self.set(resp)
|
||||
self.trigger('interacted', self)
|
||||
}});
|
||||
|
||||
},
|
||||
|
||||
unlike : function() {
|
||||
var self = this;
|
||||
var likeModel = new app.models.Like(this.get("user_like"));
|
||||
likeModel.url = this.likes.url + "/" + likeModel.id;
|
||||
|
||||
likeModel.destroy({success : function(model, resp) {
|
||||
self.set(resp);
|
||||
self.trigger('interacted', this)
|
||||
}});
|
||||
},
|
||||
|
||||
comment : function (text) {
|
||||
|
||||
var self = this
|
||||
, postComments = this.comments;
|
||||
|
||||
postComments.create({"text": text}, {
|
||||
url : postComments.url(),
|
||||
wait:true, // added a wait for the time being. 0.5.3 was not optimistic, but 0.9.2 is.
|
||||
error:function () {
|
||||
alert(Diaspora.I18n.t("failed_to_post_message"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
headline : function() {
|
||||
var headline = this.get("text").trim()
|
||||
, newlineIdx = headline.indexOf("\n")
|
||||
|
||||
116
app/assets/javascripts/app/models/post/interactions.js
Normal file
116
app/assets/javascripts/app/models/post/interactions.js
Normal file
@@ -0,0 +1,116 @@
|
||||
//require ../post
|
||||
|
||||
app.models.Post.Interactions = Backbone.Model.extend({
|
||||
url : function(){
|
||||
return this.post.url() + "/interactions"
|
||||
},
|
||||
|
||||
initialize : function(options){
|
||||
this.post = options.post
|
||||
this.comments = new app.collections.Comments(this.get("comments"), {post : this.post})
|
||||
this.likes = new app.collections.Likes(this.get("likes"), {post : this.post});
|
||||
this.reshares = new app.collections.Reshares(this.get("reshares"), {post : this.post});
|
||||
},
|
||||
|
||||
parse : function(resp){
|
||||
this.comments.reset(resp.comments)
|
||||
this.likes.reset(resp.likes)
|
||||
this.reshares.reset(resp.reshares)
|
||||
|
||||
var comments = this.comments
|
||||
, likes = this.likes
|
||||
, reshares = this.reshares
|
||||
|
||||
return {
|
||||
comments : comments,
|
||||
likes : likes,
|
||||
reshares : reshares,
|
||||
fetched : true
|
||||
}
|
||||
},
|
||||
|
||||
likesCount : function(){
|
||||
return (this.get("fetched") ? this.likes.models.length : this.get("likes_count") )
|
||||
},
|
||||
|
||||
resharesCount : function(){
|
||||
return this.get("fetched") ? this.reshares.models.length : this.get("reshares_count")
|
||||
},
|
||||
|
||||
commentsCount : function(){
|
||||
return this.get("fetched") ? this.comments.models.length : this.get("comments_count")
|
||||
},
|
||||
|
||||
userLike : function(){
|
||||
return this.likes.select(function(like){ return like.get("author").guid == app.currentUser.get("guid")})[0]
|
||||
},
|
||||
|
||||
userReshare : function(){
|
||||
return this.reshares.select(function(reshare){ return reshare.get("author").guid == app.currentUser.get("guid")})[0]
|
||||
},
|
||||
|
||||
toggleLike : function() {
|
||||
if(this.userLike()) {
|
||||
this.unlike()
|
||||
} else {
|
||||
this.like()
|
||||
}
|
||||
},
|
||||
|
||||
like : function() {
|
||||
var self = this;
|
||||
this.likes.create({}, {success : function(){
|
||||
self.trigger("change")
|
||||
self.set({"likes_count" : self.get("likes_count") + 1})
|
||||
}})
|
||||
},
|
||||
|
||||
unlike : function() {
|
||||
var self = this;
|
||||
this.userLike().destroy({success : function(model, resp) {
|
||||
self.trigger('change')
|
||||
self.set({"likes_count" : self.get("likes_count") - 1})
|
||||
}});
|
||||
},
|
||||
|
||||
comment : function (text) {
|
||||
var self = this;
|
||||
|
||||
this.comments.make(text).fail(function () {
|
||||
alert(Diaspora.I18n.t("failed_to_post_message"));
|
||||
}).done(function() {
|
||||
self.trigger('change') //updates after sync
|
||||
});
|
||||
|
||||
this.trigger("change") //updates count in an eager manner
|
||||
},
|
||||
|
||||
reshare : function(){
|
||||
var interactions = this
|
||||
, reshare = this.post.reshare()
|
||||
|
||||
reshare.save({}, {
|
||||
success : function(resp){
|
||||
var flash = new Diaspora.Widgets.FlashMessages;
|
||||
flash.render({
|
||||
success: true,
|
||||
notice: Diaspora.I18n.t("reshares.successful")
|
||||
});
|
||||
}
|
||||
}).done(function(){
|
||||
interactions.reshares.add(reshare)
|
||||
}).done(function(){
|
||||
interactions.trigger("change")
|
||||
});
|
||||
},
|
||||
|
||||
userCanReshare : function(){
|
||||
var isReshare = this.post.get("post_type") == "Reshare"
|
||||
, rootExists = (isReshare ? this.post.get("root") : true)
|
||||
, publicPost = this.post.get("public")
|
||||
, userIsNotAuthor = this.post.get("author").diaspora_id != app.currentUser.get("diaspora_id")
|
||||
, userIsNotRootAuthor = rootExists && (isReshare ? this.post.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
|
||||
|
||||
return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor;
|
||||
}
|
||||
});
|
||||
@@ -1,4 +1,6 @@
|
||||
app.models.Reshare = app.models.Post.extend({
|
||||
urlRoot : "/reshares",
|
||||
|
||||
rootPost : function(){
|
||||
this._rootPost = this._rootPost || new app.models.Post(this.get("root"));
|
||||
return this._rootPost
|
||||
|
||||
@@ -9,8 +9,10 @@ app.pages.PostViewer = app.views.Base.extend({
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
this.model = new app.models.Post({ id : options.id });
|
||||
var post = this.model = new app.models.Post({ id : options.id });
|
||||
this.model.preloadOrFetch().done(_.bind(this.initViews, this));
|
||||
this.model.interactions.fetch() //async, yo, might want to throttle this later.
|
||||
|
||||
this.bindEvents()
|
||||
},
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ app.views.CommentStream = app.views.Base.extend({
|
||||
|
||||
presenter: function(){
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
moreCommentsCount : (this.model.get("comments_count") - 3),
|
||||
showExpandCommentsLink : (this.model.get("comments_count") > 3)
|
||||
moreCommentsCount : (this.model.interactions.commentsCount() - 3),
|
||||
showExpandCommentsLink : (this.model.interactions.commentsCount() > 3),
|
||||
commentsCount : this.model.interactions.commentsCount()
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -4,11 +4,15 @@ app.views.Comment = app.views.Content.extend({
|
||||
className : "comment media",
|
||||
|
||||
events : function() {
|
||||
return _.extend(app.views.Content.prototype.events, {
|
||||
return _.extend({}, app.views.Content.prototype.events, {
|
||||
"click .comment_delete": "destroyModel"
|
||||
});
|
||||
},
|
||||
|
||||
initialize : function(){
|
||||
this.model.on("change", this.render, this)
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
canRemove: this.canRemove(),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
app.views.Feedback = app.views.Base.extend({
|
||||
|
||||
templateName: "feedback",
|
||||
|
||||
className : "info",
|
||||
@@ -10,47 +9,30 @@ app.views.Feedback = app.views.Base.extend({
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('interacted', this.render, this);
|
||||
this.model.interactions.on('change', this.render, this);
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
userCanReshare : this.userCanReshare()
|
||||
var interactions = this.model.interactions
|
||||
|
||||
return _.extend(this.defaultPresenter(),{
|
||||
commentsCount : interactions.commentsCount(),
|
||||
likesCount : interactions.likesCount(),
|
||||
resharesCount : interactions.resharesCount(),
|
||||
userCanReshare : interactions.userCanReshare(),
|
||||
userLike : interactions.userLike(),
|
||||
userReshare : interactions.userReshare(),
|
||||
})
|
||||
},
|
||||
|
||||
toggleLike: function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
this.model.toggleLike();
|
||||
this.model.interactions.toggleLike();
|
||||
},
|
||||
|
||||
resharePost : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
if(!window.confirm(Diaspora.I18n.t("reshares.post", {name: this.model.reshareAuthor().name}))) { return }
|
||||
var reshare = this.model.reshare()
|
||||
var model = this.model
|
||||
|
||||
reshare.save({}, {
|
||||
url: this.model.createReshareUrl,
|
||||
success : function(resp){
|
||||
var flash = new Diaspora.Widgets.FlashMessages;
|
||||
flash.render({
|
||||
success: true,
|
||||
notice: Diaspora.I18n.t("reshares.successful")
|
||||
});
|
||||
model.trigger("interacted")
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
userCanReshare : function() {
|
||||
var isReshare = this.model.get("post_type") == "Reshare"
|
||||
var rootExists = (isReshare ? this.model.get("root") : true)
|
||||
|
||||
var publicPost = this.model.get("public");
|
||||
var userIsNotAuthor = this.model.get("author").diaspora_id != app.currentUser.get("diaspora_id");
|
||||
var userIsNotRootAuthor = rootExists && (isReshare ? this.model.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
|
||||
|
||||
return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor;
|
||||
this.model.interactions.reshare();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,23 +10,19 @@ app.views.LikesInfo = app.views.StreamObject.extend({
|
||||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('expandedLikes', this.render, this)
|
||||
this.model.interactions.bind('change', this.render, this)
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
likes : this.model.likes.models
|
||||
likes : this.model.interactions.likes.toJSON(),
|
||||
likesCount : this.model.interactions.likesCount(),
|
||||
likes_fetched : this.model.interactions.get("fetched"),
|
||||
})
|
||||
},
|
||||
|
||||
showAvatars : function(evt){
|
||||
if(evt) { evt.preventDefault() }
|
||||
var self = this;
|
||||
this.model.likes.fetch()
|
||||
.done(function(resp){
|
||||
// set like attribute and like collection
|
||||
self.model.set({likes : self.model.likes.reset(resp)})
|
||||
self.model.trigger("expandedLikes")
|
||||
})
|
||||
this.model.interactions.fetch()
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,6 +18,11 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({
|
||||
|
||||
tooltipSelector : ".label, .home-button",
|
||||
|
||||
initialize : function(){
|
||||
this.model.interactions.on("change", this.render, this)
|
||||
},
|
||||
|
||||
|
||||
postRenderTemplate : function() {
|
||||
this.sneakyVisiblity()
|
||||
},
|
||||
@@ -36,5 +41,4 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({
|
||||
alert("you must be logged in to do that!")
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -5,7 +5,8 @@ app.views.PostViewerInteractions = app.views.Base.extend({
|
||||
subviews : {
|
||||
"#post-feedback" : "feedbackView",
|
||||
"#post-reactions" : "reactionsView",
|
||||
"#new-post-comment" : "newCommentView"
|
||||
"#new-post-comment" : "newCommentView",
|
||||
".interaction_counts" : "interactionCountsView"
|
||||
},
|
||||
|
||||
templateName: "post-viewer/interactions",
|
||||
@@ -18,7 +19,7 @@ app.views.PostViewerInteractions = app.views.Base.extend({
|
||||
},
|
||||
|
||||
initViews : function() {
|
||||
this.reactionsView = new app.views.PostViewerReactions({ model : this.model })
|
||||
this.reactionsView = new app.views.PostViewerReactions({ model : this.model.interactions })
|
||||
|
||||
/* subviews that require user */
|
||||
this.feedbackView = new app.views.PostViewerFeedback({ model : this.model })
|
||||
|
||||
@@ -10,7 +10,7 @@ app.views.PostViewerNewComment = app.views.Base.extend({
|
||||
scrollableArea : "#post-reactions",
|
||||
|
||||
initialize : function(){
|
||||
this.model.comments.bind("sync", this.clearAndReactivateForm, this)
|
||||
this.model.interactions.comments.bind("sync", this.clearAndReactivateForm, this)
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
@@ -25,7 +25,6 @@ app.views.PostViewerNewComment = app.views.Base.extend({
|
||||
},
|
||||
|
||||
clearAndReactivateForm : function() {
|
||||
this.model.trigger("interacted")
|
||||
this.toggleFormState()
|
||||
this.$("textarea").val("")
|
||||
.css('height', '18px')
|
||||
|
||||
@@ -7,7 +7,16 @@ app.views.PostViewerReactions = app.views.Base.extend({
|
||||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('interacted', this.render, this);
|
||||
this.model.on('change', this.render, this);
|
||||
this.model.comments.bind("add", this.appendComment, this)
|
||||
},
|
||||
|
||||
presenter : function(){
|
||||
return {
|
||||
likes : this.model.likes.toJSON(),
|
||||
comments : this.model.comments.toJSON(),
|
||||
reshares : this.model.reshares.toJSON()
|
||||
}
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
@@ -21,14 +30,15 @@ app.views.PostViewerReactions = app.views.Base.extend({
|
||||
|
||||
/* copy pasta from commentStream */
|
||||
appendComment: function(comment) {
|
||||
// Set the post as the comment's parent, so we can check
|
||||
// on post ownership in the Comment view.
|
||||
comment.set({parent : this.model.toJSON()})
|
||||
// Set the post as the comment's parent, so we can check on post ownership in the Comment view.
|
||||
// model was post on old view, is interactions on new view
|
||||
|
||||
var parent = this.model.get("post_type") ? this.model.toJSON : this.model.post.toJSON()
|
||||
comment.set({parent : parent})
|
||||
|
||||
this.$("#post-comments").append(new app.views.Comment({
|
||||
model: comment,
|
||||
className : "post-comment media"
|
||||
}).render().el);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="comments"> </div>
|
||||
|
||||
{{#if loggedIn}}
|
||||
<div class="comment no-border media new_comment_form_wrapper {{#unless comments_count}} hidden {{/unless}}">
|
||||
<div class="comment no-border media new_comment_form_wrapper {{#unless commentsCount}} hidden {{/unless}}">
|
||||
{{#with current_user}}
|
||||
<a href="/people/{{guid}}" class="img">
|
||||
{{{personImage this}}}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
|
||||
<a href="#" class="like_action" rel='nofollow'>
|
||||
{{#if user_like}}
|
||||
{{#if userLike}}
|
||||
{{t "stream.unlike"}}
|
||||
{{else}}
|
||||
{{t "stream.like"}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{#if likes_count}}
|
||||
{{#if likesCount}}
|
||||
<div class="comment">
|
||||
<div class="media">
|
||||
<span class="img">
|
||||
@@ -6,21 +6,20 @@
|
||||
</span>
|
||||
|
||||
<div class="bd">
|
||||
{{#unless likes.length}}
|
||||
{{#unless likes_fetched}}
|
||||
<a href="#" class="expand_likes grey">
|
||||
{{t "stream.likes" count=likes_count}}
|
||||
{{t "stream.likes" count=likesCount}}
|
||||
</a>
|
||||
|
||||
{{else}}
|
||||
|
||||
{{#each likes}}
|
||||
{{#with attributes.author}}
|
||||
{{#with author}}
|
||||
<a href="/people/{{guid}}">
|
||||
<img src="{{avatar.small}}" class="avatar micro" title="{{name}}"/>
|
||||
</a>
|
||||
{{/with}}
|
||||
{{/each}}
|
||||
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
<a href="#" rel="auth-required" class="label like" title="{{#if user_like}} {{t "viewer.unlike"}} {{else}} {{t "viewer.like"}} {{/if}}">
|
||||
{{#if user_like}}
|
||||
<a href="#" rel="auth-required" class="label like" title="{{#if userLike}} {{t "viewer.unlike"}} {{else}} {{t "viewer.like"}} {{/if}}">
|
||||
{{#if userLike}}
|
||||
<i class="icon-heart icon-red"></i>
|
||||
{{else}}
|
||||
<i class="icon-heart icon-white"></i>
|
||||
{{/if}}
|
||||
{{likes_count}}
|
||||
{{likesCount}}
|
||||
</a>
|
||||
|
||||
{{#if userCanReshare}}
|
||||
<a href="#" rel="auth-required" class="label reshare" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if user_reshare}}
|
||||
<a href="#" rel="auth-required" class="label reshare" title="{{#if userReshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if userReshare}}
|
||||
<i class="icon-retweet icon-blue"></i>
|
||||
{{else}}
|
||||
<i class="icon-retweet icon-white"></i>
|
||||
{{/if}}
|
||||
{{reshares_count}}
|
||||
{{resharesCount}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a class="label reshare-viewonly" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if user_reshare}}
|
||||
<a class="label reshare-viewonly" title="{{#if userReshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if userReshare}}
|
||||
<i class="icon-retweet icon-blue"></i>
|
||||
{{else}}
|
||||
<i class="icon-retweet icon-white"></i>
|
||||
{{/if}}
|
||||
{{reshares_count}}
|
||||
{{resharesCount}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
<a href="#" class="label comment" rel="invoke-interaction-pane" title="{{t "viewer.comment"}}">
|
||||
<i class="icon-comment icon-white"></i>
|
||||
{{comments_count}}
|
||||
{{commentsCount}}
|
||||
</a>
|
||||
|
||||
<!-- this acts as a dock underlay -->
|
||||
|
||||
@@ -38,9 +38,9 @@
|
||||
<i class="icon-time timestamp" title="{{created_at}}" rel="tooltip"></i>
|
||||
<i class="icon-chevron-right permalink" title="View Post" rel="tooltip"></i>
|
||||
|
||||
<i class="icon-heart"></i> {{likes_count}}
|
||||
<i class="icon-retweet"></i> {{reshares_count}}
|
||||
<i class="icon-comment"></i> {{comments_count}}
|
||||
<i class="icon-heart"></i> {{likesCount}}
|
||||
<i class="icon-retweet"></i> {{resharesCount}}
|
||||
<i class="icon-comment"></i> {{commentsCount}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@ class CommentsController < ApplicationController
|
||||
|
||||
@comments = @post.comments.for_a_stream
|
||||
respond_with do |format|
|
||||
format.json { render :json => CommentPresenter.new(@comments), :status => 200 }
|
||||
format.json { render :json => CommentPresenter.as_collection(@comments), :status => 200 }
|
||||
format.mobile{render :layout => false}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,13 +13,13 @@ class LikesController < ApplicationController
|
||||
:json
|
||||
|
||||
def create
|
||||
@like = current_user.like!(target) if target
|
||||
@like = current_user.like!(target) if target rescue ActiveRecord::RecordInvalid
|
||||
|
||||
if @like
|
||||
respond_to do |format|
|
||||
format.html { render :nothing => true, :status => 201 }
|
||||
format.mobile { redirect_to post_path(@like.post_id) }
|
||||
format.json { render :json => find_json_for_like, :status => 201 }
|
||||
format.json { render :json => @like.as_api_response(:backbone), :status => 201 }
|
||||
end
|
||||
else
|
||||
render :nothing => true, :status => 422
|
||||
@@ -27,32 +27,22 @@ class LikesController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@like = Like.where(:id => params[:id], :author_id => current_user.person.id).first
|
||||
@like = Like.find_by_id_and_author_id!(params[:id], current_user.person.id)
|
||||
|
||||
if @like
|
||||
current_user.retract(@like)
|
||||
respond_to do |format|
|
||||
format.json { render :json => find_json_for_like, :status => 202 }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.mobile { redirect_to :back }
|
||||
format.json { render :nothing => true, :status => 403}
|
||||
end
|
||||
current_user.retract(@like)
|
||||
respond_to do |format|
|
||||
format.json { render :nothing => true, :status => 204 }
|
||||
end
|
||||
end
|
||||
|
||||
#I can go when the old stream goes.
|
||||
def index
|
||||
if target
|
||||
@likes = target.likes.includes(:author => :profile)
|
||||
@people = @likes.map(&:author)
|
||||
@likes = target.likes.includes(:author => :profile)
|
||||
@people = @likes.map(&:author)
|
||||
|
||||
respond_to do |format|
|
||||
format.all{ render :layout => false }
|
||||
format.json{ render :json => @likes.as_api_response(:backbone) }
|
||||
end
|
||||
else
|
||||
render :nothing => true, :status => 404
|
||||
respond_to do |format|
|
||||
format.all { render :layout => false }
|
||||
format.json { render :json => @likes.as_api_response(:backbone) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -60,21 +50,11 @@ class LikesController < ApplicationController
|
||||
|
||||
def target
|
||||
@target ||= if params[:post_id]
|
||||
current_user.find_visible_shareable_by_id(Post, params[:post_id])
|
||||
current_user.find_visible_shareable_by_id(Post, params[:post_id]) || raise(ActiveRecord::RecordNotFound.new)
|
||||
else
|
||||
comment = Comment.find(params[:comment_id])
|
||||
comment = nil unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
|
||||
comment
|
||||
end
|
||||
end
|
||||
|
||||
def find_json_for_like
|
||||
if @like.parent.is_a? Post
|
||||
ExtremePostPresenter.new(@like.parent, current_user).as_json
|
||||
elsif @like.parent.is_a? Comment
|
||||
CommentPresenter.new(@like.parent)
|
||||
else
|
||||
@like.parent.respond_to?(:as_api_response) ? @like.parent.as_api_response(:backbone) : @like.parent.as_json
|
||||
Comment.find(params[:comment_id]).tap do |comment|
|
||||
raise(ActiveRecord::RecordNotFound.new) unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require Rails.root.join("app", "presenters", "post_presenter")
|
||||
|
||||
class ParticipationsController < ApplicationController
|
||||
include ApplicationHelper
|
||||
before_filter :authenticate_user!
|
||||
|
||||
respond_to :mobile,
|
||||
:json
|
||||
|
||||
def create
|
||||
@participation = current_user.participate!(target) if target
|
||||
|
||||
if @participation
|
||||
respond_to do |format|
|
||||
format.mobile { redirect_to post_path(@participation.post_id) }
|
||||
format.json { render :json => ExtremePostPresenter.new(@participation.parent, current_user), :status => 201 }
|
||||
end
|
||||
else
|
||||
render :nothing => true, :status => 422
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@participation = Participation.where(:id => params[:id], :author_id => current_user.person.id).first
|
||||
|
||||
if @participation
|
||||
current_user.retract(@participation)
|
||||
respond_to do |format|
|
||||
format.json { render :json => ExtremePostPresenter.new(@participation.parent, current_user), :status => 202 }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.mobile { redirect_to :back }
|
||||
format.json { render :nothing => true, :status => 403}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
if target
|
||||
@participations = target.participations.includes(:author => :profile)
|
||||
@people = @participations.map(&:author)
|
||||
|
||||
respond_to do |format|
|
||||
format.all{ render :layout => false }
|
||||
format.json{ render :json => @participations.as_api_response(:backbone) }
|
||||
end
|
||||
else
|
||||
render :nothing => true, :status => 404
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def target
|
||||
@target ||= if params[:post_id]
|
||||
current_user.find_visible_shareable_by_id(Post, params[:post_id])
|
||||
else
|
||||
comment = Comment.find(params[:comment_id])
|
||||
comment = nil unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
|
||||
comment
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,7 +9,7 @@ class PostsController < ApplicationController
|
||||
|
||||
before_filter :authenticate_user!, :except => [:show, :iframe, :oembed]
|
||||
before_filter :set_format_if_malformed_from_status_net, :only => :show
|
||||
before_filter :find_post, :only => [:show, :next, :previous]
|
||||
before_filter :find_post, :only => [:show, :next, :previous, :interactions]
|
||||
|
||||
layout 'post'
|
||||
|
||||
@@ -25,15 +25,13 @@ class PostsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
return log_and_redirect_back unless @post
|
||||
|
||||
mark_corresponding_notification_read if user_signed_in?
|
||||
|
||||
respond_to do |format|
|
||||
format.html{ gon.post = ExtremePostPresenter.new(@post, current_user); render 'posts/show.html.haml' }
|
||||
format.html{ gon.post = PostPresenter.new(@post, current_user); render 'posts/show.html.haml' }
|
||||
format.xml{ render :xml => @post.to_diaspora_xml }
|
||||
format.mobile{render 'posts/show.mobile.haml', :layout => "application"}
|
||||
format.json{ render :json => ExtremePostPresenter.new(@post, current_user) }
|
||||
format.json{ render :json => PostPresenter.new(@post, current_user) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,7 +41,7 @@ class PostsController < ApplicationController
|
||||
|
||||
def oembed
|
||||
post_id = OEmbedPresenter.id_from_url(params.delete(:url))
|
||||
post = find_by_guid_or_id_with_current_user(post_id)
|
||||
post = Post.find_by_guid_or_id_with_user(post_id, current_user)
|
||||
if post.present?
|
||||
oembed = OEmbedPresenter.new(post, params.slice(:format, :maxheight, :minheight))
|
||||
render :json => oembed
|
||||
@@ -52,72 +50,54 @@ class PostsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@post = current_user.posts.where(:id => params[:id]).first
|
||||
if @post
|
||||
current_user.retract(@post)
|
||||
respond_to do |format|
|
||||
format.js {render 'destroy'}
|
||||
format.json { render :nothing => true, :status => 204 }
|
||||
format.all {redirect_to stream_path}
|
||||
end
|
||||
else
|
||||
Rails.logger.info "event=post_destroy status=failure user=#{current_user.diaspora_handle} reason='User does not own post'"
|
||||
render :nothing => true, :status => 404
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@post = current_user.posts.find(params[:id])
|
||||
if @post
|
||||
@post.favorite = !@post.favorite
|
||||
@post.save
|
||||
render :nothing => true, :status => 202
|
||||
end
|
||||
end
|
||||
|
||||
def next
|
||||
next_post = visible_posts_from_author.newer(@post)
|
||||
next_post = Post.visible_from_author(@post.author, current_user).newer(@post)
|
||||
|
||||
respond_to do |format|
|
||||
format.html{ redirect_to post_path(next_post) }
|
||||
format.json{ render :json => ExtremePostPresenter.new(next_post, current_user)}
|
||||
format.json{ render :json => PostPresenter.new(next_post, current_user)}
|
||||
end
|
||||
end
|
||||
|
||||
def previous
|
||||
previous_post = visible_posts_from_author.older(@post)
|
||||
previous_post = Post.visible_from_author(@post.author, current_user).older(@post)
|
||||
|
||||
respond_to do |format|
|
||||
format.html{ redirect_to post_path(previous_post) }
|
||||
format.json{ render :json => ExtremePostPresenter.new(previous_post, current_user)}
|
||||
format.json{ render :json => PostPresenter.new(previous_post, current_user)}
|
||||
end
|
||||
end
|
||||
|
||||
def interactions
|
||||
respond_with(PostInteractionPresenter.new(@post, current_user))
|
||||
end
|
||||
|
||||
def destroy
|
||||
find_current_user_post(params[:id])
|
||||
current_user.retract(@post)
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render 'destroy' }
|
||||
format.json { render :nothing => true, :status => 204 }
|
||||
format.all { redirect_to stream_path }
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
find_current_user_post(params[:id])
|
||||
@post.favorite = !@post.favorite
|
||||
@post.save
|
||||
render :nothing => true, :status => 202
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def log_and_redirect_back #preserving old functionality, but this should probably be removed
|
||||
user_id = (user_signed_in? ? current_user : nil)
|
||||
Rails.logger.info(":event => :link_to_nonexistent_post, :ref => #{request.env['HTTP_REFERER']}, :user_id => #{user_id}, :post_id => #{params[:id]}")
|
||||
flash[:error] = I18n.t('posts.show.not_found')
|
||||
redirect_to :back
|
||||
def find_post #checks whether current user can see it
|
||||
@post = Post.find_by_guid_or_id_with_user(params[:id], current_user)
|
||||
end
|
||||
|
||||
def find_post
|
||||
@post = find_by_guid_or_id_with_current_user(params[:id])
|
||||
end
|
||||
|
||||
def visible_posts_from_author
|
||||
Post.visible_from_author(@post.author, current_user)
|
||||
end
|
||||
|
||||
def find_by_guid_or_id_with_current_user(id)
|
||||
key = id.to_s.length <= 8 ? :id : :guid
|
||||
if user_signed_in?
|
||||
current_user.find_visible_shareable_by_id(Post, id, :key => key)
|
||||
else
|
||||
Post.where(key => id, :public => true).includes(:author, :comments => :author).first
|
||||
end
|
||||
def find_current_user_post(id) #makes sure current_user can modify
|
||||
@post = current_user.posts.find(id)
|
||||
end
|
||||
|
||||
def set_format_if_malformed_from_status_net
|
||||
|
||||
@@ -143,4 +143,15 @@ class Post < ActiveRecord::Base
|
||||
def nsfw
|
||||
self.author.profile.nsfw?
|
||||
end
|
||||
|
||||
def self.find_by_guid_or_id_with_user(id, user=nil)
|
||||
key = id.to_s.length <= 8 ? :id : :guid
|
||||
post = if user
|
||||
user.find_visible_shareable_by_id(Post, id, :key => key)
|
||||
else
|
||||
Post.where(key => id, :public => true).includes(:author, :comments => :author).first
|
||||
end
|
||||
|
||||
post || raise(ActiveRecord::RecordNotFound.new("could not find a post with id #{id}"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,6 @@ class ExtremePostPresenter
|
||||
def as_json(options={})
|
||||
post = PostPresenter.new(@post, @current_user)
|
||||
interactions = PostInteractionPresenter.new(@post, @current_user)
|
||||
post.as_json.merge!(interactions.as_json)
|
||||
post.as_json.merge!(:interactions => interactions.as_json)
|
||||
end
|
||||
end
|
||||
@@ -4,6 +4,8 @@ class LastThreeCommentsDecorator
|
||||
end
|
||||
|
||||
def as_json(options={})
|
||||
@presenter.as_json.merge({:last_three_comments => CommentPresenter.as_collection(@presenter.post.last_three_comments)})
|
||||
@presenter.as_json.tap do |post|
|
||||
post[:interactions].merge!(:comments => CommentPresenter.as_collection(@presenter.post.last_three_comments))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -20,9 +20,6 @@ class PostPresenter
|
||||
:public => @post.public,
|
||||
:created_at => @post.created_at,
|
||||
:interacted_at => @post.interacted_at,
|
||||
:comments_count => @post.comments_count,
|
||||
:likes_count => @post.likes_count,
|
||||
:reshares_count => @post.reshares_count,
|
||||
:provider_display_name => @post.provider_display_name,
|
||||
:post_type => @post.post_type,
|
||||
:image_url => @post.image_url,
|
||||
@@ -38,8 +35,14 @@ class PostPresenter
|
||||
:title => title,
|
||||
:next_post => next_post_path,
|
||||
:previous_post => previous_post_path,
|
||||
:user_like => user_like,
|
||||
:user_reshare => user_reshare
|
||||
|
||||
:interactions => {
|
||||
:likes => [user_like].compact,
|
||||
:reshares => [user_reshare].compact,
|
||||
:comments_count => @post.comments_count,
|
||||
:likes_count => @post.likes_count,
|
||||
:reshares_count => @post.reshares_count,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -17,8 +17,10 @@ Diaspora::Application.routes.draw do
|
||||
member do
|
||||
get :next
|
||||
get :previous
|
||||
get :interactions
|
||||
end
|
||||
resources :likes, :only => [:create, :destroy, :index]
|
||||
|
||||
resources :likes, :only => [:create, :destroy, :index ]
|
||||
resources :participations, :only => [:create, :destroy, :index]
|
||||
resources :comments, :only => [:new, :create, :destroy, :index]
|
||||
end
|
||||
|
||||
@@ -7,9 +7,10 @@ Feature: Post Viewer
|
||||
Background:
|
||||
Given a user with email "alice@alice.com"
|
||||
And I sign in as "alice@alice.com"
|
||||
|
||||
@wip
|
||||
Scenario: Paging through posts
|
||||
Given I have posts for each type of template
|
||||
Then I visit all of my posts
|
||||
And I should have seen all of my posts displayed with the correct template
|
||||
|
||||
# Wip tag sad on new cucumber, commenting for now.
|
||||
# @wip
|
||||
# Scenario: Paging through posts
|
||||
# Given I have posts for each type of template
|
||||
# Then I visit all of my posts
|
||||
# And I should have seen all of my posts displayed with the correct template
|
||||
|
||||
@@ -7,7 +7,7 @@ module Federated
|
||||
|
||||
def create!(options={})
|
||||
relayable = build(options)
|
||||
if relayable.save
|
||||
if relayable.save!
|
||||
FEDERATION_LOGGER.info("user:#{@user.id} dispatching #{relayable.class}:#{relayable.guid}")
|
||||
Postzord::Dispatcher.defer_build_and_post(@user, relayable)
|
||||
relayable
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
@@ -88,7 +88,7 @@ describe LikesController do
|
||||
|
||||
it 'returns a 404 for a post not visible to the user' do
|
||||
sign_in eve
|
||||
get :index, id_field => @message.id
|
||||
expect{get :index, id_field => @message.id}.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'returns an array of likes for a post' do
|
||||
@@ -114,22 +114,19 @@ describe LikesController do
|
||||
expect {
|
||||
delete :destroy, :format => :json, id_field => @like.target_id, :id => @like.id
|
||||
}.should change(Like, :count).by(-1)
|
||||
response.status.should == 202
|
||||
response.status.should == 204
|
||||
end
|
||||
|
||||
it 'does not let a user destroy other likes' do
|
||||
like2 = eve.like!(@message)
|
||||
|
||||
like_count = Like.count
|
||||
expect {
|
||||
delete :destroy, :format => :json, id_field => like2.target_id, :id => like2.id
|
||||
}.should_not change(Like, :count)
|
||||
}.should raise_error(ActiveRecord::RecordNotFound)
|
||||
|
||||
response.status.should == 403
|
||||
end
|
||||
Like.count.should == like_count
|
||||
|
||||
it 'returns the parent post presenter' do
|
||||
delete :destroy, :format => :json, id_field => @like.target_id, :id => @like.id
|
||||
response.body.should include 'post' if class_const != Comment
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ParticipationsController do
|
||||
before do
|
||||
@alices_aspect = alice.aspects.where(:name => "generic").first
|
||||
@bobs_aspect = bob.aspects.where(:name => "generic").first
|
||||
|
||||
sign_in :user, alice
|
||||
end
|
||||
|
||||
context "Posts" do
|
||||
let(:id_field){ "post_id" }
|
||||
|
||||
describe '#create' do
|
||||
let(:participation_hash) {
|
||||
{ id_field => "#{@target.id}",
|
||||
:format => :json}
|
||||
}
|
||||
let(:disparticipation_hash) {
|
||||
{ id_field => "#{@target.id}",
|
||||
:format => :json }
|
||||
}
|
||||
|
||||
context "on my own post" do
|
||||
it 'succeeds' do
|
||||
@target = alice.post :status_message, :text => "AWESOME", :to => @alices_aspect.id
|
||||
post :create, participation_hash
|
||||
response.code.should == '201'
|
||||
end
|
||||
end
|
||||
|
||||
context "on a post from a contact" do
|
||||
before do
|
||||
@target = bob.post(:status_message, :text => "AWESOME", :to => @bobs_aspect.id)
|
||||
end
|
||||
|
||||
it 'participations' do
|
||||
post :create, participation_hash
|
||||
response.code.should == '201'
|
||||
end
|
||||
|
||||
it 'disparticipations' do
|
||||
post :create, disparticipation_hash
|
||||
response.code.should == '201'
|
||||
end
|
||||
|
||||
it "doesn't post multiple times" do
|
||||
alice.participate!(@target)
|
||||
post :create, disparticipation_hash
|
||||
response.code.should == '422'
|
||||
end
|
||||
end
|
||||
|
||||
context "on a post from a stranger" do
|
||||
before do
|
||||
@target = eve.post :status_message, :text => "AWESOME", :to => eve.aspects.first.id
|
||||
end
|
||||
|
||||
it "doesn't post" do
|
||||
alice.should_not_receive(:participate!)
|
||||
post :create, participation_hash
|
||||
response.code.should == '422'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before do
|
||||
@message = alice.post(:status_message, :text => "hey", :to => @alices_aspect.id)
|
||||
end
|
||||
|
||||
it 'generates a jasmine fixture', :fixture => true do
|
||||
get :index, id_field => @message.id, :format => :json
|
||||
|
||||
save_fixture(response.body, "ajax_participations_on_posts")
|
||||
end
|
||||
|
||||
it 'returns a 404 for a post not visible to the user' do
|
||||
sign_in eve
|
||||
get :index, id_field => @message.id, :format => :json
|
||||
end
|
||||
|
||||
it 'returns an array of participations for a post' do
|
||||
bob.participate!(@message)
|
||||
get :index, id_field => @message.id, :format => :json
|
||||
assigns[:participations].map(&:id).should == @message.participation_ids
|
||||
end
|
||||
|
||||
it 'returns an empty array for a post with no participations' do
|
||||
get :index, id_field => @message.id, :format => :json
|
||||
assigns[:participations].should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
before do
|
||||
@message = bob.post(:status_message, :text => "hey", :to => @alices_aspect.id)
|
||||
@participation = alice.participate!(@message)
|
||||
end
|
||||
|
||||
it 'lets a user destroy their participation' do
|
||||
expect {
|
||||
delete :destroy, :format => :json, id_field => @participation.target_id, :id => @participation.id
|
||||
}.should change(Participation, :count).by(-1)
|
||||
response.status.should == 202
|
||||
end
|
||||
|
||||
it 'does not let a user destroy other participations' do
|
||||
participation2 = eve.participate!(@message)
|
||||
|
||||
expect {
|
||||
delete :destroy, :format => :json, id_field => participation2.target_id, :id => participation2.id
|
||||
}.should_not change(Participation, :count)
|
||||
|
||||
response.status.should == 403
|
||||
end
|
||||
|
||||
it 'returns the parent post presenter' do
|
||||
delete :destroy, :format => :json, id_field => @participation.target_id, :id => @participation.id
|
||||
response.body.should include 'post'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -55,9 +55,8 @@ describe PostsController do
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it 'redirects if the post is missing' do
|
||||
get :show, :id => 1234567
|
||||
response.should be_redirect
|
||||
it '404 if the post is missing' do
|
||||
expect { get :show, :id => 1234567 }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,8 +85,7 @@ describe PostsController do
|
||||
|
||||
it 'does not show a private post' do
|
||||
status = alice.post(:status_message, :text => "hello", :public => false, :to => 'all')
|
||||
get :show, :id => status.id
|
||||
response.status = 302
|
||||
expect { get :show, :id => status.id }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
# We want to be using guids from now on for this post route, but do not want to break
|
||||
@@ -128,8 +126,7 @@ describe PostsController do
|
||||
end
|
||||
|
||||
it 'returns a 404 response when the post is not found' do
|
||||
get :oembed, :url => "/posts/#{@message.id}"
|
||||
response.should_not be_success
|
||||
expect { get :oembed, :url => "/posts/#{@message.id}" }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -155,15 +152,13 @@ describe PostsController do
|
||||
|
||||
it 'will not let you destroy posts visible to you' do
|
||||
message = bob.post(:status_message, :text => "hey", :to => bob.aspects.first.id)
|
||||
delete :destroy, :format => :js, :id => message.id
|
||||
response.should_not be_success
|
||||
expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
StatusMessage.exists?(message.id).should be_true
|
||||
end
|
||||
|
||||
it 'will not let you destory posts you do not own' do
|
||||
message = eve.post(:status_message, :text => "hey", :to => eve.aspects.first.id)
|
||||
delete :destroy, :format => :js, :id => message.id
|
||||
response.should_not be_success
|
||||
expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
StatusMessage.exists?(message.id).should be_true
|
||||
end
|
||||
end
|
||||
@@ -171,8 +166,8 @@ describe PostsController do
|
||||
describe "#next" do
|
||||
before do
|
||||
sign_in alice
|
||||
#lets make a class and unit test it, because this is still not working
|
||||
@controller.stub_chain(:visible_posts_from_author, :newer).and_return(next_post)
|
||||
Post.stub(:find_by_guid_or_id_with_user).and_return(mock_model(Post, :author => 4))
|
||||
Post.stub_chain(:visible_from_author, :newer).and_return(next_post)
|
||||
end
|
||||
|
||||
let(:next_post){ mock_model(StatusMessage, :id => 34)}
|
||||
@@ -181,7 +176,7 @@ describe PostsController do
|
||||
let(:mock_presenter) { mock(:as_json => {:title => "the unbearable lightness of being"}) }
|
||||
|
||||
it "should return a show presenter the next post" do
|
||||
ExtremePostPresenter.should_receive(:new).with(next_post, alice).and_return(mock_presenter)
|
||||
PostPresenter.should_receive(:new).with(next_post, alice).and_return(mock_presenter)
|
||||
get :next, :id => 14, :format => :json
|
||||
response.body.should == {:title => "the unbearable lightness of being"}.to_json
|
||||
end
|
||||
@@ -198,8 +193,8 @@ describe PostsController do
|
||||
describe "previous" do
|
||||
before do
|
||||
sign_in alice
|
||||
#lets make a class and unit test it, because this is still not working
|
||||
@controller.stub_chain(:visible_posts_from_author, :older).and_return(previous_post)
|
||||
Post.stub(:find_by_guid_or_id_with_user).and_return(mock_model(Post, :author => 4))
|
||||
Post.stub_chain(:visible_from_author, :older).and_return(previous_post)
|
||||
end
|
||||
|
||||
let(:previous_post){ mock_model(StatusMessage, :id => 11)}
|
||||
@@ -208,7 +203,7 @@ describe PostsController do
|
||||
let(:mock_presenter) { mock(:as_json => {:title => "existential crises"})}
|
||||
|
||||
it "should return a show presenter the next post" do
|
||||
ExtremePostPresenter.should_receive(:new).with(previous_post, alice).and_return(mock_presenter)
|
||||
PostPresenter.should_receive(:new).with(previous_post, alice).and_return(mock_presenter)
|
||||
get :previous, :id => 14, :format => :json
|
||||
response.body.should == {:title => "existential crises"}.to_json
|
||||
end
|
||||
|
||||
45
spec/javascripts/app/models/post/interacations_spec.js
Normal file
45
spec/javascripts/app/models/post/interacations_spec.js
Normal file
@@ -0,0 +1,45 @@
|
||||
describe("app.models.Post.Interactions", function(){
|
||||
beforeEach(function(){
|
||||
this.interactions = factory.post()
|
||||
this.interactions = this.interactions.interactions
|
||||
this.author = factory.author({guid: "loggedInAsARockstar"})
|
||||
loginAs({guid: "loggedInAsARockstar"})
|
||||
|
||||
this.userLike = new app.models.Like({author : this.author})
|
||||
})
|
||||
|
||||
describe("toggleLike", function(){
|
||||
it("calls unliked when the user_like exists", function(){
|
||||
this.interactions.likes.add(this.userLike)
|
||||
spyOn(this.interactions, "unlike").andReturn(true);
|
||||
this.interactions.toggleLike();
|
||||
expect(this.interactions.unlike).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
it("calls liked when the user_like does not exist", function(){
|
||||
this.interactions.likes.reset([]);
|
||||
spyOn(this.interactions, "like").andReturn(true);
|
||||
this.interactions.toggleLike();
|
||||
expect(this.interactions.like).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
|
||||
describe("like", function(){
|
||||
it("calls create on the likes collection", function(){
|
||||
spyOn(this.interactions.likes, "create");
|
||||
|
||||
this.interactions.like();
|
||||
expect(this.interactions.likes.create).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
|
||||
describe("unlike", function(){
|
||||
it("calls destroy on the likes collection", function(){
|
||||
this.interactions.likes.add(this.userLike)
|
||||
spyOn(this.userLike, "destroy");
|
||||
|
||||
this.interactions.unlike();
|
||||
expect(this.userLike.destroy).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -36,43 +36,4 @@ describe("app.models.Post", function() {
|
||||
expect(this.post.createdAt()).toEqual(+date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toggleLike", function(){
|
||||
it("calls unliked when the user_like exists", function(){
|
||||
this.post.set({user_like : "123"});
|
||||
spyOn(this.post, "unlike").andReturn(true);
|
||||
|
||||
this.post.toggleLike();
|
||||
expect(this.post.unlike).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
it("calls liked when the user_like does not exist", function(){
|
||||
this.post.set({user_like : null});
|
||||
spyOn(this.post, "like").andReturn(true);
|
||||
|
||||
this.post.toggleLike();
|
||||
expect(this.post.like).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
|
||||
describe("like", function(){
|
||||
it("calls create on the likes collection", function(){
|
||||
spyOn(this.post.likes, "create");
|
||||
|
||||
this.post.like();
|
||||
expect(this.post.likes.create).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
|
||||
describe("unlike", function(){
|
||||
it("calls destroy on the likes collection", function(){
|
||||
var like = new app.models.Like();
|
||||
this.post.set({user_like : like.toJSON()})
|
||||
|
||||
spyOn(app.models.Like.prototype, "destroy");
|
||||
|
||||
this.post.unlike();
|
||||
expect(app.models.Like.prototype.destroy).toHaveBeenCalled();
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@@ -29,28 +29,6 @@ describe("app.views.CommentStream", function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe("createComment", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(this.view.model.comments, "create")
|
||||
})
|
||||
|
||||
it("clears the new comment textarea", function(){
|
||||
var comment = {
|
||||
"id": 1234,
|
||||
"text": "hey",
|
||||
"author": "not_null"
|
||||
};
|
||||
spyOn($, "ajax").andCallFake(function(params) {
|
||||
params.success(comment);
|
||||
});
|
||||
|
||||
$(this.view.el).html($("<textarea/>", {"class" : 'comment_box'}).val(comment.text))
|
||||
this.view.createComment()
|
||||
expect(this.view.$(".comment_box").val()).toBe("")
|
||||
expect(this.view.model.comments.create).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("appendComment", function(){
|
||||
it("appends this.model as 'parent' to the comment", function(){
|
||||
var comment = new app.models.Comment(factory.comment())
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("app.views.Feedback", function(){
|
||||
describe("triggers", function() {
|
||||
it('re-renders when the model triggers feedback', function(){
|
||||
spyOn(this.view, "postRenderTemplate")
|
||||
this.view.model.trigger("interacted")
|
||||
this.view.model.interactions.trigger("change")
|
||||
expect(this.view.postRenderTemplate).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -32,15 +32,17 @@ describe("app.views.Feedback", function(){
|
||||
|
||||
context("likes", function(){
|
||||
it("calls 'toggleLike' on the target post", function(){
|
||||
loginAs(this.post.interactions.likes.models[0].get("author"))
|
||||
this.view.render();
|
||||
spyOn(this.post, "toggleLike");
|
||||
|
||||
spyOn(this.post.interactions, "toggleLike");
|
||||
this.link().click();
|
||||
expect(this.post.toggleLike).toHaveBeenCalled();
|
||||
expect(this.post.interactions.toggleLike).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
context("when the user likes the post", function(){
|
||||
it("the like action should be 'Unlike'", function(){
|
||||
spyOn(this.post.interactions, "userLike").andReturn(factory.like());
|
||||
this.view.render()
|
||||
expect(this.link().text()).toContain(Diaspora.I18n.t('stream.unlike'))
|
||||
})
|
||||
})
|
||||
@@ -137,7 +139,7 @@ describe("app.views.Feedback", function(){
|
||||
|
||||
it("reshares the model", function(){
|
||||
spyOn(window, "confirm").andReturn(true);
|
||||
spyOn(this.view.model.reshare(), "save")
|
||||
spyOn(this.view.model.reshare(), "save").andReturn(new $.Deferred)
|
||||
this.view.$(".reshare_action").first().click();
|
||||
expect(this.view.model.reshare().save).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
@@ -16,34 +16,32 @@ describe("app.views.LikesInfo", function(){
|
||||
|
||||
describe(".render", function(){
|
||||
it("displays a the like count if it is above zero", function() {
|
||||
spyOn(this.view.model.interactions, "likesCount").andReturn(3);
|
||||
this.view.render();
|
||||
this.view.model.set({"likes_count" : 1})
|
||||
|
||||
expect($(this.view.el).find(".expand_likes").length).toBe(1)
|
||||
})
|
||||
|
||||
it("does not display the like count if it is zero", function() {
|
||||
this.post.save({likes_count : 0});
|
||||
spyOn(this.view.model.interactions, "likesCount").andReturn(0);
|
||||
this.view.render();
|
||||
|
||||
expect($(this.view.el).html().trim()).toBe("");
|
||||
})
|
||||
|
||||
it("fires on a model change", function(){
|
||||
spyOn(this.view, "postRenderTemplate")
|
||||
this.view.model.trigger('expandedLikes')
|
||||
this.view.model.interactions.trigger('change')
|
||||
expect(this.view.postRenderTemplate).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("showAvatars", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(this.post.likes, "fetch").andCallThrough()
|
||||
spyOn(this.post.interactions, "fetch").andCallThrough()
|
||||
})
|
||||
|
||||
it("calls fetch on the model's like collection", function(){
|
||||
this.view.showAvatars();
|
||||
expect(this.post.likes.fetch).toHaveBeenCalled();
|
||||
expect(this.post.interactions.fetch).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
it("sets the fetched response to the model's likes", function(){
|
||||
|
||||
@@ -57,20 +57,24 @@ factory = {
|
||||
"provider_display_name" : null,
|
||||
"created_at" : "2012-01-03T19:53:13Z",
|
||||
"interacted_at" : '2012-01-03T19:53:13Z',
|
||||
"last_three_comments" : null,
|
||||
"public" : false,
|
||||
"guid" : this.guid(),
|
||||
"image_url" : null,
|
||||
"o_embed_cache" : null,
|
||||
"photos" : [],
|
||||
"text" : "jasmine is bomb",
|
||||
"reshares_count" : 0,
|
||||
"id" : this.id.next(),
|
||||
"object_url" : null,
|
||||
"root" : null,
|
||||
"post_type" : "StatusMessage",
|
||||
"likes_count" : 0,
|
||||
"comments_count" : 0
|
||||
"interactions" : {
|
||||
"reshares_count" : 0,
|
||||
"likes_count" : 0,
|
||||
"comments_count" : 0,
|
||||
"comments" : [],
|
||||
"likes" : [],
|
||||
"reshares" : []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -77,9 +77,10 @@ describe User::SocialActions do
|
||||
|
||||
it "does not allow multiple likes" do
|
||||
alice.like!(@status)
|
||||
lambda {
|
||||
alice.like!(@status)
|
||||
}.should_not change(@status, :likes)
|
||||
likes = @status.likes
|
||||
expect { alice.like!(@status) }.to raise_error
|
||||
|
||||
@status.reload.likes.should == likes
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user