author.rb |
|
---|---|
The Author model represents someone who creates information that’s shared via a feed. It is decoupled from a User, since we can also have remote authors, from feeds that originate from outside of our site. |
class Author
include MongoMapper::Document |
Constants that are useful for avatars using gravatar |
GRAVATAR = "gravatar.com"
GRAVATAR_SIGNUP = "http://gravatar.com/site/signup"
ENCODED_DEFAULT_AVATAR = URI.encode_www_form_component(
RstatUs::DEFAULT_AVATAR
) |
public keys are good for 4 weeks |
PUBLIC_KEY_LEASE_DAYS = 28 |
We’ve got a bunch of data that gets stored in Author. And basically none of it is val*idated right now. Fun. Then again, not all of it is neccesary. |
key :username, String |
This contains the domain that the author’s feed originates. |
key :domain, String
validates_presence_of :domain |
Normalize the domain so we can use them the same way |
before_save :normalize_domain |
The Author has a profile and with that various entries |
key :name, String
key :email, String
key :website, String
key :bio, String
key :image_url, String |
Authors MIGHT have a salmon endpoint |
key :salmon_url, String |
Authors have a public key that they use to sign salmon responses. Leasing: To ensure that keys can only be compromised in a small window but not require the server to retrieve a key per update, we store a lease. When the lease expires, and a notification comes, we retrieve the key. |
key :public_key, String
key :public_key_lease, Date |
The url of their profile page |
key :remote_url, String |
For sorting by signup, Authors require timestamps |
timestamps! |
We cannot put a :unique tag above because of a MongoMapper bug |
validates_uniqueness_of :remote_url, :allow_nil => :true |
Associations |
|
As we said, an Author has a Feed that they’re the… author of. And if they’re local, they also have a User, too. |
one :feed
one :user |
This takes results from an omniauth reponse and generates an author |
def self.create_from_hash!(hash, domain) |
Omniauth user information, as a hash |
user = hash['info'] |
Grabs each of the important user details |
name = user['name']
username = user['username']
website = user['urls']['Website']
bio = user['description']
image = user['image']
remote = user['url'] |
Creates an Author object with the details |
create!(
name: name,
username: username,
website: website,
bio: bio,
image_url: image,
remote_url: remote,
domain: domain
)
end
def self.new_from_session!(session, params, domain)
new(
:name => session[:name],
:username => params[:username],
:website => session[:website],
:bio => session[:description],
:image => session[:image],
:domain => domain
)
end
def self.create_from_session!(session, params, domain)
create!(
:name => session[:name],
:username => params[:username],
:website => session[:website],
:bio => session[:description],
:image => session[:image],
:domain => domain
)
end |
Reset the public key lease, which will be called when the public key is retrieved from a trusted source. |
def reset_key_lease
public_key_lease = (DateTime.now + PUBLIC_KEY_LEASE_DAYS).to_date
end |
Retrieves a valid RSA::KeyPair for the Author’s public key |
def retrieve_public_key
Crypto.make_rsa_keypair(public_key, nil)
end
def check_public_key_lease
if public_key_lease.nil? or public_key_lease < DateTime.now |
Lease has expired, get the public key again |
|
Retrieve the user xrd |
remote_host = remote_url[/^.*?:\/\/(.*?)\//,1]
webfinger = "#{username}@#{remote_host}"
acct = Redfinger.finger(webfinger) |
Retrieve the public key |
public_key = acct.links.find { |l| l['rel'] == 'magic-public-key' }
public_key = public_key.href[/^.*?,(.*)$/,1]
self.public_key = public_key
reset_key_lease
unless new?
save!
end
end
end |
Returns a locally useful url for the Author |
def url
if remote_url.present?
remote_url
else
"/users/#{username}"
end
end |
Returns a locally useful url for the Author’s avatar |
|
We’ve got a couple of options here. If they have some sort of image from Twitter, we use that, and if they don’t, we go with Gravatar. If none of that is around, then we show the RstatUs::DEFAULT_AVATAR |
def avatar_url |
If the user has a twitter image, return it |
if image_url.present?
image_url |
If the user has an email, look for a gravatar url. |
elsif email.present?
gravatar_url |
Otherwise return the default avatar |
else
RstatUs::DEFAULT_AVATAR
end
end |
Determine the display name from the username or name |
def display_name |
If the user has a name, return it |
if name.present?
name |
Otherwise return the username |
else
username
end
end |
Return the gravatar url Query described here. |
def gravatar_url
email_digest = Digest::MD5.hexdigest email
"http://#{GRAVATAR}/avatar/#{email_digest}?s=48&r=r&d=#{ENCODED_DEFAULT_AVATAR}"
end |
Returns an OStatus::Author instance describing this author model |
def to_atom |
Determine global url for this author |
author_url = url
if author_url.start_with?("/")
author_url = "http://#{domain}/feeds/#{feed.id}"
end |
Set up PortableContacts |
poco = OStatus::PortableContacts.new(:id => author_url,
:preferred_username => username)
poco.display_name = display_name |
Set up and return Author |
avatar_url_abs = avatar_url
if avatar_url_abs.start_with?("/")
avatar_url_abs = "http://#{domain}#{avatar_url_abs}"
end
author = OStatus::Author.new(:name => username,
:uri => author_url,
:portable_contacts => poco,
:links => [Atom::Link.new(:rel => "avatar",
:type => "image/png",
:href => avatar_url_abs)])
author
end
def normalize_domain
norm = self.domain.gsub(/^.*:\/\//, "")
norm = norm.gsub(/^www./, "")
norm = norm.gsub(/\/.*$/, "")
norm = norm.gsub(/\?.*$/, "")
norm = norm.gsub(/#.*$/, "")
self.domain = norm
end
def to_param
username
end
def self.search(params = {})
if params[:search] && !params[:search].empty?
Author.where(:username => /#{params[:search]}/i)
else
[]
end
end
end |