Merge pull request #85 from SuperTux88/add-author-to-diaspora-url

Add author to diaspora:// URL
This commit is contained in:
Dennis Schubert 2017-09-13 08:08:27 +02:00
commit 0a358c8724
No known key found for this signature in database
GPG key ID: 5A0304BEA7966D7E
39 changed files with 84 additions and 84 deletions

View file

@ -13,20 +13,25 @@ it as software specific URL.
The format is similar to the route used for [fetching][fetching], so if the The format is similar to the route used for [fetching][fetching], so if the
receiving server doesn't know the linked entity yet, it can just be fetched. receiving server doesn't know the linked entity yet, it can just be fetched.
When the entity with that `guid` is already available locally, the recipient
should validate that it's from `author` before linking to it.
### Format ### Format
`diaspora://:type/:guid` `diaspora://:author/:type/:guid`
#### Parameters #### Parameters
| Name | Description | | Name | Description |
| ------ | ---------------------------------------------- | | -------- | -------------------------------------------------------------------- |
| `type` | The type of the linked entity in `snake_case`. | | `author` | The [diaspora\* ID][diaspora-id] of the author of the linked entity. |
| `guid` | The [GUID][guid] of the linked entity. | | `type` | The type of the linked entity in `snake_case`. |
| `guid` | The [GUID][guid] of the linked entity. |
#### Example #### Example
`diaspora://post/17faf230675101350d995254001bd39e` `diaspora://alice@example.org/post/17faf230675101350d995254001bd39e`
[fetching]: {{ site.baseurl }}/federation/fetching.html [fetching]: {{ site.baseurl }}/federation/fetching.html
[diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
[guid]: {{ site.baseurl }}/federation/types.html#guid [guid]: {{ site.baseurl }}/federation/types.html#guid

View file

@ -10,7 +10,7 @@ module DiasporaFederation
# The diaspora* ID of the person who posted the original post # The diaspora* ID of the person who posted the original post
# @see Person#author # @see Person#author
# @return [String] diaspora* ID # @return [String] diaspora* ID
property :root_author, :string, xml_name: :root_diaspora_id property :root_author, :string, optional: true, xml_name: :root_diaspora_id
# @!attribute [r] root_guid # @!attribute [r] root_guid
# Guid of the original post # Guid of the original post

View file

@ -5,22 +5,27 @@ module DiasporaFederation
include Logging include Logging
# Regex to find diaspora:// URLs # Regex to find diaspora:// URLs
DIASPORA_URL_REGEX = %r{diaspora://(#{Entity::ENTITY_NAME_REGEX})/(#{Validation::Rule::Guid::VALID_CHARS})} DIASPORA_URL_REGEX = %r{
diaspora://
(#{Validation::Rule::DiasporaId::DIASPORA_ID_REGEX})/
(#{Entity::ENTITY_NAME_REGEX})/
(#{Validation::Rule::Guid::VALID_CHARS})
}ux
# Parses all diaspora:// URLs from the text and fetches the entities from # Parses all diaspora:// URLs from the text and fetches the entities from
# the remote server if needed. # the remote server if needed.
# @param [String] sender the diaspora* ID of the sender of the entity # @param [String] sender the diaspora* ID of the sender of the entity
# @param [String] text text with diaspora:// URLs to fetch # @param [String] text text with diaspora:// URLs to fetch
def self.fetch_linked_entities(sender, text) def self.fetch_linked_entities(text)
text.scan(DIASPORA_URL_REGEX).each do |type, guid| text.scan(DIASPORA_URL_REGEX).each do |author, type, guid|
fetch_entity(sender, type, guid) fetch_entity(author, type, guid)
end end
end end
private_class_method def self.fetch_entity(sender, type, guid) private_class_method def self.fetch_entity(author, type, guid)
class_name = Entity.entity_class(type).to_s.rpartition("::").last class_name = Entity.entity_class(type).to_s.rpartition("::").last
return if DiasporaFederation.callbacks.trigger(:fetch_related_entity, class_name, guid) return if DiasporaFederation.callbacks.trigger(:fetch_related_entity, class_name, guid)
Fetcher.fetch_public(sender, type, guid) Fetcher.fetch_public(author, type, guid)
rescue => e rescue => e
logger.error "Failed to fetch linked entity #{type}:#{guid}: #{e.class}: #{e.message}" logger.error "Failed to fetch linked entity #{type}:#{guid}: #{e.class}: #{e.message}"
end end

View file

@ -46,7 +46,7 @@ module DiasporaFederation
end end
def fetch_linked_entities_from_text def fetch_linked_entities_from_text
DiasporaUrlParser.fetch_linked_entities(sender, entity.text) if entity.respond_to?(:text) && entity.text DiasporaUrlParser.fetch_linked_entities(entity.text) if entity.respond_to?(:text) && entity.text
end end
end end
end end

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class AccountDeletionValidator < OptionalAwareValidator class AccountDeletionValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
end end
end end
end end

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class AccountMigrationValidator < OptionalAwareValidator class AccountMigrationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :profile, :not_nil rule :profile, :not_nil
end end

View file

@ -4,8 +4,8 @@ module DiasporaFederation
class ContactValidator < OptionalAwareValidator class ContactValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :recipient, %i[not_empty diaspora_id] rule :recipient, :diaspora_id
rule :following, :boolean rule :following, :boolean
rule :sharing, :boolean rule :sharing, :boolean
end end

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class ConversationValidator < OptionalAwareValidator class ConversationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid
rule :subject, [:not_empty, length: {maximum: 255}] rule :subject, [:not_empty, length: {maximum: 255}]

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class EventValidator < OptionalAwareValidator class EventValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class MessageValidator < OptionalAwareValidator class MessageValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid
rule :conversation_guid, :guid rule :conversation_guid, :guid

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class ParticipationValidator < OptionalAwareValidator class ParticipationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid
rule :parent_guid, :guid rule :parent_guid, :guid
rule :parent_type, [:not_empty, regular_expression: {regex: /\APost\z/}] rule :parent_type, [:not_empty, regular_expression: {regex: /\APost\z/}]

View file

@ -6,7 +6,7 @@ module DiasporaFederation
rule :guid, :guid rule :guid, :guid
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :url, %i[not_nil URI] rule :url, %i[not_nil URI]

View file

@ -6,7 +6,7 @@ module DiasporaFederation
rule :guid, :guid rule :guid, :guid
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :public, :boolean rule :public, :boolean

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class RelatedEntityValidator < Validation::Validator class RelatedEntityValidator < Validation::Validator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :local, :boolean rule :local, :boolean
rule :public, :boolean rule :public, :boolean
end end

View file

@ -6,7 +6,7 @@ module DiasporaFederation
# @param [Validation::Validator] validator the validator in which it is included # @param [Validation::Validator] validator the validator in which it is included
def self.included(validator) def self.included(validator)
validator.class_eval do validator.class_eval do
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid
rule :parent_guid, :guid rule :parent_guid, :guid
rule :parent, :not_nil rule :parent, :not_nil

View file

@ -8,7 +8,7 @@ module DiasporaFederation
rule :root_guid, :guid rule :root_guid, :guid
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class RetractionValidator < OptionalAwareValidator class RetractionValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :target_guid, :guid rule :target_guid, :guid
rule :target_type, :not_empty rule :target_type, :not_empty

View file

@ -5,23 +5,25 @@ module Validation
# A simple rule to validate the base structure of diaspora* IDs. # A simple rule to validate the base structure of diaspora* IDs.
class DiasporaId class DiasporaId
# The Regex for a valid diaspora* ID # The Regex for a valid diaspora* ID
DIASPORA_ID = begin DIASPORA_ID_REGEX = begin
letter = "a-zA-Z" letter = "a-zA-Z"
digit = "0-9" digit = "0-9"
hexadecimal = "[a-fA-F#{digit}]" hexadecimal = "[a-fA-F#{digit}]"
username = "[#{letter}#{digit}\\-\\_\\.]+" username = "[#{letter}#{digit}\\-\\_\\.]+"
hostname_part = "[#{letter}#{digit}\\-]" hostname_part = "[#{letter}#{digit}\\-]"
hostname = "#{hostname_part}+([.]#{hostname_part}*)*" hostname = "#{hostname_part}+(?:[.]#{hostname_part}*)*"
ipv4 = "(?:[#{digit}]{1,3}\\.){3}[#{digit}]{1,3}" ipv4 = "(?:[#{digit}]{1,3}\\.){3}[#{digit}]{1,3}"
ipv6 = "\\[(?:#{hexadecimal}{0,4}:){0,7}#{hexadecimal}{1,4}\\]" ipv6 = "\\[(?:#{hexadecimal}{0,4}:){0,7}#{hexadecimal}{1,4}\\]"
ip_addr = "(?:#{ipv4}|#{ipv6})" ip_addr = "(?:#{ipv4}|#{ipv6})"
domain = "(?:#{hostname}|#{ip_addr})" domain = "(?:#{hostname}|#{ip_addr})"
port = "(:[#{digit}]+)?" port = "(?::[#{digit}]+)?"
addr_spec = "(#{username}\\@#{domain}#{port})?"
/\A#{addr_spec}\z/u "#{username}\\@#{domain}#{port}"
end end
# The Regex for validating a full diaspora* ID
DIASPORA_ID = /\A#{DIASPORA_ID_REGEX}\z/u
# The error key for this rule # The error key for this rule
# @return [Symbol] error key # @return [Symbol] error key
def error_key def error_key
@ -30,7 +32,7 @@ module Validation
# Determines if value is a valid diaspora* ID # Determines if value is a valid diaspora* ID
def valid_value?(value) def valid_value?(value)
value.nil? || !DIASPORA_ID.match(value).nil? value.is_a?(String) && value =~ DIASPORA_ID
end end
# This rule has no params. # This rule has no params.

View file

@ -9,7 +9,7 @@ module Validation
# Special chars aren't allowed at the end. # Special chars aren't allowed at the end.
class Guid class Guid
# Allowed chars to validate a GUID with a regex # Allowed chars to validate a GUID with a regex
VALID_CHARS = "[0-9A-Za-z\\-_@.:]{15,254}[0-9a-z]".freeze VALID_CHARS = "[0-9A-Za-z\\-_@.:]{15,254}[0-9A-Za-z]".freeze
# The error key for this rule # The error key for this rule
# @return [Symbol] error key # @return [Symbol] error key

View file

@ -4,7 +4,7 @@ module DiasporaFederation
class StatusMessageValidator < OptionalAwareValidator class StatusMessageValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, :diaspora_id
rule :guid, :guid rule :guid, :guid

View file

@ -1,6 +1,6 @@
module DiasporaFederation module DiasporaFederation
describe Federation::DiasporaUrlParser do describe Federation::DiasporaUrlParser do
let(:sender) { Fabricate.sequence(:diaspora_id) } let(:author) { Fabricate.sequence(:diaspora_id) }
let(:guid) { Fabricate.sequence(:guid) } let(:guid) { Fabricate.sequence(:guid) }
describe ".fetch_linked_entities" do describe ".fetch_linked_entities" do
@ -11,56 +11,56 @@ module DiasporaFederation
expect_callback(:fetch_related_entity, "Post", guid2).and_return(double) expect_callback(:fetch_related_entity, "Post", guid2).and_return(double)
expect_callback(:fetch_related_entity, "Post", guid3).and_return(double) expect_callback(:fetch_related_entity, "Post", guid3).and_return(double)
text = "This is a [link to a post with markdown](diaspora://post/#{guid}) and one without " \ text = "This is a [link to a post with markdown](diaspora://#{author}/post/#{guid}) and one without " \
"diaspora://post/#{guid2} and finally a last one diaspora://post/#{guid3}." "diaspora://#{author}/post/#{guid2} and finally a last one diaspora://#{author}/post/#{guid3}."
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
end end
it "ignores invalid diaspora:// urls" do it "ignores invalid diaspora:// urls" do
expect(DiasporaFederation.callbacks).not_to receive(:trigger) expect(DiasporaFederation.callbacks).not_to receive(:trigger)
text = "This is an invalid link diaspora://Post/#{guid}) and another one: " \ text = "This is an invalid link diaspora://#{author}/Post/#{guid} and another one " \
"diaspora://post/abcd." "diaspora://#{author}/post/abcd and last one: diaspora://example.org/post/#{guid}."
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
end end
it "allows to link other entities" do it "allows to link other entities" do
expect_callback(:fetch_related_entity, "Event", guid).and_return(double) expect_callback(:fetch_related_entity, "Event", guid).and_return(double)
text = "This is a link to an event diaspora://event/#{guid}." text = "This is a link to an event diaspora://#{author}/event/#{guid}."
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
end end
it "handles unknown entities gracefully" do it "handles unknown entities gracefully" do
expect(DiasporaFederation.callbacks).not_to receive(:trigger) expect(DiasporaFederation.callbacks).not_to receive(:trigger)
text = "This is a link to an event diaspora://unknown/#{guid}." text = "This is a link to an event diaspora://#{author}/unknown/#{guid}."
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
end end
it "fetches entities from sender when not found locally" do it "fetches entities from sender when not found locally" do
expect_callback(:fetch_related_entity, "Post", guid).and_return(nil) expect_callback(:fetch_related_entity, "Post", guid).and_return(nil)
expect(Federation::Fetcher).to receive(:fetch_public).with(sender, "post", guid) expect(Federation::Fetcher).to receive(:fetch_public).with(author, "post", guid)
text = "This is a link to a post: diaspora://post/#{guid}." text = "This is a link to a post: diaspora://#{author}/post/#{guid}."
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
end end
it "handles fetch errors gracefully" do it "handles fetch errors gracefully" do
expect_callback(:fetch_related_entity, "Post", guid).and_return(nil) expect_callback(:fetch_related_entity, "Post", guid).and_return(nil)
expect(Federation::Fetcher).to receive(:fetch_public).with( expect(Federation::Fetcher).to receive(:fetch_public).with(
sender, "post", guid author, "post", guid
).and_raise(Federation::Fetcher::NotFetchable, "Something went wrong!") ).and_raise(Federation::Fetcher::NotFetchable, "Something went wrong!")
text = "This is a link to a post: diaspora://post/#{guid}." text = "This is a link to a post: diaspora://#{author}/post/#{guid}."
expect { expect {
Federation::DiasporaUrlParser.fetch_linked_entities(sender, text) Federation::DiasporaUrlParser.fetch_linked_entities(text)
}.not_to raise_error }.not_to raise_error
end end
end end

View file

@ -119,7 +119,7 @@ module DiasporaFederation
end end
it "fetches linked entities when the received entity has a text property" do it "fetches linked entities when the received entity has a text property" do
expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(post.author, post.text) expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(post.text)
described_class.new(magic_env, recipient).receive described_class.new(magic_env, recipient).receive
end end
@ -128,7 +128,7 @@ module DiasporaFederation
profile = Fabricate(:profile_entity) profile = Fabricate(:profile_entity)
magic_env = Salmon::MagicEnvelope.new(profile, profile.author) magic_env = Salmon::MagicEnvelope.new(profile, profile.author)
expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(profile.author, profile.bio) expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(profile.bio)
described_class.new(magic_env, recipient).receive described_class.new(magic_env, recipient).receive
end end

View file

@ -141,7 +141,7 @@ module DiasporaFederation
end end
it "fetches linked entities when the received entity has a text property" do it "fetches linked entities when the received entity has a text property" do
expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(post.author, post.text) expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(post.text)
described_class.new(magic_env).receive described_class.new(magic_env).receive
end end
@ -150,7 +150,7 @@ module DiasporaFederation
profile = Fabricate(:profile_entity, public: true) profile = Fabricate(:profile_entity, public: true)
magic_env = Salmon::MagicEnvelope.new(profile, profile.author) magic_env = Salmon::MagicEnvelope.new(profile, profile.author)
expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(profile.author, profile.bio) expect(Federation::DiasporaUrlParser).to receive(:fetch_linked_entities).with(profile.bio)
described_class.new(magic_env).receive described_class.new(magic_env).receive
end end

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
end end
end end

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#person" do describe "#person" do

View file

@ -8,7 +8,6 @@ module DiasporaFederation
describe "##{prop}" do describe "##{prop}" do
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { prop } let(:property) { prop }
let(:mandatory) { true }
end end
end end
end end

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
it_behaves_like "a guid validator" do it_behaves_like "a guid validator" do

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
it_behaves_like "a guid validator" do it_behaves_like "a guid validator" do

View file

@ -5,7 +5,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#guid" do describe "#guid" do

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#guid" do describe "#guid" do

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
it_behaves_like "a guid validator" do it_behaves_like "a guid validator" do

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#guid" do describe "#guid" do

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { false }
end end
%i[first_name last_name].each do |prop| %i[first_name last_name].each do |prop|

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
%i[local public].each do |prop| %i[local public].each do |prop|

View file

@ -6,7 +6,6 @@ module DiasporaFederation
describe "#author" do describe "#author" do
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
end end
@ -23,9 +22,10 @@ module DiasporaFederation
end end
describe "#root_author" do describe "#root_author" do
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a property with a value validation/restriction" do
let(:property) { :root_author } let(:property) { :root_author }
let(:mandatory) { false } let(:wrong_values) { ["i am a weird diaspora* ID @@@ ### 12345"] }
let(:correct_values) { [nil, "alice@example.org"] }
end end
end end

View file

@ -9,7 +9,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#target_type" do describe "#target_type" do

View file

@ -83,13 +83,13 @@ describe Validation::Rule::DiasporaId do
expect(validator.errors).to include(:diaspora_id) expect(validator.errors).to include(:diaspora_id)
end end
it "allows nil and empty" do it "fails for nil and empty" do
[nil, ""].each do |val| [nil, ""].each do |val|
validator = Validation::Validator.new(OpenStruct.new(diaspora_id: val)) validator = Validation::Validator.new(OpenStruct.new(diaspora_id: val))
validator.rule(:diaspora_id, :diaspora_id) validator.rule(:diaspora_id, :diaspora_id)
expect(validator).to be_valid expect(validator).not_to be_valid
expect(validator.errors).to be_empty expect(validator.errors).to include(:diaspora_id)
end end
end end
end end

View file

@ -6,7 +6,6 @@ module DiasporaFederation
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
it_behaves_like "a guid validator" do it_behaves_like "a guid validator" do

View file

@ -20,7 +20,6 @@ end
shared_examples "a relayable validator" do shared_examples "a relayable validator" do
it_behaves_like "a diaspora* ID validator" do it_behaves_like "a diaspora* ID validator" do
let(:property) { :author } let(:property) { :author }
let(:mandatory) { true }
end end
describe "#guid" do describe "#guid" do
@ -74,16 +73,18 @@ shared_examples "a diaspora* ID validator" do
[nil, ""].each do |val| [nil, ""].each do |val|
validator = described_class.new(entity_stub(entity, property => val)) validator = described_class.new(entity_stub(entity, property => val))
if mandatory expect(validator).not_to be_valid
expect(validator).not_to be_valid expect(validator.errors).to include(property)
expect(validator.errors).to include(property)
else
expect(validator).to be_valid
expect(validator.errors).to be_empty
end
end end
end end
it "validates a well-formed diaspora* ID" do
validator = described_class.new(entity_stub(entity, property => "alice@example.org"))
expect(validator).to be_valid
expect(validator.errors).to be_empty
end
it "must be a valid diaspora* ID" do it "must be a valid diaspora* ID" do
validator = described_class.new(entity_stub(entity, property => "i am a weird diaspora* ID @@@ ### 12345")) validator = described_class.new(entity_stub(entity, property => "i am a weird diaspora* ID @@@ ### 12345"))