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:
parent
f9a452265d
commit
298e195a8f
20 changed files with 424 additions and 318 deletions
3
Gemfile
3
Gemfile
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
34
app/assets/javascripts/app/views/location_map.js
Normal file
34
app/assets/javascripts/app/views/location_map.js
Normal 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 © <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
|
||||||
|
|
@ -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 });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,4 @@
|
||||||
//= require osmlocator
|
//= require osmlocator
|
||||||
//= require bootstrap-switch
|
//= require bootstrap-switch
|
||||||
//= require blueimp-gallery
|
//= require blueimp-gallery
|
||||||
|
//= require leaflet
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
||||||
13
app/assets/stylesheets/map.scss
Normal file
13
app/assets/stylesheets/map.scss
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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}}
|
||||||
|
|
|
||||||
4
app/assets/templates/status-message-map_tpl.jst.hbs
Normal file
4
app/assets/templates/status-message-map_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{{#if location}}
|
||||||
|
<div id="map">
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
|
||||||
|
|
@ -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?,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,20 +37,21 @@ 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
|
||||||
|
|
@ -60,133 +61,125 @@ describe Reshare, :type => :model do
|
||||||
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
|
|
||||||
|
context "serialization" do
|
||||||
|
it "serializes root_diaspora_id" do
|
||||||
|
expect(xml).to include("root_diaspora_id")
|
||||||
|
expect(xml).to include(reshare.author.diaspora_handle)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'serialization' do
|
it "serializes root_guid" do
|
||||||
it 'serializes root_diaspora_id' do
|
expect(xml).to include("root_guid")
|
||||||
expect(@xml).to include("root_diaspora_id")
|
expect(xml).to include(reshare.root.guid)
|
||||||
expect(@xml).to include(@reshare.author.diaspora_handle)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'serializes root_guid' do
|
|
||||||
expect(@xml).to include("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 {
|
||||||
|
|
@ -195,37 +188,37 @@ describe Reshare, :type => :model do
|
||||||
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,45 +237,45 @@ 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)
|
||||||
|
|
@ -290,11 +283,32 @@ describe Reshare, :type => :model do
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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, text: @test_string)
|
||||||
FactoryGirl.create(:status_message, :text => @test_string )
|
|
||||||
FactoryGirl.create(:status_message)
|
FactoryGirl.create(:status_message)
|
||||||
|
|
||||||
expect(StatusMessage.where_person_is_mentioned(@bo).count).to eq(2)
|
expect(StatusMessage.where_person_is_mentioned(bob).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 )
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
describe '#create_mentions' do
|
it "does not barf if it gets called twice" do
|
||||||
it 'creates a mention for everyone mentioned in the message' do
|
status_message.create_mentions
|
||||||
expect(Diaspora::Mentionable).to receive(:people_from_string).and_return(@people)
|
|
||||||
@sm.mentions.delete_all
|
|
||||||
@sm.create_mentions
|
|
||||||
expect(@sm.mentions(true).map{|m| m.person}.to_set).to eq(@people.to_set)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not barf if it gets called twice' do
|
|
||||||
@sm.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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue