add a map subview

- 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)
This commit is contained in:
zaziemo 2015-07-17 16:58:53 +02:00 committed by realtin
parent f9a452265d
commit 298e195a8f
20 changed files with 424 additions and 318 deletions

View file

@ -128,6 +128,9 @@ gem "rails-i18n", "4.0.4"
gem "markerb", "1.0.2" gem "markerb", "1.0.2"
gem "messagebus_ruby_api", "1.0.3" gem "messagebus_ruby_api", "1.0.3"
# Map
gem "leaflet-rails", "0.7.4"
# Parsing # Parsing
gem "nokogiri", "1.6.6.2" gem "nokogiri", "1.6.6.2"

View file

@ -409,6 +409,7 @@ GEM
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
kgio (2.9.3) kgio (2.9.3)
leaflet-rails (0.7.4)
listen (3.0.3) listen (3.0.3)
rb-fsevent (>= 0.9.3) rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9) rb-inotify (>= 0.9)
@ -833,6 +834,7 @@ DEPENDENCIES
jshintrb (= 0.3.0) jshintrb (= 0.3.0)
json (= 1.8.3) json (= 1.8.3)
json-schema (= 2.5.1) json-schema (= 2.5.1)
leaflet-rails (= 0.7.4)
logging-rails (= 0.5.0) logging-rails (= 0.5.0)
markerb (= 1.0.2) markerb (= 1.0.2)
messagebus_ruby_api (= 1.0.3) messagebus_ruby_api (= 1.0.3)

View file

@ -29,7 +29,6 @@ app.views.Content = app.views.Base.extend({
return photos; return photos;
}, },
expandPost: function(evt) { expandPost: function(evt) {
var el = $(this.el).find('.collapsible'); var el = $(this.el).find('.collapsible');
el.removeClass('collapsed').addClass('opened'); el.removeClass('collapsed').addClass('opened');
@ -155,4 +154,5 @@ app.views.SPVOpenGraph = app.views.OpenGraph.extend({
// override with nothing // override with nothing
} }
}); });
// @license-end // @license-end

View file

@ -0,0 +1,34 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
app.views.LocationMap = app.views.Content.extend({
templateName: "status-message-map",
map: function() {
var coordinates = this.model.get("coordinates");
// if (coordinates != "" && tileserver.enable) { // for when the tileserver is set via the diaspora.yml
if (coordinates.lat) {
var tileLayerSource = "https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}";
var map = L.map("map").setView([coordinates.lat, coordinates.lng], 16);
var attribution = "Map data &copy; <a href='http://openstreetmap.org'>OpenStreetMap</a> contributors, " +
"<a href='http://creativecommons.org/licenses/by-sa/2.0/''>CC-BY-SA</a>, " +
"Imagery © <a href='http://mapbox.com'>Mapbox</a>";
L.tileLayer(tileLayerSource, {
attribution: attribution,
maxZoom: 18,
id: "zaziemo.mpn66kn8",
accessToken: "pk.eyJ1IjoiemF6aWVtbyIsImEiOiI3ODVjMzVjNmM2ZTU3YWM3YTE5YWYwMTRhODljM2M1MSJ9.-nVgyS4PLnV4m9YkvMB5wA"
}).addTo(map);
var markerOnMap = L.marker(coordinates).addTo(map);
return map;
}
},
postRenderTemplate : function(){
_.defer(_.bind(this.map, this));
}
});
// @license-end

View file

@ -11,7 +11,8 @@ app.views.SinglePostContent = app.views.Base.extend({
".oembed" : "oEmbedView", ".oembed" : "oEmbedView",
".opengraph" : "openGraphView", ".opengraph" : "openGraphView",
".status-message-location" : "postLocationStreamView", ".status-message-location" : "postLocationStreamView",
".poll": "pollView" ".map" : "postMapView",
'.poll': 'pollView',
}, },
initialize : function() { initialize : function() {
@ -20,6 +21,7 @@ app.views.SinglePostContent = app.views.Base.extend({
this.oEmbedView = new app.views.OEmbed({model : this.model}); this.oEmbedView = new app.views.OEmbed({model : this.model});
this.openGraphView = new app.views.SPVOpenGraph({model : this.model}); this.openGraphView = new app.views.SPVOpenGraph({model : this.model});
this.postContentView = new app.views.ExpandedStatusMessage({model: this.model}); this.postContentView = new app.views.ExpandedStatusMessage({model: this.model});
this.postMapView = new app.views.LocationMap({model: this.model});
this.pollView = new app.views.Poll({ model: this.model }); this.pollView = new app.views.Poll({ model: this.model });
}, },

View file

@ -45,3 +45,4 @@
//= require osmlocator //= require osmlocator
//= require bootstrap-switch //= require bootstrap-switch
//= require blueimp-gallery //= require blueimp-gallery
//= require leaflet

View file

@ -42,6 +42,10 @@
@import 'single-post-view'; @import 'single-post-view';
@import 'new_styles/poll'; @import 'new_styles/poll';
/* map*/
@import 'leaflet';
@import 'map';
/* conversations */ /* conversations */
@import 'conversations'; @import 'conversations';

View file

@ -0,0 +1,13 @@
#map {
height: 180px;
position: relative;
overflow: hidden;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 0;
}
.leaflet-right .leaflet-control {
margin-right: 0;
}

View file

@ -13,6 +13,7 @@
color: lighten($text-grey,10%); color: lighten($text-grey,10%);
font-size: 12px; font-size: 12px;
.post-time a { color: $text-grey; } .post-time a { color: $text-grey; }
.near-from a { color: $text-grey; }
.post_scope { margin-right: 5px; } .post_scope { margin-right: 5px; }
.status-message-location { .status-message-location {
padding-top: 2px; padding-top: 2px;

View file

@ -83,7 +83,7 @@
float: left; float: left;
margin-top: 6px; margin-top: 6px;
} }
.status-message-location .near-from { .status-message-location .near-from a {
font-size: $font-size-small; font-size: $font-size-small;
color: $text-grey; color: $text-grey;
} }

View file

@ -99,4 +99,5 @@
<div id="body" class="row"> <div id="body" class="row">
<div id="real-post-content" class="post-content col-md-12"> <div id="real-post-content" class="post-content col-md-12">
</div> </div>
<div class="map col-md-12"></div>
</div> </div>

View file

@ -1,5 +1,5 @@
{{#if location}} {{#if location}}
<div class='near-from'> <div class='near-from'>
{{ t "publisher.near_from" location=location}} <a href="/posts/{{id}}">{{ t "publisher.near_from" location=location}}</a>
</div> </div>
{{/if}} {{/if}}

View file

@ -0,0 +1,4 @@
{{#if location}}
<div id="map">
</div>
{{/if}}

View file

@ -3,7 +3,6 @@
# the COPYRIGHT file. # the COPYRIGHT file.
class Reshare < Post class Reshare < Post
belongs_to :root, :class_name => 'Post', :foreign_key => :root_guid, :primary_key => :guid belongs_to :root, :class_name => 'Post', :foreign_key => :root_guid, :primary_key => :guid
validate :root_must_be_public validate :root_must_be_public
validates_presence_of :root, :on => :create validates_presence_of :root, :on => :create
@ -49,6 +48,10 @@ class Reshare < Post
absolute_root.try(:location).try(:address) absolute_root.try(:location).try(:address)
end end
def coordinates
{lat: absolute_root.try(:location).try(:lat), lng: absolute_root.try(:location).try(:lng)}
end
def poll def poll
absolute_root.try(:poll) || super absolute_root.try(:poll) || super
end end

View file

@ -162,6 +162,10 @@ class StatusMessage < Post
location.try(:address) location.try(:address)
end end
def coordinates
{lat: location.try(:lat), lng: location.try(:lng)}
end
protected protected
def presence_of_content def presence_of_content
if text_and_photos_blank? if text_and_photos_blank?

View file

@ -32,6 +32,7 @@ class PostPresenter < BasePresenter
root: root, root: root,
title: title, title: title,
address: @post.address, address: @post.address,
coordinates: @post.coordinates,
poll: @post.poll, poll: @post.poll,
already_participated_in_poll: already_participated_in_poll, already_participated_in_poll: already_participated_in_poll,
participation: participate?, participation: participate?,

View file

@ -140,9 +140,10 @@ FactoryGirl.define do
end end
factory(:location) do factory(:location) do
address "unicorn city" address "Starco Mart, Mission Street, West SoMa, San Francisco, San Francisco "\
lat 1 "City and County, Kalifornien, 94103, Vereinigte Staaten von Amerika"
lng 2 lat 37.78
lng -122.41
end end
factory(:poll) do factory(:poll) do

View file

@ -24,5 +24,11 @@ describe("app.views.Content", function(){
this.post.set({post_type : "Reshare"}); this.post.set({post_type : "Reshare"});
expect(this.view.presenter().isReshare).toBeTruthy(); expect(this.view.presenter().isReshare).toBeTruthy();
}); });
// it("provides coordinates", function(){
// this.post.location;
// console.log(this.view.presenter());
// console.log(this.post.location);
// });
}); });
}); });

View file

@ -1,33 +1,33 @@
require 'spec_helper' require "spec_helper"
describe Reshare, :type => :model do describe Reshare, type: :model do
it 'has a valid Factory' do it "has a valid Factory" do
expect(FactoryGirl.build(:reshare)).to be_valid expect(FactoryGirl.build(:reshare)).to be_valid
end end
it 'requires root' do it "requires root" do
reshare = FactoryGirl.build(:reshare, :root => nil) reshare = FactoryGirl.build(:reshare, root: nil)
expect(reshare).not_to be_valid expect(reshare).not_to be_valid
end end
it 'require public root' do it "require public root" do
reshare = FactoryGirl.build(:reshare, :root => FactoryGirl.create(:status_message, :public => false)) reshare = FactoryGirl.build(:reshare, root: FactoryGirl.create(:status_message, public: false))
expect(reshare).not_to be_valid expect(reshare).not_to be_valid
expect(reshare.errors[:base]).to include('Only posts which are public may be reshared.') expect(reshare.errors[:base]).to include("Only posts which are public may be reshared.")
end end
it 'forces public' do it "forces public" do
expect(FactoryGirl.create(:reshare, :public => false).public).to be true expect(FactoryGirl.create(:reshare, public: false).public).to be true
end end
describe "#root_diaspora_id" do describe "#root_diaspora_id" do
let(:reshare) { create(:reshare, root: FactoryGirl.build(:status_message, author: bob.person, public: true)) }
it "should return the root diaspora id" do it "should return the root diaspora id" do
reshare = FactoryGirl.create(:reshare, root: FactoryGirl.build(:status_message, author: bob.person, public: true))
expect(reshare.root_diaspora_id).to eq(bob.person.diaspora_handle) expect(reshare.root_diaspora_id).to eq(bob.person.diaspora_handle)
end end
it "should be nil if no root found" do it "should be nil if no root found" do
reshare = FactoryGirl.create(:reshare, root: FactoryGirl.build(:status_message, author: bob.person, public: true))
reshare.root = nil reshare.root = nil
expect(reshare.root_diaspora_id).to be_nil expect(reshare.root_diaspora_id).to be_nil
end end
@ -37,195 +37,188 @@ describe Reshare, :type => :model do
let(:receive_reshare) { @reshare.receive(@root.author.owner, @reshare.author) } let(:receive_reshare) { @reshare.receive(@root.author.owner, @reshare.author) }
before do before do
@reshare = FactoryGirl.create(:reshare, :root => FactoryGirl.build(:status_message, :author => bob.person, :public => true)) @reshare = FactoryGirl.create(:reshare, root:
FactoryGirl.build(:status_message, author: bob.person, public: true))
@root = @reshare.root @root = @reshare.root
end end
it 'increments the reshare count' do it "increments the reshare count" do
receive_reshare receive_reshare
expect(@root.resharers.count).to eq(1) expect(@root.resharers.count).to eq(1)
end end
it 'adds the resharer to the re-sharers of the post' do it "adds the resharer to the re-sharers of the post" do
receive_reshare receive_reshare
expect(@root.resharers).to include(@reshare.author) expect(@root.resharers).to include(@reshare.author)
end end
it 'does not error if the root author has a contact for the resharer' do it "does not error if the root author has a contact for the resharer" do
bob.share_with @reshare.author, bob.aspects.first bob.share_with @reshare.author, bob.aspects.first
expect { expect {
Timeout.timeout(5) do Timeout.timeout(5) do
receive_reshare #This doesn't ever terminate on my machine before it was fixed. receive_reshare # This doesn't ever terminate on my machine before it was fixed.
end end
}.not_to raise_error }.not_to raise_error
end end
end end
describe '#nsfw' do describe "#nsfw" do
before do let(:sfw) { build(:status_message, author: alice.person, public: true) }
sfw = FactoryGirl.build(:status_message, :author => alice.person, :public => true) let(:nsfw) { build(:status_message, author: alice.person, public: true, text: "This is #nsfw") }
nsfw = FactoryGirl.build(:status_message, :author => alice.person, :public => true, :text => "This is #nsfw") let(:sfw_reshare) { build(:reshare, root: sfw) }
@sfw_reshare = FactoryGirl.build(:reshare, :root => sfw) let(:nsfw_reshare) { build(:reshare, root: nsfw) }
@nsfw_reshare = FactoryGirl.build(:reshare, :root => nsfw)
end
it 'deletates #nsfw to the root post' do it "deletates #nsfw to the root post" do
expect(@sfw_reshare.nsfw).not_to be true expect(sfw_reshare.nsfw).not_to be true
expect(@nsfw_reshare.nsfw).to be_truthy expect(nsfw_reshare.nsfw).to be_truthy
end end
end end
describe '#poll' do describe "#poll" do
before do let(:root_post) { create(:status_message_with_poll, public: true) }
@root_post = FactoryGirl.create(:status_message_with_poll, public: true) let(:reshare) { create(:reshare, root: root_post) }
@reshare = FactoryGirl.create(:reshare, root: @root_post)
end
it 'contains root poll' do it "contains root poll" do
expect(@reshare.poll).to eq @root_post.poll expect(reshare.poll).to eq root_post.poll
end end
end end
describe '#notification_type' do describe "#notification_type" do
before do let(:status_message) { build(:status_message, author: alice.person, public: true) }
sm = FactoryGirl.build(:status_message, :author => alice.person, :public => true) let(:reshare) { build(:reshare, root: status_message) }
@reshare = FactoryGirl.build(:reshare, :root => sm)
end it "does not return anything for non-author of the original post" do
it 'does not return anything for non-author of the original post' do expect(reshare.notification_type(bob, reshare.author)).to be_nil
expect(@reshare.notification_type(bob, @reshare.author)).to be_nil
end end
it 'returns "Reshared" for the original post author' do it "returns 'Reshared' for the original post author" do
expect(@reshare.notification_type(alice, @reshare.author)).to eq(Notifications::Reshared) expect(reshare.notification_type(alice, reshare.author)).to eq(Notifications::Reshared)
end end
it 'does not error out if the root was deleted' do it "does not error out if the root was deleted" do
@reshare.root = nil reshare.root = nil
expect { expect {
@reshare.notification_type(alice, @reshare.author) reshare.notification_type(alice, reshare.author)
}.to_not raise_error }.to_not raise_error
end end
end end
describe '#absolute_root' do describe "#absolute_root" do
before do before do
@sm = FactoryGirl.build(:status_message, :author => alice.person, :public => true) @status_message = FactoryGirl.build(:status_message, author: alice.person, public: true)
rs1 = FactoryGirl.build(:reshare, :root=>@sm) reshare_1 = FactoryGirl.build(:reshare, root: @status_message)
rs2 = FactoryGirl.build(:reshare, :root=>rs1) reshare_2 = FactoryGirl.build(:reshare, root: reshare_1)
@rs3 = FactoryGirl.build(:reshare, :root=>rs2) @reshare_3 = FactoryGirl.build(:reshare, root: reshare_2)
sm = FactoryGirl.create(:status_message, :author => alice.person, :public => true) status_message = FactoryGirl.create(:status_message, author: alice.person, public: true)
rs1 = FactoryGirl.create(:reshare, :root => sm) reshare_1 = FactoryGirl.create(:reshare, root: status_message)
@of_deleted = FactoryGirl.build(:reshare, :root => rs1) @of_deleted = FactoryGirl.build(:reshare, root: reshare_1)
sm.destroy status_message.destroy
rs1.reload reshare_1.reload
end end
it 'resolves root posts to the top level' do it "resolves root posts to the top level" do
expect(@rs3.absolute_root).to eq(@sm) expect(@reshare_3.absolute_root).to eq(@status_message)
end end
it 'can handle deleted reshares' do it "can handle deleted reshares" do
expect(@of_deleted.absolute_root).to be_nil expect(@of_deleted.absolute_root).to be_nil
end end
it 'is used everywhere' do it "is used everywhere" do
expect(@rs3.message).to eq @sm.message expect(@reshare_3.message).to eq @status_message.message
expect(@of_deleted.message).to be_nil expect(@of_deleted.message).to be_nil
expect(@rs3.photos).to eq @sm.photos expect(@reshare_3.photos).to eq @status_message.photos
expect(@of_deleted.photos).to be_empty expect(@of_deleted.photos).to be_empty
expect(@rs3.o_embed_cache).to eq @sm.o_embed_cache expect(@reshare_3.o_embed_cache).to eq @status_message.o_embed_cache
expect(@of_deleted.o_embed_cache).to be_nil expect(@of_deleted.o_embed_cache).to be_nil
expect(@rs3.open_graph_cache).to eq @sm.open_graph_cache expect(@reshare_3.open_graph_cache).to eq @status_message.open_graph_cache
expect(@of_deleted.open_graph_cache).to be_nil expect(@of_deleted.open_graph_cache).to be_nil
expect(@rs3.mentioned_people).to eq @sm.mentioned_people expect(@reshare_3.mentioned_people).to eq @status_message.mentioned_people
expect(@of_deleted.mentioned_people).to be_empty expect(@of_deleted.mentioned_people).to be_empty
expect(@rs3.nsfw).to eq @sm.nsfw expect(@reshare_3.nsfw).to eq @status_message.nsfw
expect(@of_deleted.nsfw).to be_nil expect(@of_deleted.nsfw).to be_nil
expect(@rs3.address).to eq @sm.location.try(:address) expect(@reshare_3.address).to eq @status_message.location.try(:address)
expect(@of_deleted.address).to be_nil expect(@of_deleted.address).to be_nil
end end
end end
describe "XML" do describe "XML" do
before do let(:reshare) { build(:reshare) }
@reshare = FactoryGirl.build(:reshare) let(:xml) { reshare.to_xml.to_s }
@xml = @reshare.to_xml.to_s
end
context 'serialization' do context "serialization" do
it 'serializes root_diaspora_id' do it "serializes root_diaspora_id" do
expect(@xml).to include("root_diaspora_id") expect(xml).to include("root_diaspora_id")
expect(@xml).to include(@reshare.author.diaspora_handle) expect(xml).to include(reshare.author.diaspora_handle)
end end
it 'serializes root_guid' do it "serializes root_guid" do
expect(@xml).to include("root_guid") expect(xml).to include("root_guid")
expect(@xml).to include(@reshare.root.guid) expect(xml).to include(reshare.root.guid)
end end
end end
context 'marshalling' do context "marshalling" do
context 'local' do let(:root_object) { reshare.root }
before do
@original_author = @reshare.root.author context "local" do
@root_object = @reshare.root let(:original_author) { reshare.root.author }
it "marshals the guid" do
expect(Reshare.from_xml(xml).root_guid).to eq(root_object.guid)
end end
it 'marshals the guid' do it "fetches the root post from root_guid" do
expect(Reshare.from_xml(@xml).root_guid).to eq(@root_object.guid) expect(Reshare.from_xml(xml).root).to eq(root_object)
end end
it 'fetches the root post from root_guid' do it "fetches the root author from root_diaspora_id" do
expect(Reshare.from_xml(@xml).root).to eq(@root_object) expect(Reshare.from_xml(xml).root.author).to eq(original_author)
end
it 'fetches the root author from root_diaspora_id' do
expect(Reshare.from_xml(@xml).root.author).to eq(@original_author)
end end
end end
describe 'destroy' do describe "destroy" do
it 'allows you to destroy the reshare if the root post is missing' do it "allows you to destroy the reshare if the root post is missing" do
reshare = FactoryGirl.build(:reshare) reshare
reshare.root = nil reshare.root = nil
expect{ expect {
reshare.destroy reshare.destroy
}.to_not raise_error }.to_not raise_error
end end
end end
context 'remote' do context "remote" do
before do before do
@root_object = @reshare.root # root_object = reshare.root
@root_object.delete root_object.delete
@response = double @response = double
allow(@response).to receive(:status).and_return(200) allow(@response).to receive(:status).and_return(200)
allow(@response).to receive(:success?).and_return(true) allow(@response).to receive(:success?).and_return(true)
end end
it 'fetches the root author from root_diaspora_id' do it "fetches the root author from root_diaspora_id" do
@original_profile = @reshare.root.author.profile.dup @original_profile = reshare.root.author.profile.dup
@reshare.root.author.profile.delete reshare.root.author.profile.delete
@original_author = @reshare.root.author.dup @original_author = reshare.root.author.dup
@reshare.root.author.delete reshare.root.author.delete
@original_author.profile = @original_profile @original_author.profile = @original_profile
expect(Person).to receive(:find_or_fetch_by_identifier).and_return(@original_author) expect(Person).to receive(:find_or_fetch_by_identifier).and_return(@original_author)
allow(@response).to receive(:body).and_return(@root_object.to_diaspora_xml) allow(@response).to receive(:body).and_return(root_object.to_diaspora_xml)
expect(Faraday.default_connection).to receive(:get).with( expect(Faraday.default_connection).to receive(:get).with(
URI.join( URI.join(
@original_author.url, @original_author.url,
Rails.application.routes.url_helpers.short_post_path( Rails.application.routes.url_helpers.short_post_path(
@root_object.guid, root_object.guid,
format: "xml" format: "xml"
) )
) )
).and_return(@response) ).and_return(@response)
Reshare.from_xml(@xml) Reshare.from_xml(xml)
end end
context "fetching post" do context "fetching post" do
@ -234,7 +227,7 @@ describe Reshare, :type => :model do
expect(Faraday.default_connection).to receive(:get).and_return(@response) expect(Faraday.default_connection).to receive(:get).and_return(@response)
expect { expect {
Reshare.from_xml(@xml) Reshare.from_xml(xml)
}.to raise_error(Diaspora::PostNotFetchable) }.to raise_error(Diaspora::PostNotFetchable)
end end
@ -244,57 +237,78 @@ describe Reshare, :type => :model do
expect(Faraday.default_connection).to receive(:get).and_return(@response) expect(Faraday.default_connection).to receive(:get).and_return(@response)
expect { expect {
Reshare.from_xml(@xml) Reshare.from_xml(xml)
}.to raise_error RuntimeError }.to raise_error RuntimeError
end end
end end
context 'saving the post' do context "saving the post" do
before do before do
allow(@response).to receive(:body).and_return(@root_object.to_diaspora_xml) allow(@response).to receive(:body).and_return(root_object.to_diaspora_xml)
allow(Faraday.default_connection).to receive(:get).with( allow(Faraday.default_connection).to receive(:get).with(
URI.join( URI.join(
@reshare.root.author.url, reshare.root.author.url,
Rails.application.routes.url_helpers.short_post_path( Rails.application.routes.url_helpers.short_post_path(
@root_object.guid, root_object.guid,
format: "xml" format: "xml"
) )
) )
).and_return(@response) ).and_return(@response)
end end
it 'fetches the root post from root_guid' do it "fetches the root post from root_guid" do
root = Reshare.from_xml(@xml).root root = Reshare.from_xml(xml).root
[:text, :guid, :diaspora_handle, :type, :public].each do |attr| %i(text guid diaspora_handle type public).each do |attr|
expect(root.send(attr)).to eq(@reshare.root.send(attr)) expect(root.send(attr)).to eq(reshare.root.send(attr))
end end
end end
it 'correctly saves the type' do it "correctly saves the type" do
expect(Reshare.from_xml(@xml).root.reload.type).to eq("StatusMessage") expect(Reshare.from_xml(xml).root.reload.type).to eq("StatusMessage")
end end
it 'correctly sets the author' do it "correctly sets the author" do
@original_author = @reshare.root.author @original_author = reshare.root.author
expect(Reshare.from_xml(@xml).root.reload.author.reload).to eq(@original_author) expect(Reshare.from_xml(xml).root.reload.author.reload).to eq(@original_author)
end end
it 'verifies that the author of the post received is the same as the author in the reshare xml' do it "verifies that the author of the post received is the same as the author in the reshare xml" do
@original_author = @reshare.root.author.dup @original_author = reshare.root.author.dup
@xml = @reshare.to_xml.to_s xml = reshare.to_xml.to_s
different_person = FactoryGirl.build(:person) different_person = FactoryGirl.build(:person)
expect(Person).to receive(:find_or_fetch_by_identifier).and_return(different_person) expect(Person).to receive(:find_or_fetch_by_identifier).and_return(different_person)
allow(different_person).to receive(:url).and_return(@original_author.url) allow(different_person).to receive(:url).and_return(@original_author.url)
expect{ expect {
Reshare.from_xml(@xml) Reshare.from_xml(xml)
}.to raise_error /^Diaspora ID \(.+\) in the root does not match the Diaspora ID \(.+\) specified in the reshare!$/ }.to raise_error /^Diaspora ID \(.+\) in the root does not match the Diaspora ID \(.+\) specified in the reshare!$/
end end
end end
end end
end end
end end
describe ".coordinates" do
let(:status_message) { build(:status_message, text: "This is a status_message", author: bob.person, public: true) }
let(:reshare) { create(:reshare, root: status_message) }
context "with location" do
let(:location) { build(:location) }
it "should deliver coordinates" do
status_message.location = location
expect(reshare.coordinates).to include(lat: location.lat, lng: location.lng)
end
end
context "without location" do
it "should deliver empty coordinates" do
expect(reshare.coordinates[:lat]).to be_nil
expect(reshare.coordinates[:lng]).to be_nil
end
end
end
end end

View file

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