about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/admin/reports_controller.rb3
-rw-r--r--app/helpers/admin/filter_helper.rb2
-rw-r--r--app/javascript/mastodon/components/modal_root.js14
-rw-r--r--app/javascript/mastodon/features/direct_timeline/components/conversation.js5
-rw-r--r--app/javascript/styles/mastodon/components.scss26
-rw-r--r--app/lib/activitypub/activity/create.rb20
-rw-r--r--app/models/concerns/ldap_authenticable.rb12
-rw-r--r--app/models/report_filter.rb2
-rw-r--r--app/views/admin/reports/index.html.haml14
-rw-r--r--app/views/relationships/show.html.haml4
10 files changed, 84 insertions, 18 deletions
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index f138376b2..09ce1761c 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -55,7 +55,8 @@ module Admin
       params.permit(
         :account_id,
         :resolved,
-        :target_account_id
+        :target_account_id,
+        :by_target_domain
       )
     end
 
diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb
index 8af1683e7..fc4f15985 100644
--- a/app/helpers/admin/filter_helper.rb
+++ b/app/helpers/admin/filter_helper.rb
@@ -2,7 +2,7 @@
 
 module Admin::FilterHelper
   ACCOUNT_FILTERS      = %i(local remote by_domain active pending silenced suspended username display_name email ip staff).freeze
-  REPORT_FILTERS       = %i(resolved account_id target_account_id).freeze
+  REPORT_FILTERS       = %i(resolved account_id target_account_id by_target_domain).freeze
   INVITE_FILTER        = %i(available expired).freeze
   CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
   TAGS_FILTERS         = %i(directory reviewed unreviewed pending_review popular active name).freeze
diff --git a/app/javascript/mastodon/components/modal_root.js b/app/javascript/mastodon/components/modal_root.js
index c55fa0f74..fa4e59192 100644
--- a/app/javascript/mastodon/components/modal_root.js
+++ b/app/javascript/mastodon/components/modal_root.js
@@ -56,15 +56,21 @@ export default class ModalRoot extends React.PureComponent {
     } else if (!nextProps.children) {
       this.setState({ revealed: false });
     }
-    if (!nextProps.children && !!this.props.children) {
-      this.activeElement.focus();
-      this.activeElement = null;
-    }
   }
 
   componentDidUpdate (prevProps) {
     if (!this.props.children && !!prevProps.children) {
       this.getSiblings().forEach(sibling => sibling.removeAttribute('inert'));
+
+      // Because of the wicg-inert polyfill, the activeElement may not be
+      // immediately selectable, we have to wait for observers to run, as
+      // described in https://github.com/WICG/inert#performance-and-gotchas
+      Promise.resolve().then(() => {
+        this.activeElement.focus();
+        this.activeElement = null;
+      }).catch((error) => {
+        console.error(error);
+      });
     }
     if (this.props.children) {
       requestAnimationFrame(() => {
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
index 2cbaa0791..235cb7ad8 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
@@ -12,6 +12,7 @@ import IconButton from 'mastodon/components/icon_button';
 import RelativeTimestamp from 'mastodon/components/relative_timestamp';
 import { HotKeys } from 'react-hotkeys';
 import { autoPlayGif } from 'mastodon/initial_state';
+import classNames from 'classnames';
 
 const messages = defineMessages({
   more: { id: 'status.more', defaultMessage: 'More' },
@@ -158,7 +159,7 @@ class Conversation extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={handlers}>
-        <div className='conversation focusable muted' tabIndex='0'>
+        <div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex='0'>
           <div className='conversation__avatar'>
             <AvatarComposite accounts={accounts} size={48} />
           </div>
@@ -166,7 +167,7 @@ class Conversation extends ImmutablePureComponent {
           <div className='conversation__content'>
             <div className='conversation__content__info'>
               <div className='conversation__content__relative-time'>
-                <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
+                {unread && <span className='conversation__unread' />} <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
               </div>
 
               <div className='conversation__content__names' ref={this.setNamesRef}>
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 3ba53f406..0ec25e3f8 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -6517,6 +6517,16 @@ noscript {
     flex: 0 0 auto;
     padding: 10px;
     padding-top: 12px;
+    position: relative;
+  }
+
+  &__unread {
+    display: inline-block;
+    background: $highlight-text-color;
+    border-radius: 50%;
+    width: 0.625rem;
+    height: 0.625rem;
+    margin: -.1ex .15em .1ex;
   }
 
   &__content {
@@ -6564,4 +6574,20 @@ noscript {
       word-break: break-word;
     }
   }
+
+  &--unread {
+    background: lighten($ui-base-color, 2%);
+
+    &:focus {
+      background: lighten($ui-base-color, 4%);
+    }
+
+    .conversation__content__info {
+      font-weight: 700;
+    }
+
+    .conversation__content__relative-time {
+      color: $primary-text-color;
+    }
+  }
 }
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index 76bf9b2e5..8a12a2b08 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -25,6 +25,14 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
 
   private
 
+  def audience_to
+    @object['to'] || @json['to']
+  end
+
+  def audience_cc
+    @object['cc'] || @json['cc']
+  end
+
   def process_status
     @tags     = []
     @mentions = []
@@ -75,7 +83,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   end
 
   def process_audience
-    (as_array(@object['to']) + as_array(@object['cc'])).uniq.each do |audience|
+    (as_array(audience_to) + as_array(audience_cc)).uniq.each do |audience|
       next if audience == ActivityPub::TagManager::COLLECTIONS[:public]
 
       # Unlike with tags, there is no point in resolving accounts we don't already
@@ -291,11 +299,11 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   end
 
   def visibility_from_audience
-    if equals_or_includes?(@object['to'], ActivityPub::TagManager::COLLECTIONS[:public])
+    if equals_or_includes?(audience_to, ActivityPub::TagManager::COLLECTIONS[:public])
       :public
-    elsif equals_or_includes?(@object['cc'], ActivityPub::TagManager::COLLECTIONS[:public])
+    elsif equals_or_includes?(audience_cc, ActivityPub::TagManager::COLLECTIONS[:public])
       :unlisted
-    elsif equals_or_includes?(@object['to'], @account.followers_url)
+    elsif equals_or_includes?(audience_to, @account.followers_url)
       :private
     else
       :direct
@@ -304,7 +312,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
 
   def audience_includes?(account)
     uri = ActivityPub::TagManager.instance.uri_for(account)
-    equals_or_includes?(@object['to'], uri) || equals_or_includes?(@object['cc'], uri)
+    equals_or_includes?(audience_to, uri) || equals_or_includes?(audience_cc, uri)
   end
 
   def replied_to_status
@@ -415,7 +423,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   def addresses_local_accounts?
     return true if @options[:delivered_to_account_id]
 
-    local_usernames = (as_array(@object['to']) + as_array(@object['cc'])).uniq.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) }
+    local_usernames = (as_array(audience_to) + as_array(audience_cc)).uniq.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) }
 
     return false if local_usernames.empty?
 
diff --git a/app/models/concerns/ldap_authenticable.rb b/app/models/concerns/ldap_authenticable.rb
index 117993947..2d2e1edbb 100644
--- a/app/models/concerns/ldap_authenticable.rb
+++ b/app/models/concerns/ldap_authenticable.rb
@@ -14,10 +14,18 @@ module LdapAuthenticable
     end
 
     def ldap_get_user(attributes = {})
-      resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
+      safe_username = attributes[Devise.ldap_uid.to_sym].first
+      if Devise.ldap_uid_conversion_enabled
+        keys = Regexp.union(Devise.ldap_uid_conversion_search.chars)
+        replacement = Devise.ldap_uid_conversion_replace
+
+        safe_username = safe_username.gsub(keys, replacement)
+      end
+
+      resource = joins(:account).find_by(accounts: { username: safe_username })
 
       if resource.blank?
-        resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first }, admin: false, external: true, confirmed_at: Time.now.utc)
+        resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc)
         resource.save!
       end
 
diff --git a/app/models/report_filter.rb b/app/models/report_filter.rb
index a392d60c3..abf53cbab 100644
--- a/app/models/report_filter.rb
+++ b/app/models/report_filter.rb
@@ -19,6 +19,8 @@ class ReportFilter
 
   def scope_for(key, value)
     case key.to_sym
+    when :by_target_domain
+      Report.where(target_account: Account.where(domain: value))
     when :resolved
       Report.resolved
     when :account_id
diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml
index bfbd32108..b09472270 100644
--- a/app/views/admin/reports/index.html.haml
+++ b/app/views/admin/reports/index.html.haml
@@ -8,6 +8,20 @@
       %li= filter_link_to t('admin.reports.unresolved'), resolved: nil
       %li= filter_link_to t('admin.reports.resolved'), resolved: '1'
 
+= form_tag admin_reports_url, method: 'GET', class: 'simple_form' do
+  .fields-group
+    - Admin::FilterHelper::REPORT_FILTERS.each do |key|
+      - if params[key].present?
+        = hidden_field_tag key, params[key]
+
+    - %i(by_target_domain).each do |key|
+      .input.string.optional
+        = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.reports.#{key}")
+
+    .actions
+      %button= t('admin.accounts.search')
+      = link_to t('admin.accounts.reset'), admin_reports_path, class: 'button negative'
+
 - @reports.group_by(&:target_account_id).each do |target_account_id, reports|
   - target_account = reports.first.target_account
   .report-card
diff --git a/app/views/relationships/show.html.haml b/app/views/relationships/show.html.haml
index 1de4e373f..408390a35 100644
--- a/app/views/relationships/show.html.haml
+++ b/app/views/relationships/show.html.haml
@@ -5,8 +5,8 @@
   .filter-subset
     %strong= t 'relationships.relationship'
     %ul
-      %li= filter_link_to t('accounts.following', count: current_account.following_count), relationship: nil
-      %li= filter_link_to t('accounts.followers', count: current_account.followers_count), relationship: 'followed_by'
+      %li= filter_link_to t('relationships.following'), relationship: nil
+      %li= filter_link_to t('relationships.followers'), relationship: 'followed_by'
       %li= filter_link_to t('relationships.mutual'), relationship: 'mutual'
 
   .filter-subset