- add coordinates in post_presenter - add map to the SPV if location is provided - add leaflet.js to render map and marker of position - make coordinates available in frontend - add map scss - make stream post location clickable and redirect to the SPV - prevent render map if no location data is provided - add tests for coordinates - use the leaflet gem instead of the JS assets (#5813)
466 lines
15 KiB
Ruby
466 lines
15 KiB
Ruby
# 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 StatusMessage, type: :model do
|
|
include PeopleHelper
|
|
|
|
let!(:user) { alice }
|
|
let!(:aspect) { user.aspects.first }
|
|
let(:status) { build(:status_message) }
|
|
|
|
describe "scopes" do
|
|
describe ".where_person_is_mentioned" do
|
|
it "returns status messages where the given person is mentioned" do
|
|
@bob = bob.person
|
|
@test_string = "@{Daniel; #{@bob.diaspora_handle}} can mention people like Raph"
|
|
FactoryGirl.create(:status_message, text: @test_string)
|
|
FactoryGirl.create(:status_message, text: @test_string)
|
|
FactoryGirl.create(:status_message)
|
|
|
|
expect(StatusMessage.where_person_is_mentioned(bob).count).to eq(2)
|
|
end
|
|
end
|
|
|
|
context "tag_streams" do
|
|
before do
|
|
@status_message_1 = FactoryGirl.create(:status_message, text: "#hashtag", public: true)
|
|
@status_message_2 = FactoryGirl.create(:status_message, text: "#hashtag")
|
|
@status_message_3 = FactoryGirl.create(:status_message, text: "hashtags are #awesome", public: true)
|
|
@status_message_4 = FactoryGirl.create(:status_message, text: "hashtags are #awesome")
|
|
|
|
@tag_id = ActsAsTaggableOn::Tag.where(name: "hashtag").first.id
|
|
end
|
|
|
|
describe ".tag_steam" do
|
|
it "returns status messages tagged with the tag" do
|
|
tag_stream = StatusMessage.send(:tag_stream, [@tag_id])
|
|
expect(tag_stream).to include @status_message_1
|
|
expect(tag_stream).to include @status_message_2
|
|
end
|
|
end
|
|
|
|
describe ".public_tag_stream" do
|
|
it "returns public status messages tagged with the tag" do
|
|
expect(StatusMessage.public_tag_stream([@tag_id])).to eq([@status_message_1])
|
|
end
|
|
end
|
|
|
|
describe ".user_tag_stream" do
|
|
it "returns tag stream thats owned or visible by" do
|
|
relation = double
|
|
expect(StatusMessage).to receive(:owned_or_visible_by_user).with(bob).and_return(relation)
|
|
expect(relation).to receive(:tag_stream).with([@tag_id])
|
|
|
|
StatusMessage.user_tag_stream(bob, [@tag_id])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".guids_for_author" do
|
|
it "returns an array of the status_message guids" do
|
|
status_message_1 = FactoryGirl.create(:status_message, author: alice.person)
|
|
status_message_2 = FactoryGirl.create(:status_message, author: bob.person)
|
|
guids = StatusMessage.guids_for_author(alice.person)
|
|
expect(guids).to eq([status_message_1.guid])
|
|
end
|
|
end
|
|
|
|
describe ".before_validation" do
|
|
it "calls build_tags" do
|
|
expect(status).to receive(:build_tags)
|
|
status.save
|
|
end
|
|
end
|
|
|
|
describe ".before_create" do
|
|
it "calls build_tags" do
|
|
expect(status).to receive(:build_tags)
|
|
status.save
|
|
end
|
|
|
|
it "calls filter_mentions" do
|
|
expect(status).to receive(:filter_mentions)
|
|
status.save
|
|
end
|
|
end
|
|
|
|
describe ".after_create" do
|
|
it "calls create_mentions" do
|
|
status = FactoryGirl.build(:status_message, text: "text @{Test; #{alice.diaspora_handle}}")
|
|
expect(status).to receive(:create_mentions).and_call_original
|
|
status.save
|
|
end
|
|
end
|
|
|
|
describe "#diaspora_handle=" do
|
|
it "sets #author" do
|
|
person = FactoryGirl.create(:person)
|
|
post = FactoryGirl.build(:status_message, author: user.person)
|
|
post.diaspora_handle = person.diaspora_handle
|
|
expect(post.author).to eq(person)
|
|
end
|
|
end
|
|
|
|
context "emptyness" do
|
|
it "needs either a message or at least one photo" do
|
|
post = user.build_post(:status_message, text: nil)
|
|
expect(post).not_to be_valid
|
|
|
|
post.text = ""
|
|
expect(post).not_to be_valid
|
|
|
|
post.text = "wales"
|
|
expect(post).to be_valid
|
|
post.text = nil
|
|
|
|
photo = user.build_post(:photo, user_file: uploaded_photo, to: aspect.id)
|
|
photo.save!
|
|
|
|
post.photos << photo
|
|
expect(post).to be_valid
|
|
expect(post.errors.full_messages).to eq([])
|
|
end
|
|
|
|
it "doesn't check for content when author is remote (federation...)" do
|
|
post = FactoryGirl.build(:status_message, text: nil)
|
|
expect(post).to be_valid
|
|
end
|
|
end
|
|
|
|
it "should be postable through the user" do
|
|
message = "Users do things"
|
|
status = user.post(:status_message, text: message, to: aspect.id)
|
|
db_status = StatusMessage.find(status.id)
|
|
expect(db_status.text).to eq(message)
|
|
end
|
|
|
|
it "should require status messages not be more than 65535 characters long" do
|
|
message = "a" * (65_535 + 1)
|
|
status_message = FactoryGirl.build(:status_message, text: message)
|
|
expect(status_message).not_to be_valid
|
|
end
|
|
|
|
describe "mentions" do
|
|
let(:people) { [alice, bob, eve].map(&:person) }
|
|
let(:test_string) {
|
|
"@{Raphael; #{people[0].diaspora_handle}} can mention people like Raphael @{Ilya; #{people[1].diaspora_handle}}
|
|
can mention people like Raphaellike Raphael @{Daniel; #{people[2].diaspora_handle}} can mention people like Raph"
|
|
}
|
|
let(:status_message) { create(:status_message, text: test_string) }
|
|
|
|
describe "#create_mentions" do
|
|
it "creates a mention for everyone mentioned in the message" do
|
|
status_message
|
|
expect(Diaspora::Mentionable).to receive(:people_from_string).and_return(people)
|
|
status_message.mentions.delete_all
|
|
status_message.create_mentions
|
|
expect(status_message.mentions(true).map(&:person).to_set).to eq(people.to_set)
|
|
end
|
|
|
|
it "does not barf if it gets called twice" do
|
|
status_message.create_mentions
|
|
|
|
expect {
|
|
status_message.create_mentions
|
|
}.to_not raise_error
|
|
end
|
|
end
|
|
|
|
describe "#mentioned_people" do
|
|
it "calls create_mentions if there are no mentions in the db" do
|
|
status_message.mentions.delete_all
|
|
expect(status_message).to receive(:create_mentions)
|
|
status_message.mentioned_people
|
|
end
|
|
it "returns the mentioned people" do
|
|
status_message.mentions.delete_all
|
|
expect(status_message.mentioned_people.to_set).to eq(people.to_set)
|
|
end
|
|
it "does not call create_mentions if there are mentions in the db" do
|
|
expect(status_message).not_to receive(:create_mentions)
|
|
status_message.mentioned_people
|
|
end
|
|
end
|
|
|
|
describe "#mentions?" do
|
|
it "returns true if the person was mentioned" do
|
|
expect(status_message.mentions?(people[0])).to be true
|
|
end
|
|
|
|
it "returns false if the person was not mentioned" do
|
|
expect(status_message.mentions?(FactoryGirl.build(:person))).to be false
|
|
end
|
|
end
|
|
|
|
describe "#notify_person" do
|
|
it "notifies the person mentioned" do
|
|
expect(Notification).to receive(:notify).with(alice, anything, anything)
|
|
status_message.notify_person(alice.person)
|
|
end
|
|
end
|
|
|
|
describe "#filter_mentions" do
|
|
it "calls Diaspora::Mentionable#filter_for_aspects" do
|
|
msg = FactoryGirl.build(:status_message_in_aspect)
|
|
|
|
msg_txt = msg.raw_message
|
|
author_usr = msg.author.owner
|
|
aspect_id = author_usr.aspects.first.id
|
|
|
|
expect(Diaspora::Mentionable).to receive(:filter_for_aspects)
|
|
.with(msg_txt, author_usr, aspect_id)
|
|
|
|
msg.send(:filter_mentions)
|
|
end
|
|
|
|
it "doesn't do anything when public" do
|
|
msg = FactoryGirl.build(:status_message, public: true)
|
|
expect(Diaspora::Mentionable).not_to receive(:filter_for_aspects)
|
|
|
|
msg.send(:filter_mentions)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#nsfw" do
|
|
it "returns MatchObject (true) if the post contains #nsfw (however capitalised)" do
|
|
status = FactoryGirl.build(:status_message, text: "This message is #nSFw")
|
|
expect(status.nsfw).to be_truthy
|
|
end
|
|
|
|
it "returns nil (false) if the post does not contain #nsfw" do
|
|
status = FactoryGirl.build(:status_message, text: "This message is #sFW")
|
|
expect(status.nsfw).to be false
|
|
end
|
|
end
|
|
|
|
describe "tags" do
|
|
before do
|
|
@object = FactoryGirl.build(:status_message)
|
|
end
|
|
it_should_behave_like "it is taggable"
|
|
|
|
it "associates different-case tags to the same tag entry" do
|
|
assert_equal ActsAsTaggableOn.force_lowercase, true
|
|
|
|
msg_lc = FactoryGirl.build(:status_message, text: "#newhere")
|
|
msg_uc = FactoryGirl.build(:status_message, text: "#NewHere")
|
|
msg_cp = FactoryGirl.build(:status_message, text: "#NEWHERE")
|
|
|
|
msg_lc.save
|
|
msg_uc.save
|
|
msg_cp.save
|
|
|
|
tag_array = msg_lc.tags
|
|
expect(msg_uc.tags).to match_array(tag_array)
|
|
expect(msg_cp.tags).to match_array(tag_array)
|
|
end
|
|
|
|
it "should require tag name not be more than 255 characters long" do
|
|
message = "##{'a' * (255 + 1)}"
|
|
status_message = FactoryGirl.build(:status_message, text: message)
|
|
expect(status_message).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe "XML" do
|
|
let(:message) { FactoryGirl.build(:status_message, text: "I hate WALRUSES!", author: user.person) }
|
|
let(:xml) { message.to_xml.to_s }
|
|
let(:marshalled) { StatusMessage.from_xml(xml) }
|
|
|
|
it "serializes the escaped, unprocessed message" do
|
|
text = "[url](http://example.org)<script> alert('xss should be federated');</script>"
|
|
message.text = text
|
|
expect(xml).to include Builder::XChar.encode(text)
|
|
end
|
|
|
|
it "serializes the message" do
|
|
expect(xml).to include "<raw_message>I hate WALRUSES!</raw_message>"
|
|
end
|
|
|
|
it "serializes the author address" do
|
|
expect(xml).to include(user.person.diaspora_handle)
|
|
end
|
|
|
|
describe ".from_xml" do
|
|
it "marshals the message" do
|
|
expect(marshalled.text).to eq("I hate WALRUSES!")
|
|
end
|
|
|
|
it "marshals the guid" do
|
|
expect(marshalled.guid).to eq(message.guid)
|
|
end
|
|
|
|
it "marshals the author" do
|
|
expect(marshalled.author).to eq(message.author)
|
|
end
|
|
|
|
it "marshals the diaspora_handle" do
|
|
expect(marshalled.diaspora_handle).to eq(message.diaspora_handle)
|
|
end
|
|
end
|
|
|
|
context "with some photos" do
|
|
before do
|
|
message.photos << FactoryGirl.build(:photo)
|
|
message.photos << FactoryGirl.build(:photo)
|
|
end
|
|
|
|
it "serializes the photos" do
|
|
expect(xml).to include "photo"
|
|
expect(xml).to include message.photos.first.remote_photo_path
|
|
end
|
|
|
|
describe ".from_xml" do
|
|
it "marshals the photos" do
|
|
expect(marshalled.photos.size).to eq(2)
|
|
end
|
|
|
|
it "handles existing photos" do
|
|
message.photos.each(&:save!)
|
|
expect(marshalled).to be_valid
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with a location" do
|
|
before do
|
|
message.location = FactoryGirl.build(:location)
|
|
end
|
|
|
|
it "serializes the location" do
|
|
expect(xml).to include "location"
|
|
expect(xml).to include "lat"
|
|
expect(xml).to include "lng"
|
|
end
|
|
|
|
describe ".from_xml" do
|
|
it "marshals the location" do
|
|
expect(marshalled.location).to be_present
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with a poll" do
|
|
before do
|
|
message.poll = FactoryGirl.build(:poll)
|
|
end
|
|
|
|
it "serializes the poll" do
|
|
expect(xml).to include "poll"
|
|
expect(xml).to include "question"
|
|
expect(xml).to include "poll_answer"
|
|
end
|
|
|
|
describe ".from_xml" do
|
|
it "marshals the poll" do
|
|
expect(marshalled.poll).to be_present
|
|
end
|
|
|
|
it "marshals the poll answers" do
|
|
expect(marshalled.poll.poll_answers.size).to eq(2)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#after_dispatch" do
|
|
before do
|
|
@photos = [alice.build_post(:photo, pending: true, user_file: File.open(photo_fixture_name)),
|
|
alice.build_post(:photo, pending: true, user_file: File.open(photo_fixture_name))]
|
|
@photos.each(&:save!)
|
|
@status_message = alice.build_post(:status_message, text: "the best pebble.")
|
|
@status_message.photos << @photos
|
|
@status_message.save!
|
|
alice.add_to_streams(@status_message, alice.aspects)
|
|
end
|
|
|
|
it "sets pending to false on any attached photos" do
|
|
@status_message.after_dispatch(alice)
|
|
expect(@photos.all? {|p| p.reload.pending }).to be false
|
|
end
|
|
|
|
it "dispatches any attached photos" do
|
|
expect(alice).to receive(:dispatch_post).twice
|
|
@status_message.after_dispatch(alice)
|
|
end
|
|
end
|
|
|
|
describe "oembed" do
|
|
let(:youtube_url) { "https://www.youtube.com/watch?v=3PtFwlKfvHI" }
|
|
let(:message_text) { "#{youtube_url} is so cool. so is this link -> https://joindiaspora.com" }
|
|
let(:status_message) { FactoryGirl.build(:status_message, text: message_text) }
|
|
|
|
it "should queue a GatherOembedData if it includes a link" do
|
|
status_message
|
|
expect(Workers::GatherOEmbedData).to receive(:perform_async).with(instance_of(Fixnum), instance_of(String))
|
|
status_message.save
|
|
end
|
|
|
|
describe "#contains_oembed_url_in_text?" do
|
|
it "returns the oembed urls found in the raw message" do
|
|
expect(status_message.contains_oembed_url_in_text?).not_to be_nil
|
|
expect(status_message.oembed_url).to eq(youtube_url)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "opengraph" do
|
|
let(:ninegag_url) { "http://9gag.com/gag/a1AMW16" }
|
|
let(:youtube_url) { "https://www.youtube.com/watch?v=3PtFwlKfvHI" }
|
|
let(:message_text) { "#{ninegag_url} is so cool. so is this link -> https://joindiaspora.com" }
|
|
let(:oemessage_text) { "#{youtube_url} is so cool. so is this link -> https://joindiaspora.com" }
|
|
let(:status_message) { build(:status_message, text: message_text) }
|
|
|
|
it "should queue a GatherOpenGraphData if it includes a link" do
|
|
status_message
|
|
expect(Workers::GatherOpenGraphData).to receive(:perform_async).with(instance_of(Fixnum), instance_of(String))
|
|
status_message.save
|
|
end
|
|
|
|
describe "#contains_open_graph_url_in_text?" do
|
|
it "returns the opengraph urls found in the raw message" do
|
|
expect(status_message.contains_open_graph_url_in_text?).not_to be_nil
|
|
expect(status_message.open_graph_url).to eq(ninegag_url)
|
|
end
|
|
it "returns nil if the link is from trusted oembed provider" do
|
|
status_message = FactoryGirl.build(:status_message, text: oemessage_text)
|
|
expect(status_message.contains_open_graph_url_in_text?).to be_nil
|
|
expect(status_message.open_graph_url).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "validation" do
|
|
let(:status_message) { build(:status_message, text: @message_text) }
|
|
|
|
it "should not be valid if the author is missing" do
|
|
status_message.author = nil
|
|
expect(status_message).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe ".coordinates" do
|
|
let(:status_message) { build(:status_message, text: @message_text) }
|
|
|
|
context "with location" do
|
|
let(:location) { build(:location) }
|
|
|
|
it "should deliver coordinates" do
|
|
status_message.location = location
|
|
expect(status_message.coordinates).to include(lat: location.lat, lng: location.lng)
|
|
end
|
|
end
|
|
|
|
context "without location" do
|
|
it "should deliver empty coordinates" do
|
|
expect(status_message.coordinates[:lat]).to be_nil
|
|
expect(status_message.coordinates[:lng]).to be_nil
|
|
end
|
|
end
|
|
end
|
|
end
|