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