about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--README.rdoc28
-rw-r--r--app/helpers/atom_helper.rb98
-rw-r--r--app/services/process_feed_service.rb5
-rw-r--r--app/services/process_interaction_service.rb1
-rw-r--r--app/views/atom/entry.xml.ruby56
-rw-r--r--app/views/atom/user_stream.xml.ruby75
-rw-r--r--config/routes.rb6
8 files changed, 181 insertions, 101 deletions
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
-<tt>rake doc:app</tt>.
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
-
-    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
+  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
+
+    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/'