Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/diaspora/diaspora.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rvmrc2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/app/collections/comments.js13
-rw-r--r--app/assets/javascripts/app/collections/participations.js7
-rw-r--r--app/assets/javascripts/app/collections/reshares.js4
-rw-r--r--app/assets/javascripts/app/models/participation.js1
-rw-r--r--app/assets/javascripts/app/models/post.js63
-rw-r--r--app/assets/javascripts/app/models/post/interactions.js116
-rw-r--r--app/assets/javascripts/app/models/reshare.js2
-rw-r--r--app/assets/javascripts/app/pages/post-viewer.js4
-rw-r--r--app/assets/javascripts/app/views/comment_stream_view.js5
-rw-r--r--app/assets/javascripts/app/views/comment_view.js6
-rw-r--r--app/assets/javascripts/app/views/feedback_view.js42
-rw-r--r--app/assets/javascripts/app/views/likes_info_view.js14
-rw-r--r--app/assets/javascripts/app/views/post-viewer/feedback.js6
-rw-r--r--app/assets/javascripts/app/views/post-viewer/interactions.js5
-rw-r--r--app/assets/javascripts/app/views/post-viewer/new_comment.js3
-rw-r--r--app/assets/javascripts/app/views/post-viewer/reactions.js20
-rw-r--r--app/assets/javascripts/app/views/small_frame.js20
-rw-r--r--app/assets/stylesheets/application.css.sass2
-rw-r--r--app/assets/stylesheets/new_styles/_base.scss8
-rw-r--r--app/assets/stylesheets/new_styles/_canvas.scss28
-rw-r--r--app/assets/stylesheets/new_styles/_profile.scss26
-rw-r--r--app/assets/stylesheets/ui.css.sass2
-rw-r--r--app/assets/templates/comment-stream.jst.hbs2
-rw-r--r--app/assets/templates/feedback.jst.hbs2
-rw-r--r--app/assets/templates/likes-info.jst.hbs9
-rw-r--r--app/assets/templates/post-viewer/feedback.jst.hbs20
-rw-r--r--app/assets/templates/profile-info.jst.hbs11
-rw-r--r--app/assets/templates/small-frame.jst.hbs6
-rw-r--r--app/controllers/comments_controller.rb2
-rw-r--r--app/controllers/likes_controller.rb52
-rw-r--r--app/controllers/participations_controller.rb68
-rw-r--r--app/controllers/posts_controller.rb82
-rw-r--r--app/models/post.rb11
-rw-r--r--app/presenters/extreme_post_presenter.rb2
-rw-r--r--app/presenters/last_three_comments_decorator.rb4
-rw-r--r--app/presenters/post_presenter.rb13
-rw-r--r--config/routes.rb4
-rw-r--r--features/post_viewer.feature30
-rw-r--r--lib/federated/generator.rb2
-rwxr-xr-xscript/install.sh14
-rw-r--r--spec/controllers/likes_controller_spec.rb15
-rw-r--r--spec/controllers/participations_controller_spec.rb128
-rw-r--r--spec/controllers/posts_controller_spec.rb29
-rw-r--r--spec/javascripts/app/models/post/interacations_spec.js45
-rw-r--r--spec/javascripts/app/models/post_spec.js39
-rw-r--r--spec/javascripts/app/views/comment_stream_view_spec.js22
-rw-r--r--spec/javascripts/app/views/feedback_view_spec.js12
-rw-r--r--spec/javascripts/app/views/likes_info_view_spec.js12
-rw-r--r--spec/javascripts/helpers/factory.js12
-rw-r--r--spec/models/user/social_actions_spec.rb7
53 files changed, 494 insertions, 566 deletions
diff --git a/.rvmrc b/.rvmrc
index 7b63509d5..01466e002 100644
--- a/.rvmrc
+++ b/.rvmrc
@@ -4,7 +4,7 @@ if [ -e '.rvmrc.local' ]; then
elif [ -e '.rvmrc_custom' ] ; then
source .rvmrc_custom;
else
- rvm --create use ruby-1.9.2-p290@diaspora
+ rvm --create use ruby-1.9.3-p125@diaspora
fi
if [ "$(gem --version)" != "1.8.17" ]; then
diff --git a/Gemfile b/Gemfile
index 2ca5f9b53..d4bcf4e4c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,8 +1,10 @@
source 'http://rubygems.org'
+gem 'bundler', '> 1.1.0'
+ruby '1.9.3' if ENV['HEROKU']
+
gem 'rails', '3.1.4'
gem 'rails_autolink'
-gem 'bundler', '~> 1.1.0'
gem 'foreman', '0.41'
gem 'whenever'
diff --git a/Gemfile.lock b/Gemfile.lock
index 152f632f5..98f4cce8a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -503,7 +503,7 @@ DEPENDENCIES
airbrake
asset_sync
bootstrap-sass (~> 2.0.2)
- bundler (~> 1.1.0)
+ bundler (> 1.1.0)
capistrano
capistrano-ext
capistrano_colors
diff --git a/app/assets/javascripts/app/collections/comments.js b/app/assets/javascripts/app/collections/comments.js
index efd825988..0b53b8cf0 100644
--- a/app/assets/javascripts/app/collections/comments.js
+++ b/app/assets/javascripts/app/collections/comments.js
@@ -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
}
});
diff --git a/app/assets/javascripts/app/collections/participations.js b/app/assets/javascripts/app/collections/participations.js
deleted file mode 100644
index bc861d784..000000000
--- a/app/assets/javascripts/app/collections/participations.js
+++ /dev/null
@@ -1,7 +0,0 @@
-app.collections.Participations = Backbone.Collection.extend({
- model: app.models.Participation,
-
- initialize : function(models, options) {
- this.url = "/posts/" + options.post.id + "/participations" //not delegating to post.url() because when it is in a stream collection it delegates to that url
- }
-});
diff --git a/app/assets/javascripts/app/collections/reshares.js b/app/assets/javascripts/app/collections/reshares.js
new file mode 100644
index 000000000..d2c74c8e5
--- /dev/null
+++ b/app/assets/javascripts/app/collections/reshares.js
@@ -0,0 +1,4 @@
+app.collections.Reshares = Backbone.Collection.extend({
+ model: app.models.Reshare,
+ url : "/reshares"
+});
diff --git a/app/assets/javascripts/app/models/participation.js b/app/assets/javascripts/app/models/participation.js
deleted file mode 100644
index 01c53d9e2..000000000
--- a/app/assets/javascripts/app/models/participation.js
+++ /dev/null
@@ -1 +0,0 @@
-app.models.Participation = Backbone.Model.extend({ });
diff --git a/app/assets/javascripts/app/models/post.js b/app/assets/javascripts/app/models/post.js
index e6f01de60..7ed5c69cd 100644
--- a/app/assets/javascripts/app/models/post.js
+++ b/app/assets/javascripts/app/models/post.js
@@ -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")
diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js
new file mode 100644
index 000000000..0cd51de81
--- /dev/null
+++ b/app/assets/javascripts/app/models/post/interactions.js
@@ -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;
+ }
+}); \ No newline at end of file
diff --git a/app/assets/javascripts/app/models/reshare.js b/app/assets/javascripts/app/models/reshare.js
index 68320eb80..7a4b83ff7 100644
--- a/app/assets/javascripts/app/models/reshare.js
+++ b/app/assets/javascripts/app/models/reshare.js
@@ -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
diff --git a/app/assets/javascripts/app/pages/post-viewer.js b/app/assets/javascripts/app/pages/post-viewer.js
index 17b0c19f8..71f1d663d 100644
--- a/app/assets/javascripts/app/pages/post-viewer.js
+++ b/app/assets/javascripts/app/pages/post-viewer.js
@@ -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()
},
diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js
index c97374fef..fbdda24d5 100644
--- a/app/assets/javascripts/app/views/comment_stream_view.js
+++ b/app/assets/javascripts/app/views/comment_stream_view.js
@@ -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()
})
},
diff --git a/app/assets/javascripts/app/views/comment_view.js b/app/assets/javascripts/app/views/comment_view.js
index cbed276a5..4a826a33d 100644
--- a/app/assets/javascripts/app/views/comment_view.js
+++ b/app/assets/javascripts/app/views/comment_view.js
@@ -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(),
diff --git a/app/assets/javascripts/app/views/feedback_view.js b/app/assets/javascripts/app/views/feedback_view.js
index 86f83bb7f..57e3a8ac8 100644
--- a/app/assets/javascripts/app/views/feedback_view.js
+++ b/app/assets/javascripts/app/views/feedback_view.js
@@ -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();
}
});
diff --git a/app/assets/javascripts/app/views/likes_info_view.js b/app/assets/javascripts/app/views/likes_info_view.js
index 5069f8946..f4f3071bb 100644
--- a/app/assets/javascripts/app/views/likes_info_view.js
+++ b/app/assets/javascripts/app/views/likes_info_view.js
@@ -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()
}
});
diff --git a/app/assets/javascripts/app/views/post-viewer/feedback.js b/app/assets/javascripts/app/views/post-viewer/feedback.js
index 7f8584ba4..de63cbbb1 100644
--- a/app/assets/javascripts/app/views/post-viewer/feedback.js
+++ b/app/assets/javascripts/app/views/post-viewer/feedback.js
@@ -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;
}
-
}); \ No newline at end of file
diff --git a/app/assets/javascripts/app/views/post-viewer/interactions.js b/app/assets/javascripts/app/views/post-viewer/interactions.js
index a0b17600b..7d78f7264 100644
--- a/app/assets/javascripts/app/views/post-viewer/interactions.js
+++ b/app/assets/javascripts/app/views/post-viewer/interactions.js
@@ -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 })
diff --git a/app/assets/javascripts/app/views/post-viewer/new_comment.js b/app/assets/javascripts/app/views/post-viewer/new_comment.js
index 16775a80c..f31da66ca 100644
--- a/app/assets/javascripts/app/views/post-viewer/new_comment.js
+++ b/app/assets/javascripts/app/views/post-viewer/new_comment.js
@@ -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')
diff --git a/app/assets/javascripts/app/views/post-viewer/reactions.js b/app/assets/javascripts/app/views/post-viewer/reactions.js
index 145ed1b02..1447bde22 100644
--- a/app/assets/javascripts/app/views/post-viewer/reactions.js
+++ b/app/assets/javascripts/app/views/post-viewer/reactions.js
@@ -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);
}
-
}); \ No newline at end of file
diff --git a/app/assets/javascripts/app/views/small_frame.js b/app/assets/javascripts/app/views/small_frame.js
index 64f69a0c2..4ea26f4de 100644
--- a/app/assets/javascripts/app/views/small_frame.js
+++ b/app/assets/javascripts/app/views/small_frame.js
@@ -26,8 +26,13 @@ app.views.SmallFrame = app.views.Post.extend({
presenter : function(){
//todo : we need to have something better for small frame text, probably using the headline() scenario.
return _.extend(this.defaultPresenter(),
- {text : this.model && app.helpers.textFormatter(this.model.get("text"), this.model),
- adjustedImageHeight : this.adjustedImageHeight()})
+ {
+ text : this.model && app.helpers.textFormatter(this.model.get("text"), this.model),
+ adjustedImageHeight : this.adjustedImageHeight(),
+ likesCount : this.model.interactions.likesCount(),
+ resharesCount : this.model.interactions.resharesCount(),
+ commentsCount : this.model.interactions.commentsCount()
+ })
},
initialize : function() {
@@ -74,9 +79,17 @@ app.views.SmallFrame = app.views.Post.extend({
if(!(this.model.get("photos") || [])[0]) { return }
var modifiers = [this.dimensionsClass(), this.colorClass()].join(' ')
+ , width;
+
+ /* mobile width
+ *
+ * currently does not re-calculate on orientation change */
+ if($(window).width() <= 767) {
+ width = $(window).width();
+ }
var firstPhoto = this.model.get("photos")[0]
- , width = (modifiers.search("x2") != -1 ? this.DOUBLE_COLUMN_WIDTH : this.SINGLE_COLUMN_WIDTH)
+ , width = width || (modifiers.search("x2") != -1 ? this.DOUBLE_COLUMN_WIDTH : this.SINGLE_COLUMN_WIDTH)
, ratio = width / firstPhoto.dimensions.width;
return(ratio * firstPhoto.dimensions.height)
@@ -109,6 +122,7 @@ app.views.SmallFrame = app.views.Post.extend({
goToPost : function(evt) {
if(evt) { evt.stopImmediatePropagation(); }
+ window.preloads.post = this.model.attributes
app.router.navigate(this.model.url(), true)
}
}); \ No newline at end of file
diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass
index d21cc3c3d..6c8c3ed3a 100644
--- a/app/assets/stylesheets/application.css.sass
+++ b/app/assets/stylesheets/application.css.sass
@@ -1841,7 +1841,7 @@ ul#press_logos
.oembed
:background image-url('ajax-loader2.gif') no-repeat center center
- :display inline-block
+ :float left
:max-width 100%
.thumb
diff --git a/app/assets/stylesheets/new_styles/_base.scss b/app/assets/stylesheets/new_styles/_base.scss
index bed2a0df2..67c96ea11 100644
--- a/app/assets/stylesheets/new_styles/_base.scss
+++ b/app/assets/stylesheets/new_styles/_base.scss
@@ -1,5 +1,6 @@
body {
background-image : image_url("pattern.png");
+ padding : none;
}
/* new link color */
@@ -472,3 +473,10 @@ div[data-template=flow] {
font-family : Roboto-Bold;
}
}
+
+/* responsive */
+@media (max-width: 767px) {
+ body {
+ padding : 0;
+ }
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/new_styles/_canvas.scss b/app/assets/stylesheets/new_styles/_canvas.scss
index 5ccb538c2..56093fbce 100644
--- a/app/assets/stylesheets/new_styles/_canvas.scss
+++ b/app/assets/stylesheets/new_styles/_canvas.scss
@@ -1,7 +1,5 @@
@mixin wide() {
width : $two-column-width + px;
- min-width : $two-column-width + px;
- max-width : $two-column-width + px;
}
.no-post-message {
text-align: center;
@@ -14,6 +12,8 @@
margin : 10px;
margin-bottom : 18px;
+ max-width : 100%;
+
/* expand / contract cursor declarations */
&.x2 .content {
cursor : nw-resize;
@@ -57,8 +57,7 @@
background-color : #fff;
width : $column-width + px;
- min-width : $column-width + px;
- max-width : $column-width + px;
+ max-width : 100%;
overflow : hidden;
@@ -338,3 +337,24 @@
}
}
}
+
+/* responsive */
+@media (max-width: 767px) {
+ body {
+ padding : 0;
+ }
+
+ .canvas-frame {
+ width : 100%;
+ margin-left : 0;
+ margin-right : 0;
+
+ margin-bottom : 10px;
+
+ .content {
+ font-size : 0.9em;
+ margin : 0;
+ width : auto !important;
+ }
+ }
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/new_styles/_profile.scss b/app/assets/stylesheets/new_styles/_profile.scss
index 3b7782ddf..506178986 100644
--- a/app/assets/stylesheets/new_styles/_profile.scss
+++ b/app/assets/stylesheets/new_styles/_profile.scss
@@ -210,4 +210,30 @@
width : $two-column-width + px;
text-align : center;
}
+}
+
+/* responsive */
+@media (max-width: 767px) {
+ #profile {
+ background-size : 767px;
+ }
+
+ .profile-image-container {
+ height : 100px;
+ width : 100px;
+ border-width : 2px;
+ }
+
+ #profile-controls {
+ display : none;
+ }
+
+ #profile-header {
+ padding : 20px;
+ }
+
+ #wallpaper-upload,
+ .edit-control {
+ display : none;
+ }
} \ No newline at end of file
diff --git a/app/assets/stylesheets/ui.css.sass b/app/assets/stylesheets/ui.css.sass
index 34da95e4d..3fcfebeaf 100644
--- a/app/assets/stylesheets/ui.css.sass
+++ b/app/assets/stylesheets/ui.css.sass
@@ -123,7 +123,7 @@ input.button
:left 24px
:position relative
:color #222
- :list-style none
+ :list-style none !important
&.selected
:background
diff --git a/app/assets/templates/comment-stream.jst.hbs b/app/assets/templates/comment-stream.jst.hbs
index 200235fda..a41b612d9 100644
--- a/app/assets/templates/comment-stream.jst.hbs
+++ b/app/assets/templates/comment-stream.jst.hbs
@@ -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}}}
diff --git a/app/assets/templates/feedback.jst.hbs b/app/assets/templates/feedback.jst.hbs
index f22facbd2..bdf99a2af 100644
--- a/app/assets/templates/feedback.jst.hbs
+++ b/app/assets/templates/feedback.jst.hbs
@@ -15,7 +15,7 @@
<a href="#" class="like_action" rel='nofollow'>
- {{#if user_like}}
+ {{#if userLike}}
{{t "stream.unlike"}}
{{else}}
{{t "stream.like"}}
diff --git a/app/assets/templates/likes-info.jst.hbs b/app/assets/templates/likes-info.jst.hbs
index 6a833be78..6820ffb05 100644
--- a/app/assets/templates/likes-info.jst.hbs
+++ b/app/assets/templates/likes-info.jst.hbs
@@ -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>
diff --git a/app/assets/templates/post-viewer/feedback.jst.hbs b/app/assets/templates/post-viewer/feedback.jst.hbs
index 742d052c5..823db8cf9 100644
--- a/app/assets/templates/post-viewer/feedback.jst.hbs
+++ b/app/assets/templates/post-viewer/feedback.jst.hbs
@@ -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 -->
diff --git a/app/assets/templates/profile-info.jst.hbs b/app/assets/templates/profile-info.jst.hbs
index 4b137f1a2..d914fa9b0 100644
--- a/app/assets/templates/profile-info.jst.hbs
+++ b/app/assets/templates/profile-info.jst.hbs
@@ -36,10 +36,13 @@
</span>
{{#if is_own_profile}}
- <span class="divider">•</span>
- <a href="/profile/edit" title="Edit Profile" rel="tooltip" style="margin-left:2px;">
- <i class="icon-cog icon-white"></i>
- </a>
+ <span class="edit-control">
+ <span class="divider">•</span>
+ <a href="/profile/edit" title="Edit Profile" rel="tooltip" style="margin-left:2px;">
+ <i class="icon-cog icon-white"></i>
+ </a>
+ </span>
+ </span>
{{/if}}
</div>
diff --git a/app/assets/templates/small-frame.jst.hbs b/app/assets/templates/small-frame.jst.hbs
index 51b7158b5..8c07e7310 100644
--- a/app/assets/templates/small-frame.jst.hbs
+++ b/app/assets/templates/small-frame.jst.hbs
@@ -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>
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 58b683405..d8f43fc3d 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -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
diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb
index 1eaf0faa1..1d99009f5 100644
--- a/app/controllers/likes_controller.rb
+++ b/app/controllers/likes_controller.rb
@@ -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
diff --git a/app/controllers/participations_controller.rb b/app/controllers/participations_controller.rb
deleted file mode 100644
index 643368621..000000000
--- a/app/controllers/participations_controller.rb
+++ /dev/null
@@ -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
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 711f2561d..761028768 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -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
- protected
+ def interactions
+ respond_with(PostInteractionPresenter.new(@post, current_user))
+ end
+
+ def destroy
+ find_current_user_post(params[:id])
+ current_user.retract(@post)
- 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
+ respond_to do |format|
+ format.js { render 'destroy' }
+ format.json { render :nothing => true, :status => 204 }
+ format.all { redirect_to stream_path }
+ end
end
- def find_post
- @post = find_by_guid_or_id_with_current_user(params[:id])
+ def update
+ find_current_user_post(params[:id])
+ @post.favorite = !@post.favorite
+ @post.save
+ render :nothing => true, :status => 202
end
- def visible_posts_from_author
- Post.visible_from_author(@post.author, current_user)
+ protected
+
+ 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_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
diff --git a/app/models/post.rb b/app/models/post.rb
index 1dc27a93d..6e24533a7 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -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
diff --git a/app/presenters/extreme_post_presenter.rb b/app/presenters/extreme_post_presenter.rb
index 49d872a18..c35b54088 100644
--- a/app/presenters/extreme_post_presenter.rb
+++ b/app/presenters/extreme_post_presenter.rb
@@ -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 \ No newline at end of file
diff --git a/app/presenters/last_three_comments_decorator.rb b/app/presenters/last_three_comments_decorator.rb
index 884d0dc49..04e1c91b3 100644
--- a/app/presenters/last_three_comments_decorator.rb
+++ b/app/presenters/last_three_comments_decorator.rb
@@ -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 \ No newline at end of file
diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb
index 40b2fb954..151f51176 100644
--- a/app/presenters/post_presenter.rb
+++ b/app/presenters/post_presenter.rb
@@ -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
diff --git a/config/routes.rb b/config/routes.rb
index 9944d9e84..249eea6e0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -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
diff --git a/features/post_viewer.feature b/features/post_viewer.feature
index 784136759..4fec33fa5 100644
--- a/features/post_viewer.feature
+++ b/features/post_viewer.feature
@@ -1,15 +1,15 @@
-@javascript
-Feature: Post Viewer
- In order to make my content look really great
- As a User
- I want my posts to have a bunch of different templates that I can page through
-
- 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
+#@javascript
+#Feature: Post Viewer
+# In order to make my content look really great
+# As a User
+# I want my posts to have a bunch of different templates that I can page through
+#
+# Background:
+# Given a user with email "alice@alice.com"
+# And I sign in as "alice@alice.com"
+#
+## Wip tag sad on new cucumber, commenting for now.
+## 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
diff --git a/lib/federated/generator.rb b/lib/federated/generator.rb
index ba90546db..96fe9006c 100644
--- a/lib/federated/generator.rb
+++ b/lib/federated/generator.rb
@@ -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
diff --git a/script/install.sh b/script/install.sh
index 13dd9738f..3ba511261 100755
--- a/script/install.sh
+++ b/script/install.sh
@@ -32,7 +32,7 @@ other ideas what we could do
# #
#### ####
-BINARIES="git ruby gem bundle sed" # required programs
+BINARIES="git ruby gem bundle sed mktemp" # required programs
D_GIT_CLONE_PATH="/srv/diaspora" # path for diaspora
@@ -257,6 +257,8 @@ prepare_install_env() {
install_or_use_ruby
load_rvmrc
js_runtime_check
+
+ run_or_error "gem install bundler"
}
# do some sanity checking
@@ -344,10 +346,18 @@ database_setup() {
# display a nice welcome message
define WELCOME_MSG <<'EOT'
#####################################################################
+
DIASPORA* INSTALL SCRIPT
+----
+
This script will guide you through the basic steps
-to get a copy of Diaspora* up and running
+to get a DEVELOPMENT setup of Diaspora* up and running
+
+For a PRODUCTION installation, please do *not* use this script!
+Follow the guide in our wiki, instead:
+-- https://github.com/diaspora/diaspora/wiki/Installation-Guides
+
#####################################################################
EOT
diff --git a/spec/controllers/likes_controller_spec.rb b/spec/controllers/likes_controller_spec.rb
index 1b91262ca..8b27516b9 100644
--- a/spec/controllers/likes_controller_spec.rb
+++ b/spec/controllers/likes_controller_spec.rb
@@ -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
diff --git a/spec/controllers/participations_controller_spec.rb b/spec/controllers/participations_controller_spec.rb
deleted file mode 100644
index 63970b7a1..000000000
--- a/spec/controllers/participations_controller_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb
index 5fb918bf3..ad74d2d9a 100644
--- a/spec/controllers/posts_controller_spec.rb
+++ b/spec/controllers/posts_controller_spec.rb
@@ -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
diff --git a/spec/javascripts/app/models/post/interacations_spec.js b/spec/javascripts/app/models/post/interacations_spec.js
new file mode 100644
index 000000000..f6a5be3ad
--- /dev/null
+++ b/spec/javascripts/app/models/post/interacations_spec.js
@@ -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();
+ })
+ })
+}) \ No newline at end of file
diff --git a/spec/javascripts/app/models/post_spec.js b/spec/javascripts/app/models/post_spec.js
index 90dbca87c..c6f6ef14b 100644
--- a/spec/javascripts/app/models/post_spec.js
+++ b/spec/javascripts/app/models/post_spec.js
@@ -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();
- })
- })
});
diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js
index bcb72a470..f808a43df 100644
--- a/spec/javascripts/app/views/comment_stream_view_spec.js
+++ b/spec/javascripts/app/views/comment_stream_view_spec.js
@@ -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())
diff --git a/spec/javascripts/app/views/feedback_view_spec.js b/spec/javascripts/app/views/feedback_view_spec.js
index 223a41e37..3c6b9ee5c 100644
--- a/spec/javascripts/app/views/feedback_view_spec.js
+++ b/spec/javascripts/app/views/feedback_view_spec.js
@@ -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();
})
diff --git a/spec/javascripts/app/views/likes_info_view_spec.js b/spec/javascripts/app/views/likes_info_view_spec.js
index e01811245..a7ffb5484 100644
--- a/spec/javascripts/app/views/likes_info_view_spec.js
+++ b/spec/javascripts/app/views/likes_info_view_spec.js
@@ -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(){
diff --git a/spec/javascripts/helpers/factory.js b/spec/javascripts/helpers/factory.js
index fc8365740..48adcd0cf 100644
--- a/spec/javascripts/helpers/factory.js
+++ b/spec/javascripts/helpers/factory.js
@@ -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" : []
+ }
}
},
diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb
index a9a88078b..33c99e675 100644
--- a/spec/models/user/social_actions_spec.rb
+++ b/spec/models/user/social_actions_spec.rb
@@ -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 \ No newline at end of file