Follow requests send e-mail notifications, but are excluded from notifications API
Better initial state for unlisted/nsfw toggles
This commit is contained in:
		| @@ -20,6 +20,7 @@ const messages = defineMessages({ | ||||
| const ComposeForm = React.createClass({ | ||||
|  | ||||
|   propTypes: { | ||||
|     intl: React.PropTypes.object.isRequired, | ||||
|     text: React.PropTypes.string.isRequired, | ||||
|     suggestion_token: React.PropTypes.string, | ||||
|     suggestions: ImmutablePropTypes.list, | ||||
| @@ -129,7 +130,7 @@ const ComposeForm = React.createClass({ | ||||
|           <span style={{ display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', marginLeft: '8px', color: '#9baec8' }}><FormattedMessage id='compose_form.private' defaultMessage='Mark as private' /></span> | ||||
|         </label> | ||||
|  | ||||
|         <Motion defaultStyle={{ opacity: 100, height: 39.5 }} style={{ opacity: spring(this.props.private ? 0 : 100), height: spring(this.props.private ? 0 : 39.5) }}> | ||||
|         <Motion defaultStyle={{ opacity: this.props.private ? 0 : 100, height: this.props.private ? 39.5 : 0 }} style={{ opacity: spring(this.props.private ? 0 : 100), height: spring(this.props.private ? 0 : 39.5) }}> | ||||
|           {({ opacity, height }) => | ||||
|             <label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle', height: `${height}px`, overflow: 'hidden', opacity: opacity / 100 }}> | ||||
|               <Toggle checked={this.props.unlisted} onChange={this.handleChangeListability} /> | ||||
| @@ -138,7 +139,7 @@ const ComposeForm = React.createClass({ | ||||
|           } | ||||
|         </Motion> | ||||
|  | ||||
|         <Motion defaultStyle={{ opacity: 100, height: 39.5 }} style={{ opacity: spring(this.props.media_count === 0 ? 0 : 100), height: spring(this.props.media_count === 0 ? 0 : 39.5) }}> | ||||
|         <Motion defaultStyle={{ opacity: 0, height: 0 }} style={{ opacity: spring(this.props.media_count === 0 ? 0 : 100), height: spring(this.props.media_count === 0 ? 0 : 39.5) }}> | ||||
|           {({ opacity, height }) => | ||||
|             <label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle', height: `${height}px`, overflow: 'hidden', opacity: opacity / 100 }}> | ||||
|               <Toggle checked={this.props.sensitive} onChange={this.handleChangeSensitivity} /> | ||||
|   | ||||
| @@ -35,7 +35,7 @@ const AccountAuthorize = ({ intl, account, onAuthorize, onReject }) => { | ||||
|   return ( | ||||
|     <div> | ||||
|       <div style={outerStyle}> | ||||
|         <Permalink href={account.get('url')} className='detailed-status__display-name' style={{ display: 'block', overflow: 'hidden', marginBottom: '15px' }}> | ||||
|         <Permalink href={account.get('url')} to={`/accounts/${account.get('id')}`} className='detailed-status__display-name' style={{ display: 'block', overflow: 'hidden', marginBottom: '15px' }}> | ||||
|           <div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={48} /></div> | ||||
|           <DisplayName account={account} /> | ||||
|         </Permalink> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ class Api::V1::NotificationsController < ApiController | ||||
|   respond_to :json | ||||
|  | ||||
|   def index | ||||
|     @notifications = Notification.where(account: current_account).paginate_by_max_id(20, params[:max_id], params[:since_id]) | ||||
|     @notifications = Notification.where(account: current_account).browserable.paginate_by_max_id(20, params[:max_id], params[:since_id]) | ||||
|     @notifications = cache_collection(@notifications, Notification) | ||||
|     statuses       = @notifications.select { |n| !n.target_status.nil? }.map(&:target_status) | ||||
|  | ||||
|   | ||||
| @@ -40,4 +40,13 @@ class NotificationMailer < ApplicationMailer | ||||
|       mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def follow_request(recipient, notification) | ||||
|     @me      = recipient | ||||
|     @account = notification.from_account | ||||
|  | ||||
|     I18n.with_locale(@me.user.locale || I18n.default_locale) do | ||||
|       mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -6,6 +6,8 @@ class FollowRequest < ApplicationRecord | ||||
|   belongs_to :account | ||||
|   belongs_to :target_account, class_name: 'Account' | ||||
|  | ||||
|   has_one :notification, as: :activity, dependent: :destroy | ||||
|  | ||||
|   validates :account, :target_account, presence: true | ||||
|   validates :account_id, uniqueness: { scope: :target_account_id } | ||||
|  | ||||
|   | ||||
| @@ -8,16 +8,18 @@ class Notification < ApplicationRecord | ||||
|   belongs_to :from_account, class_name: 'Account' | ||||
|   belongs_to :activity, polymorphic: true | ||||
|  | ||||
|   belongs_to :mention,   foreign_type: 'Mention',   foreign_key: 'activity_id' | ||||
|   belongs_to :status,    foreign_type: 'Status',    foreign_key: 'activity_id' | ||||
|   belongs_to :follow,    foreign_type: 'Follow',    foreign_key: 'activity_id' | ||||
|   belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id' | ||||
|   belongs_to :mention,        foreign_type: 'Mention',       foreign_key: 'activity_id' | ||||
|   belongs_to :status,         foreign_type: 'Status',        foreign_key: 'activity_id' | ||||
|   belongs_to :follow,         foreign_type: 'Follow',        foreign_key: 'activity_id' | ||||
|   belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id' | ||||
|   belongs_to :favourite,      foreign_type: 'Favourite',     foreign_key: 'activity_id' | ||||
|  | ||||
|   validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] } | ||||
|  | ||||
|   STATUS_INCLUDES = [:account, :stream_entry, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :media_attachments, :tags, mentions: :account]].freeze | ||||
|  | ||||
|   scope :cache_ids, -> { select(:id, :updated_at, :activity_type, :activity_id) } | ||||
|   scope :browserable, -> { where.not(activity_type: ['FollowRequest']) } | ||||
|  | ||||
|   cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account | ||||
|  | ||||
| @@ -30,7 +32,7 @@ class Notification < ApplicationRecord | ||||
|     when 'Status' | ||||
|       :reblog | ||||
|     else | ||||
|       activity_type.downcase.to_sym | ||||
|       activity_type.underscore.to_sym | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @@ -43,6 +45,10 @@ class Notification < ApplicationRecord | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def browserable? | ||||
|     type != :follow_request | ||||
|   end | ||||
|  | ||||
|   class << self | ||||
|     def reload_stale_associations!(cached_items) | ||||
|       account_ids = cached_items.map(&:from_account_id).uniq | ||||
| @@ -61,7 +67,7 @@ class Notification < ApplicationRecord | ||||
|  | ||||
|   def set_from_account | ||||
|     case activity_type | ||||
|     when 'Status', 'Follow', 'Favourite' | ||||
|     when 'Status', 'Follow', 'Favourite', 'FollowRequest' | ||||
|       self.from_account_id = activity(false)&.account_id | ||||
|     when 'Mention' | ||||
|       self.from_account_id = activity(false)&.status&.account_id | ||||
|   | ||||
| @@ -15,7 +15,7 @@ class User < ApplicationRecord | ||||
|   scope :admins,   -> { where(admin: true) } | ||||
|  | ||||
|   has_settings do |s| | ||||
|     s.key :notification_emails, defaults: { follow: false, reblog: false, favourite: false, mention: false } | ||||
|     s.key :notification_emails, defaults: { follow: false, reblog: false, favourite: false, mention: false, follow_request: true } | ||||
|     s.key :interactions, defaults: { must_be_follower: false, must_be_following: false } | ||||
|   end | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,12 @@ class FollowService < BaseService | ||||
|   private | ||||
|  | ||||
|   def request_follow(source_account, target_account) | ||||
|     FollowRequest.create!(account: source_account, target_account: target_account) | ||||
|     return unless target_account.local? | ||||
|  | ||||
|     follow_request = FollowRequest.create!(account: source_account, target_account: target_account) | ||||
|     NotifyService.new.call(target_account, follow_request) | ||||
|  | ||||
|     follow_request | ||||
|   end | ||||
|  | ||||
|   def direct_follow(source_account, target_account) | ||||
|   | ||||
| @@ -32,6 +32,10 @@ class NotifyService < BaseService | ||||
|     false | ||||
|   end | ||||
|  | ||||
|   def blocked_follow_request? | ||||
|     false | ||||
|   end | ||||
|  | ||||
|   def blocked? | ||||
|     blocked   = @recipient.suspended?                                                                                             # Skip if the recipient account is suspended anyway | ||||
|     blocked ||= @recipient.id == @notification.from_account.id                                                                    # Skip for interactions with self | ||||
| @@ -45,6 +49,7 @@ class NotifyService < BaseService | ||||
|  | ||||
|   def create_notification | ||||
|     @notification.save! | ||||
|     return unless @notification.browserable? | ||||
|     FeedManager.instance.broadcast(@recipient.id, type: 'notification', message: FeedManager.instance.inline_render(@recipient, 'api/v1/notifications/show', @notification)) | ||||
|   end | ||||
|  | ||||
|   | ||||
							
								
								
									
										5
									
								
								app/views/notification_mailer/follow_request.text.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/views/notification_mailer/follow_request.text.erb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| <%= display_name(@me) %>, | ||||
|  | ||||
| <%= t('notification_mailer.follow_request.body', name: @account.acct) %> | ||||
|  | ||||
| <%= web_url("follow_requests") %> | ||||
| @@ -54,6 +54,9 @@ en: | ||||
|     follow: | ||||
|       body: "%{name} is now following you!" | ||||
|       subject: "%{name} is now following you" | ||||
|     follow_request: | ||||
|       body: "%{name} has requested to follow you" | ||||
|       subject: 'Pending follower: %{name}' | ||||
|     mention: | ||||
|       body: 'You were mentioned by %{name} in:' | ||||
|       subject: You were mentioned by %{name} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user