parent
11ff92c9d7
commit
0e8f59c16f
@ -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/
|
@ -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.
|
||||
// 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.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,3 @@
|
||||
module AccountsHelper
|
||||
|
||||
end
|
@ -0,0 +1,2 @@
|
||||
module Api::SalmonHelper
|
||||
end
|
@ -0,0 +1,2 @@
|
||||
module Api::SubscriptionsHelper
|
||||
end
|
@ -1,4 +1,4 @@
|
||||
module ProfileHelper
|
||||
module StreamEntriesHelper
|
||||
def display_name(account)
|
||||
account.display_name.blank? ? account.username : account.display_name
|
||||
end
|
@ -1,9 +1,4 @@
|
||||
class User < ActiveRecord::Base
|
||||
belongs_to :account, inverse_of: :user
|
||||
|
||||
validates :account, presence: true
|
||||
|
||||
def timeline
|
||||
StreamEntry.where(account_id: self.account.following, activity_type: 'Status').order('id desc')
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,4 @@
|
||||
class BaseService
|
||||
include RoutingHelper
|
||||
include ApplicationHelper
|
||||
end
|
||||
|
@ -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 }
|
@ -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|
|
||||
xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
|
||||
xml.Subject @canonical_account_uri
|
||||
xml.Alias profile_url(@account)
|
||||
xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: profile_url(@account))
|
||||
xml.Alias url_for_target(@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: 'salmon', href: salmon_url(@account))
|
||||
xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
|
||||
xml.Link(rel: 'magic-public-key', href: @magic_key)
|
||||
end
|
||||
end.to_xml
|
||||
|
@ -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
|
@ -0,0 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::SalmonController, type: :controller do
|
||||
describe 'POST #update' do
|
||||
pending
|
||||
end
|
||||
end
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AtomHelper, type: :helper do
|
||||
RSpec.describe AtomBuilderHelper, type: :helper do
|
||||
describe '#stream_updated_at' do
|
||||
pending
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ProfileHelper, type: :helper do
|
||||
RSpec.describe StreamEntriesHelper, type: :helper do
|
||||
describe '#display_name' do
|
||||
pending
|
||||
end
|
Loading…
Reference in new issue