381 lines
13 KiB
Ruby
381 lines
13 KiB
Ruby
module MentioningSpecHelpers
|
|
def notifications_about_mentioning(user, object)
|
|
table = object.class.table_name
|
|
|
|
if object.is_a?(StatusMessage)
|
|
klass = Notifications::MentionedInPost
|
|
elsif object.is_a?(Comment)
|
|
klass = Notifications::MentionedInComment
|
|
end
|
|
|
|
klass
|
|
.where(recipient_id: user.id)
|
|
.joins("LEFT OUTER JOIN mentions ON notifications.target_id = mentions.id AND "\
|
|
"notifications.target_type = 'Mention'")
|
|
.joins("LEFT OUTER JOIN #{table} ON mentions_container_id = #{table}.id AND "\
|
|
"mentions_container_type = '#{object.class.base_class}'").where(table.to_sym => {id: object.id})
|
|
end
|
|
|
|
def mention_container_path(object)
|
|
object.is_a?(Post) ? post_path(object) : post_path(object.parent, anchor: object.guid)
|
|
end
|
|
|
|
def mentioning_mail_notification(user, object)
|
|
ActionMailer::Base.deliveries.select {|delivery|
|
|
delivery.to.include?(user.email) &&
|
|
delivery.subject.include?(I18n.t("notifier.mentioned.subject", name: "")) &&
|
|
delivery.body.parts[0].body.include?(mention_container_path(object))
|
|
}
|
|
end
|
|
|
|
def also_commented_mail_notification(user, post)
|
|
ActionMailer::Base.deliveries.select {|delivery|
|
|
delivery.to.include?(user.email) &&
|
|
delivery.subject.include?(I18n.t("notifier.also_commented.limited_subject")) &&
|
|
delivery.body.parts[0].body.include?(post_path(post))
|
|
}
|
|
end
|
|
|
|
def stream_for(user)
|
|
stream = Stream::Multi.new(user)
|
|
stream.posts
|
|
end
|
|
|
|
def mention_stream_for(user)
|
|
stream = Stream::Mention.new(user)
|
|
stream.posts
|
|
end
|
|
|
|
def post_status_message(mentioned_user, aspects=nil)
|
|
aspects = user1.aspects.first.id.to_s if aspects.nil?
|
|
sign_in user1
|
|
status_msg = nil
|
|
inlined_jobs do
|
|
post "/status_messages.json", status_message: {text: text_mentioning(mentioned_user)}, aspect_ids: aspects
|
|
status_msg = StatusMessage.find(JSON.parse(response.body)["id"])
|
|
end
|
|
status_msg
|
|
end
|
|
|
|
def receive_each(entity, recipients)
|
|
inlined_jobs do
|
|
recipients.each do |recipient|
|
|
DiasporaFederation.callbacks.trigger(:receive_entity, entity, entity.author, recipient.id)
|
|
end
|
|
end
|
|
end
|
|
|
|
def find_private_message(guid)
|
|
StatusMessage.find_by(guid: guid).tap do |status_msg|
|
|
expect(status_msg).not_to be_nil
|
|
expect(status_msg.public?).to be false
|
|
end
|
|
end
|
|
|
|
def receive_status_message_via_federation(text, *recipients)
|
|
entity = FactoryGirl.build(
|
|
:status_message_entity,
|
|
author: remote_raphael.diaspora_handle,
|
|
text: text,
|
|
public: false
|
|
)
|
|
|
|
expect {
|
|
receive_each(entity, recipients)
|
|
}.to change(Post, :count).by(1).and change(ShareVisibility, :count).by(recipients.count)
|
|
|
|
find_private_message(entity.guid)
|
|
end
|
|
|
|
def receive_comment_via_federation(text, parent)
|
|
entity = build_relayable_federation_entity(
|
|
:comment,
|
|
parent_guid: parent.guid,
|
|
author: remote_raphael.diaspora_handle,
|
|
parent: Diaspora::Federation::Entities.related_entity(parent),
|
|
text: text
|
|
)
|
|
|
|
receive_each(entity, [parent.author.owner])
|
|
|
|
Comment.find_by(guid: entity.guid)
|
|
end
|
|
end
|
|
|
|
describe "mentioning", type: :request do
|
|
include MentioningSpecHelpers
|
|
|
|
RSpec::Matchers.define :be_mentioned_in do |object|
|
|
include Rails.application.routes.url_helpers
|
|
|
|
def user_notified?(user, object)
|
|
notifications_about_mentioning(user, object).any? && mentioning_mail_notification(user, object).any?
|
|
end
|
|
|
|
match do |user|
|
|
object.message.markdownified.include?(person_path(id: user.person.guid)) && user_notified?(user, object)
|
|
end
|
|
|
|
match_when_negated do |user|
|
|
!user_notified?(user, object)
|
|
end
|
|
end
|
|
|
|
RSpec::Matchers.define :be_in_streams_of do |user|
|
|
match do |status_message|
|
|
stream_for(user).map(&:id).include?(status_message.id) &&
|
|
mention_stream_for(user).map(&:id).include?(status_message.id)
|
|
end
|
|
|
|
match_when_negated do |status_message|
|
|
!stream_for(user).map(&:id).include?(status_message.id) &&
|
|
!mention_stream_for(user).map(&:id).include?(status_message.id)
|
|
end
|
|
end
|
|
|
|
let(:user1) { FactoryGirl.create(:user_with_aspect) }
|
|
let(:user2) { FactoryGirl.create(:user_with_aspect, friends: [user1, user3]) }
|
|
let(:user3) { FactoryGirl.create(:user_with_aspect) }
|
|
|
|
# see: https://github.com/diaspora/diaspora/issues/4160
|
|
it "only mentions people that are in the target aspect" do
|
|
status_msg = nil
|
|
expect {
|
|
status_msg = post_status_message(user3)
|
|
}.to change(Post, :count).by(1).and change(AspectVisibility, :count).by(1)
|
|
|
|
expect(status_msg).not_to be_nil
|
|
expect(status_msg.public?).to be false
|
|
expect(status_msg.text).to include(user3.name)
|
|
|
|
expect(user3).not_to be_mentioned_in(status_msg)
|
|
expect(status_msg).not_to be_in_streams_of(user3)
|
|
end
|
|
|
|
context "in private post via federation" do
|
|
let(:status_msg) {
|
|
receive_status_message_via_federation(text_mentioning(user2, user3), user3)
|
|
}
|
|
|
|
it "receiver is mentioned in status message" do
|
|
expect(user3).to be_mentioned_in(status_msg)
|
|
end
|
|
|
|
it "receiver can see status message in streams" do
|
|
expect(status_msg).to be_in_streams_of(user3)
|
|
end
|
|
|
|
it "non-receiver is not mentioned in status message" do
|
|
expect(user2).not_to be_mentioned_in(status_msg)
|
|
end
|
|
|
|
it "non-receiver can't see status message in streams" do
|
|
expect(status_msg).not_to be_in_streams_of(user2)
|
|
end
|
|
end
|
|
|
|
context "in private post via federation with multiple recipients" do
|
|
let(:status_msg) {
|
|
receive_status_message_via_federation(text_mentioning(user3, user2), user3, user2)
|
|
}
|
|
|
|
it "mentions all recipients in the status message" do
|
|
[user2, user3].each do |user|
|
|
expect(user).to be_mentioned_in(status_msg)
|
|
end
|
|
end
|
|
|
|
it "all recipients can see status message in streams" do
|
|
[user2, user3].each do |user|
|
|
expect(status_msg).to be_in_streams_of(user)
|
|
end
|
|
end
|
|
end
|
|
|
|
it "mentions people in public posts" do
|
|
status_msg = nil
|
|
expect {
|
|
status_msg = post_status_message(user3, "public")
|
|
}.to change(Post, :count).by(1)
|
|
|
|
expect(status_msg).not_to be_nil
|
|
expect(status_msg.public?).to be true
|
|
expect(status_msg.text).to include(user3.name)
|
|
expect(status_msg.text).to include(user3.diaspora_handle)
|
|
|
|
expect(user3).to be_mentioned_in(status_msg)
|
|
expect(status_msg).to be_in_streams_of(user3)
|
|
end
|
|
|
|
it "mentions people that are in the target aspect" do
|
|
status_msg = nil
|
|
expect {
|
|
status_msg = post_status_message(user2)
|
|
}.to change(Post, :count).by(1).and change(AspectVisibility, :count).by(1)
|
|
|
|
expect(status_msg).not_to be_nil
|
|
expect(status_msg.public?).to be false
|
|
expect(status_msg.text).to include(user2.name)
|
|
expect(status_msg.text).to include(user2.diaspora_handle)
|
|
|
|
expect(user2).to be_mentioned_in(status_msg)
|
|
expect(status_msg).to be_in_streams_of(user2)
|
|
end
|
|
|
|
context "in comments" do
|
|
let(:author) { FactoryGirl.create(:user_with_aspect) }
|
|
|
|
shared_context "commenter is author" do
|
|
let(:commenter) { author }
|
|
end
|
|
|
|
shared_context "commenter is author's friend" do
|
|
let(:commenter) { FactoryGirl.create(:user_with_aspect, friends: [author]) }
|
|
end
|
|
|
|
shared_context "commenter is not author's friend" do
|
|
let(:commenter) { FactoryGirl.create(:user) }
|
|
end
|
|
|
|
shared_context "mentioned user is author" do
|
|
let(:mentioned_user) { author }
|
|
end
|
|
|
|
shared_context "mentioned user is author's friend" do
|
|
let(:mentioned_user) { FactoryGirl.create(:user_with_aspect, friends: [author]) }
|
|
end
|
|
|
|
shared_context "mentioned user is not author's friend" do
|
|
let(:mentioned_user) { FactoryGirl.create(:user) }
|
|
end
|
|
|
|
context "with public post" do
|
|
let(:status_msg) { FactoryGirl.create(:status_message, author: author.person, public: true) }
|
|
|
|
[
|
|
["commenter is author's friend", "mentioned user is not author's friend"],
|
|
["commenter is author's friend", "mentioned user is author"],
|
|
["commenter is not author's friend", "mentioned user is author's friend"],
|
|
["commenter is not author's friend", "mentioned user is not author's friend"],
|
|
["commenter is author", "mentioned user is author's friend"],
|
|
["commenter is author", "mentioned user is not author's friend"]
|
|
].each do |commenters_context, mentioned_context|
|
|
context "when #{commenters_context} and #{mentioned_context}" do
|
|
include_context commenters_context
|
|
include_context mentioned_context
|
|
|
|
let(:comment) {
|
|
inlined_jobs do
|
|
commenter.comment!(status_msg, text_mentioning(mentioned_user))
|
|
end
|
|
}
|
|
|
|
subject { mentioned_user }
|
|
it { is_expected.to be_mentioned_in(comment) }
|
|
end
|
|
end
|
|
|
|
context "when comment is received via federation" do
|
|
context "when mentioned user is remote" do
|
|
it "relays the comment to the mentioned user" do
|
|
mentioned_person = FactoryGirl.create(:person)
|
|
expect_any_instance_of(Diaspora::Federation::Dispatcher::Public)
|
|
.to receive(:deliver_to_remote).with([mentioned_person])
|
|
|
|
receive_comment_via_federation(text_mentioning(mentioned_person), status_msg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with private post" do
|
|
[
|
|
["commenter is author's friend", "mentioned user is author's friend"],
|
|
["commenter is author", "mentioned user is author's friend"],
|
|
["commenter is author's friend", "mentioned user is author"]
|
|
].each do |commenters_context, mentioned_context|
|
|
context "when #{commenters_context} and #{mentioned_context}" do
|
|
include_context commenters_context
|
|
include_context mentioned_context
|
|
|
|
let(:parent) { FactoryGirl.create(:status_message_in_aspect, author: author.person) }
|
|
let(:comment) {
|
|
inlined_jobs do
|
|
commenter.comment!(parent, text_mentioning(mentioned_user))
|
|
end
|
|
}
|
|
|
|
before do
|
|
mentioned_user.like!(parent)
|
|
end
|
|
|
|
subject { mentioned_user }
|
|
it { is_expected.to be_mentioned_in(comment) }
|
|
end
|
|
end
|
|
|
|
context "when comment is received via federation" do
|
|
let(:parent) { FactoryGirl.create(:status_message_in_aspect, author: user2.person) }
|
|
|
|
before do
|
|
user3.like!(parent)
|
|
user1.like!(parent)
|
|
end
|
|
|
|
let(:comment_text) { text_mentioning(user2, user3, user1) }
|
|
let(:comment) { receive_comment_via_federation(comment_text, parent) }
|
|
|
|
it "mentions all the recepients" do
|
|
[user1, user2, user3].each do |user|
|
|
expect(user).to be_mentioned_in(comment)
|
|
end
|
|
end
|
|
|
|
context "with only post author mentioned" do
|
|
let(:post_author) { parent.author.owner }
|
|
let(:comment_text) { text_mentioning(post_author) }
|
|
|
|
it "makes only one notification for each recipient" do
|
|
expect {
|
|
comment
|
|
}.to change { Notifications::MentionedInComment.for(post_author).count }.by(1)
|
|
.and change { Notifications::AlsoCommented.for(user1).count }.by(1)
|
|
.and change { Notifications::AlsoCommented.for(user3).count }.by(1)
|
|
|
|
expect(mentioning_mail_notification(post_author, comment).count).to eq(1)
|
|
|
|
[user1, user3].each do |user|
|
|
expect(also_commented_mail_notification(user, parent).count).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "commenter can't mention a non-participant" do
|
|
let(:status_msg) { FactoryGirl.create(:status_message_in_aspect, author: author.person) }
|
|
|
|
[
|
|
["commenter is author's friend", "mentioned user is not author's friend"],
|
|
["commenter is not author's friend", "mentioned user is author's friend"],
|
|
["commenter is not author's friend", "mentioned user is not author's friend"],
|
|
["commenter is author", "mentioned user is author's friend"],
|
|
["commenter is author", "mentioned user is not author's friend"]
|
|
].each do |commenters_context, mentioned_context|
|
|
context "when #{commenters_context} and #{mentioned_context}" do
|
|
include_context commenters_context
|
|
include_context mentioned_context
|
|
|
|
let(:comment) {
|
|
inlined_jobs do
|
|
commenter.comment!(status_msg, text_mentioning(mentioned_user))
|
|
end
|
|
}
|
|
|
|
subject { mentioned_user }
|
|
it { is_expected.not_to be_mentioned_in(comment) }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|