use person object with attributes to generate hcard

This commit is contained in:
Benjamin Neff 2015-07-02 02:03:32 +02:00
parent 6e6171fc93
commit 99d5ffdc04
7 changed files with 96 additions and 158 deletions

View file

@ -14,7 +14,7 @@ module DiasporaFederation
return render nothing: true, status: 404 if person.nil?
logger.info "hcard profile request for: #{person.diaspora_handle}"
render html: WebFinger::HCard.from_profile(person.hcard_profile_hash).to_html.html_safe
render html: WebFinger::HCard.from_person(person).to_html.html_safe
end
end
end

View file

@ -84,18 +84,11 @@ module DiasporaFederation
def validate_config
configuration_error "missing server_uri" unless @server_uri.respond_to? :host
validate_class(@person_class, "person_class", %i(
find_local_by_diaspora_handle
find_local_by_guid
diaspora_handle
alias_url
hcard_url
seed_url
profile_url
atom_url
salmon_url
guid
public_key
hcard_profile_hash
find_local_by_diaspora_handle find_local_by_guid
diaspora_handle nickname guid public_key searchable
alias_url hcard_url seed_url profile_url atom_url salmon_url
photo_large_url photo_medium_url photo_small_url
full_name first_name last_name
))
logger.info "successfully configured the federation engine"
end

View file

@ -10,8 +10,7 @@ module DiasporaFederation
#
# * if the +webfinger_url+ is missing or malformed in {HostMeta.from_base_url} or {HostMeta.from_xml}
# * if the parsed XML from {WebFinger.from_xml} is incomplete
# * if the params passed to {HCard.from_profile} or {HCard.from_html}
# are in some way malformed, invalid or incomplete.
# * if the html passed to {HCard.from_html} in some way is malformed, invalid or incomplete.
class InvalidData < RuntimeError
end
end

View file

@ -14,21 +14,21 @@ module DiasporaFederation
# correctly nested according to the hCard standard and class names are
# partially wrong. Also, apart from that, it's just ugly.
#
# @example Creating a hCard document from account data
# hc = HCard.from_profile({
# guid: "0123456789abcdef",
# nickname: "user",
# full_name: "User Name",
# url: "https://server.example/",
# photo_large_url: "https://server.example/uploads/l.jpg",
# photo_medium_url: "https://server.example/uploads/m.jpg",
# photo_small_url: "https://server.example/uploads/s.jpg",
# pubkey: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
# searchable: true,
# first_name: "User",
# last_name: "Name"
# })
# html_string = hc.to_html
# @example Creating a hCard document from a person object
# html_string = HCard.from_person(person).to_html
#
# The person object should have the following attributes (with examples)
# guid: "0123456789abcdef",
# nickname: "user",
# full_name: "User Name",
# seed_url: "https://server.example/",
# photo_large_url: "https://server.example/uploads/l.jpg",
# photo_medium_url: "https://server.example/uploads/m.jpg",
# photo_small_url: "https://server.example/uploads/s.jpg",
# public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
# searchable: true,
# first_name: "User",
# last_name: "Name"
#
# @example Create a HCard instance from an hCard document
# hc = HCard.from_html(html_string)
@ -68,7 +68,7 @@ module DiasporaFederation
# DER-encoded PKCS#1 key beginning with the text
# "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
# @return [String] public key
attr_reader :pubkey
attr_reader :public_key
# @return [String] url to the big avatar (300x300)
attr_reader :photo_large_url
@ -128,7 +128,7 @@ module DiasporaFederation
add_simple_property(content, :searchable, "searchable", @searchable)
add_property(content, :key) do |html|
html.pre(@pubkey.to_s, class: "key")
html.pre(@public_key.to_s, class: "key")
end
# TODO: remove me! ###################
@ -145,28 +145,28 @@ module DiasporaFederation
builder.doc.to_xhtml(indent: 2, indent_text: " ")
end
# Creates a new HCard instance from the given Hash containing profile data
# @param [Hash] data account data
# Creates a new HCard instance from the given person
# @param [Person] person the person object
# @return [HCard] HCard instance
# @raise [InvalidData] if the account data Hash is invalid or incomplete
def self.from_profile(data)
raise InvalidData unless account_data_complete?(data)
def self.from_person(person)
raise ArgumentError, "person is nil" if person.nil?
hc = allocate
hc.instance_eval {
@guid = data[:guid]
@nickname = data[:nickname]
@full_name = data[:full_name]
@url = data[:url]
@photo_large_url = data[:photo_large_url]
@photo_medium_url = data[:photo_medium_url]
@photo_small_url = data[:photo_small_url]
@pubkey = data[:pubkey]
@searchable = data[:searchable]
@guid = person.guid
@nickname = person.nickname
@full_name = person.full_name
@url = person.seed_url
@photo_large_url = person.photo_large_url
@photo_medium_url = person.photo_medium_url
@photo_small_url = person.photo_small_url
@public_key = person.public_key
@searchable = person.searchable
# TODO: remove me! ###################
@first_name = data[:first_name]
@last_name = data[:last_name]
@first_name = person.first_name
@last_name = person.last_name
#######################################
}
hc
@ -188,7 +188,7 @@ module DiasporaFederation
@photo_large_url = photo_from_doc(doc, :photo)
@photo_medium_url = photo_from_doc(doc, :photo_medium)
@photo_small_url = photo_from_doc(doc, :photo_small)
@pubkey = content_from_doc(doc, :key) unless element_from_doc(doc, :key).nil?
@public_key = content_from_doc(doc, :key) unless element_from_doc(doc, :key).nil?
@searchable = content_from_doc(doc, :searchable) == "true"
# TODO: change me! ###################
@ -271,19 +271,6 @@ module DiasporaFederation
end
end
# Checks the given account data Hash for correct type and completeness.
# @param [Hash] data account data
# @return [Boolean] validation result
def self.account_data_complete?(data)
data.instance_of?(Hash) &&
%i(
guid nickname full_name url
photo_large_url photo_medium_url photo_small_url
pubkey searchable first_name last_name
).all? {|k| data.key? k }
end
private_class_method :account_data_complete?
# Make sure some of the most important elements are present in the parsed
# HTML document.
# @param [LibXML::XML::Document] doc HTML document

View file

@ -25,7 +25,7 @@ module DiasporaFederation
end
it "calls WebFinger::HCard.from_profile" do
expect(WebFinger::HCard).to receive(:from_profile).with(alice.hcard_profile_hash).and_call_original
expect(WebFinger::HCard).to receive(:from_person).with(alice).and_call_original
get :hcard, "guid" => alice.guid
end
end

View file

@ -1,16 +1,6 @@
module DiasporaFederation
describe WebFinger::HCard do
let(:guid) { "abcdef0123456789" }
let(:nickname) { "user" }
let(:first_name) { "Test" }
let(:last_name) { "Testington" }
let(:name) { "#{first_name} #{last_name}" }
let(:url) { "https://pod.example.tld/users/me" }
let(:photo_url) { "https://pod.example.tld/uploads/f.jpg" }
let(:photo_url_m) { "https://pod.example.tld/uploads/m.jpg" }
let(:photo_url_s) { "https://pod.example.tld/uploads/s.jpg" }
let(:key) { "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----" }
let(:searchable) { true }
let(:person) { FactoryGirl.create(:person) }
let(:html) {
<<-HTML
@ -19,77 +9,77 @@ module DiasporaFederation
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="UTF-8" />
<title>#{name}</title>
<title>#{person.full_name}</title>
</head>
<body>
<div id="content">
<h1>#{name}</h1>
<h1>#{person.full_name}</h1>
<div id="content_inner" class="entity_profile vcard author">
<h2>User profile</h2>
<dl class="entity_uid">
<dt>Uid</dt>
<dd>
<span class="uid">#{guid}</span>
<span class="uid">#{person.guid}</span>
</dd>
</dl>
<dl class="entity_nickname">
<dt>Nickname</dt>
<dd>
<span class="nickname">#{nickname}</span>
<span class="nickname">#{person.nickname}</span>
</dd>
</dl>
<dl class="entity_full_name">
<dt>Full_name</dt>
<dd>
<span class="fn">#{name}</span>
<span class="fn">#{person.full_name}</span>
</dd>
</dl>
<dl class="entity_searchable">
<dt>Searchable</dt>
<dd>
<span class="searchable">#{searchable}</span>
<span class="searchable">#{person.searchable}</span>
</dd>
</dl>
<dl class="entity_key">
<dt>Key</dt>
<dd>
<pre class="key">#{key}</pre>
<pre class="key">#{person.public_key}</pre>
</dd>
</dl>
<dl class="entity_first_name">
<dt>First_name</dt>
<dd>
<span class="given_name">#{first_name}</span>
<span class="given_name">#{person.first_name}</span>
</dd>
</dl>
<dl class="entity_family_name">
<dt>Family_name</dt>
<dd>
<span class="family_name">#{last_name}</span>
<span class="family_name">#{person.last_name}</span>
</dd>
</dl>
<dl class="entity_url">
<dt>Url</dt>
<dd>
<a id="pod_location" class="url" rel="me" href="#{url}">#{url}</a>
<a id="pod_location" class="url" rel="me" href="#{person.seed_url}">#{person.seed_url}</a>
</dd>
</dl>
<dl class="entity_photo">
<dt>Photo</dt>
<dd>
<img class="photo avatar" width="300" height="300" src="#{photo_url}" />
<img class="photo avatar" width="300" height="300" src="#{person.photo_large_url}" />
</dd>
</dl>
<dl class="entity_photo_medium">
<dt>Photo_medium</dt>
<dd>
<img class="photo avatar" width="100" height="100" src="#{photo_url_m}" />
<img class="photo avatar" width="100" height="100" src="#{person.photo_medium_url}" />
</dd>
</dl>
<dl class="entity_photo_small">
<dt>Photo_small</dt>
<dd>
<img class="photo avatar" width="50" height="50" src="#{photo_url_s}" />
<img class="photo avatar" width="50" height="50" src="#{person.photo_small_url}" />
</dd>
</dl>
</div>
@ -105,60 +95,35 @@ HTML
context "generation" do
it "creates an instance from a data hash" do
hcard = WebFinger::HCard.from_profile(
guid: guid,
nickname: nickname,
full_name: name,
url: url,
photo_large_url: photo_url,
photo_medium_url: photo_url_m,
photo_small_url: photo_url_s,
pubkey: key,
searchable: searchable,
first_name: first_name,
last_name: last_name
)
hcard = WebFinger::HCard.from_person(person)
expect(hcard.to_html).to eq(html)
end
it "fails if some params are missing" do
expect {
WebFinger::HCard.from_profile(
guid: guid,
nickname: nickname
)
}.to raise_error WebFinger::InvalidData
end
it "fails if nothing was given" do
expect { WebFinger::HCard.from_profile({}) }.to raise_error WebFinger::InvalidData
end
it "fails if nil was given" do
expect { WebFinger::HCard.from_profile(nil) }.to raise_error WebFinger::InvalidData
expect { WebFinger::HCard.from_person(nil) }.to raise_error ArgumentError
end
end
context "parsing" do
it "reads its own output" do
hcard = WebFinger::HCard.from_html(html)
expect(hcard.guid).to eq(guid)
expect(hcard.nickname).to eq(nickname)
expect(hcard.full_name).to eq(name)
expect(hcard.url).to eq(url)
expect(hcard.photo_large_url).to eq(photo_url)
expect(hcard.photo_medium_url).to eq(photo_url_m)
expect(hcard.photo_small_url).to eq(photo_url_s)
expect(hcard.pubkey).to eq(key)
expect(hcard.searchable).to eq(searchable)
expect(hcard.guid).to eq(person.guid)
expect(hcard.nickname).to eq(person.nickname)
expect(hcard.full_name).to eq(person.full_name)
expect(hcard.url).to eq(person.seed_url)
expect(hcard.photo_large_url).to eq(person.photo_large_url)
expect(hcard.photo_medium_url).to eq(person.photo_medium_url)
expect(hcard.photo_small_url).to eq(person.photo_small_url)
expect(hcard.public_key).to eq(person.public_key)
expect(hcard.searchable).to eq(person.searchable)
expect(hcard.first_name).to eq(first_name)
expect(hcard.last_name).to eq(last_name)
expect(hcard.first_name).to eq(person.first_name)
expect(hcard.last_name).to eq(person.last_name)
end
it "searchable is false, if it is empty in html" do
changed_html = html.sub(
"class=\"searchable\">#{searchable}<",
"class=\"searchable\">#{person.searchable}<",
"class=\"searchable\"><"
)
@ -170,62 +135,62 @@ HTML
it "reads old-style HTML" do
historic_html = <<-HTML
<div id="content">
<h1>#{name}</h1>
<h1>#{person.full_name}</h1>
<div id="content_inner">
<div class="entity_profile vcard author" id="i">
<h2>User profile</h2>
<dl class="entity_nickname">
<dt>Nickname</dt>
<dd>
<a class="nickname url uid" href="#{url}" rel="me">#{name}</a>
<a class="nickname url uid" href="#{person.seed_url}" rel="me">#{person.full_name}</a>
</dd>
</dl>
<dl class="entity_given_name">
<dt>First name</dt>
<dd>
<span class="given_name">#{first_name}</span>
<span class="given_name">#{person.first_name}</span>
</dd>
</dl>
<dl class="entity_family_name">
<dt>Family name</dt>
<dd>
<span class="family_name">#{last_name}</span>
<span class="family_name">#{person.last_name}</span>
</dd>
</dl>
<dl class="entity_fn">
<dt>Full name</dt>
<dd>
<span class="fn">#{name}</span>
<span class="fn">#{person.full_name}</span>
</dd>
</dl>
<dl class="entity_url">
<dt>URL</dt>
<dd>
<a class="url" href="#{url}" id="pod_location" rel="me">#{url}</a>
<a class="url" href="#{person.seed_url}" id="pod_location" rel="me">#{person.seed_url}</a>
</dd>
</dl>
<dl class="entity_photo">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="300px" src="#{photo_url}" width="300px">
<img class="photo avatar" height="300px" src="#{person.photo_large_url}" width="300px">
</dd>
</dl>
<dl class="entity_photo_medium">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="100px" src="#{photo_url_m}" width="100px">
<img class="photo avatar" height="100px" src="#{person.photo_medium_url}" width="100px">
</dd>
</dl>
<dl class="entity_photo_small">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="50px" src="#{photo_url_s}" width="50px">
<img class="photo avatar" height="50px" src="#{person.photo_small_url}" width="50px">
</dd>
</dl>
<dl class="entity_searchable">
<dt>Searchable</dt>
<dd>
<span class="searchable">#{searchable}</span>
<span class="searchable">#{person.searchable}</span>
</dd>
</dl>
</div>
@ -234,20 +199,20 @@ HTML
HTML
hcard = WebFinger::HCard.from_html(historic_html)
expect(hcard.url).to eq(url)
expect(hcard.photo_large_url).to eq(photo_url)
expect(hcard.photo_medium_url).to eq(photo_url_m)
expect(hcard.photo_small_url).to eq(photo_url_s)
expect(hcard.searchable).to eq(searchable)
expect(hcard.url).to eq(person.seed_url)
expect(hcard.photo_large_url).to eq(person.photo_large_url)
expect(hcard.photo_medium_url).to eq(person.photo_medium_url)
expect(hcard.photo_small_url).to eq(person.photo_small_url)
expect(hcard.searchable).to eq(person.searchable)
expect(hcard.first_name).to eq(first_name)
expect(hcard.last_name).to eq(last_name)
expect(hcard.first_name).to eq(person.first_name)
expect(hcard.last_name).to eq(person.last_name)
end
it "fails if the document is incomplete" do
invalid_html = <<-HTML
<div id="content">
<span class="fn">#{name}</span>
<span class="fn">#{person.full_name}</span>
</div>
HTML
expect { WebFinger::HCard.from_html(invalid_html) }.to raise_error WebFinger::InvalidData

View file

@ -10,21 +10,15 @@ class Person < ActiveRecord::Base
alias_attribute :seed_url, :url
alias_attribute :public_key, :serialized_public_key
def hcard_profile_hash
{
guid: guid,
nickname: diaspora_handle.split("@")[0],
full_name: "Dummy User",
url: url,
photo_large_url: "#{url}assets/user/default.png",
photo_medium_url: "#{url}assets/user/default.png",
photo_small_url: "#{url}assets/user/default.png",
pubkey: serialized_public_key,
searchable: true,
first_name: "Dummy",
last_name: "User"
}
end
def nickname; diaspora_handle.split("@")[0] end
def photo_large_url; "#{url}assets/user/default.png" end
def photo_medium_url; "#{url}assets/user/default.png" end
def photo_small_url; "#{url}assets/user/default.png" end
def searchable; true end
def full_name; "Dummy User" end
def first_name; "Dummy" end
def last_name; "User" end
def self.find_local_by_diaspora_handle(identifier)
# no remote? and closed_account? check ... this class is only for testing