diff --git a/docs/_entities/reshare.md b/docs/_entities/reshare.md index b863ce3..dc08931 100644 --- a/docs/_entities/reshare.md +++ b/docs/_entities/reshare.md @@ -7,6 +7,10 @@ This entity represents a reshare of a [StatusMessage][status_message]. It inheri The recipient must [fetch][fetching] the root from `root_author` if the post is not already known. When the `root_guid` is already available locally, the recipient must validate that it's from `root_author`. +A special case when the entity doesn't include `root_author` and `root_guid` is allowed. This case represents +a reshare for a deleted post. If there is only one of `root_author` and `root_guid` is present, then the entity +is not valid. + ## Properties | Property | Type | Description | diff --git a/lib/diaspora_federation/entities/reshare.rb b/lib/diaspora_federation/entities/reshare.rb index fb59dcf..2ccc577 100644 --- a/lib/diaspora_federation/entities/reshare.rb +++ b/lib/diaspora_federation/entities/reshare.rb @@ -31,6 +31,11 @@ module DiasporaFederation # Fetch and receive root post from remote, if not available locally # and validates if it's from the correct author def validate_root + return if root_author.nil? && root_guid.nil? + + raise Entity::ValidationError, "#{self}: root_guid can't be nil if root_author is present" if root_guid.nil? + raise Entity::ValidationError, "#{self}: root_author can't be nil if root_guid is present" if root_author.nil? + root = RelatedEntity.fetch(root_author, "Post", root_guid) return if root_author == root.author diff --git a/lib/diaspora_federation/validators/reshare_validator.rb b/lib/diaspora_federation/validators/reshare_validator.rb index bf6ea77..71f9c86 100644 --- a/lib/diaspora_federation/validators/reshare_validator.rb +++ b/lib/diaspora_federation/validators/reshare_validator.rb @@ -4,9 +4,9 @@ module DiasporaFederation class ReshareValidator < Validation::Validator include Validation - rule :root_author, %i[not_empty diaspora_id] + rule :root_author, :diaspora_id - rule :root_guid, :guid + rule :root_guid, guid: {nilable: true} rule :author, %i[not_empty diaspora_id] diff --git a/spec/lib/diaspora_federation/entities/reshare_spec.rb b/spec/lib/diaspora_federation/entities/reshare_spec.rb index 664ddfd..2ba066b 100644 --- a/spec/lib/diaspora_federation/entities/reshare_spec.rb +++ b/spec/lib/diaspora_federation/entities/reshare_spec.rb @@ -74,6 +74,31 @@ XML Entities::Reshare.from_xml(Nokogiri::XML(xml).root) }.to raise_error Entity::ValidationError end + + it "validates a reshare with no root" do + data[:root_author] = nil + data[:root_guid] = nil + + reshare = Entities::Reshare.from_xml(Nokogiri::XML(xml).root) + expect(reshare.root_author).to be_nil + expect(reshare.root_guid).to be_nil + end + + it "disallows root_author without root_guid" do + data[:root_guid] = nil + + expect { + Entities::Reshare.from_xml(Nokogiri::XML(xml).root) + }.to raise_error Entity::ValidationError + end + + it "disallows root_guid without root_author" do + data[:root_author] = nil + + expect { + Entities::Reshare.from_xml(Nokogiri::XML(xml).root) + }.to raise_error Entity::ValidationError + end end end end diff --git a/spec/lib/diaspora_federation/validators/reshare_validator_spec.rb b/spec/lib/diaspora_federation/validators/reshare_validator_spec.rb index 47e646f..e78905d 100644 --- a/spec/lib/diaspora_federation/validators/reshare_validator_spec.rb +++ b/spec/lib/diaspora_federation/validators/reshare_validator_spec.rb @@ -3,20 +3,29 @@ module DiasporaFederation let(:entity) { :reshare_entity } it_behaves_like "a common validator" - %i[root_author author].each do |prop| - describe "##{prop}" do - it_behaves_like "a diaspora* ID validator" do - let(:property) { prop } - let(:mandatory) { true } - end + describe "#author" do + it_behaves_like "a diaspora* ID validator" do + let(:property) { :author } + let(:mandatory) { true } end end - %i[root_guid guid].each do |prop| - describe "##{prop}" do - it_behaves_like "a guid validator" do - let(:property) { prop } - end + describe "#guid" do + it_behaves_like "a guid validator" do + let(:property) { :guid } + end + end + + describe "#root_guid" do + it_behaves_like "a nilable guid validator" do + let(:property) { :root_guid } + end + end + + describe "#root_author" do + it_behaves_like "a diaspora* ID validator" do + let(:property) { :root_author } + let(:mandatory) { false } end end diff --git a/spec/support/shared_validator_specs.rb b/spec/support/shared_validator_specs.rb index d539b16..58a5c0a 100644 --- a/spec/support/shared_validator_specs.rb +++ b/spec/support/shared_validator_specs.rb @@ -92,7 +92,7 @@ shared_examples "a diaspora* ID validator" do end end -shared_examples "a guid validator" do +shared_examples "common guid validator" do it "validates a well-formed guid from redmatrix" do validator = described_class.new(entity_stub(entity, property => "1234567890ABCDefgh_ijkl-mnopQR@example.com:3000")) @@ -113,6 +113,10 @@ shared_examples "a guid validator" do expect(validator).not_to be_valid expect(validator.errors).to include(property) end +end + +shared_examples "a guid validator" do + include_examples "common guid validator" it "must not be nil or empty" do [nil, ""].each do |val| @@ -124,6 +128,17 @@ shared_examples "a guid validator" do end end +shared_examples "a nilable guid validator" do + include_examples "common guid validator" + + it "can be nil" do + validator = described_class.new(entity_stub(entity, property => nil)) + + expect(validator).to be_valid + expect(validator.errors).to be_empty + end +end + shared_examples "a boolean validator" do it "validates a well-formed boolean" do [true, "true", false, "false"].each do |val|