gearheads
/
mastodon
Archived
2
0
Fork 0

Add ability to use remote follow function on other sites

gh/stable
Eugen Rochko 2016-12-29 16:54:54 +01:00
parent 8b94d283fb
commit d7dc84439c
18 changed files with 166 additions and 32 deletions

View File

@ -324,3 +324,61 @@
padding-bottom: 25px; padding-bottom: 25px;
cursor: default; cursor: default;
} }
.account-card {
padding: 14px 10px;
background: #fff;
border-radius: 4px;
text-align: left;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
.detailed-status__display-name {
display: block;
overflow: hidden;
margin-bottom: 15px;
& > div {
float: left;
margin-right: 10px;
width: 48px;
height: 48px;
}
.avatar {
display: block;
border-radius: 4px;
}
.display-name {
display: block;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
cursor: default;
strong {
font-weight: 500;
color: #282c37;
}
span {
font-size: 14px;
color: #9baec8;
}
}
&:hover {
.display-name {
strong {
text-decoration: none;
}
}
}
}
.account__header__content {
font-size: 14px;
color: #282c37;
}
}

View File

@ -214,11 +214,13 @@ body {
.footer { .footer {
text-align: center; text-align: center;
margin-top: 30px; margin-top: 30px;
font-size: 12px;
color: darken(#d9e1e8, 25%);
.domain { .domain {
font-size: 12px; //font-size: 12px;
font-weight: 400; font-weight: 500;
font-family: 'Roboto Mono', monospace; //font-family: 'Roboto Mono', monospace;
a { a {
color: inherit; color: inherit;
@ -227,13 +229,12 @@ body {
} }
.powered-by { .powered-by {
font-size: 12px;
font-weight: 400; font-weight: 400;
color: darken(#d9e1e8, 25%);
a { a {
color: inherit; color: inherit;
text-decoration: underline; text-decoration: underline;
font-weight: 500;
&:hover { &:hover {
text-decoration: none; text-decoration: none;

View File

@ -185,7 +185,7 @@ code {
} }
} }
.oauth-prompt { .oauth-prompt, .follow-prompt {
margin-bottom: 30px; margin-bottom: 30px;
text-align: center; text-align: center;
color: #9baec8; color: #9baec8;

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class AuthorizeFollowController < ApplicationController
layout 'public'
before_action :authenticate_user!
def new
@account = FollowRemoteAccountService.new.call(params[:acct])
render :error if @account.nil?
end
def create
@account = FollowService.new.call(current_account, params[:acct]).try(:target_account)
if @account.nil?
render :error
else
redirect_to web_url("accounts/#{@account.id}")
end
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermitted
render :error
end
end

View File

@ -0,0 +1,2 @@
module AuthorizeFollowHelper
end

View File

@ -1,6 +1,6 @@
.account-grid-card .account-grid-card
.account-grid-card__header .account-grid-card__header
.avatar= image_tag account.avatar.url( :original) .avatar= image_tag account.avatar.url(:original)
.name .name
= link_to TagManager.instance.url_for(account) do = link_to TagManager.instance.url_for(account) do
%span.display_name= display_name(account) %span.display_name= display_name(account)

View File

@ -0,0 +1,3 @@
.form-container
.flash-message#error_explanation
= t('authorize_follow.error')

View File

@ -0,0 +1,21 @@
- content_for :page_title do
= t('authorize_follow.title', acct: @account.acct)
.form-container
.follow-prompt
%h2= t('authorize_follow.prompt_html', self: current_account.username)
.account-card
.detailed-status__display-name
%div
= image_tag @account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar'
%span.display-name
%strong= display_name(@account)
%span= "@#{@account.acct}"
.account__header__content= Formatter.instance.simplified_format(@account)
= form_tag authorize_follow_path, method: :post, class: 'simple_form' do
= hidden_field_tag :acct, @account.acct
= button_tag t('authorize_follow.follow'), type: :submit

View File

@ -1,2 +1,3 @@
.flash-message#error_explanation .form-container
= @pre_auth.error_response.body[:error_description] .flash-message#error_explanation
= @pre_auth.error_response.body[:error_description]

View File

@ -1,25 +1,26 @@
- content_for :page_title do - content_for :page_title do
= t('doorkeeper.authorizations.new.title') = t('doorkeeper.authorizations.new.title')
.oauth-prompt .form-container
%h2= t('doorkeeper.authorizations.new.prompt', client_name: @pre_auth.client.name) .oauth-prompt
%h2= t('doorkeeper.authorizations.new.prompt', client_name: @pre_auth.client.name)
%p %p
= t('doorkeeper.authorizations.new.able_to') = t('doorkeeper.authorizations.new.able_to')
= @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| "<strong>#{s}</strong>"}.to_sentence.html_safe = @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| "<strong>#{s}</strong>"}.to_sentence.html_safe
= form_tag oauth_authorization_path, method: :post, class: 'simple_form' do = form_tag oauth_authorization_path, method: :post, class: 'simple_form' do
= hidden_field_tag :client_id, @pre_auth.client.uid = hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
= hidden_field_tag :state, @pre_auth.state = hidden_field_tag :state, @pre_auth.state
= hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :scope, @pre_auth.scope
= button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit
= form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do = form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do
= hidden_field_tag :client_id, @pre_auth.client.uid = hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
= hidden_field_tag :state, @pre_auth.state = hidden_field_tag :state, @pre_auth.state
= hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :scope, @pre_auth.scope
= button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative' = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative'

View File

@ -1,2 +1,3 @@
.flash-message .form-container
%code= params[:code] .flash-message
%code= params[:code]

View File

@ -11,6 +11,7 @@ node(:links) do
{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: TagManager.instance.url_for(@account) }, { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: TagManager.instance.url_for(@account) },
{ rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }, { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom') },
{ rel: 'salmon', href: api_salmon_url(@account.id) }, { rel: 'salmon', href: api_salmon_url(@account.id) },
{ rel: 'magic-public-key', href: "data:application/magic-public-key,#{@magic_key}" } { rel: 'magic-public-key', href: "data:application/magic-public-key,#{@magic_key}" },
{ rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_follow_url}?acct={uri}" },
] ]
end end

View File

@ -6,5 +6,6 @@ Nokogiri::XML::Builder.new do |xml|
xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom')) xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom'))
xml.Link(rel: 'salmon', href: api_salmon_url(@account.id)) xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
xml.Link(rel: 'magic-public-key', href: "data:application/magic-public-key,#{@magic_key}") xml.Link(rel: 'magic-public-key', href: "data:application/magic-public-key,#{@magic_key}")
xml.Link(rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_follow_url}?acct={uri}")
end end
end.to_xml end.to_xml

View File

@ -45,7 +45,7 @@ module Mastodon
config.browserify_rails.commandline_options = '--transform [ babelify --presets [ es2015 react ] ] --extension=".jsx"' config.browserify_rails.commandline_options = '--transform [ babelify --presets [ es2015 react ] ] --extension=".jsx"'
config.to_prepare do config.to_prepare do
Doorkeeper::AuthorizationsController.layout 'auth' Doorkeeper::AuthorizationsController.layout 'public'
end end
config.action_dispatch.default_headers = { config.action_dispatch.default_headers = {

View File

@ -26,6 +26,11 @@ en:
resend_confirmation: Resend confirmation instructions resend_confirmation: Resend confirmation instructions
reset_password: Reset password reset_password: Reset password
set_new_password: Set new password set_new_password: Set new password
authorize_follow:
error: Unfortunately, there was an error looking up the remote account
follow: Follow
prompt_html: 'You (<strong>%{self}</strong>) have requested to follow:'
title: Follow %{acct}
datetime: datetime:
distance_in_words: distance_in_words:
about_x_hours: "%{count}h" about_x_hours: "%{count}h"

View File

@ -48,6 +48,10 @@ Rails.application.routes.draw do
resources :media, only: [:show] resources :media, only: [:show]
resources :tags, only: [:show] resources :tags, only: [:show]
# Remote follow
get :authorize_follow, to: 'authorize_follow#new'
post :authorize_follow, to: 'authorize_follow#create'
namespace :admin do namespace :admin do
resources :pubsubhubbub, only: [:index] resources :pubsubhubbub, only: [:index]
resources :domain_blocks, only: [:index, :create] resources :domain_blocks, only: [:index, :create]

View File

@ -0,0 +1,6 @@
require 'rails_helper'
RSpec.describe AuthorizeFollowController, type: :controller do
describe 'GET #new'
describe 'POST #create'
end

View File

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe AuthorizeFollowHelper, type: :helper do
end