Refactoring Grape API methods into normal controllers & other things
This commit is contained in:
		
							parent
							
								
									11ff92c9d7
								
							
						
					
					
						commit
						0e8f59c16f
					
				
							
								
								
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							| @ -22,6 +22,7 @@ gem 'grape-entity' | |||||||
| gem 'hashie-forbidden_attributes' | gem 'hashie-forbidden_attributes' | ||||||
| gem 'paranoia', '~> 2.0' | gem 'paranoia', '~> 2.0' | ||||||
| gem 'paperclip', '~> 4.3' | gem 'paperclip', '~> 4.3' | ||||||
|  | gem 'backport_new_renderer' | ||||||
| 
 | 
 | ||||||
| gem 'http' | gem 'http' | ||||||
| gem 'addressable' | gem 'addressable' | ||||||
|  | |||||||
| @ -43,6 +43,8 @@ GEM | |||||||
|       descendants_tracker (~> 0.0.4) |       descendants_tracker (~> 0.0.4) | ||||||
|       ice_nine (~> 0.11.0) |       ice_nine (~> 0.11.0) | ||||||
|       thread_safe (~> 0.3, >= 0.3.1) |       thread_safe (~> 0.3, >= 0.3.1) | ||||||
|  |     backport_new_renderer (1.0.0) | ||||||
|  |       rails | ||||||
|     better_errors (2.1.1) |     better_errors (2.1.1) | ||||||
|       coderay (>= 1.0.0) |       coderay (>= 1.0.0) | ||||||
|       erubis (>= 2.6.6) |       erubis (>= 2.6.6) | ||||||
| @ -320,6 +322,7 @@ PLATFORMS | |||||||
| 
 | 
 | ||||||
| DEPENDENCIES | DEPENDENCIES | ||||||
|   addressable |   addressable | ||||||
|  |   backport_new_renderer | ||||||
|   better_errors |   better_errors | ||||||
|   binding_of_caller |   binding_of_caller | ||||||
|   coffee-rails (~> 4.1.0) |   coffee-rails (~> 4.1.0) | ||||||
|  | |||||||
| @ -1,8 +0,0 @@ | |||||||
| module Mastodon |  | ||||||
|   class API < Grape::API |  | ||||||
|     rescue_from :all |  | ||||||
| 
 |  | ||||||
|     mount Mastodon::Ostatus |  | ||||||
|     mount Mastodon::Rest |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -1,54 +0,0 @@ | |||||||
| module Mastodon |  | ||||||
|   module Entities |  | ||||||
|     class Account < Grape::Entity |  | ||||||
|       include ApplicationHelper |  | ||||||
| 
 |  | ||||||
|       expose :id |  | ||||||
|       expose :username |  | ||||||
| 
 |  | ||||||
|       expose :domain do |account| |  | ||||||
|         account.local? ? LOCAL_DOMAIN : account.domain |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       expose :display_name |  | ||||||
|       expose :note |  | ||||||
| 
 |  | ||||||
|       expose :url do |account| |  | ||||||
|         account.local? ? profile_url(name: account.username) : account.url |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     class Status < Grape::Entity |  | ||||||
|       include ApplicationHelper |  | ||||||
| 
 |  | ||||||
|       format_with(:iso_timestamp) { |dt| dt.iso8601 } |  | ||||||
| 
 |  | ||||||
|       expose :id |  | ||||||
| 
 |  | ||||||
|       expose :uri do |status| |  | ||||||
|         status.local? ? unique_tag(status.stream_entry.created_at, status.stream_entry.activity_id, status.stream_entry.activity_type) : status.uri |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       expose :url do |status| |  | ||||||
|         status.local? ? status_url(name: status.account.username, id: status.id) : status.url |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       expose :text |  | ||||||
|       expose :in_reply_to_id |  | ||||||
| 
 |  | ||||||
|       expose :reblog_of_id |  | ||||||
|       expose :reblog, using: Mastodon::Entities::Status |  | ||||||
| 
 |  | ||||||
|       expose :account, using: Mastodon::Entities::Account |  | ||||||
| 
 |  | ||||||
|       with_options(format_with: :iso_timestamp) do |  | ||||||
|         expose :created_at |  | ||||||
|         expose :updated_at |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     class StreamEntry < Grape::Entity |  | ||||||
|       expose :activity, using: Mastodon::Entities::Status |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -1,62 +0,0 @@ | |||||||
| module Mastodon |  | ||||||
|   class Ostatus < Grape::API |  | ||||||
|     format :txt |  | ||||||
| 
 |  | ||||||
|     before do |  | ||||||
|       @account = Account.find(params[:id]) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     resource :subscriptions do |  | ||||||
|       helpers do |  | ||||||
|         include ApplicationHelper |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       desc 'Receive updates from an account' |  | ||||||
| 
 |  | ||||||
|       params do |  | ||||||
|         requires :id, type: String, desc: 'Account ID' |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       post ':id' do |  | ||||||
|         body = request.body.read |  | ||||||
| 
 |  | ||||||
|         if @account.subscription(subscription_url(@account)).verify(body, env['HTTP_X_HUB_SIGNATURE']) |  | ||||||
|           ProcessFeedService.new.(body, @account) |  | ||||||
|           status 201 |  | ||||||
|         else |  | ||||||
|           status 202 |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       desc 'Confirm PuSH subscription to an account' |  | ||||||
| 
 |  | ||||||
|       params do |  | ||||||
|         requires :id, type: String, desc: 'Account ID' |  | ||||||
|         requires 'hub.topic', type: String, desc: 'Topic URL' |  | ||||||
|         requires 'hub.verify_token', type: String, desc: 'Verification token' |  | ||||||
|         requires 'hub.challenge', type: String, desc: 'Hub challenge' |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       get ':id' do |  | ||||||
|         if @account.subscription(subscription_url(@account)).valid?(params['hub.topic'], params['hub.verify_token']) |  | ||||||
|           params['hub.challenge'] |  | ||||||
|         else |  | ||||||
|           error! :not_found, 404 |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     resource :salmon do |  | ||||||
|       desc 'Receive Salmon updates targeted to account' |  | ||||||
| 
 |  | ||||||
|       params do |  | ||||||
|         requires :id, type: String, desc: 'Account ID' |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       post ':id' do |  | ||||||
|         ProcessInteractionService.new.(request.body.read, @account) |  | ||||||
|         status 201 |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| module Mastodon |  | ||||||
|   class Rest < Grape::API |  | ||||||
|     version 'v1', using: :path |  | ||||||
|     format :json |  | ||||||
| 
 |  | ||||||
|     helpers do |  | ||||||
|       def current_user |  | ||||||
|         User.first |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     resource :timelines do |  | ||||||
|       desc 'Return a public timeline' |  | ||||||
| 
 |  | ||||||
|       get :public do |  | ||||||
|         # todo |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       desc 'Return the home timeline of a logged in user' |  | ||||||
| 
 |  | ||||||
|       get :home do |  | ||||||
|         present current_user.timeline, with: Mastodon::Entities::StreamEntry |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       desc 'Return the notifications timeline of a logged in user' |  | ||||||
| 
 |  | ||||||
|       get :notifications do |  | ||||||
|         # todo |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     resource :accounts do |  | ||||||
|       desc 'Return a user profile' |  | ||||||
| 
 |  | ||||||
|       params do |  | ||||||
|         requires :id, type: String, desc: 'Account ID' |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       get ':id' do |  | ||||||
|         present Account.find(params[:id]), with: Mastodon::Entities::Account |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Place all the behaviors and hooks related to the matching controller here. |  | ||||||
| # All this logic will automatically be available in application.js. |  | ||||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Place all the behaviors and hooks related to the matching controller here. |  | ||||||
| # All this logic will automatically be available in application.js. |  | ||||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Place all the behaviors and hooks related to the matching controller here. |  | ||||||
| # All this logic will automatically be available in application.js. |  | ||||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Place all the behaviors and hooks related to the matching controller here. |  | ||||||
| # All this logic will automatically be available in application.js. |  | ||||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ |  | ||||||
							
								
								
									
										39
									
								
								app/assets/stylesheets/accounts.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/assets/stylesheets/accounts.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | .card { | ||||||
|  |   display: flex; | ||||||
|  |   background: $primary-color; | ||||||
|  |   box-shadow: 4px 3px 0 rgba(0, 0, 0, 0.1); | ||||||
|  | 
 | ||||||
|  |   .bio { | ||||||
|  |     flex-grow: 1; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .name { | ||||||
|  |     font-size: 20px; | ||||||
|  |     line-height: 18px * 1.5; | ||||||
|  |     color: $quaternary-color; | ||||||
|  | 
 | ||||||
|  |     small { | ||||||
|  |       display: block; | ||||||
|  |       font-size: 14px; | ||||||
|  |       color: $quaternary-color; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .avatar { | ||||||
|  |     width: 96px; | ||||||
|  |     float: left; | ||||||
|  |     margin-right: 10px; | ||||||
|  |     padding: 10px; | ||||||
|  |     padding-right: 0; | ||||||
|  |     padding-left: 9px; | ||||||
|  |     margin-top: -30px; | ||||||
|  | 
 | ||||||
|  |     img { | ||||||
|  |       width: 94px; | ||||||
|  |       height: 94px; | ||||||
|  |       display: block; | ||||||
|  |       border-radius: 5px; | ||||||
|  |       box-shadow: 4px 3px 0 rgba(0, 0, 0, 0.1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,3 +1,3 @@ | |||||||
| // Place all the styles related to the Atom controller here. | // Place all the styles related to the API::Salmon controller here. | ||||||
| // They will automatically be included in application.css. | // They will automatically be included in application.css. | ||||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | // You can use Sass (SCSS) here: http://sass-lang.com/ | ||||||
| @ -1,3 +1,3 @@ | |||||||
| // Place all the styles related to the XRD controller here. | // Place all the styles related to the API::Subscriptions controller here. | ||||||
| // They will automatically be included in application.css. | // They will automatically be included in application.css. | ||||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | // You can use Sass (SCSS) here: http://sass-lang.com/ | ||||||
| @ -20,7 +20,7 @@ body { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .container { | .container { | ||||||
|   width: 800px; |   width: 700px; | ||||||
|   margin: 0 auto; |   margin: 0 auto; | ||||||
|   margin-top: 40px; |   margin-top: 40px; | ||||||
| } | } | ||||||
| @ -40,4 +40,5 @@ body { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @import 'home'; | @import 'home'; | ||||||
| @import 'profile'; | @import 'accounts'; | ||||||
|  | @import 'stream_entries'; | ||||||
|  | |||||||
| @ -1,59 +1,32 @@ | |||||||
| .card { |  | ||||||
|   display: flex; |  | ||||||
|   background: $darker-background-color; |  | ||||||
|   border: 1px solid darken($darker-background-color, 15%); |  | ||||||
|   box-shadow: 4px 3px 0 rgba(0, 0, 0, 0.1); |  | ||||||
| 
 |  | ||||||
|   .bio { |  | ||||||
|     flex-grow: 1; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .name { |  | ||||||
|     font-size: 24px; |  | ||||||
|     line-height: 18px * 1.5; |  | ||||||
|     color: $text-color; |  | ||||||
| 
 |  | ||||||
|     small { |  | ||||||
|       display: block; |  | ||||||
|       font-size: 14px; |  | ||||||
|       color: $lighter-text-color; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .avatar { |  | ||||||
|     width: 96px; |  | ||||||
|     float: left; |  | ||||||
|     margin-right: 10px; |  | ||||||
|     padding: 10px; |  | ||||||
|     padding-left: 9px; |  | ||||||
|     margin-top: -30px; |  | ||||||
| 
 |  | ||||||
|     img { |  | ||||||
|       width: 94px; |  | ||||||
|       height: 94px; |  | ||||||
|       display: block; |  | ||||||
|       border: 2px solid $lighter-text-color; |  | ||||||
|       border-radius: 5px; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| .activity-stream { | .activity-stream { | ||||||
|   clear: both; |   clear: both; | ||||||
|   box-shadow: 4px 3px 0 rgba(0, 0, 0, 0.1); |   box-shadow: 4px 3px 0 rgba(0, 0, 0, 0.1); | ||||||
| 
 | 
 | ||||||
|   .entry { |   .entry { | ||||||
|     border-bottom: 1px solid darken($background-color, 10%); |     border-bottom: 1px solid $darker-background-color; | ||||||
|     background: $background-color; |     background: $background-color; | ||||||
|     border-left: 2px solid $primary-color; |     border-left: 2px solid $primary-color; | ||||||
| 
 | 
 | ||||||
|     &.entry-reblog { |     &.entry-reblog { | ||||||
|       border-left: 2px solid $tertiary-color; |       border-left: 2px solid $tertiary-color; | ||||||
|  | 
 | ||||||
|  |       .content { | ||||||
|  |         a { | ||||||
|  |           color: $tertiary-color; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.entry-predecessor, &.entry-successor { |     &.entry-predecessor, &.entry-successor { | ||||||
|       border-left: 2px solid $lighter-text-color; |       border-left: 2px solid $lighter-text-color; | ||||||
|       background: darken($background-color, 5%); |       background: darken($background-color, 5%); | ||||||
|  | 
 | ||||||
|  |       .content { | ||||||
|  |         a { | ||||||
|  |           color: $lighter-text-color; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.entry-follow, &.entry-favourite { |     &.entry-follow, &.entry-favourite { | ||||||
| @ -92,9 +65,10 @@ | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .header { |   .header { | ||||||
|     margin-bottom: 10px; |     margin-bottom: 5px; | ||||||
|     padding: 10px; |     padding: 10px; | ||||||
|     padding-bottom: 0; |     padding-bottom: 0; | ||||||
|  |     padding-left: 8px; | ||||||
| 
 | 
 | ||||||
|     .name { |     .name { | ||||||
|       text-decoration: none; |       text-decoration: none; | ||||||
| @ -113,7 +87,7 @@ | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .pre-header { |   .pre-header { | ||||||
|     border-bottom: 1px solid darken($background-color, 10%); |     border-bottom: 1px solid darken($background-color, 5%); | ||||||
|     color: $tertiary-color; |     color: $tertiary-color; | ||||||
|     padding: 5px 10px; |     padding: 5px 10px; | ||||||
|     padding-left: 8px; |     padding-left: 8px; | ||||||
| @ -131,9 +105,10 @@ | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .content { |   .content { | ||||||
|     font-size: 16px; |     font-size: 14px; | ||||||
|     padding: 0 10px; |     padding: 0 10px; | ||||||
|     padding-left: 8px; |     padding-left: 8px; | ||||||
|  |     padding-bottom: 25px; | ||||||
| 
 | 
 | ||||||
|     a { |     a { | ||||||
|       color: $primary-color; |       color: $primary-color; | ||||||
| @ -153,24 +128,4 @@ | |||||||
|       text-decoration: underline; |       text-decoration: underline; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   .counters { |  | ||||||
|     margin-top: 15px; |  | ||||||
|     color: $lighter-text-color; |  | ||||||
|     cursor: default; |  | ||||||
|     padding: 10px; |  | ||||||
|     padding-top: 0; |  | ||||||
| 
 |  | ||||||
|     .counter { |  | ||||||
|       display: inline-block; |  | ||||||
|       margin-right: 10px; |  | ||||||
|       color: $lighter-text-color; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .conversation-link { |  | ||||||
|       color: $primary-color; |  | ||||||
|       text-decoration: underline; |  | ||||||
|       float: right; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } | } | ||||||
							
								
								
									
										16
									
								
								app/controllers/accounts_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/controllers/accounts_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | class AccountsController < ApplicationController | ||||||
|  |   before_action :set_account | ||||||
|  | 
 | ||||||
|  |   def show | ||||||
|  |     respond_to do |format| | ||||||
|  |       format.html | ||||||
|  |       format.atom | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def set_account | ||||||
|  |     @account = Account.find_by!(username: params[:username], domain: nil) | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										14
									
								
								app/controllers/api/salmon_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/controllers/api/salmon_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | class Api::SalmonController < ApplicationController | ||||||
|  |   before_action :set_account | ||||||
|  | 
 | ||||||
|  |   def update | ||||||
|  |     ProcessInteractionService.new.(request.body.read, @account) | ||||||
|  |     render nothing: true, status: 201 | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def set_account | ||||||
|  |     @account = Account.find(params[:id]) | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										28
									
								
								app/controllers/api/subscriptions_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/controllers/api/subscriptions_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | class Api::SubscriptionsController < ApplicationController | ||||||
|  |   before_action :set_account | ||||||
|  | 
 | ||||||
|  |   def show | ||||||
|  |     if @account.subscription(api_subscription_url(@account.id)).valid?(params['hub.topic'], params['hub.verify_token']) | ||||||
|  |       render text: params['hub.challenge'], status: 200 | ||||||
|  |     else | ||||||
|  |       render nothing: true, status: 404 | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def update | ||||||
|  |     body = request.body.read | ||||||
|  | 
 | ||||||
|  |     if @account.subscription(api_subscription_url(@account.id)).verify(body, env['HTTP_X_HUB_SIGNATURE']) | ||||||
|  |       ProcessFeedService.new.(body, @account) | ||||||
|  |       render nothing: true, status: 201 | ||||||
|  |     else | ||||||
|  |       render nothing: true, status: 202 | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def set_account | ||||||
|  |     @account = Account.find(params[:id]) | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -1,18 +0,0 @@ | |||||||
| class AtomController < ApplicationController |  | ||||||
|   before_filter :set_format |  | ||||||
| 
 |  | ||||||
|   def user_stream |  | ||||||
|     @account = Account.find_by!(id: params[:id], domain: nil) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def entry |  | ||||||
|     @entry = StreamEntry.find(params[:id]) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   private |  | ||||||
| 
 |  | ||||||
|   def set_format |  | ||||||
|     request.format = 'xml' |  | ||||||
|     response.headers['Content-Type'] = 'application/atom+xml' |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -1,17 +0,0 @@ | |||||||
| class ProfileController < ApplicationController |  | ||||||
|   before_action :set_account |  | ||||||
| 
 |  | ||||||
|   def show |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def entry |  | ||||||
|     @entry = @account.stream_entries.find(params[:id]) |  | ||||||
|     @type  = @entry.activity_type.downcase |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   private |  | ||||||
| 
 |  | ||||||
|   def set_account |  | ||||||
|     @account = Account.find_by!(username: params[:name], domain: nil) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
							
								
								
									
										23
									
								
								app/controllers/stream_entries_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/controllers/stream_entries_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | class StreamEntriesController < ApplicationController | ||||||
|  |   before_action :set_account | ||||||
|  |   before_action :set_stream_entry | ||||||
|  | 
 | ||||||
|  |   def show | ||||||
|  |     @type = @stream_entry.activity_type.downcase | ||||||
|  | 
 | ||||||
|  |     respond_to do |format| | ||||||
|  |       format.html | ||||||
|  |       format.atom | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def set_account | ||||||
|  |     @account = Account.find_by!(username: params[:account_username], domain: nil) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def set_stream_entry | ||||||
|  |     @stream_entry = @account.stream_entries.find(params[:id]) | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -9,6 +9,8 @@ class XrdController < ApplicationController | |||||||
|     @account = Account.find_by!(username: username_from_resource, domain: nil) |     @account = Account.find_by!(username: username_from_resource, domain: nil) | ||||||
|     @canonical_account_uri = "acct:#{@account.username}@#{LOCAL_DOMAIN}" |     @canonical_account_uri = "acct:#{@account.username}@#{LOCAL_DOMAIN}" | ||||||
|     @magic_key = pem_to_magic_key(@account.keypair.public_key) |     @magic_key = pem_to_magic_key(@account.keypair.public_key) | ||||||
|  |   rescue ActiveRecord::RecordNotFound | ||||||
|  |     render nothing: true, status: 404 | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								app/helpers/accounts_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/helpers/accounts_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | module AccountsHelper | ||||||
|  | 
 | ||||||
|  | end | ||||||
							
								
								
									
										2
									
								
								app/helpers/api/salmon_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/helpers/api/salmon_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | module Api::SalmonHelper | ||||||
|  | end | ||||||
							
								
								
									
										2
									
								
								app/helpers/api/subscriptions_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/helpers/api/subscriptions_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | module Api::SubscriptionsHelper | ||||||
|  | end | ||||||
| @ -1,6 +1,4 @@ | |||||||
| module ApplicationHelper | module ApplicationHelper | ||||||
|   include RoutingHelper |  | ||||||
| 
 |  | ||||||
|   def unique_tag(date, id, type) |   def unique_tag(date, id, type) | ||||||
|     "tag:#{LOCAL_DOMAIN},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}" |     "tag:#{LOCAL_DOMAIN},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}" | ||||||
|   end |   end | ||||||
| @ -13,24 +11,4 @@ module ApplicationHelper | |||||||
|   def local_id?(id) |   def local_id?(id) | ||||||
|     id.start_with?("tag:#{LOCAL_DOMAIN}") |     id.start_with?("tag:#{LOCAL_DOMAIN}") | ||||||
|   end |   end | ||||||
| 
 |  | ||||||
|   def subscription_url(account) |  | ||||||
|     add_base_url_prefix subscriptions_path(id: account.id, format: '') |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def salmon_url(account) |  | ||||||
|     add_base_url_prefix salmon_path(id: account.id, format: '') |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def profile_url(account) |  | ||||||
|     account.local? ? super(name: account.username) : account.url |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def status_url(status) |  | ||||||
|     status.local? ? super(name: status.account.username, id: status.stream_entry.id) : status.url |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def add_base_url_prefix(suffix) |  | ||||||
|     File.join(root_url, "api", suffix) |  | ||||||
|   end |  | ||||||
| end | end | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| module AtomHelper | module AtomBuilderHelper | ||||||
|   def stream_updated_at |   def stream_updated_at | ||||||
|     @account.stream_entries.last ? (@account.updated_at > @account.stream_entries.last.created_at ? @account.updated_at : @account.stream_entries.last.created_at) : @account.updated_at |     @account.stream_entries.last ? (@account.updated_at > @account.stream_entries.last.created_at ? @account.updated_at : @account.stream_entries.last.created_at) : @account.updated_at | ||||||
|   end |   end | ||||||
| @ -97,10 +97,10 @@ module AtomHelper | |||||||
|     xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' }) |     xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' }) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def disambiguate_uri(target) |   def uri_for_target(target) | ||||||
|     if target.local? |     if target.local? | ||||||
|       if target.object_type == :person |       if target.object_type == :person | ||||||
|         profile_url(target) |         account_url(target) | ||||||
|       else |       else | ||||||
|         unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type) |         unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type) | ||||||
|       end |       end | ||||||
| @ -109,12 +109,12 @@ module AtomHelper | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def disambiguate_url(target) |   def url_for_target(target) | ||||||
|     if target.local? |     if target.local? | ||||||
|       if target.object_type == :person |       if target.object_type == :person | ||||||
|         profile_url(target) |         account_url(target) | ||||||
|       else |       else | ||||||
|         status_url(target) |         account_stream_entry_url(target.account, target.stream_entry) | ||||||
|       end |       end | ||||||
|     else |     else | ||||||
|       target.url |       target.url | ||||||
| @ -122,13 +122,13 @@ module AtomHelper | |||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def link_mention(xml, account) |   def link_mention(xml, account) | ||||||
|     xml.link(rel: 'mentioned', href: disambiguate_uri(account)) |     xml.link(rel: 'mentioned', href: uri_for_target(account)) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def link_avatar(xml, account) |   def link_avatar(xml, account) | ||||||
|     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '300', 'media:height' =>'300', 'href' => asset_url(account.avatar.url(:large))) |     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '300', 'media:height' =>'300', 'href' => asset_url(account.avatar.url(:large, false))) | ||||||
|     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '96', 'media:height' =>'96', 'href' => asset_url(account.avatar.url(:medium))) |     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '96', 'media:height' =>'96', 'href' => asset_url(account.avatar.url(:medium, false))) | ||||||
|     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '48', 'media:height' =>'48', 'href' => asset_url(account.avatar.url(:small))) |     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => '48', 'media:height' =>'48', 'href' => asset_url(account.avatar.url(:small, false))) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def logo(xml, url) |   def logo(xml, url) | ||||||
| @ -137,10 +137,10 @@ module AtomHelper | |||||||
| 
 | 
 | ||||||
|   def include_author(xml, account) |   def include_author(xml, account) | ||||||
|     object_type      xml, :person |     object_type      xml, :person | ||||||
|     uri              xml, profile_url(account) |     uri              xml, url_for_target(account) | ||||||
|     name             xml, account.username |     name             xml, account.username | ||||||
|     summary          xml, account.note |     summary          xml, account.note | ||||||
|     link_alternate   xml, profile_url(account) |     link_alternate   xml, url_for_target(account) | ||||||
|     link_avatar      xml, account |     link_avatar      xml, account | ||||||
|     portable_contact xml, account |     portable_contact xml, account | ||||||
|   end |   end | ||||||
| @ -152,20 +152,20 @@ module AtomHelper | |||||||
|     title        xml, stream_entry.title |     title        xml, stream_entry.title | ||||||
|     content      xml, stream_entry.content |     content      xml, stream_entry.content | ||||||
|     verb         xml, stream_entry.verb |     verb         xml, stream_entry.verb | ||||||
|     link_self    xml, atom_entry_url(id: stream_entry.id) |     link_self    xml, account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom') | ||||||
|     object_type  xml, stream_entry.object_type |     object_type  xml, stream_entry.object_type | ||||||
| 
 | 
 | ||||||
|     # Comments need thread element |     # Comments need thread element | ||||||
|     if stream_entry.threaded? |     if stream_entry.threaded? | ||||||
|       in_reply_to xml, disambiguate_uri(stream_entry.thread), disambiguate_url(stream_entry.thread) |       in_reply_to xml, uri_for_target(stream_entry.thread), url_for_target(stream_entry.thread) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if stream_entry.targeted? |     if stream_entry.targeted? | ||||||
|       target(xml) do |       target(xml) do | ||||||
|         object_type    xml, stream_entry.target.object_type |         object_type    xml, stream_entry.target.object_type | ||||||
|         simple_id      xml, disambiguate_uri(stream_entry.target) |         simple_id      xml, uri_for_target(stream_entry.target) | ||||||
|         title          xml, stream_entry.target.title |         title          xml, stream_entry.target.title | ||||||
|         link_alternate xml, disambiguate_url(stream_entry.target) |         link_alternate xml, url_for_target(stream_entry.target) | ||||||
| 
 | 
 | ||||||
|         # People have summary and portable contacts information |         # People have summary and portable contacts information | ||||||
|         if stream_entry.target.object_type == :person |         if stream_entry.target.object_type == :person | ||||||
| @ -1,4 +1,4 @@ | |||||||
| module ProfileHelper | module StreamEntriesHelper | ||||||
|   def display_name(account) |   def display_name(account) | ||||||
|     account.display_name.blank? ? account.username : account.display_name |     account.display_name.blank? ? account.username : account.display_name | ||||||
|   end |   end | ||||||
| @ -76,6 +76,10 @@ class Account < ActiveRecord::Base | |||||||
|     @avatar_remote_url = url |     @avatar_remote_url = url | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def to_param | ||||||
|  |     self.username | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   before_create do |   before_create do | ||||||
|     if local? |     if local? | ||||||
|       keypair = OpenSSL::PKey::RSA.new(Rails.env.test? ? 1024 : 2048) |       keypair = OpenSSL::PKey::RSA.new(Rails.env.test? ? 1024 : 2048) | ||||||
|  | |||||||
| @ -1,9 +1,4 @@ | |||||||
| class User < ActiveRecord::Base | class User < ActiveRecord::Base | ||||||
|   belongs_to :account, inverse_of: :user |   belongs_to :account, inverse_of: :user | ||||||
| 
 |  | ||||||
|   validates :account, presence: true |   validates :account, presence: true | ||||||
| 
 |  | ||||||
|   def timeline |  | ||||||
|     StreamEntry.where(account_id: self.account.following, activity_type: 'Status').order('id desc') |  | ||||||
|   end |  | ||||||
| end | end | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
| class BaseService | class BaseService | ||||||
|  |   include RoutingHelper | ||||||
|   include ApplicationHelper |   include ApplicationHelper | ||||||
| end | end | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ class FollowRemoteAccountService < BaseService | |||||||
|       account.secret       = SecureRandom.hex |       account.secret       = SecureRandom.hex | ||||||
|       account.verify_token = SecureRandom.hex |       account.verify_token = SecureRandom.hex | ||||||
| 
 | 
 | ||||||
|       subscription = account.subscription(subscription_url(account)) |       subscription = account.subscription(api_subscription_url(account.id)) | ||||||
|       subscription.subscribe |       subscription.subscribe | ||||||
| 
 | 
 | ||||||
|       account.save! |       account.save! | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ class FollowService < BaseService | |||||||
| 
 | 
 | ||||||
|     follow = source_account.follow!(target_account) |     follow = source_account.follow!(target_account) | ||||||
|     send_interaction_service.(follow.stream_entry, target_account) |     send_interaction_service.(follow.stream_entry, target_account) | ||||||
|     source_account.ping!(atom_user_stream_url(id: source_account.id), [HUB_URL]) |     source_account.ping!(account_url(account, format: 'atom'), [HUB_URL]) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ class PostStatusService < BaseService | |||||||
|   def call(account, text, in_reply_to = nil) |   def call(account, text, in_reply_to = nil) | ||||||
|     status = account.statuses.create!(text: text, thread: in_reply_to) |     status = account.statuses.create!(text: text, thread: in_reply_to) | ||||||
|     process_mentions_service.(status) |     process_mentions_service.(status) | ||||||
|     account.ping!(atom_user_stream_url(id: account.id), [HUB_URL]) |     account.ping!(account_url(account, format: 'atom'), [HUB_URL]) | ||||||
|     status |     status | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ class ProcessInteractionService < BaseService | |||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def mentions_account?(xml, account) |   def mentions_account?(xml, account) | ||||||
|     xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]').each { |mention_link| return true if mention_link.attribute('href').value == profile_url(account) } |     xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]').each { |mention_link| return true if mention_link.attribute('href').value == url_for_target(account) } | ||||||
|     false |     false | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ class ReblogService < BaseService | |||||||
|   # @return [Status] |   # @return [Status] | ||||||
|   def call(account, reblogged_status) |   def call(account, reblogged_status) | ||||||
|     reblog = account.statuses.create!(reblog: reblogged_status, text: '') |     reblog = account.statuses.create!(reblog: reblogged_status, text: '') | ||||||
|     account.ping!(atom_user_stream_url(id: account.id), [HUB_URL]) |     account.ping!(account_url(account, format: 'atom'), [HUB_URL]) | ||||||
|     return reblog if reblogged_status.local? |     return reblog if reblogged_status.local? | ||||||
|     send_interaction_service.(reblog.stream_entry, reblogged_status.account) |     send_interaction_service.(reblog.stream_entry, reblogged_status.account) | ||||||
|     reblog |     reblog | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| class SendInteractionService < BaseService | class SendInteractionService < BaseService | ||||||
|   include AtomHelper |   include AtomBuilderHelper | ||||||
| 
 | 
 | ||||||
|   # Send an Atom representation of an interaction to a remote Salmon endpoint |   # Send an Atom representation of an interaction to a remote Salmon endpoint | ||||||
|   # @param [StreamEntry] stream_entry |   # @param [StreamEntry] stream_entry | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| Nokogiri::XML::Builder.new do |xml| | Nokogiri::XML::Builder.new do |xml| | ||||||
|   feed(xml) do |   feed(xml) do | ||||||
|     simple_id  xml, atom_user_stream_url(id: @account.id) |     simple_id  xml, account_url(@account, format: 'atom') | ||||||
|     title      xml, @account.display_name |     title      xml, @account.display_name | ||||||
|     subtitle   xml, @account.note |     subtitle   xml, @account.note | ||||||
|     updated_at xml, stream_updated_at |     updated_at xml, stream_updated_at | ||||||
| @ -10,10 +10,10 @@ Nokogiri::XML::Builder.new do |xml| | |||||||
|       include_author xml, @account |       include_author xml, @account | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     link_alternate xml, profile_url(@account) |     link_alternate xml, url_for_target(@account) | ||||||
|     link_self      xml, atom_user_stream_url(id: @account.id) |     link_self      xml, account_url(@account, format: 'atom') | ||||||
|     link_hub       xml, HUB_URL |     link_hub       xml, HUB_URL | ||||||
|     link_salmon    xml, salmon_url(@account) |     link_salmon    xml, api_salmon_url(@account.id) | ||||||
| 
 | 
 | ||||||
|     @account.stream_entries.order('id desc').each do |stream_entry| |     @account.stream_entries.order('id desc').each do |stream_entry| | ||||||
|       entry(xml, false) do |       entry(xml, false) do | ||||||
| @ -1,6 +1,6 @@ | |||||||
| - content_for :header_tags do | - content_for :header_tags do | ||||||
|   %link{ rel: 'salmon', href: salmon_url(@account) }/ |   %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/ | ||||||
|   %link{ rel: 'alternate', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id) }/ |   %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/ | ||||||
| 
 | 
 | ||||||
| .card | .card | ||||||
|   .avatar= image_tag @account.avatar.url(:medium) |   .avatar= image_tag @account.avatar.url(:medium) | ||||||
| @ -11,4 +11,4 @@ | |||||||
| 
 | 
 | ||||||
| .activity-stream | .activity-stream | ||||||
|   - @account.statuses.order('id desc').each do |status| |   - @account.statuses.order('id desc').each do |status| | ||||||
|     = render partial: 'status', locals: { status: status, include_threads: false, is_successor: false, is_predecessor: false } |     = render partial: 'stream_entries/status', locals: { status: status, include_threads: false, is_successor: false, is_predecessor: false } | ||||||
| @ -1,2 +0,0 @@ | |||||||
| - if status.reply? |  | ||||||
|   = link_to "In response to #{status.thread.account.acct}", status_url(status.thread), class: 'conversation-link' |  | ||||||
| @ -1,7 +0,0 @@ | |||||||
| = link_to profile_url(status.account), class: 'name' do |  | ||||||
|   %strong= display_name(status.account) |  | ||||||
|   = "@#{status.account.acct}" |  | ||||||
| 
 |  | ||||||
| = link_to status_url(status), class: 'time' do |  | ||||||
|   %span{ title: status.created_at } |  | ||||||
|     = relative_time(status.created_at) |  | ||||||
| @ -1,5 +0,0 @@ | |||||||
| - content_for :header_tags do |  | ||||||
|   %link{ rel: 'alternate', type: 'application/atom+xml', href: atom_entry_url(id: @entry.id) }/ |  | ||||||
| 
 |  | ||||||
| .activity-stream |  | ||||||
|   = render partial: @type, locals: { @type.to_sym => @entry.activity, include_threads: true, is_predecessor: false, is_successor: false } |  | ||||||
| @ -6,17 +6,23 @@ | |||||||
|     .pre-header |     .pre-header | ||||||
|       %i.fa.fa-retweet |       %i.fa.fa-retweet | ||||||
|       Shared by |       Shared by | ||||||
|       = link_to display_name(status.account), profile_url(status.account), class: 'name' |       = link_to display_name(status.account), url_for_target(status.account), class: 'name' | ||||||
|  | 
 | ||||||
|   .entry__container |   .entry__container | ||||||
|     .avatar |     .avatar | ||||||
|       = image_tag avatar_for_status_url(status) |       = image_tag avatar_for_status_url(status) | ||||||
|  | 
 | ||||||
|     .entry__container__container |     .entry__container__container | ||||||
|       .header |       .header | ||||||
|         = render partial: 'status_header', locals: { status: status.reblog? ? status.reblog : status } |         = link_to url_for_target(status.reblog? ? status.reblog.account : status.account), class: 'name' do | ||||||
|  |           %strong= display_name(status.reblog? ? status.reblog.account : status.account) | ||||||
|  |           = "@#{status.reblog? ? status.reblog.account.acct : status.account.acct}" | ||||||
|  |         = link_to url_for_target(status.reblog? ? status.reblog : status), class: 'time' do | ||||||
|  |           %span{ title: status.reblog? ? status.reblog.created_at : status.created_at } | ||||||
|  |             = relative_time(status.reblog? ? status.reblog.created_at : status.created_at) | ||||||
|  | 
 | ||||||
|       .content |       .content | ||||||
|         = status.content.html_safe |         = status.content.html_safe | ||||||
|       .counters |  | ||||||
|         = render partial: 'status_footer', locals: { status: status.reblog? ? status.reblog : status } |  | ||||||
| 
 | 
 | ||||||
| - if include_threads | - if include_threads | ||||||
|   - status.replies.each do |status| |   - status.replies.each do |status| | ||||||
							
								
								
									
										5
									
								
								app/views/stream_entries/show.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/views/stream_entries/show.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | - content_for :header_tags do | ||||||
|  |   %link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/ | ||||||
|  | 
 | ||||||
|  | .activity-stream | ||||||
|  |   = render partial: @type, locals: { @type.to_sym => @stream_entry.activity, include_threads: true, is_predecessor: false, is_successor: false } | ||||||
| @ -1,10 +1,10 @@ | |||||||
| Nokogiri::XML::Builder.new do |xml| | Nokogiri::XML::Builder.new do |xml| | ||||||
|   xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do |   xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do | ||||||
|     xml.Subject @canonical_account_uri |     xml.Subject @canonical_account_uri | ||||||
|     xml.Alias profile_url(@account) |     xml.Alias url_for_target(@account) | ||||||
|     xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: profile_url(@account)) |     xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: url_for_target(@account)) | ||||||
|     xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id)) |     xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id)) | ||||||
|     xml.Link(rel: 'salmon', href: salmon_url(@account)) |     xml.Link(rel: 'salmon', href: api_salmon_url(@account.id)) | ||||||
|     xml.Link(rel: 'magic-public-key', href: @magic_key) |     xml.Link(rel: 'magic-public-key', href: @magic_key) | ||||||
|   end |   end | ||||||
| end.to_xml | end.to_xml | ||||||
|  | |||||||
| @ -2,12 +2,15 @@ Rails.application.routes.draw do | |||||||
|   get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta |   get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta | ||||||
|   get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger |   get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger | ||||||
| 
 | 
 | ||||||
|   get 'atom/entries/:id', to: 'atom#entry',       as: :atom_entry |   resources :accounts, path: 'users', only: [:show], param: :username do | ||||||
|   get 'atom/users/:id',   to: 'atom#user_stream', as: :atom_user_stream |     resources :stream_entries, path: 'updates', only: [:show] | ||||||
|   get 'users/:name',      to: 'profile#show',     as: :profile |   end | ||||||
|   get 'users/:name/:id',  to: 'profile#entry',    as: :status |  | ||||||
| 
 | 
 | ||||||
|   mount Mastodon::API => '/api/' |   namespace :api do | ||||||
|  |     resources :subscriptions, only: [:show] | ||||||
|  |     post '/subscriptions/:id', to: 'subscriptions#update' | ||||||
|  |     post '/salmon/:id', to: 'salmon#update', as: :salmon | ||||||
|  |   end | ||||||
| 
 | 
 | ||||||
|   root 'home#index' |   root 'home#index' | ||||||
| end | end | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								spec/controllers/accounts_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								spec/controllers/accounts_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe AccountsController, type: :controller do | ||||||
|  |   let(:alice)  { Fabricate(:account, username: 'alice') } | ||||||
|  | 
 | ||||||
|  |   describe 'GET #show' do | ||||||
|  |     it 'returns 200' do | ||||||
|  |       get :show, username: alice.username | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns 200 with Atom' do | ||||||
|  |       get :show, username: alice.username, format: 'atom' | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										7
									
								
								spec/controllers/api/salmon_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								spec/controllers/api/salmon_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe Api::SalmonController, type: :controller do | ||||||
|  |   describe 'POST #update' do | ||||||
|  |     pending | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										11
									
								
								spec/controllers/api/subscriptions_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								spec/controllers/api/subscriptions_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe Api::SubscriptionsController, type: :controller do | ||||||
|  |   describe 'GET #show' do | ||||||
|  |     pending | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe 'POST #update' do | ||||||
|  |     pending | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -1,11 +0,0 @@ | |||||||
| require 'rails_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe AtomController, type: :controller do |  | ||||||
|   describe 'GET #user_stream' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe 'GET #entry' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| @ -2,6 +2,9 @@ require 'rails_helper' | |||||||
| 
 | 
 | ||||||
| RSpec.describe HomeController, type: :controller do | RSpec.describe HomeController, type: :controller do | ||||||
|   describe 'GET #index' do |   describe 'GET #index' do | ||||||
|     pending |     it 'returns 200' do | ||||||
|  |       get :index | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -1,11 +0,0 @@ | |||||||
| require 'rails_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe ProfileController, type: :controller do |  | ||||||
|   describe 'GET #show' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe 'GET #entry' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| end |  | ||||||
							
								
								
									
										18
									
								
								spec/controllers/stream_entries_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								spec/controllers/stream_entries_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe StreamEntriesController, type: :controller do | ||||||
|  |   let(:alice)  { Fabricate(:account, username: 'alice') } | ||||||
|  |   let(:status) { Fabricate(:status, account: alice) } | ||||||
|  | 
 | ||||||
|  |   describe 'GET #show' do | ||||||
|  |     it 'returns 200 with HTML' do | ||||||
|  |       get :show, account_username: alice.username, id: status.stream_entry.id | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns 200 with Atom' do | ||||||
|  |       get :show, account_username: alice.username, id: status.stream_entry.id, format: 'atom' | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -2,10 +2,23 @@ require 'rails_helper' | |||||||
| 
 | 
 | ||||||
| RSpec.describe XrdController, type: :controller do | RSpec.describe XrdController, type: :controller do | ||||||
|   describe 'GET #host_meta' do |   describe 'GET #host_meta' do | ||||||
|     pending |     it 'returns 200' do | ||||||
|  |       get :host_meta | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'GET #webfinger' do |   describe 'GET #webfinger' do | ||||||
|     pending |     let(:alice) { Fabricate(:account, username: 'alice') } | ||||||
|  | 
 | ||||||
|  |     it 'returns 200 when account can be found' do | ||||||
|  |       get :webfinger, resource: "acct:#{alice.username}@anything.com" | ||||||
|  |       expect(response).to have_http_status(:success) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns 404 when account cannot be found' do | ||||||
|  |       get :webfinger, resource: 'acct:not@existing.com' | ||||||
|  |       expect(response).to have_http_status(:not_found) | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								spec/helpers/accounts_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								spec/helpers/accounts_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | # Specs in this file have access to a helper object that includes | ||||||
|  | # the AccountsHelper. For example: | ||||||
|  | # | ||||||
|  | # describe AccountsHelper do | ||||||
|  | #   describe "string concat" do | ||||||
|  | #     it "concats two strings with spaces" do | ||||||
|  | #       expect(helper.concat_strings("this","that")).to eq("this that") | ||||||
|  | #     end | ||||||
|  | #   end | ||||||
|  | # end | ||||||
|  | RSpec.describe AccountsHelper, type: :helper do | ||||||
|  |   pending "add some examples to (or delete) #{__FILE__}" | ||||||
|  | end | ||||||
							
								
								
									
										15
									
								
								spec/helpers/api/salmon_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								spec/helpers/api/salmon_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | # Specs in this file have access to a helper object that includes | ||||||
|  | # the Api::SalmonHelper. For example: | ||||||
|  | # | ||||||
|  | # describe Api::SalmonHelper do | ||||||
|  | #   describe "string concat" do | ||||||
|  | #     it "concats two strings with spaces" do | ||||||
|  | #       expect(helper.concat_strings("this","that")).to eq("this that") | ||||||
|  | #     end | ||||||
|  | #   end | ||||||
|  | # end | ||||||
|  | RSpec.describe Api::SalmonHelper, type: :helper do | ||||||
|  |   pending "add some examples to (or delete) #{__FILE__}" | ||||||
|  | end | ||||||
							
								
								
									
										15
									
								
								spec/helpers/api/subscriptions_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								spec/helpers/api/subscriptions_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | # Specs in this file have access to a helper object that includes | ||||||
|  | # the Api::SubscriptionsHelper. For example: | ||||||
|  | # | ||||||
|  | # describe Api::SubscriptionsHelper do | ||||||
|  | #   describe "string concat" do | ||||||
|  | #     it "concats two strings with spaces" do | ||||||
|  | #       expect(helper.concat_strings("this","that")).to eq("this that") | ||||||
|  | #     end | ||||||
|  | #   end | ||||||
|  | # end | ||||||
|  | RSpec.describe Api::SubscriptionsHelper, type: :helper do | ||||||
|  |   pending "add some examples to (or delete) #{__FILE__}" | ||||||
|  | end | ||||||
| @ -28,18 +28,4 @@ RSpec.describe ApplicationHelper, type: :helper do | |||||||
|       expect(helper.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false |       expect(helper.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 |  | ||||||
|   describe '#add_base_url_prefix' do |  | ||||||
|     it 'returns full API URL from base to suffix' do |  | ||||||
|       expect(helper.add_base_url_prefix('test')).to eql "#{root_url}api/test" |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#profile_url' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#status_url' do |  | ||||||
|     pending |  | ||||||
|   end |  | ||||||
| end | end | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
| 
 | 
 | ||||||
| RSpec.describe AtomHelper, type: :helper do | RSpec.describe AtomBuilderHelper, type: :helper do | ||||||
|   describe '#stream_updated_at' do |   describe '#stream_updated_at' do | ||||||
|     pending |     pending | ||||||
|   end |   end | ||||||
| @ -1,6 +1,6 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
| 
 | 
 | ||||||
| RSpec.describe ProfileHelper, type: :helper do | RSpec.describe StreamEntriesHelper, type: :helper do | ||||||
|   describe '#display_name' do |   describe '#display_name' do | ||||||
|     pending |     pending | ||||||
|   end |   end | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user