Merge branch 'stable' into develop
This commit is contained in:
commit
6ee3843449
12 changed files with 324 additions and 229 deletions
|
|
@ -60,6 +60,7 @@ With the port to Bootstrap 3, app/views/terms/default.haml has a new structure.
|
||||||
|
|
||||||
## Refactor
|
## Refactor
|
||||||
* Drop broken correlations from the admin pages [#6223](https://github.com/diaspora/diaspora/pull/6223)
|
* Drop broken correlations from the admin pages [#6223](https://github.com/diaspora/diaspora/pull/6223)
|
||||||
|
* Extract PostService from PostsController [#6208](https://github.com/diaspora/diaspora/pull/6208)
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
* Fix indentation and a link title on the default home page [#6212](https://github.com/diaspora/diaspora/pull/6212)
|
* Fix indentation and a link title on the default home page [#6212](https://github.com/diaspora/diaspora/pull/6212)
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
||||||
.done(function(){ app.events.trigger('person:block:'+personId); });
|
.done(function(){ app.events.trigger('person:block:'+personId); });
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleFavorite : function(options){
|
|
||||||
this.set({favorite : !this.get("favorite")});
|
|
||||||
|
|
||||||
/* guard against attempting to save a model that a user doesn't own */
|
|
||||||
if(options.save){ this.save() }
|
|
||||||
},
|
|
||||||
|
|
||||||
headline : function() {
|
headline : function() {
|
||||||
var headline = this.get("text").trim()
|
var headline = this.get("text").trim()
|
||||||
, newlineIdx = headline.indexOf("\n");
|
, newlineIdx = headline.indexOf("\n");
|
||||||
|
|
|
||||||
|
|
@ -5,94 +5,58 @@
|
||||||
class PostsController < ApplicationController
|
class PostsController < ApplicationController
|
||||||
include PostsHelper
|
include PostsHelper
|
||||||
|
|
||||||
before_action :authenticate_user!, :except => [:show, :iframe, :oembed, :interactions]
|
before_action :authenticate_user!, only: :destroy
|
||||||
before_action :set_format_if_malformed_from_status_net, :only => :show
|
before_action :set_format_if_malformed_from_status_net, only: :show
|
||||||
before_action :find_post, :only => [:show, :interactions]
|
|
||||||
|
|
||||||
respond_to :html,
|
respond_to :html, :mobile, :json, :xml
|
||||||
:mobile,
|
|
||||||
:json,
|
|
||||||
:xml
|
|
||||||
|
|
||||||
rescue_from Diaspora::NonPublic do |exception|
|
rescue_from Diaspora::NonPublic do
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.all { render :template=>'errors/not_public', :status=>404, :layout => "application"}
|
format.all { render template: "errors/not_public", status: 404, layout: "application" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
mark_corresponding_notifications_read if user_signed_in?
|
post_service = PostService.new(id: params[:id], user: current_user)
|
||||||
|
post_service.mark_user_notifications
|
||||||
|
@post = post_service.post
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html { gon.post = post_service.present_json }
|
||||||
gon.post = PostPresenter.new(@post, current_user)
|
|
||||||
render "posts/show"
|
|
||||||
}
|
|
||||||
format.xml { render xml: @post.to_diaspora_xml }
|
format.xml { render xml: @post.to_diaspora_xml }
|
||||||
format.mobile { render "posts/show" }
|
format.json { render json: post_service.present_json }
|
||||||
format.json { render json: PostPresenter.new(@post, current_user) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def iframe
|
def iframe
|
||||||
render :text => post_iframe_url(params[:id]), :layout => false
|
render text: post_iframe_url(params[:id]), layout: false
|
||||||
end
|
end
|
||||||
|
|
||||||
def oembed
|
def oembed
|
||||||
post_id = OEmbedPresenter.id_from_url(params.delete(:url))
|
post_id = OEmbedPresenter.id_from_url(params.delete(:url))
|
||||||
post = Post.find_by_guid_or_id_with_user(post_id, current_user)
|
post_service = PostService.new(id: post_id, user: current_user,
|
||||||
if post.present?
|
oembed: params.slice(:format, :maxheight, :minheight))
|
||||||
oembed = OEmbedPresenter.new(post, params.slice(:format, :maxheight, :minheight))
|
render json: post_service.present_oembed
|
||||||
render :json => oembed
|
|
||||||
else
|
|
||||||
render :nothing => true, :status => 404
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def interactions
|
def interactions
|
||||||
respond_with(PostInteractionPresenter.new(@post, current_user))
|
post_service = PostService.new(id: params[:id], user: current_user)
|
||||||
|
respond_with post_service.present_interactions_json
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
find_current_user_post(params[:id])
|
post_service = PostService.new(id: params[:id], user: current_user)
|
||||||
current_user.retract(@post)
|
post_service.retract_post
|
||||||
|
@post = post_service.post
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.js { render 'destroy',:layout => false, :format => :js }
|
format.js { render "destroy", layout: false, format: :js }
|
||||||
format.json { render :nothing => true, :status => 204 }
|
format.json { render nothing: true, status: 204 }
|
||||||
format.any { redirect_to stream_path }
|
format.any { redirect_to stream_path }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
private
|
||||||
find_current_user_post(params[:id])
|
|
||||||
@post.favorite = !@post.favorite
|
|
||||||
@post.save
|
|
||||||
render :nothing => true, :status => 202
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def find_post #checks whether current user can see it
|
|
||||||
@post = Post.find_by_guid_or_id_with_user(params[:id], current_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_current_user_post(id) #makes sure current_user can modify
|
|
||||||
@post = current_user.posts.find(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_format_if_malformed_from_status_net
|
def set_format_if_malformed_from_status_net
|
||||||
request.format = :html if request.format == 'application/html+xml'
|
request.format = :html if request.format == "application/html+xml"
|
||||||
end
|
|
||||||
|
|
||||||
def mark_corresponding_notifications_read
|
|
||||||
# For comments, reshares, likes
|
|
||||||
Notification.where(recipient_id: current_user.id, target_type: "Post", target_id: @post.id, unread: true).each do |n|
|
|
||||||
n.set_read_state( true )
|
|
||||||
end
|
|
||||||
|
|
||||||
# For mentions
|
|
||||||
mention = @post.mentions.where(person_id: current_user.person_id).first
|
|
||||||
Notification.where(recipient_id: current_user.id, target_type: "Mention", target_id: mention.id, unread: true).first.try(:set_read_state, true) if mention
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -148,17 +148,20 @@ class Post < ActiveRecord::Base
|
||||||
self.author.profile.nsfw?
|
self.author.profile.nsfw?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.find_by_guid_or_id_with_user(id, user=nil)
|
def self.find_public(id)
|
||||||
key = id.to_s.length <= 8 ? :id : :guid
|
where(post_key(id) => id).includes(:author, comments: :author).first.tap do |post|
|
||||||
post = if user
|
raise ActiveRecord::RecordNotFound.new("could not find a post with id #{id}") unless post
|
||||||
user.find_visible_shareable_by_id(Post, id, :key => key)
|
raise Diaspora::NonPublic unless post.public?
|
||||||
else
|
end
|
||||||
Post.where(key => id).includes(:author, :comments => :author).first
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# is that a private post?
|
def self.find_non_public_by_guid_or_id_with_user(id, user)
|
||||||
raise(Diaspora::NonPublic) unless user || post.try(:public?)
|
user.find_visible_shareable_by_id(Post, id, key: post_key(id)).tap do |post|
|
||||||
|
raise ActiveRecord::RecordNotFound.new("could not find a post with id #{id}") unless post
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
post || raise(ActiveRecord::RecordNotFound.new("could not find a post with id #{id}"))
|
def self.post_key(id)
|
||||||
|
id.to_s.length <= 8 ? :id : :guid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ class PostInteractionPresenter
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def participations
|
def participations
|
||||||
return @post.participations.none unless @current_user
|
return @post.participations.none unless @current_user
|
||||||
@post.participations.where(author: @current_user.person)
|
@post.participations.where(author: @current_user.person)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ class PostPresenter
|
||||||
:post_type => @post.post_type,
|
:post_type => @post.post_type,
|
||||||
:image_url => @post.image_url,
|
:image_url => @post.image_url,
|
||||||
:object_url => @post.object_url,
|
:object_url => @post.object_url,
|
||||||
:favorite => @post.favorite,
|
|
||||||
:nsfw => @post.nsfw,
|
:nsfw => @post.nsfw,
|
||||||
:author => @post.author.as_api_response(:backbone),
|
:author => @post.author.as_api_response(:backbone),
|
||||||
:o_embed_cache => @post.o_embed_cache.try(:as_api_response, :backbone),
|
:o_embed_cache => @post.o_embed_cache.try(:as_api_response, :backbone),
|
||||||
|
|
|
||||||
65
app/services/post_service.rb
Normal file
65
app/services/post_service.rb
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
class PostService
|
||||||
|
attr_reader :post
|
||||||
|
|
||||||
|
def initialize(params)
|
||||||
|
@id = params[:id]
|
||||||
|
@user = params[:user]
|
||||||
|
@oembed = params[:oembed] || {}
|
||||||
|
assign_post
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_post
|
||||||
|
if user
|
||||||
|
@post = Post.find_non_public_by_guid_or_id_with_user(id, user)
|
||||||
|
else
|
||||||
|
@post = Post.find_public(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def present_json
|
||||||
|
PostPresenter.new(post, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def present_interactions_json
|
||||||
|
PostInteractionPresenter.new(post, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def present_oembed
|
||||||
|
OEmbedPresenter.new(post, oembed)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_user_notifications
|
||||||
|
mark_corresponding_notifications_read if user
|
||||||
|
end
|
||||||
|
|
||||||
|
def retract_post
|
||||||
|
raise Diaspora::NotMine unless user_owns_post?
|
||||||
|
user.retract(@post)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :user, :id, :oembed
|
||||||
|
|
||||||
|
def user_owns_post?
|
||||||
|
post.author == user.person
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_corresponding_notifications_read
|
||||||
|
mark_comment_reshare_like_notifications_read
|
||||||
|
mark_mention_notifications_read
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_comment_reshare_like_notifications_read
|
||||||
|
notification = Notification.where(recipient_id: user.id, target_type: "Post", target_id: post.id, unread: true)
|
||||||
|
notification.each do |notification|
|
||||||
|
notification.set_read_state(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_mention_notifications_read
|
||||||
|
mention = post.mentions.where(person_id: user.person_id).first
|
||||||
|
Notification.where(recipient_id: user.id, target_type: "Mention", target_id: mention.id, unread: true)
|
||||||
|
.first.try(:set_read_state, true) if mention
|
||||||
|
end
|
||||||
|
end
|
||||||
9
db/migrate/20150724152052_remove_favorites_from_posts.rb
Normal file
9
db/migrate/20150724152052_remove_favorites_from_posts.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
class RemoveFavoritesFromPosts < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
remove_column :posts, :favorite
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
add_column :posts, :favorite, :boolean, default: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150630221004) do
|
ActiveRecord::Schema.define(version: 20150724152052) do
|
||||||
|
|
||||||
create_table "account_deletions", force: :cascade do |t|
|
create_table "account_deletions", force: :cascade do |t|
|
||||||
t.string "diaspora_handle", limit: 255
|
t.string "diaspora_handle", limit: 255
|
||||||
|
|
@ -375,7 +375,6 @@ ActiveRecord::Schema.define(version: 20150630221004) do
|
||||||
t.integer "reshares_count", limit: 4, default: 0
|
t.integer "reshares_count", limit: 4, default: 0
|
||||||
t.datetime "interacted_at"
|
t.datetime "interacted_at"
|
||||||
t.string "frame_name", limit: 255
|
t.string "frame_name", limit: 255
|
||||||
t.boolean "favorite", default: false
|
|
||||||
t.string "facebook_id", limit: 255
|
t.string "facebook_id", limit: 255
|
||||||
t.string "tweet_id", limit: 255
|
t.string "tweet_id", limit: 255
|
||||||
t.integer "open_graph_cache_id", limit: 4
|
t.integer "open_graph_cache_id", limit: 4
|
||||||
|
|
|
||||||
|
|
@ -2,191 +2,112 @@
|
||||||
# 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 PostsController, type: :controller do
|
||||||
|
let!(:post_service_double) { double("post_service") }
|
||||||
|
|
||||||
describe PostsController, :type => :controller do
|
|
||||||
before do
|
before do
|
||||||
aspect = alice.aspects.first
|
aspect = alice.aspects.first
|
||||||
@message = alice.build_post :status_message, :text => "ohai", :to => aspect.id
|
@message = alice.build_post :status_message, text: "ohai", to: aspect.id
|
||||||
@message.save!
|
@message.save!
|
||||||
|
|
||||||
alice.add_to_streams(@message, [aspect])
|
alice.add_to_streams(@message, [aspect])
|
||||||
alice.dispatch_post @message, :to => aspect.id
|
alice.dispatch_post @message, to: aspect.id
|
||||||
|
|
||||||
|
allow(PostService).to receive(:new).and_return(post_service_double)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#show' do
|
describe "#show" do
|
||||||
context 'user signed in' do
|
before do
|
||||||
|
expect(post_service_double).to receive(:mark_user_notifications)
|
||||||
|
allow(post_service_double).to receive(:present_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "user signed in" do
|
||||||
before do
|
before do
|
||||||
sign_in :user, alice
|
sign_in :user, alice
|
||||||
|
expect(post_service_double).to receive(:post).and_return(@message)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds' do
|
it "succeeds" do
|
||||||
get :show, "id" => @message.id
|
get :show, id: @message.id
|
||||||
expect(response).to be_success
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'succeeds on mobile' do
|
|
||||||
get :show, "id" => @message.id
|
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds after removing a mention when closing the mentioned user\'s account' do
|
it 'succeeds after removing a mention when closing the mentioned user\'s account' do
|
||||||
user = FactoryGirl.create(:user, :username => "user")
|
user = FactoryGirl.create(:user, username: "user")
|
||||||
alice.share_with(user.person, alice.aspects.first)
|
alice.share_with(user.person, alice.aspects.first)
|
||||||
msg = alice.build_post :status_message, text: "Mention @{User ; #{user.diaspora_handle}}", :public => true, :to => 'all'
|
msg = alice.build_post :status_message,
|
||||||
|
text: "Mention @{User ; #{user.diaspora_handle}}", public: true, to: "all"
|
||||||
msg.save!
|
msg.save!
|
||||||
expect(msg.mentioned_people.count).to eq(1)
|
expect(msg.mentioned_people.count).to eq(1)
|
||||||
user.destroy
|
user.destroy
|
||||||
get :show, "id" => msg.id
|
get :show, id: msg.id
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the application layout on mobile' do
|
it "renders the application layout on mobile" do
|
||||||
get :show, :id => @message.id, :format => :mobile
|
get :show, id: @message.id, format: :mobile
|
||||||
expect(response).to render_template('layouts/application')
|
expect(response).to render_template("layouts/application")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds on mobile with a reshare' do
|
it "succeeds on mobile with a reshare" do
|
||||||
get :show, "id" => FactoryGirl.create(:reshare, :author => alice.person).id, :format => :mobile
|
get :show, id: FactoryGirl.create(:reshare, author: alice.person).id, format: :mobile
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'marks a corresponding notifications as read' do
|
|
||||||
FactoryGirl.create(:notification, :recipient => alice, :target => @message, :unread => true)
|
|
||||||
note = FactoryGirl.create(:notification, :recipient => alice, :target => @message, :unread => true)
|
|
||||||
|
|
||||||
expect {
|
|
||||||
get :show, :id => @message.id
|
|
||||||
note.reload
|
|
||||||
}.to change(Notification.where(:unread => true), :count).by(-2)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'marks a corresponding mention notification as read' do
|
|
||||||
status_msg = bob.post(:status_message, {text: "this is a text mentioning @{Mention User ; #{alice.diaspora_handle}} ... have fun testing!", :public => true, :to => 'all'})
|
|
||||||
mention = status_msg.mentions.where(person_id: alice.person.id).first
|
|
||||||
note = FactoryGirl.create(:notification, :recipient => alice, :target_type => "Mention", :target_id => mention.id, :unread => true)
|
|
||||||
|
|
||||||
expect {
|
|
||||||
get :show, :id => status_msg.id
|
|
||||||
note.reload
|
|
||||||
}.to change(Notification.where(:unread => true), :count).by(-1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it '404 if the post is missing' do
|
|
||||||
expect {
|
|
||||||
get :show, :id => 1234567
|
|
||||||
}.to raise_error(ActiveRecord::RecordNotFound)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'user not signed in' do
|
context "user not signed in" do
|
||||||
context 'given a public post' do
|
context "given a public post" do
|
||||||
before :each do
|
before :each do
|
||||||
@status = alice.post(:status_message, :text => "hello", :public => true, :to => 'all')
|
@status = alice.post(:status_message, text: "hello", public: true, to: "all")
|
||||||
|
expect(post_service_double).to receive(:post).and_return(@status)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows a public post' do
|
it "shows a public post" do
|
||||||
get :show, :id => @status.id
|
get :show, id: @status.id
|
||||||
expect(response.status).to eq(200)
|
expect(response.body).to match "hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds for statusnet' do
|
it "succeeds for statusnet" do
|
||||||
@request.env["HTTP_ACCEPT"] = "application/html+xml,text/html"
|
@request.env["HTTP_ACCEPT"] = "application/html+xml,text/html"
|
||||||
get :show, :id => @status.id
|
get :show, id: @status.id
|
||||||
expect(response).to be_success
|
expect(response.body).to match "hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'responds with diaspora xml if format is xml' do
|
it "responds with diaspora xml if format is xml" do
|
||||||
get :show, :id => @status.guid, :format => :xml
|
get :show, id: @status.guid, format: :xml
|
||||||
expect(response.body).to eq(@status.to_diaspora_xml)
|
expect(response.body).to eq(@status.to_diaspora_xml)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not show a private post' do
|
|
||||||
status = alice.post(:status_message, :text => "hello", :public => false, :to => 'all')
|
|
||||||
get :show, :id => status.id
|
|
||||||
expect(response.status).to eq(404)
|
|
||||||
end
|
|
||||||
|
|
||||||
# We want to be using guids from now on for this post route, but do not want to break
|
|
||||||
# pre-exisiting permalinks. We can assume a guid is 8 characters long as we have
|
|
||||||
# guids set to hex(8) since we started using them.
|
|
||||||
context 'id/guid switch' do
|
|
||||||
before do
|
|
||||||
@status = alice.post(:status_message, :text => "hello", :public => true, :to => 'all')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'assumes guids less than 8 chars are ids and not guids' do
|
|
||||||
p = Post.where(:id => @status.id.to_s)
|
|
||||||
expect(Post).to receive(:where)
|
|
||||||
.with(hash_including(:id => @status.id.to_s))
|
|
||||||
.and_return(p)
|
|
||||||
get :show, :id => @status.id
|
|
||||||
expect(response).to be_success
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'assumes guids more than (or equal to) 8 chars are actually guids' do
|
|
||||||
p = Post.where(:guid => @status.guid)
|
|
||||||
expect(Post).to receive(:where)
|
|
||||||
.with(hash_including(:guid => @status.guid))
|
|
||||||
.and_return(p)
|
|
||||||
get :show, :id => @status.guid
|
|
||||||
expect(response).to be_success
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'iframe' do
|
describe "iframe" do
|
||||||
it 'contains an iframe' do
|
it "contains an iframe" do
|
||||||
get :iframe, :id => @message.id
|
get :iframe, id: @message.id
|
||||||
expect(response.body).to match /iframe/
|
expect(response.body).to match /iframe/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'oembed' do
|
describe "oembed" do
|
||||||
it 'works when you can see it' do
|
it "receives a present oembed" do
|
||||||
sign_in alice
|
expect(post_service_double).to receive(:present_oembed)
|
||||||
get :oembed, :url => "/posts/#{@message.id}"
|
get :oembed, url: "/posts/#{@message.id}"
|
||||||
expect(response.body).to match /iframe/
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a 404 response when the post is not found' do
|
|
||||||
get :oembed, :url => "/posts/#{@message.id}"
|
|
||||||
expect(response.status).to eq(404)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#destroy' do
|
describe "#destroy" do
|
||||||
before do
|
before do
|
||||||
sign_in alice
|
sign_in alice
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'let a user delete his message' do
|
it "will receive a retract post" do
|
||||||
message = alice.post(:status_message, :text => "hey", :to => alice.aspects.first.id)
|
expect(post_service_double).to receive(:retract_post)
|
||||||
delete :destroy, :format => :js, :id => message.id
|
expect(post_service_double).to receive(:post).and_return(@message)
|
||||||
expect(response).to be_success
|
message = alice.post(:status_message, text: "hey", to: alice.aspects.first.id)
|
||||||
expect(StatusMessage.find_by_id(message.id)).to be_nil
|
delete :destroy, format: :js, id: message.id
|
||||||
end
|
|
||||||
|
|
||||||
it 'sends a retraction on delete' do
|
|
||||||
allow(controller).to receive(:current_user).and_return alice
|
|
||||||
message = alice.post(:status_message, :text => "hey", :to => alice.aspects.first.id)
|
|
||||||
expect(alice).to receive(:retract).with(message)
|
|
||||||
delete :destroy, :format => :js, :id => message.id
|
|
||||||
expect(response).to be_success
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'will not let you destroy posts visible to you' do
|
|
||||||
message = bob.post(:status_message, :text => "hey", :to => bob.aspects.first.id)
|
|
||||||
expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
|
|
||||||
expect(StatusMessage.exists?(message.id)).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'will not let you destory posts you do not own' do
|
|
||||||
message = eve.post(:status_message, :text => "hey", :to => eve.aspects.first.id)
|
|
||||||
expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
|
|
||||||
expect(StatusMessage.exists?(message.id)).to be true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -400,43 +400,55 @@ describe Post, :type => :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#find_by_guid_or_id_with_user" do
|
describe "#find_public" do
|
||||||
it "succeeds with an id" do
|
it "succeeds with an id" do
|
||||||
post = FactoryGirl.create :status_message, public: true
|
post = FactoryGirl.create :status_message, public: true
|
||||||
expect(Post.find_by_guid_or_id_with_user(post.id)).to eq(post)
|
expect(Post.find_public post.id).to eq(post)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "succeeds with an guid" do
|
it "succeeds with an guid" do
|
||||||
post = FactoryGirl.create :status_message, public: true
|
post = FactoryGirl.create :status_message, public: true
|
||||||
expect(Post.find_by_guid_or_id_with_user(post.guid)).to eq(post)
|
expect(Post.find_public post.guid).to eq(post)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ActiveRecord::RecordNotFound for a non-existing id without a user" do
|
||||||
|
allow(Post).to receive_messages where: double(includes: double(first: nil))
|
||||||
|
expect {
|
||||||
|
Post.find_public 123
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises Diaspora::NonPublic for a private post without a user" do
|
||||||
|
post = FactoryGirl.create :status_message
|
||||||
|
expect {
|
||||||
|
Post.find_public post.id
|
||||||
|
}.to raise_error Diaspora::NonPublic
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#find_non_public_by_guid_or_id_with_user" do
|
||||||
|
it "succeeds with an id" do
|
||||||
|
post = FactoryGirl.create :status_message_in_aspect
|
||||||
|
expect(Post.find_non_public_by_guid_or_id_with_user(post.id, post.author.owner)).to eq(post)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "succeeds with an guid" do
|
||||||
|
post = FactoryGirl.create :status_message_in_aspect
|
||||||
|
expect(Post.find_non_public_by_guid_or_id_with_user(post.guid, post.author.owner)).to eq(post)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "looks up on the passed user object if it's non-nil" do
|
it "looks up on the passed user object if it's non-nil" do
|
||||||
post = FactoryGirl.create :status_message
|
post = FactoryGirl.create :status_message
|
||||||
user = double
|
user = double
|
||||||
expect(user).to receive(:find_visible_shareable_by_id).with(Post, post.id, key: :id).and_return(post)
|
expect(user).to receive(:find_visible_shareable_by_id).with(Post, post.id, key: :id).and_return(post)
|
||||||
Post.find_by_guid_or_id_with_user post.id, user
|
Post.find_non_public_by_guid_or_id_with_user(post.id, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises ActiveRecord::RecordNotFound with a non-existing id and a user" do
|
it "raises ActiveRecord::RecordNotFound with a non-existing id and a user" do
|
||||||
user = double(find_visible_shareable_by_id: nil)
|
user = double(find_visible_shareable_by_id: nil)
|
||||||
expect {
|
expect {
|
||||||
Post.find_by_guid_or_id_with_user 123, user
|
Post.find_non_public_by_guid_or_id_with_user(123, user)
|
||||||
}.to raise_error ActiveRecord::RecordNotFound
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises Diaspora::NonPublic for a non-existing id without a user" do
|
|
||||||
allow(Post).to receive_messages where: double(includes: double(first: nil))
|
|
||||||
expect {
|
|
||||||
Post.find_by_guid_or_id_with_user 123
|
|
||||||
}.to raise_error Diaspora::NonPublic
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises Diaspora::NonPublic for a private post without a user" do
|
|
||||||
post = FactoryGirl.create :status_message
|
|
||||||
expect {
|
|
||||||
Post.find_by_guid_or_id_with_user post.id
|
|
||||||
}.to raise_error Diaspora::NonPublic
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
127
spec/services/post_service_spec.rb
Normal file
127
spec/services/post_service_spec.rb
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe PostService do
|
||||||
|
before do
|
||||||
|
aspect = alice.aspects.first
|
||||||
|
@message = alice.build_post :status_message, text: "ohai", to: aspect.id
|
||||||
|
@message.save!
|
||||||
|
|
||||||
|
alice.add_to_streams(@message, [aspect])
|
||||||
|
alice.dispatch_post @message, to: aspect.id
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#assign_post" do
|
||||||
|
context "when the post is private" do
|
||||||
|
it "RecordNotFound if the post cannot be found" do
|
||||||
|
expect { PostService.new(id: 1_234_567, user: alice) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
it "NonPublic if there is no user" do
|
||||||
|
expect { PostService.new(id: @message.id) }.to raise_error(Diaspora::NonPublic)
|
||||||
|
end
|
||||||
|
it "RecordNotFound if user cannot see post" do
|
||||||
|
expect { PostService.new(id: @message.id, user: eve) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the post is public" do
|
||||||
|
it "RecordNotFound if the post cannot be found" do
|
||||||
|
expect { PostService.new(id: 1_234_567) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# We want to be using guids from now on for this post route, but do not want to break
|
||||||
|
# pre-exisiting permalinks. We can assume a guid is 8 characters long as we have
|
||||||
|
# guids set to hex(8) since we started using them.
|
||||||
|
context "id/guid switch" do
|
||||||
|
before do
|
||||||
|
@status = alice.post(:status_message, text: "hello", public: true, to: "all")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assumes guids less than 8 chars are ids and not guids" do
|
||||||
|
post = Post.where(id: @status.id.to_s)
|
||||||
|
expect(Post).to receive(:where).with(hash_including(id: @status.id)).and_return(post).at_least(:once)
|
||||||
|
PostService.new(id: @status.id, user: alice)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assumes guids more than (or equal to) 8 chars are actually guids" do
|
||||||
|
post = Post.where(guid: @status.guid)
|
||||||
|
expect(Post).to receive(:where).with(hash_including(guid: @status.guid)).and_return(post).at_least(:once)
|
||||||
|
PostService.new(id: @status.guid, user: alice)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#mark_user_notifications" do
|
||||||
|
it "marks a corresponding notifications as read" do
|
||||||
|
FactoryGirl.create(:notification, recipient: alice, target: @message, unread: true)
|
||||||
|
FactoryGirl.create(:notification, recipient: alice, target: @message, unread: true)
|
||||||
|
post_service = PostService.new(id: @message.id, user: alice)
|
||||||
|
expect { post_service.mark_user_notifications }.to change(Notification.where(unread: true), :count).by(-2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "marks a corresponding mention notification as read" do
|
||||||
|
status_text = "this is a text mentioning @{Mention User ; #{alice.diaspora_handle}} ... have fun testing!"
|
||||||
|
status_msg =
|
||||||
|
bob.post(:status_message, text: status_text, public: true, to: "all")
|
||||||
|
mention = status_msg.mentions.where(person_id: alice.person.id).first
|
||||||
|
FactoryGirl.create(:notification, recipient: alice, target_type: "Mention", target_id: mention.id, unread: true)
|
||||||
|
post_service = PostService.new(id: status_msg.id, user: alice)
|
||||||
|
expect { post_service.mark_user_notifications }.to change(Notification.where(unread: true), :count).by(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#present_json" do
|
||||||
|
it "works for a private post" do
|
||||||
|
post_service = PostService.new(id: @message.id, user: alice)
|
||||||
|
expect(post_service.present_json.to_json).to match(/\"text\"\:\"ohai\"/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works for a public post " do
|
||||||
|
status = alice.post(:status_message, text: "hello", public: true, to: "all")
|
||||||
|
post_service = PostService.new(id: status.id)
|
||||||
|
expect(post_service.present_json.to_json).to match(/\"text\"\:\"hello\"/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#present_oembed" do
|
||||||
|
it "works for a private post" do
|
||||||
|
post_service = PostService.new(id: @message.id, user: alice)
|
||||||
|
expect(post_service.present_oembed.to_json).to match(/iframe/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works for a public post" do
|
||||||
|
status = alice.post(:status_message, text: "hello", public: true, to: "all")
|
||||||
|
post_service = PostService.new(id: status.id)
|
||||||
|
expect(post_service.present_oembed.to_json).to match(/iframe/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#retract_post" do
|
||||||
|
it "let a user delete his message" do
|
||||||
|
message = alice.post(:status_message, text: "hey", to: alice.aspects.first.id)
|
||||||
|
post_service = PostService.new(id: message.id, user: alice)
|
||||||
|
post_service.retract_post
|
||||||
|
expect(StatusMessage.find_by_id(message.id)).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sends a retraction on delete" do
|
||||||
|
message = alice.post(:status_message, text: "hey", to: alice.aspects.first.id)
|
||||||
|
post_service = PostService.new(id: message.id, user: alice)
|
||||||
|
expect(alice).to receive(:retract).with(message)
|
||||||
|
post_service.retract_post
|
||||||
|
end
|
||||||
|
|
||||||
|
it "will not let you destroy posts visible to you but that you do not own" do
|
||||||
|
message = bob.post(:status_message, text: "hey", to: bob.aspects.first.id)
|
||||||
|
post_service = PostService.new(id: message.id, user: alice)
|
||||||
|
expect { post_service.retract_post }.to raise_error(Diaspora::NotMine)
|
||||||
|
expect(StatusMessage.exists?(message.id)).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "will not let you destroy posts that are not visible to you" do
|
||||||
|
message = eve.post(:status_message, text: "hey", to: eve.aspects.first.id)
|
||||||
|
expect { PostService.new(id: message.id, user: alice) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
expect(StatusMessage.exists?(message.id)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue