diff --git a/Changelog.md b/Changelog.md
index c0aba9a85..1a7c2d134 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -177,6 +177,7 @@ diaspora.yml file**. The existing settings from 0.4.x and before will not work a
* Give admins the ability to lock & unlock accounts [#5643](https://github.com/diaspora/diaspora/pull/5643)
* Add reshares to the stream view immediately [#5699](https://github.com/diaspora/diaspora/pull/5699)
* Start help section for the chat [#5665](https://github.com/diaspora/diaspora/pull/5665)
+* Expose participation controls in the stream view [#5511](https://github.com/diaspora/diaspora/pull/5511)
# 0.4.1.2
diff --git a/app/assets/images/icons-s71323e8d98.png b/app/assets/images/icons-s71323e8d98.png
deleted file mode 100644
index 026503b9a..000000000
Binary files a/app/assets/images/icons-s71323e8d98.png and /dev/null differ
diff --git a/app/assets/images/icons-sbcb16d92c7.png b/app/assets/images/icons-sbcb16d92c7.png
new file mode 100644
index 000000000..8ddc17847
Binary files /dev/null and b/app/assets/images/icons-sbcb16d92c7.png differ
diff --git a/app/assets/images/icons/create_participation.png b/app/assets/images/icons/create_participation.png
new file mode 100644
index 000000000..7496495b9
Binary files /dev/null and b/app/assets/images/icons/create_participation.png differ
diff --git a/app/assets/images/icons/destroy_participation.png b/app/assets/images/icons/destroy_participation.png
new file mode 100644
index 000000000..f13d187a6
Binary files /dev/null and b/app/assets/images/icons/destroy_participation.png differ
diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js
index da34f8bd8..5a317bdd4 100644
--- a/app/assets/javascripts/app/views/stream_post_views.js
+++ b/app/assets/javascripts/app/views/stream_post_views.js
@@ -23,10 +23,13 @@ app.views.StreamPost = app.views.Post.extend({
"click .remove_post": "destroyModel",
"click .hide_post": "hidePost",
"click .post_report": "report",
- "click .block_user": "blockUser"
+ "click .block_user": "blockUser",
+
+ "click .create_participation": "createParticipation",
+ "click .destroy_participation": "destroyParticipation"
},
- tooltipSelector : ".timeago, .post_scope, .block_user, .delete",
+ tooltipSelector : ".timeago, .post_scope, .block_user, .delete, .create_participation, .destroy_participation",
initialize : function(){
var personId = this.model.get('author').id;
@@ -113,6 +116,24 @@ app.views.StreamPost = app.views.Post.extend({
});
},
+ createParticipation: function (evt) {
+ if(evt) { evt.preventDefault(); }
+ that = this;
+ $.post(Routes.post_participation_path(this.model.get("id")), {}, function () {
+ that.model.set({participation: true});
+ that.render();
+ });
+ },
+
+ destroyParticipation: function (evt) {
+ if(evt) { evt.preventDefault(); }
+ that = this;
+ $.post(Routes.post_participation_path(this.model.get("id")), { _method: "delete" }, function () {
+ that.model.set({participation: false});
+ that.render();
+ });
+ },
+
focusCommentTextarea: function(evt){
evt.preventDefault();
this.$(".new_comment_form_wrapper").removeClass("hidden");
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss
index a3e81c602..65f0771cd 100644
--- a/app/assets/stylesheets/application.css.scss
+++ b/app/assets/stylesheets/application.css.scss
@@ -279,6 +279,20 @@ ul.as-selections {
width: 14px;
}
}
+ .create_participation {
+ display: inline-block;
+ .icons-create_participation {
+ height: 14px;
+ width: 14px;
+ }
+ }
+ .destroy_participation {
+ display: inline-block;
+ .icons-destroy_participation {
+ height: 14px;
+ width: 14px;
+ }
+ }
.delete {
display: inline-block;
.icons-deletelabel {
diff --git a/app/assets/templates/stream-element_tpl.jst.hbs b/app/assets/templates/stream-element_tpl.jst.hbs
index 9a6952808..4ed0daeb9 100644
--- a/app/assets/templates/stream-element_tpl.jst.hbs
+++ b/app/assets/templates/stream-element_tpl.jst.hbs
@@ -16,6 +16,15 @@
+ {{#if participation}}
+
+
+
+ {{else}}
+
+
+
+ {{/if}}
@@ -26,7 +35,7 @@
{{/unless}}
{{/if}}
-
+
{{#with author}}
{{name}}
diff --git a/app/controllers/participations_controller.rb b/app/controllers/participations_controller.rb
new file mode 100644
index 000000000..95e8a2c03
--- /dev/null
+++ b/app/controllers/participations_controller.rb
@@ -0,0 +1,23 @@
+class ParticipationsController < ApplicationController
+ before_action :authenticate_user!
+
+ def create
+ post = current_user.find_visible_shareable_by_id(Post, params[:post_id])
+ if post
+ current_user.participate! post
+ render nothing: true, status: :created
+ else
+ render nothing: true, status: :forbidden
+ end
+ end
+
+ def destroy
+ participation = current_user.participations.find_by target_id: params[:post_id]
+ if participation
+ participation.destroy
+ render nothing: true, status: :ok
+ else
+ render nothing: true, status: :unprocessable_entity
+ end
+ end
+end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index b71fcaa22..aa86daedb 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -60,7 +60,7 @@ class Comment < ActiveRecord::Base
def notification_type(user, person)
if self.post.author == user.person
return Notifications::CommentOnPost
- elsif self.post.comments.where(:author_id => user.person.id) != [] && self.author_id != user.person.id
+ elsif user.participations.where(:target_id => self.post).exists? && self.author_id != user.person.id
return Notifications::AlsoCommented
else
return false
diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb
index ff3877bf7..766961e96 100644
--- a/app/presenters/post_presenter.rb
+++ b/app/presenters/post_presenter.rb
@@ -41,13 +41,14 @@ class PostPresenter
:address => @post.address,
:poll => @post.poll(),
:already_participated_in_poll => already_participated_in_poll,
+ :participation => participate?,
:interactions => {
:likes => [user_like].compact,
:reshares => [user_reshare].compact,
:comments_count => @post.comments_count,
:likes_count => @post.likes_count,
- :reshares_count => @post.reshares_count,
+ :reshares_count => @post.reshares_count
}
}
end
@@ -86,6 +87,10 @@ class PostPresenter
end
end
+ def participate?
+ user_signed_in? && @current_user.participations.where(:target_id => @post).exists?
+ end
+
end
class PostInteractionPresenter
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index 09f19b739..03d7e5337 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -166,6 +166,8 @@ en:
hide_nsfw_posts: "Hide #nsfw posts"
follow: "Follow"
unfollow: "Unfollow"
+ enable_post_notifications: "Enable notifications for this post"
+ disable_post_notifications: "Disable notifications for this post"
via: "via <%= provider %>"
likes:
diff --git a/config/routes.rb b/config/routes.rb
index 8eed61639..e31d8409d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -36,7 +36,7 @@ Diaspora::Application.routes.draw do
resources :poll_participations, :only => [:create]
resources :likes, :only => [:create, :destroy, :index ]
- resources :participations, :only => [:create, :destroy, :index]
+ resource :participation, :only => [:create, :destroy]
resources :comments, :only => [:new, :create, :destroy, :index]
end
diff --git a/spec/controllers/participations_controller_spec.rb b/spec/controllers/participations_controller_spec.rb
new file mode 100644
index 000000000..f9de58b39
--- /dev/null
+++ b/spec/controllers/participations_controller_spec.rb
@@ -0,0 +1,79 @@
+require 'spec_helper'
+
+describe ParticipationsController, :type => :controller do
+ before do
+ allow(@controller).to receive(:current_user).and_return(alice)
+ sign_in :user, alice
+ end
+
+ describe '#create' do
+ let(:stranger) { FactoryGirl.create(:user) }
+
+ shared_examples 'on a visible post' do
+ it 'creates the participation' do
+ post :create, post_id: @post.id
+ expect(alice.participations.where(:target_id => @post.id)).to exist
+ expect(response.code).to eq('201')
+ end
+ end
+
+ context 'on my own post' do
+ before do
+ aspect_to_post = alice.aspects.where(:name => 'generic').first
+ @post = alice.post :status_message, :text => 'something', :to => aspect_to_post
+ end
+
+ it_behaves_like 'on a visible post'
+ end
+
+ context 'on a post from a contact' do
+ before do
+ aspect_to_post = bob.aspects.where(:name => 'generic').first
+ @post = bob.post :status_message, :text => 'something', :to => aspect_to_post
+ end
+
+ it_behaves_like 'on a visible post'
+ end
+
+ context 'on a public post from a stranger' do
+ before do
+ @post = stranger.post :status_message, :text => 'something', :public => true, :to => 'all'
+ end
+
+ it_behaves_like 'on a visible post'
+ end
+
+ context 'on a non visible post' do
+ before do
+ @post = stranger.post :status_message, :text => 'something', :public => false, :to => 'all'
+ end
+
+ it 'should not create the participation' do
+ post :create, post_id: @post.id
+ expect(alice.participations.where(:target_id => @post.id)).not_to exist
+ expect(response.code).to eq('403')
+ end
+ end
+ end
+
+ describe '#destroy' do
+ let(:post) { FactoryGirl.create(:status_message) }
+
+ context 'on a post you partecipate to' do
+ before { alice.participate! post }
+
+ it 'should remove participation' do
+ delete :destroy, post_id: post.id
+ expect(alice.participations.where(:target_id => post.id)).not_to exist
+ expect(response.code).to eq('204')
+ end
+ end
+
+ context 'on a post you do not partecipate to' do
+ it 'says it is an unprocessable request' do
+ delete :destroy, post_id: post.id
+ expect(response.code).to eq('422')
+ end
+ end
+ end
+end
diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb
index efc7eacdc..2e2a91205 100644
--- a/spec/models/comment_spec.rb
+++ b/spec/models/comment_spec.rb
@@ -12,11 +12,17 @@ describe Comment, :type => :model do
end
describe 'comment#notification_type' do
+ let (:comment) { alice.comment!(@status, "why so formal?") }
+
it "returns 'comment_on_post' if the comment is on a post you own" do
- comment = alice.comment!(@status, "why so formal?")
expect(comment.notification_type(bob, alice.person)).to eq(Notifications::CommentOnPost)
end
+ it "returns 'also_commented' if the comment is on a post you participate to" do
+ eve.participate! @status
+ expect(comment.notification_type(eve, alice.person)).to eq(Notifications::AlsoCommented)
+ end
+
it 'returns false if the comment is not on a post you own and no one "also_commented"' do
comment = alice.comment!(@status, "I simply felt like issuing a greeting. Do step off.")
expect(comment.notification_type(eve, alice.person)).to be false