refactor HCard to use the PropertiesDSL

This commit is contained in:
Benjamin Neff 2015-07-07 01:18:37 +02:00
parent 2c50d34370
commit 6ceddae27b
6 changed files with 134 additions and 125 deletions

View file

@ -7,12 +7,12 @@ module DiasporaFederation
#
# GET /hcard/users/:guid
def hcard
person = DiasporaFederation.person_class.find_local_by_guid(params[:guid])
person_hcard = DiasporaFederation.callbacks.trigger(:person_hcard_fetch, params[:guid])
return render nothing: true, status: 404 if person.nil?
return render nothing: true, status: 404 if person_hcard.nil?
logger.info "hcard profile request for: #{person.diaspora_handle}"
render html: WebFinger::HCard.from_person(person).to_html.html_safe
logger.info "hcard profile request for: #{person_hcard.nickname}:#{person_hcard.guid}"
render html: person_hcard.to_html.html_safe
end
end
end

View file

@ -13,21 +13,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 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",
# serialized_public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
# searchable: true,
# first_name: "User",
# last_name: "Name"
# @example Creating a hCard document from a person hash
# hc = HCard.new(
# 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",
# serialized_public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
# searchable: true,
# first_name: "User",
# last_name: "Name"
# )
# html_string = hc.to_html
#
# @example Create a HCard instance from an hCard document
# hc = HCard.from_html(html_string)
@ -39,65 +39,74 @@ module DiasporaFederation
# @see http://microformats.org/wiki/h-card "h-card" (draft)
# @see http://www.ietf.org/rfc/rfc2426.txt "vCard MIME Directory Profile" (obsolete)
# @see http://www.ietf.org/rfc/rfc6350.txt "vCard Format Specification"
class HCard
private_class_method :new
class HCard < Entity
# @!attribute [r] guid
# This is just the guid. When a user creates an account on a pod, the pod
# MUST assign them a guid - a random hexadecimal string of at least 8
# hexadecimal digits.
# @return [String] guid
property :guid
# This is just the guid. When a user creates an account on a pod, the pod
# MUST assign them a guid - a random hexadecimal string of at least 8
# hexadecimal digits.
# @return [String] guid
attr_reader :guid
# @!attribute [r] nickname
# the first part of the diaspora handle
# @return [String] nickname
property :nickname
# the first part of the diaspora handle
# @return [String] nickname
attr_reader :nickname
# @!attribute [r] full_name
# @return [String] display name of the user
property :full_name
# @return [String] display name of the user
attr_reader :full_name
# @deprecated should be changed to the profile url. The pod url is in
# the WebFinger (see {WebFinger#seed_url}, will affect older Diaspora*
# installations).
# @!attribute [r] url
# @deprecated should be changed to the profile url. The pod url is in
# the WebFinger (see {WebFinger#seed_url}, will affect older Diaspora*
# installations).
#
# @return [String] link to the pod
attr_reader :url
# @return [String] link to the pod
property :url
# When a user is created on the pod, the pod MUST generate a pgp keypair
# for them. This key is used for signing messages. The format is a
# DER-encoded PKCS#1 key beginning with the text
# "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
# @return [String] public key
attr_reader :public_key
# @!attribute [r] public_key
# When a user is created on the pod, the pod MUST generate a pgp keypair
# for them. This key is used for signing messages. The format is a
# DER-encoded PKCS#1 key beginning with the text
# "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
# @return [String] public key
property :public_key
# @return [String] url to the big avatar (300x300)
attr_reader :photo_large_url
# @return [String] url to the medium avatar (100x100)
attr_reader :photo_medium_url
# @return [String] url to the small avatar (50x50)
attr_reader :photo_small_url
# @!attribute [r] photo_large_url
# @return [String] url to the big avatar (300x300)
property :photo_large_url
# @!attribute [r] photo_medium_url
# @return [String] url to the medium avatar (100x100)
property :photo_medium_url
# @!attribute [r] photo_small_url
# @return [String] url to the small avatar (50x50)
property :photo_small_url
# @deprecated We decided to only use one name field, these should be removed
# in later iterations (will affect older Diaspora* installations).
# @!attribute [r] first_name
# @deprecated We decided to only use one name field, these should be removed
# in later iterations (will affect older Diaspora* installations).
#
# @see #full_name
# @return [String] first name
attr_reader :first_name
# @see #full_name
# @return [String] first name
property :first_name
# @deprecated We decided to only use one name field, these should be removed
# in later iterations (will affect older Diaspora* installations).
# @!attribute [r] last_name
# @deprecated We decided to only use one name field, these should be removed
# in later iterations (will affect older Diaspora* installations).
#
# @see #full_name
# @return [String] last name
attr_reader :last_name
# @see #full_name
# @return [String] last name
property :last_name
# @deprecated As this is a simple property, consider move to WebFinger instead
# of HCard. vCard has no comparable field for this information, but
# Webfinger may declare arbitrary properties (will affect older Diaspora*
# installations).
# @!attribute [r] searchable
# @deprecated As this is a simple property, consider move to WebFinger instead
# of HCard. vCard has no comparable field for this information, but
# Webfinger may declare arbitrary properties (will affect older Diaspora*
# installations).
#
# flag if a user is searchable by name
# @return [Boolean] searchable flag
attr_reader :searchable
# flag if a user is searchable by name
# @return [Boolean] searchable flag
property :searchable
# CSS selectors for finding all the hCard fields
SELECTORS = {
@ -144,33 +153,6 @@ module DiasporaFederation
builder.doc.to_xhtml(indent: 2, indent_text: " ")
end
# 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_person(person)
raise ArgumentError, "person is nil" if person.nil?
hc = allocate
hc.instance_eval {
@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.serialized_public_key
@searchable = person.searchable
# TODO: remove me! ###################
@first_name = person.first_name
@last_name = person.last_name
#######################################
}
hc
end
# Creates a new HCard instance from the given HTML string.
# @param html_string [String] HTML string
# @return [HCard] HCard instance

View file

@ -24,8 +24,10 @@ module DiasporaFederation
expect(response).to be_not_found
end
it "calls WebFinger::HCard.from_profile" do
expect(WebFinger::HCard).to receive(:from_person).with(alice).and_call_original
it "calls the person_hcard_fetch callback" do
expect(DiasporaFederation.callbacks).to receive(:trigger)
.with(:person_hcard_fetch, alice.guid)
.and_call_original
get :hcard, "guid" => alice.guid
end
end

View file

@ -1,6 +1,9 @@
module DiasporaFederation
describe WebFinger::HCard do
let(:person) { FactoryGirl.create(:person) }
let(:photo_large_url) { "#{person.url}/upload/large.png" }
let(:photo_medium_url) { "#{person.url}/upload/medium.png" }
let(:photo_small_url) { "#{person.url}/upload/small.png" }
let(:html) {
<<-HTML
@ -61,25 +64,25 @@ module DiasporaFederation
<dl class="entity_url">
<dt>Url</dt>
<dd>
<a id="pod_location" class="url" rel="me" href="#{person.seed_url}">#{person.seed_url}</a>
<a id="pod_location" class="url" rel="me" href="#{person.url}">#{person.url}</a>
</dd>
</dl>
<dl class="entity_photo">
<dt>Photo</dt>
<dd>
<img class="photo avatar" width="300" height="300" src="#{person.photo_large_url}" />
<img class="photo avatar" width="300" height="300" src="#{photo_large_url}" />
</dd>
</dl>
<dl class="entity_photo_medium">
<dt>Photo_medium</dt>
<dd>
<img class="photo avatar" width="100" height="100" src="#{person.photo_medium_url}" />
<img class="photo avatar" width="100" height="100" src="#{photo_medium_url}" />
</dd>
</dl>
<dl class="entity_photo_small">
<dt>Photo_small</dt>
<dd>
<img class="photo avatar" width="50" height="50" src="#{person.photo_small_url}" />
<img class="photo avatar" width="50" height="50" src="#{photo_small_url}" />
</dd>
</dl>
</div>
@ -90,17 +93,29 @@ HTML
}
it "must not create blank instances" do
expect { WebFinger::HCard.new }.to raise_error NameError
expect { WebFinger::HCard.new({}) }.to raise_error ArgumentError
end
context "generation" do
it "creates an instance from a data hash" do
hcard = WebFinger::HCard.from_person(person)
hcard = WebFinger::HCard.new(
guid: person.guid,
nickname: person.nickname,
full_name: person.full_name,
url: person.url,
photo_large_url: photo_large_url,
photo_medium_url: photo_medium_url,
photo_small_url: photo_small_url,
public_key: person.serialized_public_key,
searchable: person.searchable,
first_name: person.first_name,
last_name: person.last_name
)
expect(hcard.to_html).to eq(html)
end
it "fails if nil was given" do
expect { WebFinger::HCard.from_person(nil) }.to raise_error ArgumentError
expect { WebFinger::HCard.new(nil) }.to raise_error ArgumentError, "expected a Hash"
end
end
@ -110,10 +125,10 @@ HTML
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.url).to eq(person.url)
expect(hcard.photo_large_url).to eq(photo_large_url)
expect(hcard.photo_medium_url).to eq(photo_medium_url)
expect(hcard.photo_small_url).to eq(photo_small_url)
expect(hcard.public_key).to eq(person.serialized_public_key)
expect(hcard.searchable).to eq(person.searchable)
@ -142,7 +157,7 @@ HTML
<dl class="entity_nickname">
<dt>Nickname</dt>
<dd>
<a class="nickname url uid" href="#{person.seed_url}" rel="me">#{person.full_name}</a>
<a class="nickname url uid" href="#{person.url}" rel="me">#{person.full_name}</a>
</dd>
</dl>
<dl class="entity_given_name">
@ -166,25 +181,25 @@ HTML
<dl class="entity_url">
<dt>URL</dt>
<dd>
<a class="url" href="#{person.seed_url}" id="pod_location" rel="me">#{person.seed_url}</a>
<a class="url" href="#{person.url}" id="pod_location" rel="me">#{person.url}</a>
</dd>
</dl>
<dl class="entity_photo">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="300px" src="#{person.photo_large_url}" width="300px">
<img class="photo avatar" height="300px" src="#{photo_large_url}" width="300px">
</dd>
</dl>
<dl class="entity_photo_medium">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="100px" src="#{person.photo_medium_url}" width="100px">
<img class="photo avatar" height="100px" src="#{photo_medium_url}" width="100px">
</dd>
</dl>
<dl class="entity_photo_small">
<dt>Photo</dt>
<dd>
<img class="photo avatar" height="50px" src="#{person.photo_small_url}" width="50px">
<img class="photo avatar" height="50px" src="#{photo_small_url}" width="50px">
</dd>
</dl>
<dl class="entity_searchable">
@ -199,10 +214,10 @@ HTML
HTML
hcard = WebFinger::HCard.from_html(historic_html)
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.url).to eq(person.url)
expect(hcard.photo_large_url).to eq(photo_large_url)
expect(hcard.photo_medium_url).to eq(photo_medium_url)
expect(hcard.photo_small_url).to eq(photo_small_url)
expect(hcard.searchable).to eq(person.searchable)
expect(hcard.first_name).to eq(person.first_name)

View file

@ -3,22 +3,16 @@ class Person < ActiveRecord::Base
def alias_url; "#{url}people/#{guid}" end
def hcard_url; "#{url}hcard/users/#{guid}" end
def profile_url; "#{url}u/#{diaspora_handle.split('@')[0]}" end
def atom_url; "#{url}public/#{diaspora_handle.split('@')[0]}.atom" end
def profile_url; "#{url}u/#{nickname}" end
def atom_url; "#{url}public/#{nickname}.atom" end
def salmon_url; "#{url}receive/users/#{guid}" 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 photo_default_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_guid(guid)
# no remote? and closed_account? check ... this class is only for testing
find_by_guid(guid)
end
end

View file

@ -24,6 +24,22 @@ DiasporaFederation.configure do |config|
end
on :person_hcard_fetch do |guid|
person = Person.find_by(guid: guid)
if person
DiasporaFederation::WebFinger::HCard.new(
guid: person.guid,
nickname: person.nickname,
full_name: person.full_name,
url: person.url,
photo_large_url: person.photo_default_url,
photo_medium_url: person.photo_default_url,
photo_small_url: person.photo_default_url,
public_key: person.serialized_public_key,
searchable: person.searchable,
first_name: person.first_name,
last_name: person.last_name
)
end
end
end
end