From 3b0bc18db928c455186273d9b9aa5b96d91e035e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 23 Feb 2016 13:08:01 +0100 Subject: [PATCH] Improved Atom rendering templates, added README --- README.md | 13 +++ README.rdoc | 28 ------ app/helpers/atom_helper.rb | 98 ++++++++++++++++++++- app/services/process_feed_service.rb | 5 +- app/services/process_interaction_service.rb | 1 + app/views/atom/entry.xml.ruby | 56 ++++++------ app/views/atom/user_stream.xml.ruby | 73 ++++++++------- config/routes.rb | 6 +- 8 files changed, 180 insertions(+), 100 deletions(-) create mode 100644 README.md delete mode 100644 README.rdoc diff --git a/README.md b/README.md new file mode 100644 index 000000000..ce820af34 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +Mastodon +======== + +Mastodon is a federated microblogging engine. An alternative implementation of the GNU Social project. Based on ActivityStreams, Webfinger, PubsubHubbub and Salmon. + +The core ideals of this project are: + +- Independence of legacy Twitter APIs - we don't want to be compatible with Twitter clients, we want our own clients +- In that vein, a strong and clean REST API and OAuth2 +- Minimalism. Just because you can do almost anything with ActivityStreams doesn't mean you should. Limit the set of possible functions to what makes sense in a microblogging engine. This will make federation as well as UI design a lot easier +- Ease of deployment. The end-goal of this project is to be distributable as a Docker image. + +**Current status of the project is early development. Documentation, licensing information &co will be added later** diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index dd4e97e22..000000000 --- a/README.rdoc +++ /dev/null @@ -1,28 +0,0 @@ -== README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... - - -Please feel free to use a different markup language if you do not plan to run -rake doc:app. diff --git a/app/helpers/atom_helper.rb b/app/helpers/atom_helper.rb index a42a49946..7c8f5ed1a 100644 --- a/app/helpers/atom_helper.rb +++ b/app/helpers/atom_helper.rb @@ -1,5 +1,101 @@ module AtomHelper def stream_updated_at - @account.stream_entries.last ? @account.stream_entries.last.created_at.iso8601 : @account.updated_at.iso8601 + @account.stream_entries.last ? @account.stream_entries.last.created_at : @account.updated_at + end + + def entry(xml, is_root, &block) + if is_root + root_tag(xml, :entry, &block) + else + xml.entry &block + end + end + + def feed(xml, &block) + root_tag(xml, :feed, &block) + end + + def unique_id(xml, date, id, type) + xml.id_ unique_tag(date, id, type) + end + + def simple_id(xml, id) + xml.id_ id + end + + def published_at(xml, date) + xml.published date.iso8601 + end + + def updated_at(xml, date) + xml.updated date.iso8601 + end + + def verb(xml, verb) + xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{verb}") + end + + def content(xml, content) + xml.content({ type: 'html' }, content) + end + + def title(xml, title) + xml.title title + end + + def author(xml, &block) + xml.author &block + end + + def target(xml, &block) + xml['activity'].object &block + end + + def object_type(xml, type) + xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{type}") + end + + def uri(xml, uri) + xml.uri uri + end + + def name(xml, name) + xml.name name + end + + def summary(xml, summary) + xml.summary summary + end + + def subtitle(xml, subtitle) + xml.subtitle subtitle + end + + def link_alternate(xml, url) + xml.link(rel: 'alternate', type: 'text/html', href: url) + end + + def link_self(xml, url) + xml.link(rel: 'self', type: 'application/atom+xml', href: url) + end + + def link_hub(xml, url) + xml.link(rel: 'hub', href: url) + end + + def link_salmon(xml, url) + xml.link(rel: 'salmon', href: url) + end + + def portable_contact(xml, account) + xml['poco'].preferredUsername account.username + xml['poco'].displayName account.display_name + xml['poco'].note account.note + end + + private + + def root_tag(xml, tag, &block) + xml.send(tag, {xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0'}, &block) end end diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb index f2523a313..f77415a30 100644 --- a/app/services/process_feed_service.rb +++ b/app/services/process_feed_service.rb @@ -6,7 +6,7 @@ class ProcessFeedService uri = entry.at_xpath('./xmlns:id').content status = Status.find_by(uri: uri) - next unless status.nil? + next if !status.nil? status = Status.new status.account = account @@ -15,6 +15,9 @@ class ProcessFeedService status.created_at = entry.at_xpath('./xmlns:published').content status.updated_at = entry.at_xpath('./xmlns:updated').content status.save! + + # todo: not everything is a status. there are follows, favourites + # todo: RTs end end end diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index e95a488d1..6f9b7cf73 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -29,6 +29,7 @@ class ProcessInteractionService private def involves_target_account(target_account) + # todo end def salmon diff --git a/app/views/atom/entry.xml.ruby b/app/views/atom/entry.xml.ruby index b66a720b3..2a26e624a 100644 --- a/app/views/atom/entry.xml.ruby +++ b/app/views/atom/entry.xml.ruby @@ -1,39 +1,37 @@ Nokogiri::XML::Builder.new do |xml| - xml.entry(xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0') do - xml.id_ unique_tag(@entry.created_at, @entry.activity_id, @entry.activity_type) + entry(xml, true) do + unique_id xml, @entry.created_at, @entry.activity_id, @entry.activity_type + published_at xml, @entry.activity.created_at + updated_at xml, @entry.activity.updated_at + title xml, @entry.title + content xml, @entry.content + verb xml, @entry.verb - xml.published @entry.activity.created_at.iso8601 - xml.updated @entry.activity.updated_at.iso8601 - - xml.title @entry.title - xml.content({ type: 'html' }, @entry.content) - xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{@entry.verb}") - - xml.author do - xml['activity'].send('object-type', 'http://activitystrea.ms/schema/1.0/person') - xml.uri profile_url(name: @entry.account.username) - xml.name @entry.account.username - xml.summary @entry.account.note - - xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @entry.account.username)) - - xml['poco'].preferredUsername @entry.account.username - xml['poco'].displayName @entry.account.display_name - xml['poco'].note @entry.account.note + author(xml) do + object_type xml, :person + uri xml, profile_url(name: @entry.account.username) + name xml, @entry.account.username + summary xml, @entry.account.note + link_alternate xml, profile_url(name: @entry.account.username) + portable_contact xml, @entry.account end if @entry.targeted? - xml['activity'].send('object') do - xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{@entry.target.object_type}") - xml.id_ @entry.target.uri - xml.title @entry.target.title - xml.summary @entry.target.summary - xml.link(rel: 'alternate', type: 'text/html', href: @entry.target.uri) + target(xml) do + object_type xml, @entry.target.object_type + simple_id xml, @entry.target.uri + title xml, @entry.target.title + summary xml, @entry.target.summary + link_alternate xml, @entry.target.uri + + if @entry.target.object_type == :person + portable_contact xml, @entry.target + end end else - xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{@entry.object_type}") + object_type xml, @entry.object_type end - xml.link(rel: 'self', type: 'application/atom+xml', href: atom_entry_url(id: @entry.id)) + link_self xml, atom_entry_url(id: @entry.id) end -end.to_xml +end diff --git a/app/views/atom/user_stream.xml.ruby b/app/views/atom/user_stream.xml.ruby index 398464a9c..2b0c0aaa0 100644 --- a/app/views/atom/user_stream.xml.ruby +++ b/app/views/atom/user_stream.xml.ruby @@ -1,52 +1,49 @@ Nokogiri::XML::Builder.new do |xml| - xml.feed(xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0') do - xml.id_ atom_user_stream_url(id: @account.id) - xml.title @account.display_name - xml.subtitle @account.note - xml.updated stream_updated_at + feed(xml) do + simple_id xml, atom_user_stream_url(id: @account.id) + title xml, @account.display_name + subtitle xml, @account.note + updated_at xml, stream_updated_at - xml.author do - xml['activity'].send('object-type', 'http://activitystrea.ms/schema/1.0/person') - xml.uri profile_url(name: @account.username) - xml.name @account.username - xml.summary @account.note - - xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username)) - - xml['poco'].preferredUsername @account.username - xml['poco'].displayName @account.display_name - xml['poco'].note @account.note + author(xml) do + object_type xml, :person + uri xml, profile_url(name: @account.username) + name xml, @account.username + summary xml, @account.note + link_alternate xml, profile_url(name: @account.username) + portable_contact xml, @account end - xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username)) - xml.link(rel: 'hub', href: HUB_URL) - xml.link(rel: 'salmon', href: salmon_url(@account)) - xml.link(rel: 'self', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id)) + link_alternate xml, profile_url(name: @account.username) + link_self xml, atom_user_stream_url(id: @account.id) + link_hub xml, HUB_URL + link_salmon xml, salmon_url(@account) @account.stream_entries.order('id desc').each do |stream_entry| - xml.entry do - xml.id_ unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type) - - xml.published stream_entry.activity.created_at.iso8601 - xml.updated stream_entry.activity.updated_at.iso8601 - - xml.title stream_entry.title - xml.content({ type: 'html' }, stream_entry.content) - xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{stream_entry.verb}") + entry(xml, false) do + unique_id xml, stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type + published_at xml, stream_entry.activity.created_at + updated_at xml, stream_entry.activity.updated_at + title xml, stream_entry.title + content xml, stream_entry.content + verb xml, stream_entry.verb + link_self xml, atom_entry_url(id: stream_entry.id) if stream_entry.targeted? - xml['activity'].send('object') do - xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.target.object_type}") - xml.id_ stream_entry.target.uri - xml.title stream_entry.target.title - xml.summary stream_entry.target.summary - xml.link(rel: 'alternate', type: 'text/html', href: stream_entry.target.uri) + target(xml) do + object_type xml, stream_entry.target.object_type + simple_id xml, stream_entry.target.uri + title xml, stream_entry.target.title + summary xml, stream_entry.target.summary + link_alternate xml, stream_entry.target.uri + + if stream_entry.target.object_type == :person + portable_contact xml, stream_entry.target + end end else - xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}") + object_type xml, stream_entry.object_type end - - xml.link(rel: 'self', type: 'application/atom+xml', href: atom_entry_url(id: stream_entry.id)) end end end diff --git a/config/routes.rb b/config/routes.rb index 16f602e4e..c57baea28 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,9 +2,9 @@ Rails.application.routes.draw do get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger - get 'atom/entry/:id', to: 'atom#entry', as: :atom_entry - get 'atom/user/:id', to: 'atom#user_stream', as: :atom_user_stream - get 'user/:name', to: 'profile#show', as: :profile + get 'atom/entries/:id', to: 'atom#entry', as: :atom_entry + get 'atom/users/:id', to: 'atom#user_stream', as: :atom_user_stream + get 'users/:name', to: 'profile#show', as: :profile mount Mastodon::API => '/api/'