From 3282448878dd2640ea47dc1a77a4ae958ba8923e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 26 Dec 2016 18:48:33 +0100 Subject: Fix #86 - resolve layout breaking on zoom-out on accounts grid --- app/assets/stylesheets/accounts.scss | 2 -- 1 file changed, 2 deletions(-) (limited to 'app/assets/stylesheets') diff --git a/app/assets/stylesheets/accounts.scss b/app/assets/stylesheets/accounts.scss index e1d5043db..7f33f178d 100644 --- a/app/assets/stylesheets/accounts.scss +++ b/app/assets/stylesheets/accounts.scss @@ -283,8 +283,6 @@ } .name { - width: 333-20-60-15px; - float: left; padding-top: 10px; a { -- cgit From e2c2fefc36cfa906034152289fe4c916e9a8d46b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 27 Dec 2016 23:30:11 +0100 Subject: Add illustration to getting started column --- .../javascripts/components/features/getting_started/index.jsx | 2 ++ app/assets/stylesheets/components.scss | 11 +++++++++++ db/schema.rb | 1 + 3 files changed, 14 insertions(+) (limited to 'app/assets/stylesheets') diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx index fdd594621..157bdf8f2 100644 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ b/app/assets/javascripts/components/features/getting_started/index.jsx @@ -48,6 +48,8 @@ const GettingStarted = ({ intl, me }) => {

+ +
); }; diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 9f2d1217f..88808b085 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -332,6 +332,7 @@ .column { width: 330px; + position: relative; } .drawer { @@ -575,3 +576,13 @@ color: #fff; } } + +.getting-started__illustration { + width: 330px; + height: 235px; + background: image-url('mastodon-getting-started.png') no-repeat 0 0; + position: absolute; + pointer-events: none; + bottom: 0; + left: 0; +} \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 180d3b14d..b9236d42f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -189,6 +189,7 @@ ActiveRecord::Schema.define(version: 20161222204147) do t.boolean "sensitive", default: false t.integer "visibility", default: 0, null: false t.integer "in_reply_to_account_id" + t.string "conversation_uri" t.index ["account_id"], name: "index_statuses_on_account_id", using: :btree t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id", using: :btree t.index ["reblog_of_id"], name: "index_statuses_on_reblog_of_id", using: :btree -- cgit From d7dc84439c60069a0cb9eeca81dc61c297a8667b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 29 Dec 2016 16:54:54 +0100 Subject: Add ability to use remote follow function on other sites --- app/assets/stylesheets/accounts.scss | 58 ++++++++++++++++++++++ app/assets/stylesheets/application.scss | 11 ++-- app/assets/stylesheets/forms.scss | 2 +- app/controllers/authorize_follow_controller.rb | 24 +++++++++ app/helpers/authorize_follow_helper.rb | 2 + app/views/accounts/_grid_card.html.haml | 2 +- app/views/authorize_follow/error.html.haml | 3 ++ app/views/authorize_follow/new.html.haml | 21 ++++++++ app/views/oauth/authorizations/error.html.haml | 5 +- app/views/oauth/authorizations/new.html.haml | 39 ++++++++------- app/views/oauth/authorizations/show.html.haml | 5 +- app/views/xrd/webfinger.json.rabl | 3 +- app/views/xrd/webfinger.xml.ruby | 1 + config/application.rb | 2 +- config/locales/en.yml | 5 ++ config/routes.rb | 4 ++ .../authorize_follow_controller_spec.rb | 6 +++ spec/helpers/authorize_follow_helper_spec.rb | 5 ++ 18 files changed, 166 insertions(+), 32 deletions(-) create mode 100644 app/controllers/authorize_follow_controller.rb create mode 100644 app/helpers/authorize_follow_helper.rb create mode 100644 app/views/authorize_follow/error.html.haml create mode 100644 app/views/authorize_follow/new.html.haml create mode 100644 spec/controllers/authorize_follow_controller_spec.rb create mode 100644 spec/helpers/authorize_follow_helper_spec.rb (limited to 'app/assets/stylesheets') diff --git a/app/assets/stylesheets/accounts.scss b/app/assets/stylesheets/accounts.scss index 7f33f178d..5d0963307 100644 --- a/app/assets/stylesheets/accounts.scss +++ b/app/assets/stylesheets/accounts.scss @@ -324,3 +324,61 @@ padding-bottom: 25px; 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; + } +} diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index d05ca3795..e4c550b81 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -214,11 +214,13 @@ body { .footer { text-align: center; margin-top: 30px; + font-size: 12px; + color: darken(#d9e1e8, 25%); .domain { - font-size: 12px; - font-weight: 400; - font-family: 'Roboto Mono', monospace; + //font-size: 12px; + font-weight: 500; + //font-family: 'Roboto Mono', monospace; a { color: inherit; @@ -227,13 +229,12 @@ body { } .powered-by { - font-size: 12px; font-weight: 400; - color: darken(#d9e1e8, 25%); a { color: inherit; text-decoration: underline; + font-weight: 500; &:hover { text-decoration: none; diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss index cf9b4fba6..e6d2e85a2 100644 --- a/app/assets/stylesheets/forms.scss +++ b/app/assets/stylesheets/forms.scss @@ -185,7 +185,7 @@ code { } } -.oauth-prompt { +.oauth-prompt, .follow-prompt { margin-bottom: 30px; text-align: center; color: #9baec8; diff --git a/app/controllers/authorize_follow_controller.rb b/app/controllers/authorize_follow_controller.rb new file mode 100644 index 000000000..a276250a4 --- /dev/null +++ b/app/controllers/authorize_follow_controller.rb @@ -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 diff --git a/app/helpers/authorize_follow_helper.rb b/app/helpers/authorize_follow_helper.rb new file mode 100644 index 000000000..43659ccfa --- /dev/null +++ b/app/helpers/authorize_follow_helper.rb @@ -0,0 +1,2 @@ +module AuthorizeFollowHelper +end diff --git a/app/views/accounts/_grid_card.html.haml b/app/views/accounts/_grid_card.html.haml index dfd7a9f5e..dfdb23161 100644 --- a/app/views/accounts/_grid_card.html.haml +++ b/app/views/accounts/_grid_card.html.haml @@ -1,6 +1,6 @@ .account-grid-card .account-grid-card__header - .avatar= image_tag account.avatar.url( :original) + .avatar= image_tag account.avatar.url(:original) .name = link_to TagManager.instance.url_for(account) do %span.display_name= display_name(account) diff --git a/app/views/authorize_follow/error.html.haml b/app/views/authorize_follow/error.html.haml new file mode 100644 index 000000000..88d33b68d --- /dev/null +++ b/app/views/authorize_follow/error.html.haml @@ -0,0 +1,3 @@ +.form-container + .flash-message#error_explanation + = t('authorize_follow.error') diff --git a/app/views/authorize_follow/new.html.haml b/app/views/authorize_follow/new.html.haml new file mode 100644 index 000000000..7368b834a --- /dev/null +++ b/app/views/authorize_follow/new.html.haml @@ -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 diff --git a/app/views/oauth/authorizations/error.html.haml b/app/views/oauth/authorizations/error.html.haml index ee72d9740..408ca2b86 100644 --- a/app/views/oauth/authorizations/error.html.haml +++ b/app/views/oauth/authorizations/error.html.haml @@ -1,2 +1,3 @@ -.flash-message#error_explanation - = @pre_auth.error_response.body[:error_description] +.form-container + .flash-message#error_explanation + = @pre_auth.error_response.body[:error_description] diff --git a/app/views/oauth/authorizations/new.html.haml b/app/views/oauth/authorizations/new.html.haml index f058e2cce..1f951c272 100644 --- a/app/views/oauth/authorizations/new.html.haml +++ b/app/views/oauth/authorizations/new.html.haml @@ -1,25 +1,26 @@ - content_for :page_title do = t('doorkeeper.authorizations.new.title') -.oauth-prompt - %h2= t('doorkeeper.authorizations.new.prompt', client_name: @pre_auth.client.name) +.form-container + .oauth-prompt + %h2= t('doorkeeper.authorizations.new.prompt', client_name: @pre_auth.client.name) - %p - = t('doorkeeper.authorizations.new.able_to') - = @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| "#{s}"}.to_sentence.html_safe + %p + = t('doorkeeper.authorizations.new.able_to') + = @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| "#{s}"}.to_sentence.html_safe -= form_tag oauth_authorization_path, method: :post, class: 'simple_form' do - = hidden_field_tag :client_id, @pre_auth.client.uid - = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri - = hidden_field_tag :state, @pre_auth.state - = hidden_field_tag :response_type, @pre_auth.response_type - = hidden_field_tag :scope, @pre_auth.scope - = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit + = form_tag oauth_authorization_path, method: :post, class: 'simple_form' do + = hidden_field_tag :client_id, @pre_auth.client.uid + = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri + = hidden_field_tag :state, @pre_auth.state + = hidden_field_tag :response_type, @pre_auth.response_type + = hidden_field_tag :scope, @pre_auth.scope + = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit -= form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do - = hidden_field_tag :client_id, @pre_auth.client.uid - = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri - = hidden_field_tag :state, @pre_auth.state - = hidden_field_tag :response_type, @pre_auth.response_type - = hidden_field_tag :scope, @pre_auth.scope - = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative' + = form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do + = hidden_field_tag :client_id, @pre_auth.client.uid + = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri + = hidden_field_tag :state, @pre_auth.state + = hidden_field_tag :response_type, @pre_auth.response_type + = hidden_field_tag :scope, @pre_auth.scope + = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative' diff --git a/app/views/oauth/authorizations/show.html.haml b/app/views/oauth/authorizations/show.html.haml index 897a15cee..b56667f35 100644 --- a/app/views/oauth/authorizations/show.html.haml +++ b/app/views/oauth/authorizations/show.html.haml @@ -1,2 +1,3 @@ -.flash-message - %code= params[:code] +.form-container + .flash-message + %code= params[:code] diff --git a/app/views/xrd/webfinger.json.rabl b/app/views/xrd/webfinger.json.rabl index 0de17ac19..e637ed9d3 100644 --- a/app/views/xrd/webfinger.json.rabl +++ b/app/views/xrd/webfinger.json.rabl @@ -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://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: '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 diff --git a/app/views/xrd/webfinger.xml.ruby b/app/views/xrd/webfinger.xml.ruby index ee5b5fc9d..80ac71d27 100644 --- a/app/views/xrd/webfinger.xml.ruby +++ b/app/views/xrd/webfinger.xml.ruby @@ -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: 'salmon', href: api_salmon_url(@account.id)) 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.to_xml diff --git a/config/application.rb b/config/application.rb index 091f9c535..79ace8521 100644 --- a/config/application.rb +++ b/config/application.rb @@ -45,7 +45,7 @@ module Mastodon config.browserify_rails.commandline_options = '--transform [ babelify --presets [ es2015 react ] ] --extension=".jsx"' config.to_prepare do - Doorkeeper::AuthorizationsController.layout 'auth' + Doorkeeper::AuthorizationsController.layout 'public' end config.action_dispatch.default_headers = { diff --git a/config/locales/en.yml b/config/locales/en.yml index 760078862..f57c72026 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -26,6 +26,11 @@ en: resend_confirmation: Resend confirmation instructions reset_password: Reset 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 (%{self}) have requested to follow:' + title: Follow %{acct} datetime: distance_in_words: about_x_hours: "%{count}h" diff --git a/config/routes.rb b/config/routes.rb index 985d6583d..1468d426b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,6 +48,10 @@ Rails.application.routes.draw do resources :media, 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 resources :pubsubhubbub, only: [:index] resources :domain_blocks, only: [:index, :create] diff --git a/spec/controllers/authorize_follow_controller_spec.rb b/spec/controllers/authorize_follow_controller_spec.rb new file mode 100644 index 000000000..954efd53e --- /dev/null +++ b/spec/controllers/authorize_follow_controller_spec.rb @@ -0,0 +1,6 @@ +require 'rails_helper' + +RSpec.describe AuthorizeFollowController, type: :controller do + describe 'GET #new' + describe 'POST #create' +end diff --git a/spec/helpers/authorize_follow_helper_spec.rb b/spec/helpers/authorize_follow_helper_spec.rb new file mode 100644 index 000000000..ba5b0a70b --- /dev/null +++ b/spec/helpers/authorize_follow_helper_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe AuthorizeFollowHelper, type: :helper do + +end -- cgit From 8724094ed0e531f4435bf2784c9c1b7176acd764 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 29 Dec 2016 17:23:27 +0100 Subject: Support remote follow request providing URL instead of acct --- app/assets/stylesheets/accounts.scss | 4 ++++ app/controllers/authorize_follow_controller.rb | 19 ++++++++++++++++++- app/views/authorize_follow/new.html.haml | 3 ++- 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'app/assets/stylesheets') diff --git a/app/assets/stylesheets/accounts.scss b/app/assets/stylesheets/accounts.scss index 5d0963307..748bb8224 100644 --- a/app/assets/stylesheets/accounts.scss +++ b/app/assets/stylesheets/accounts.scss @@ -337,6 +337,10 @@ overflow: hidden; margin-bottom: 15px; + &:last-child { + margin-bottom: 0; + } + & > div { float: left; margin-right: 10px; diff --git a/app/controllers/authorize_follow_controller.rb b/app/controllers/authorize_follow_controller.rb index a276250a4..ca72c9691 100644 --- a/app/controllers/authorize_follow_controller.rb +++ b/app/controllers/authorize_follow_controller.rb @@ -6,7 +6,14 @@ class AuthorizeFollowController < ApplicationController before_action :authenticate_user! def new - @account = FollowRemoteAccountService.new.call(params[:acct]) + uri = Addressable::URI.parse(params[:acct]) + + if uri.path && %w(http https).include?(uri.scheme) + set_account_from_url + else + set_account_from_acct + end + render :error if @account.nil? end @@ -21,4 +28,14 @@ class AuthorizeFollowController < ApplicationController rescue ActiveRecord::RecordNotFound, Mastodon::NotPermitted render :error end + + private + + def set_account_from_url + @account = FetchRemoteAccountService.new.call(params[:acct]) + end + + def set_account_from_acct + @account = FollowRemoteAccountService.new.call(params[:acct]) + end end diff --git a/app/views/authorize_follow/new.html.haml b/app/views/authorize_follow/new.html.haml index 7368b834a..44bf575ff 100644 --- a/app/views/authorize_follow/new.html.haml +++ b/app/views/authorize_follow/new.html.haml @@ -14,7 +14,8 @@ %strong= display_name(@account) %span= "@#{@account.acct}" - .account__header__content= Formatter.instance.simplified_format(@account) + - unless @account.note.blank? + .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 -- cgit From 8f47f6a7ec4bdbf0a540efe3a3f9c6b493b2dc34 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 1 Jan 2017 19:52:25 +0100 Subject: Adding remote follow button --- Gemfile.lock | 10 +++-- .../features/account/components/header.jsx | 4 +- app/assets/stylesheets/components.scss | 8 +++- app/controllers/remote_follow_controller.rb | 47 ++++++++++++++++++++++ app/models/remote_follow.rb | 13 ++++++ app/views/accounts/_header.html.haml | 7 +++- app/views/authorize_follow/_card.html.haml | 11 +++++ app/views/authorize_follow/new.html.haml | 12 +----- app/views/remote_follow/new.html.haml | 13 ++++++ config/locales/en.yml | 6 +++ config/routes.rb | 3 ++ 11 files changed, 114 insertions(+), 20 deletions(-) create mode 100644 app/controllers/remote_follow_controller.rb create mode 100644 app/models/remote_follow.rb create mode 100644 app/views/authorize_follow/_card.html.haml create mode 100644 app/views/remote_follow/new.html.haml (limited to 'app/assets/stylesheets') diff --git a/Gemfile.lock b/Gemfile.lock index b01ac36eb..2467b76cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,7 +39,8 @@ GEM i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.4.0) + addressable (2.5.0) + public_suffix (~> 2.0, >= 2.0.2) arel (7.1.4) ast (2.3.0) autoprefixer-rails (6.5.0.2) @@ -98,7 +99,7 @@ GEM warden (~> 1.2.3) diff-lcs (1.2.5) docile (1.1.5) - domain_name (0.5.20160826) + domain_name (0.5.20161129) unf (>= 0.0.5, < 1.0.0) doorkeeper (4.2.0) railties (>= 4.2) @@ -121,7 +122,7 @@ GEM ruby-progressbar (~> 1.4) globalid (0.3.7) activesupport (>= 4.1.0) - goldfinger (1.1.0) + goldfinger (1.1.2) addressable (~> 2.4) http (~> 2.0) nokogiri (~> 1.6) @@ -138,7 +139,7 @@ GEM highline (1.7.8) hiredis (0.6.1) htmlentities (4.3.4) - http (2.0.3) + http (2.1.0) addressable (~> 2.3) http-cookie (~> 1.0) http-form_data (~> 1.0.1) @@ -226,6 +227,7 @@ GEM slop (~> 3.4) pry-rails (0.3.4) pry (>= 0.9.10) + public_suffix (2.0.4) puma (3.6.0) rabl (0.13.1) activesupport (>= 2.3.14) diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx index adf9ab5ae..6ae5ac002 100644 --- a/app/assets/javascripts/components/features/account/components/header.jsx +++ b/app/assets/javascripts/components/features/account/components/header.jsx @@ -61,10 +61,10 @@ const Header = React.createClass({ const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; return ( -
+
-
+
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 88808b085..290b370a9 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -147,6 +147,12 @@ } } +@media screen and (max-height: 800px) { + .account__header__avatar, .account__header__content { + display: none; + } +} + .account__header__content { word-wrap: break-word; font-weight: 300; @@ -585,4 +591,4 @@ pointer-events: none; bottom: 0; left: 0; -} \ No newline at end of file +} diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb new file mode 100644 index 000000000..5e923c88f --- /dev/null +++ b/app/controllers/remote_follow_controller.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class RemoteFollowController < ApplicationController + layout 'public' + + before_action :set_account + before_action :check_account_suspension + + def new + @remote_follow = RemoteFollow.new + end + + def create + @remote_follow = RemoteFollow.new(resource_params) + + if @remote_follow.valid? + resource = Goldfinger.finger("acct:#{@remote_follow.acct}") + redirect_url_link = resource&.link('http://ostatus.org/schema/1.0/subscribe') + + if redirect_url_link.nil? || redirect_url_link.template.nil? + @remote_follow.errors.add(:acct, I18n.t('remote_follow.missing_resource')) + render(:new) && return + end + + redirect_to Addressable::Template.new(redirect_url_link.template).expand(uri: "acct:#{@account.username}@#{Rails.configuration.x.local_domain}").to_s + else + render :new + end + rescue Goldfinger::Error + @remote_follow.errors.add(:acct, I18n.t('remote_follow.missing_resource')) + render :new + end + + private + + def resource_params + params.require(:remote_follow).permit(:acct) + end + + def set_account + @account = Account.find_local!(params[:account_username]) + end + + def check_account_suspension + head 410 if @account.suspended? + end +end diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb new file mode 100644 index 000000000..13281a4fc --- /dev/null +++ b/app/models/remote_follow.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class RemoteFollow + include ActiveModel::Validations + + attr_accessor :acct + + validates :acct, presence: true + + def initialize(attrs = {}) + @acct = attrs[:acct] + end +end diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 01e639205..1c6b5f0f6 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -5,8 +5,11 @@ = link_to t('accounts.unfollow'), unfollow_account_path(@account), data: { method: :post }, class: 'button' - else = link_to t('accounts.follow'), follow_account_path(@account), data: { method: :post }, class: 'button' - - .avatar= image_tag @account.avatar.url( :original) + - else + .controls + .remote-follow + = link_to t('accounts.remote_follow'), account_remote_follow_path(@account), class: 'button' + .avatar= image_tag @account.avatar.url(:original) %h1.name = display_name(@account) %small diff --git a/app/views/authorize_follow/_card.html.haml b/app/views/authorize_follow/_card.html.haml new file mode 100644 index 000000000..a9b02c746 --- /dev/null +++ b/app/views/authorize_follow/_card.html.haml @@ -0,0 +1,11 @@ +.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}" + + - unless account.note.blank? + .account__header__content= Formatter.instance.simplified_format(account) diff --git a/app/views/authorize_follow/new.html.haml b/app/views/authorize_follow/new.html.haml index 44bf575ff..95601253e 100644 --- a/app/views/authorize_follow/new.html.haml +++ b/app/views/authorize_follow/new.html.haml @@ -5,17 +5,7 @@ .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}" - - - unless @account.note.blank? - .account__header__content= Formatter.instance.simplified_format(@account) + = render partial: 'card', locals: { account: @account } = form_tag authorize_follow_path, method: :post, class: 'simple_form' do = hidden_field_tag :acct, @account.acct diff --git a/app/views/remote_follow/new.html.haml b/app/views/remote_follow/new.html.haml new file mode 100644 index 000000000..e88ccccce --- /dev/null +++ b/app/views/remote_follow/new.html.haml @@ -0,0 +1,13 @@ +.form-container + .follow-prompt + %h2= t('remote_follow.prompt') + + = render partial: 'authorize_follow/card', locals: { account: @account } + + = simple_form_for @remote_follow, as: :remote_follow, url: account_remote_follow_path(@account) do |f| + = render 'shared/error_messages', object: @remote_follow + + = f.input :acct, placeholder: t('remote_follow.acct') + + .actions + = f.button :button, t('remote_follow.proceed'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index f57c72026..e166fc717 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -14,6 +14,7 @@ en: people_followed_by: People whom %{name} follows people_who_follow: People who follow %{name} posts: Posts + remote_follow: Remote follow unfollow: Unfollow application_mailer: signature: Mastodon notifications from %{instance} @@ -71,6 +72,11 @@ en: pagination: next: Next prev: Prev + remote_follow: + acct: Enter your username@domain you want to follow from + missing_resource: Could not find the required redirect URL for your account + proceed: Proceed to follow + prompt: 'You are going to follow:' settings: edit_profile: Edit profile preferences: Preferences diff --git a/config/routes.rb b/config/routes.rb index 842fbe71e..18c239c48 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,9 @@ Rails.application.routes.draw do end end + get :remote_follow, to: 'remote_follow#new' + post :remote_follow, to: 'remote_follow#create' + member do get :followers get :following -- cgit From 4d300e2507c1f8f5aeebc1079eeddcad1edca4a5 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Tue, 3 Jan 2017 00:36:48 -0800 Subject: On file-drag, show a border around textarea --- .../components/components/autosuggest_textarea.jsx | 41 ++++++++++++++++++++-- .../features/compose/components/compose_form.jsx | 2 ++ .../compose/containers/compose_form_container.jsx | 1 + .../javascripts/components/reducers/compose.jsx | 6 +++- app/assets/stylesheets/components.scss | 10 ++++-- 5 files changed, 54 insertions(+), 6 deletions(-) (limited to 'app/assets/stylesheets') diff --git a/app/assets/javascripts/components/components/autosuggest_textarea.jsx b/app/assets/javascripts/components/components/autosuggest_textarea.jsx index 8d9da1601..39ccbcaf9 100644 --- a/app/assets/javascripts/components/components/autosuggest_textarea.jsx +++ b/app/assets/javascripts/components/components/autosuggest_textarea.jsx @@ -32,6 +32,7 @@ const AutosuggestTextarea = React.createClass({ value: React.PropTypes.string, suggestions: ImmutablePropTypes.list, disabled: React.PropTypes.bool, + fileDropDate: React.PropTypes.instanceOf(Date), placeholder: React.PropTypes.string, onSuggestionSelected: React.PropTypes.func.isRequired, onSuggestionsClearRequested: React.PropTypes.func.isRequired, @@ -42,6 +43,8 @@ const AutosuggestTextarea = React.createClass({ getInitialState () { return { + isFileDragging: false, + fileDraggingDate: undefined, suggestionsHidden: false, selectedSuggestion: 0, lastToken: null, @@ -120,21 +123,51 @@ const AutosuggestTextarea = React.createClass({ if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) { this.setState({ suggestionsHidden: false }); } + + const fileDropDate = nextProps.fileDropDate; + const { isFileDragging, fileDraggingDate } = this.state; + + /* + * We can't detect drop events, because they might not be on the textarea (the app allows dropping anywhere in the + * window). Instead, on-drop, we notify this textarea to stop its hover effect by passing in a prop with the + * drop-date. + */ + if (isFileDragging && fileDraggingDate && fileDropDate // if dragging when props updated, and dates aren't undefined + && fileDropDate > fileDraggingDate) { // and if the drop date is now greater than when we started dragging + // then we should stop dragging + this.setState({ + isFileDragging: false + }); + } }, setTextarea (c) { this.textarea = c; }, + onDragEnter () { + this.setState({ + isFileDragging: true, + fileDraggingDate: new Date() + }) + }, + + onDragExit () { + this.setState({ + isFileDragging: false + }) + }, + render () { - const { value, suggestions, disabled, placeholder, onKeyUp } = this.props; - const { suggestionsHidden, selectedSuggestion } = this.state; + const { value, suggestions, fileDropDate, disabled, placeholder, onKeyUp } = this.props; + const { isFileDragging, suggestionsHidden, selectedSuggestion } = this.state; + const className = isFileDragging ? 'autosuggest-textarea__textarea file-drop' : 'autosuggest-textarea__textarea'; return (