From e2fbf8bc7479967baa84ef26eb03e19f0fd868e8 Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Sat, 4 Feb 2017 14:46:23 -0800
Subject: [PATCH 1/7] Add an account endpoint for ActivityPub and link to it on
 HTML profile pages

---
 .../api/activitypub/accounts_controller.rb    | 20 +++++++++++++++++++
 app/views/accounts/show.html.haml             |  1 +
 app/views/api/activitypub/accounts/show.rabl  | 10 ++++++++++
 config/routes.rb                              |  6 ++++++
 4 files changed, 37 insertions(+)
 create mode 100644 app/controllers/api/activitypub/accounts_controller.rb
 create mode 100644 app/views/api/activitypub/accounts/show.rabl

diff --git a/app/controllers/api/activitypub/accounts_controller.rb b/app/controllers/api/activitypub/accounts_controller.rb
new file mode 100644
index 000000000..efb6413a0
--- /dev/null
+++ b/app/controllers/api/activitypub/accounts_controller.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class Api::Activitypub::AccountsController < ApiController
+  before_action -> { doorkeeper_authorize! :read }, except: [:show]
+  before_action :require_user!, except: [:show]
+  before_action :set_account, except: [:verify_credentials, :suggestions, :search]
+
+  respond_to :'application/activity+json'
+  respond_to :'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"'
+
+  def show
+    render content_type: :'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"'
+  end
+
+  private
+
+  def set_account
+    @account = Account.find(params[:id])
+  end
+end
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index c194ce33d..cd5398908 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -4,6 +4,7 @@
 - content_for :header_tags do
   %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
   %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
+  %link{ rel: 'alternate', type: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"', href: "http://mastodon.dev/api/v1/activitypub/accounts/#{@account.username}" }/
 
   %meta{ property: 'og:site_name', content: 'Mastodon' }/
   %meta{ property: 'og:type', content: 'profile' }/
diff --git a/app/views/api/activitypub/accounts/show.rabl b/app/views/api/activitypub/accounts/show.rabl
new file mode 100644
index 000000000..806789d00
--- /dev/null
+++ b/app/views/api/activitypub/accounts/show.rabl
@@ -0,0 +1,10 @@
+object @account
+
+node(:'@context')         { 'https://www.w3.org/ns/activitystreams' }
+node(:type)               { 'Person' }
+node(:id)                 { request.original_url }
+node(:url)                { |account| TagManager.instance.url_for(account) }
+node(:name)               { |account| account.display_name }
+node(:preferredUsername)  { |account| account.username }
+node(:summary)            { |account| account.note }
+node(:icon)               { |account| full_asset_url(account.avatar.url(:original)) }
diff --git a/config/routes.rb b/config/routes.rb
index 699f56833..f831c4239 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -153,6 +153,12 @@ Rails.application.routes.draw do
       end
     end
 
+    namespace :activitypub do
+      resources :accounts do
+        get '/:id', to: 'accounts#show'
+      end
+    end
+
     namespace :web do
       resource :settings, only: [:update]
     end

From 8bd8ea7c0406a8eeb145471475b105366e195e6a Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Sat, 4 Feb 2017 14:49:24 -0800
Subject: [PATCH 2/7] Remove unnecessary leftover code

---
 app/controllers/api/activitypub/accounts_controller.rb | 4 +---
 config/routes.rb                                       | 4 +---
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/app/controllers/api/activitypub/accounts_controller.rb b/app/controllers/api/activitypub/accounts_controller.rb
index efb6413a0..82936f062 100644
--- a/app/controllers/api/activitypub/accounts_controller.rb
+++ b/app/controllers/api/activitypub/accounts_controller.rb
@@ -1,9 +1,7 @@
 # frozen_string_literal: true
 
 class Api::Activitypub::AccountsController < ApiController
-  before_action -> { doorkeeper_authorize! :read }, except: [:show]
-  before_action :require_user!, except: [:show]
-  before_action :set_account, except: [:verify_credentials, :suggestions, :search]
+  before_action :set_account
 
   respond_to :'application/activity+json'
   respond_to :'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"'
diff --git a/config/routes.rb b/config/routes.rb
index f831c4239..4d0138b82 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -154,9 +154,7 @@ Rails.application.routes.draw do
     end
 
     namespace :activitypub do
-      resources :accounts do
-        get '/:id', to: 'accounts#show'
-      end
+      resources :accounts, only: [:show]
     end
 
     namespace :web do

From 94e213c6c11fb3476a6c151425052775427574e1 Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Mon, 6 Feb 2017 01:19:05 -0800
Subject: [PATCH 3/7] Reuse existing controller and route

---
 app/controllers/accounts_controller.rb         |  2 ++
 .../api/activitypub/accounts_controller.rb     | 18 ------------------
 app/views/accounts/show.html.haml              |  1 -
 .../{api/activitypub => }/accounts/show.rabl   |  5 ++---
 app/views/activitypub/base.rabl                |  1 +
 app/views/activitypub/intransient.rabl         |  3 +++
 app/views/activitypub/types/person.rabl        |  3 +++
 config/initializers/mime_types.rb              |  5 +++--
 config/routes.rb                               |  4 ----
 9 files changed, 14 insertions(+), 28 deletions(-)
 delete mode 100644 app/controllers/api/activitypub/accounts_controller.rb
 rename app/views/{api/activitypub => }/accounts/show.rabl (68%)
 create mode 100644 app/views/activitypub/base.rabl
 create mode 100644 app/views/activitypub/intransient.rabl
 create mode 100644 app/views/activitypub/types/person.rabl

diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 411a41ccc..b837f006e 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -18,6 +18,8 @@ class AccountsController < ApplicationController
       format.atom do
         @entries = @account.stream_entries.order('id desc').where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
       end
+
+      format.activitystreams2
     end
   end
 
diff --git a/app/controllers/api/activitypub/accounts_controller.rb b/app/controllers/api/activitypub/accounts_controller.rb
deleted file mode 100644
index 82936f062..000000000
--- a/app/controllers/api/activitypub/accounts_controller.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-class Api::Activitypub::AccountsController < ApiController
-  before_action :set_account
-
-  respond_to :'application/activity+json'
-  respond_to :'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"'
-
-  def show
-    render content_type: :'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"'
-  end
-
-  private
-
-  def set_account
-    @account = Account.find(params[:id])
-  end
-end
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index cd5398908..c194ce33d 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -4,7 +4,6 @@
 - content_for :header_tags do
   %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
   %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
-  %link{ rel: 'alternate', type: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams#"', href: "http://mastodon.dev/api/v1/activitypub/accounts/#{@account.username}" }/
 
   %meta{ property: 'og:site_name', content: 'Mastodon' }/
   %meta{ property: 'og:type', content: 'profile' }/
diff --git a/app/views/api/activitypub/accounts/show.rabl b/app/views/accounts/show.rabl
similarity index 68%
rename from app/views/api/activitypub/accounts/show.rabl
rename to app/views/accounts/show.rabl
index 806789d00..76aa4a809 100644
--- a/app/views/api/activitypub/accounts/show.rabl
+++ b/app/views/accounts/show.rabl
@@ -1,8 +1,7 @@
+extends 'activitypub/types/person.rabl'
+
 object @account
 
-node(:'@context')         { 'https://www.w3.org/ns/activitystreams' }
-node(:type)               { 'Person' }
-node(:id)                 { request.original_url }
 node(:url)                { |account| TagManager.instance.url_for(account) }
 node(:name)               { |account| account.display_name }
 node(:preferredUsername)  { |account| account.username }
diff --git a/app/views/activitypub/base.rabl b/app/views/activitypub/base.rabl
new file mode 100644
index 000000000..c5e94997a
--- /dev/null
+++ b/app/views/activitypub/base.rabl
@@ -0,0 +1 @@
+node(:'@context') { 'https://www.w3.org/ns/activitystreams' }
diff --git a/app/views/activitypub/intransient.rabl b/app/views/activitypub/intransient.rabl
new file mode 100644
index 000000000..21261f56d
--- /dev/null
+++ b/app/views/activitypub/intransient.rabl
@@ -0,0 +1,3 @@
+extends 'activitypub/base.rabl'
+
+node(:id) { request.original_url }
diff --git a/app/views/activitypub/types/person.rabl b/app/views/activitypub/types/person.rabl
new file mode 100644
index 000000000..17c53bb7b
--- /dev/null
+++ b/app/views/activitypub/types/person.rabl
@@ -0,0 +1,3 @@
+extends 'activitypub/intransient.rabl'
+
+node(:type) { 'Person' }
\ No newline at end of file
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index 5a16a14e8..b1b73c846 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -1,4 +1,5 @@
 # Be sure to restart your server when you modify this file.
 
-Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/jrd+json )
-Mime::Type.register "text/xml",         :xml,  %w( application/xml application/atom+xml application/xrd+xml )
+Mime::Type.register "application/json",           :json, %w( text/x-json application/jsonrequest application/jrd+json )
+Mime::Type.register "text/xml",                   :xml,  %w( application/xml application/atom+xml application/xrd+xml )
+Mime::Type.register "application/activity+json",  :activitystreams2
diff --git a/config/routes.rb b/config/routes.rb
index 4d0138b82..699f56833 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -153,10 +153,6 @@ Rails.application.routes.draw do
       end
     end
 
-    namespace :activitypub do
-      resources :accounts, only: [:show]
-    end
-
     namespace :web do
       resource :settings, only: [:update]
     end

From 3fa5d059977388066d71e475e484728f6019d04e Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Mon, 6 Feb 2017 11:39:08 -0800
Subject: [PATCH 4/7] Simplify RABL

---
 app/views/accounts/show.rabl | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/app/views/accounts/show.rabl b/app/views/accounts/show.rabl
index 76aa4a809..def91b425 100644
--- a/app/views/accounts/show.rabl
+++ b/app/views/accounts/show.rabl
@@ -2,8 +2,7 @@ extends 'activitypub/types/person.rabl'
 
 object @account
 
-node(:url)                { |account| TagManager.instance.url_for(account) }
-node(:name)               { |account| account.display_name }
-node(:preferredUsername)  { |account| account.username }
-node(:summary)            { |account| account.note }
-node(:icon)               { |account| full_asset_url(account.avatar.url(:original)) }
+attributes display_name: :name, username: :preferredUsername, note: :summary
+
+node(:icon)   { |account| full_asset_url(account.avatar.url(:original)) }
+node(:image)  { |account| full_asset_url(account.header.url(:original)) }

From da7f24c23827d9d4e8808367735f9ea6b050e6d8 Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Mon, 6 Feb 2017 12:14:02 -0800
Subject: [PATCH 5/7] Add test

---
 spec/controllers/accounts_controller_spec.rb | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index 34f17a943..d2c93c707 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -24,6 +24,16 @@ RSpec.describe AccountsController, type: :controller do
       end
     end
 
+    context 'activitystreams2' do
+      before do
+        get :show, params: { username: alice.username }, format: 'activitystreams2'
+      end
+
+      it 'returns http success with Activity Streams 2.0' do
+        expect(response).to have_http_status(:success)
+      end
+    end
+
     context 'html' do
       before do
         get :show, params: { username: alice.username }

From 53234e59479095968155bf7769e51614ef91c12d Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Mon, 6 Feb 2017 12:15:47 -0800
Subject: [PATCH 6/7] Add trailing newline

---
 app/views/activitypub/types/person.rabl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/activitypub/types/person.rabl b/app/views/activitypub/types/person.rabl
index 17c53bb7b..c284fc53b 100644
--- a/app/views/activitypub/types/person.rabl
+++ b/app/views/activitypub/types/person.rabl
@@ -1,3 +1,3 @@
 extends 'activitypub/intransient.rabl'
 
-node(:type) { 'Person' }
\ No newline at end of file
+node(:type) { 'Person' }

From 28cbb6dc2176cb9ba57841c6dc52b9dbfaf074c8 Mon Sep 17 00:00:00 2001
From: Evan Minto <evan.minto@gmail.com>
Date: Mon, 6 Feb 2017 17:00:55 -0800
Subject: [PATCH 7/7] Add AS2 format to RABL files

---
 app/views/accounts/{show.rabl => show.activitystreams2.rabl}   | 2 +-
 .../activitypub/{base.rabl => base.activitystreams2.rabl}      | 0
 app/views/activitypub/intransient.activitystreams2.rabl        | 3 +++
 app/views/activitypub/intransient.rabl                         | 3 ---
 app/views/activitypub/types/person.activitystreams2.rabl       | 3 +++
 app/views/activitypub/types/person.rabl                        | 3 ---
 6 files changed, 7 insertions(+), 7 deletions(-)
 rename app/views/accounts/{show.rabl => show.activitystreams2.rabl} (81%)
 rename app/views/activitypub/{base.rabl => base.activitystreams2.rabl} (100%)
 create mode 100644 app/views/activitypub/intransient.activitystreams2.rabl
 delete mode 100644 app/views/activitypub/intransient.rabl
 create mode 100644 app/views/activitypub/types/person.activitystreams2.rabl
 delete mode 100644 app/views/activitypub/types/person.rabl

diff --git a/app/views/accounts/show.rabl b/app/views/accounts/show.activitystreams2.rabl
similarity index 81%
rename from app/views/accounts/show.rabl
rename to app/views/accounts/show.activitystreams2.rabl
index def91b425..dabae3f29 100644
--- a/app/views/accounts/show.rabl
+++ b/app/views/accounts/show.activitystreams2.rabl
@@ -1,4 +1,4 @@
-extends 'activitypub/types/person.rabl'
+extends 'activitypub/types/person.activitystreams2.rabl'
 
 object @account
 
diff --git a/app/views/activitypub/base.rabl b/app/views/activitypub/base.activitystreams2.rabl
similarity index 100%
rename from app/views/activitypub/base.rabl
rename to app/views/activitypub/base.activitystreams2.rabl
diff --git a/app/views/activitypub/intransient.activitystreams2.rabl b/app/views/activitypub/intransient.activitystreams2.rabl
new file mode 100644
index 000000000..968e451c2
--- /dev/null
+++ b/app/views/activitypub/intransient.activitystreams2.rabl
@@ -0,0 +1,3 @@
+extends 'activitypub/base.activitystreams2.rabl'
+
+node(:id) { request.original_url }
diff --git a/app/views/activitypub/intransient.rabl b/app/views/activitypub/intransient.rabl
deleted file mode 100644
index 21261f56d..000000000
--- a/app/views/activitypub/intransient.rabl
+++ /dev/null
@@ -1,3 +0,0 @@
-extends 'activitypub/base.rabl'
-
-node(:id) { request.original_url }
diff --git a/app/views/activitypub/types/person.activitystreams2.rabl b/app/views/activitypub/types/person.activitystreams2.rabl
new file mode 100644
index 000000000..487a60791
--- /dev/null
+++ b/app/views/activitypub/types/person.activitystreams2.rabl
@@ -0,0 +1,3 @@
+extends 'activitypub/intransient.activitystreams2.rabl'
+
+node(:type) { 'Person' }
diff --git a/app/views/activitypub/types/person.rabl b/app/views/activitypub/types/person.rabl
deleted file mode 100644
index c284fc53b..000000000
--- a/app/views/activitypub/types/person.rabl
+++ /dev/null
@@ -1,3 +0,0 @@
-extends 'activitypub/intransient.rabl'
-
-node(:type) { 'Person' }