From 8da4bf0f901d7b20f3ca7c6975a0d21a56fb735c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 5 May 2018 21:11:19 +0200 Subject: 4 profile fields max, store only 255 characters per name/value (#7348) Fix #7303 --- app/models/account.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'app/models/account.rb') diff --git a/app/models/account.rb b/app/models/account.rb index a166fb474..72ba0398e 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -74,6 +74,7 @@ class Account < ApplicationRecord validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? } validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? } validates :note, length: { maximum: 160 }, if: -> { local? && will_save_change_to_note? } + validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? } # Timelines has_many :stream_entries, inverse_of: :account, dependent: :destroy @@ -198,9 +199,11 @@ class Account < ApplicationRecord def fields_attributes=(attributes) fields = [] - attributes.each_value do |attr| - next if attr[:name].blank? - fields << attr + if attributes.is_a?(Hash) + attributes.each_value do |attr| + next if attr[:name].blank? + fields << attr + end end self[:fields] = fields @@ -269,8 +272,8 @@ class Account < ApplicationRecord def initialize(account, attr) @account = account - @name = attr['name'] - @value = attr['value'] + @name = attr['name'].strip[0, 255] + @value = attr['value'].strip[0, 255] @errors = {} end -- cgit From 61a90186070395e133ad2f8e959bdf003a8615ca Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 6 May 2018 11:48:51 +0200 Subject: Enable custom emojis in profiles (notes, field values, display names) (#7374) Follow-up to #6124 --- app/helpers/stream_entries_helper.rb | 4 ++-- .../mastodon/actions/importer/normalizer.js | 19 +++++++++++-------- app/lib/formatter.rb | 12 ++++++++++-- app/models/account.rb | 6 +++++- app/serializers/rest/account_serializer.rb | 1 + app/views/about/_administration.html.haml | 2 +- app/views/about/_contact.html.haml | 2 +- app/views/accounts/_grid_card.html.haml | 2 +- app/views/accounts/_header.html.haml | 4 ++-- app/views/accounts/_moved_strip.html.haml | 4 ++-- app/views/admin/reports/_account.html.haml | 2 +- app/views/authorize_follows/_card.html.haml | 2 +- app/views/remote_unfollows/_card.html.haml | 2 +- app/views/shared/_landing_strip.html.haml | 2 +- app/views/stream_entries/_detailed_status.html.haml | 2 +- app/views/stream_entries/_simple_status.html.haml | 2 +- app/views/stream_entries/_status.html.haml | 2 +- 17 files changed, 43 insertions(+), 27 deletions(-) (limited to 'app/models/account.rb') diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index c6f12ecd4..707c8e26c 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -4,8 +4,8 @@ module StreamEntriesHelper EMBEDDED_CONTROLLER = 'statuses' EMBEDDED_ACTION = 'embed' - def display_name(account) - account.display_name.presence || account.username + def display_name(account, **options) + Formatter.instance.format_display_name(account, options) end def account_description(account) diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index 5f1274fab..057bff58b 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -3,18 +3,25 @@ import emojify from '../../features/emoji/emoji'; const domParser = new DOMParser(); +const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => { + obj[`:${emoji.shortcode}:`] = emoji; + return obj; +}, {}); + export function normalizeAccount(account) { account = { ...account }; + const emojiMap = makeEmojiMap(account); const displayName = account.display_name.length === 0 ? account.username : account.display_name; - account.display_name_html = emojify(escapeTextContentForBrowser(displayName)); - account.note_emojified = emojify(account.note); + + account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap); + account.note_emojified = emojify(account.note, emojiMap); if (account.fields) { account.fields = account.fields.map(pair => ({ ...pair, name_emojified: emojify(escapeTextContentForBrowser(pair.name)), - value_emojified: emojify(pair.value), + value_emojified: emojify(pair.value, emojiMap), })); } @@ -42,11 +49,7 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.hidden = normalOldStatus.get('hidden'); } else { const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(//g, '\n').replace(/<\/p>

/g, '\n\n'); - - const emojiMap = normalStatus.emojis.reduce((obj, emoji) => { - obj[`:${emoji.shortcode}:`] = emoji; - return obj; - }, {}); + const emojiMap = makeEmojiMap(normalStatus); normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; normalStatus.contentHtml = emojify(normalStatus.content, emojiMap); diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 050c651ee..e1ab05cc0 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -67,9 +67,17 @@ class Formatter html.html_safe # rubocop:disable Rails/OutputSafety end - def format_field(account, str) + def format_display_name(account, **options) + html = encode(account.display_name.presence || account.username) + html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify] + html.html_safe # rubocop:disable Rails/OutputSafety + end + + def format_field(account, str, **options) return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety - encode_and_link_urls(str, me: true).html_safe # rubocop:disable Rails/OutputSafety + html = encode_and_link_urls(str, me: true) + html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify] + html.html_safe # rubocop:disable Rails/OutputSafety end def linkify(text) diff --git a/app/models/account.rb b/app/models/account.rb index 72ba0398e..4467d1512 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -398,7 +398,7 @@ class Account < ApplicationRecord end def emojis - @emojis ||= CustomEmoji.from_text(note, domain) + @emojis ||= CustomEmoji.from_text(emojifiable_text, domain) end before_create :generate_keys @@ -425,4 +425,8 @@ class Account < ApplicationRecord self.domain = TagManager.instance.normalize_domain(domain) end + + def emojifiable_text + [note, display_name, fields.map(&:value)].join(' ') + end end diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 863238eb7..8761bbb5e 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -8,6 +8,7 @@ class REST::AccountSerializer < ActiveModel::Serializer :followers_count, :following_count, :statuses_count has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested? + has_many :emojis, serializer: REST::CustomEmojiSerializer class FieldSerializer < ActiveModel::Serializer attributes :name, :value diff --git a/app/views/about/_administration.html.haml b/app/views/about/_administration.html.haml index ec5834f9c..02286d68b 100644 --- a/app/views/about/_administration.html.haml +++ b/app/views/about/_administration.html.haml @@ -6,7 +6,7 @@ .account__avatar{ style: "background-image: url(#{@instance_presenter.contact_account.avatar.url})" } %span.display-name %bdi - %strong.display-name__html.emojify= display_name(@instance_presenter.contact_account) + %strong.display-name__html.emojify= display_name(@instance_presenter.contact_account, custom_emojify: true) %span.display-name__account @#{@instance_presenter.contact_account.acct} - else .account__display-name diff --git a/app/views/about/_contact.html.haml b/app/views/about/_contact.html.haml index cf21ad5a3..3215d50b5 100644 --- a/app/views/about/_contact.html.haml +++ b/app/views/about/_contact.html.haml @@ -12,7 +12,7 @@ .avatar= image_tag contact.contact_account.avatar.url .name = link_to TagManager.instance.url_for(contact.contact_account) do - %span.display_name.emojify= display_name(contact.contact_account) + %span.display_name.emojify= display_name(contact.contact_account, custom_emojify: true) %span.username @#{contact.contact_account.acct} - else .owner diff --git a/app/views/accounts/_grid_card.html.haml b/app/views/accounts/_grid_card.html.haml index 95acbd581..a59ed128e 100644 --- a/app/views/accounts/_grid_card.html.haml +++ b/app/views/accounts/_grid_card.html.haml @@ -5,7 +5,7 @@ .avatar= image_tag account.avatar.url(:original) .name = link_to TagManager.instance.url_for(account) do - %span.display_name.emojify= display_name(account) + %span.display_name.emojify= display_name(account, custom_emojify: true) %span.username @#{account.local? ? account.local_username_and_domain : account.acct} = fa_icon('lock') if account.locked? diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 41315f039..13dcaf616 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -5,7 +5,7 @@ .card__bio %h1.name - %span.p-name.emojify= display_name(account) + %span.p-name.emojify= display_name(account, custom_emojify: true) %small< %span>< @#{account.local_username_and_domain} = fa_icon('lock') if account.locked? @@ -28,7 +28,7 @@ - account.fields.each do |field| %dl %dt.emojify{ title: field.name }= field.name - %dd.emojify{ title: field.value }= Formatter.instance.format_field(account, field.value) + %dd.emojify{ title: field.value }= Formatter.instance.format_field(account, field.value, custom_emojify: true) .details-counters .counter{ class: active_nav_class(short_account_url(account)) } diff --git a/app/views/accounts/_moved_strip.html.haml b/app/views/accounts/_moved_strip.html.haml index 6a14a5dd3..ae18c6dc7 100644 --- a/app/views/accounts/_moved_strip.html.haml +++ b/app/views/accounts/_moved_strip.html.haml @@ -3,7 +3,7 @@ .moved-strip .moved-strip__message = fa_icon 'suitcase' - = t('accounts.moved_html', name: content_tag(:strong, display_name(account), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention')) + = t('accounts.moved_html', name: content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention')) .moved-strip__card = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do @@ -13,5 +13,5 @@ .account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" } %span.display-name - %strong.emojify= display_name(moved_to_account) + %strong.emojify= display_name(moved_to_account, custom_emojify: true) %span @#{moved_to_account.acct} diff --git a/app/views/admin/reports/_account.html.haml b/app/views/admin/reports/_account.html.haml index 22b7a0861..9ac161c9c 100644 --- a/app/views/admin/reports/_account.html.haml +++ b/app/views/admin/reports/_account.html.haml @@ -15,5 +15,5 @@ .account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" } %span.display-name %bdi - %strong.display-name__html.emojify= display_name(account) + %strong.display-name__html.emojify= display_name(account, custom_emojify: true) %span.display-name__account @#{account.acct} diff --git a/app/views/authorize_follows/_card.html.haml b/app/views/authorize_follows/_card.html.haml index e81e292ba..9abcfd37e 100644 --- a/app/views/authorize_follows/_card.html.haml +++ b/app/views/authorize_follows/_card.html.haml @@ -6,7 +6,7 @@ %span.display-name - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do - %strong.emojify= display_name(account) + %strong.emojify= display_name(account, custom_emojify: true) %span @#{account.acct} - if account.note? diff --git a/app/views/remote_unfollows/_card.html.haml b/app/views/remote_unfollows/_card.html.haml index e81e292ba..9abcfd37e 100644 --- a/app/views/remote_unfollows/_card.html.haml +++ b/app/views/remote_unfollows/_card.html.haml @@ -6,7 +6,7 @@ %span.display-name - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do - %strong.emojify= display_name(account) + %strong.emojify= display_name(account, custom_emojify: true) %span @#{account.acct} - if account.note? diff --git a/app/views/shared/_landing_strip.html.haml b/app/views/shared/_landing_strip.html.haml index ae26fc1ff..78f5ed4bc 100644 --- a/app/views/shared/_landing_strip.html.haml +++ b/app/views/shared/_landing_strip.html.haml @@ -2,7 +2,7 @@ = image_tag asset_pack_path('logo.svg'), class: 'logo' %div - = t('landing_strip_html', name: content_tag(:span, display_name(account), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path)) + = t('landing_strip_html', name: content_tag(:span, display_name(account, custom_emojify: true), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path)) - if open_registrations? = t('landing_strip_signup_html', sign_up_path: new_user_registration_path) diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index afc66d148..c0f1e4f0f 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -4,7 +4,7 @@ .avatar = image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo' %span.display-name - %strong.p-name.emojify= display_name(status.account) + %strong.p-name.emojify= display_name(status.account, custom_emojify: true) %span= acct(status.account) - if embedded_view? diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index a6f5120fb..b89860ad9 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -10,7 +10,7 @@ %div = image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo' %span.display-name - %strong.p-name.emojify= display_name(status.account) + %strong.p-name.emojify= display_name(status.account, custom_emojify: true) %span= acct(status.account) .status__content.p-name.emojify< diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml index 9764bc74d..b87ca2177 100644 --- a/app/views/stream_entries/_status.html.haml +++ b/app/views/stream_entries/_status.html.haml @@ -28,7 +28,7 @@ = fa_icon('retweet fw') %span = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do - %strong.emojify= display_name(status.account) + %strong.emojify= display_name(status.account, custom_emojify: true) = t('stream_entries.reblogged') - elsif pinned .pre-header -- cgit From 42cd363542abf0a12a4e877b3ad26024f24577ef Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 May 2018 09:31:07 +0200 Subject: Bot nameplates (#7391) * Store actor type in database * Add bot nameplate to web UI, add setting to preferences, API, AP Fix #7365 * Fix code style issues --- app/controllers/api/v1/accounts/credentials_controller.rb | 2 +- app/controllers/settings/profiles_controller.rb | 2 +- app/javascript/mastodon/features/account/components/header.js | 4 ++++ app/javascript/styles/mastodon/components.scss | 6 ++++++ app/javascript/styles/mastodon/forms.scss | 4 ++++ app/models/account.rb | 11 +++++++++++ app/serializers/activitypub/actor_serializer.rb | 2 +- app/serializers/rest/account_serializer.rb | 2 +- app/services/activitypub/process_account_service.rb | 1 + app/views/accounts/_header.html.haml | 6 +++++- app/views/settings/profiles/show.html.haml | 3 +++ config/locales/en.yml | 1 + config/locales/simple_form.en.yml | 2 ++ db/migrate/20180506221944_add_actor_type_to_accounts.rb | 5 +++++ db/schema.rb | 3 ++- 15 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20180506221944_add_actor_type_to_accounts.rb (limited to 'app/models/account.rb') diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index a3c4008e6..259d07be8 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController private def account_params - params.permit(:display_name, :note, :avatar, :header, :locked, fields_attributes: [:name, :value]) + params.permit(:display_name, :note, :avatar, :header, :locked, :bot, fields_attributes: [:name, :value]) end def user_settings_params diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index 5d81668de..1b01fc75f 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -27,7 +27,7 @@ class Settings::ProfilesController < ApplicationController private def account_params - params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, fields_attributes: [:name, :value]) + params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, fields_attributes: [:name, :value]) end def set_account diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 47915e6fb..7358053da 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -131,6 +131,7 @@ export default class Header extends ImmutablePureComponent { const content = { __html: account.get('note_emojified') }; const displayNameHtml = { __html: account.get('display_name_html') }; const fields = account.get('fields'); + const badge = account.get('bot') ? (

) : null; return (
@@ -139,6 +140,9 @@ export default class Header extends ImmutablePureComponent { @{account.get('acct')} {lockedIcon} + + {badge} +
{fields.size > 0 && ( diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 3e2a1ae10..158bf6851 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5159,6 +5159,12 @@ noscript { } } +.account__header .roles { + margin-top: 20px; + margin-bottom: 20px; + padding: 0 15px; +} + .account__header .account__header__fields { font-size: 14px; line-height: 20px; diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index f97890187..de16784a8 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -87,6 +87,10 @@ code { align-items: flex-start; } + &.file .label_input { + flex-wrap: nowrap; + } + &.select .label_input { align-items: initial; } diff --git a/app/models/account.rb b/app/models/account.rb index 4467d1512..2b3ef5cdc 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -45,6 +45,7 @@ # moved_to_account_id :bigint(8) # featured_collection_url :string # fields :jsonb +# actor_type :string # class Account < ApplicationRecord @@ -149,6 +150,16 @@ class Account < ApplicationRecord moved_to_account_id.present? end + def bot? + %w(Application Service).include? actor_type + end + + alias bot bot? + + def bot=(val) + self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person' + end + def acct local? ? username : "#{username}@#{domain}" end diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index fcf3bdf17..41c9aa44e 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -37,7 +37,7 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer end def type - 'Person' + object.bot? ? 'Service' : 'Person' end def following diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 8761bbb5e..6adcd7039 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -3,7 +3,7 @@ class REST::AccountSerializer < ActiveModel::Serializer include RoutingHelper - attributes :id, :username, :acct, :display_name, :locked, :created_at, + attributes :id, :username, :acct, :display_name, :locked, :bot, :created_at, :note, :url, :avatar, :avatar_static, :header, :header_static, :followers_count, :following_count, :statuses_count diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index f67ebb443..cc416b671 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -71,6 +71,7 @@ class ActivityPub::ProcessAccountService < BaseService @account.note = @json['summary'] || '' @account.locked = @json['manuallyApprovesFollowers'] || false @account.fields = property_values || {} + @account.actor_type = @json['type'] end def set_fetchable_attributes! diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 13dcaf616..4098d6778 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -10,7 +10,11 @@ %span>< @#{account.local_username_and_domain} = fa_icon('lock') if account.locked? - - if Setting.show_staff_badge + - if account.bot? + .roles + .account-role.bot + = t 'accounts.roles.bot' + - elsif Setting.show_staff_badge - if account.user_admin? .roles .account-role.admin diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index f28834d72..a84f8a7da 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -19,6 +19,9 @@ .fields-group = f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked') + .fields-group + = f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot') + .fields-group .input.with_block_label %label= t('simple_form.labels.defaults.fields') diff --git a/config/locales/en.yml b/config/locales/en.yml index e18354eac..5369311ac 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -49,6 +49,7 @@ en: reserved_username: The username is reserved roles: admin: Admin + bot: Bot moderator: Mod unfollow: Unfollow admin: diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 7ba32906d..495c6166b 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -4,6 +4,7 @@ en: hints: defaults: avatar: PNG, GIF or JPG. At most 2MB. Will be downscaled to 400x400px + bot: Warns people that the account does not represent a person digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence display_name: one: 1 character left @@ -29,6 +30,7 @@ en: value: Content defaults: avatar: Avatar + bot: This is a bot account confirm_new_password: Confirm new password confirm_password: Confirm password current_password: Current password diff --git a/db/migrate/20180506221944_add_actor_type_to_accounts.rb b/db/migrate/20180506221944_add_actor_type_to_accounts.rb new file mode 100644 index 000000000..7cfed640f --- /dev/null +++ b/db/migrate/20180506221944_add_actor_type_to_accounts.rb @@ -0,0 +1,5 @@ +class AddActorTypeToAccounts < ActiveRecord::Migration[5.2] + def change + add_column :accounts, :actor_type, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 566a320d8..f7fa24b83 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_04_16_210259) do +ActiveRecord::Schema.define(version: 2018_05_06_221944) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -75,6 +75,7 @@ ActiveRecord::Schema.define(version: 2018_04_16_210259) do t.bigint "moved_to_account_id" t.string "featured_collection_url" t.jsonb "fields" + t.string "actor_type" t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower" t.index ["uri"], name: "index_accounts_on_uri" -- cgit From 1e02dc871533de78174b48a6a527f11b0f2bc7ec Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 18 May 2018 02:26:51 +0200 Subject: Add preference to hide following/followers lists (#7532) * Add preference to hide following/followers lists - Public pages - ActivityPub collections (does not return pages but does give total) - REST API (unless it's your own) (does not federate) Fix #6901 * Add preference * Add delegation * Fix issue * Fix issue --- .../api/v1/accounts/follower_accounts_controller.rb | 2 ++ .../api/v1/accounts/following_accounts_controller.rb | 2 ++ app/controllers/follower_accounts_controller.rb | 4 ++++ app/controllers/following_accounts_controller.rb | 4 ++++ app/controllers/settings/preferences_controller.rb | 1 + app/javascript/styles/mastodon/accounts.scss | 13 +++++++++++-- app/javascript/styles/mastodon/footer.scss | 2 +- app/lib/user_settings_decorator.rb | 5 +++++ app/models/account.rb | 1 + app/models/user.rb | 6 +++++- app/views/accounts/_follow_grid.html.haml | 3 ++- app/views/accounts/_follow_grid_hidden.html.haml | 3 +++ app/views/follower_accounts/index.html.haml | 5 ++++- app/views/following_accounts/index.html.haml | 5 ++++- app/views/layouts/public.html.haml | 4 ++-- app/views/settings/preferences/show.html.haml | 3 +++ config/locales/en.yml | 1 + config/locales/simple_form.en.yml | 2 ++ config/settings.yml | 1 + 19 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 app/views/accounts/_follow_grid_hidden.html.haml (limited to 'app/models/account.rb') diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index c4f600c54..4578cf6ca 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -19,6 +19,8 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController end def load_accounts + return [] if @account.user_hides_network? && current_account.id != @account.id + default_accounts.merge(paginated_follows).to_a end diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 90b1f7fc5..ce2bbda85 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -19,6 +19,8 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController end def load_accounts + return [] if @account.user_hides_network? && current_account.id != @account.id + default_accounts.merge(paginated_follows).to_a end diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb index ac0d4c54e..99cb3676f 100644 --- a/app/controllers/follower_accounts_controller.rb +++ b/app/controllers/follower_accounts_controller.rb @@ -6,11 +6,15 @@ class FollowerAccountsController < ApplicationController def index respond_to do |format| format.html do + next if @account.user_hides_network? + follows @relationships = AccountRelationshipsPresenter.new(follows.map(&:account_id), current_user.account_id) if user_signed_in? end format.json do + raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? + render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb index 974d95c8e..03c4b1046 100644 --- a/app/controllers/following_accounts_controller.rb +++ b/app/controllers/following_accounts_controller.rb @@ -6,11 +6,15 @@ class FollowingAccountsController < ApplicationController def index respond_to do |format| format.html do + next if @account.user_hides_network? + follows @relationships = AccountRelationshipsPresenter.new(follows.map(&:target_account_id), current_user.account_id) if user_signed_in? end format.json do + raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? + render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index 839763138..57793d776 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -44,6 +44,7 @@ class Settings::PreferencesController < ApplicationController :setting_system_font_ui, :setting_noindex, :setting_theme, + :setting_hide_network, notification_emails: %i(follow follow_request reblog favourite mention digest), interactions: %i(must_be_follower must_be_following) ) diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss index b063ca52d..93aa134cf 100644 --- a/app/javascript/styles/mastodon/accounts.scss +++ b/app/javascript/styles/mastodon/accounts.scss @@ -322,6 +322,15 @@ z-index: 2; position: relative; + &.empty img { + position: absolute; + opacity: 0.2; + height: 200px; + left: 0; + bottom: 0; + pointer-events: none; + } + @media screen and (max-width: 740px) { border-radius: 0; box-shadow: none; @@ -438,8 +447,8 @@ font-size: 14px; font-weight: 500; text-align: center; - padding: 60px 0; - padding-top: 55px; + padding: 130px 0; + padding-top: 125px; margin: 0 auto; cursor: default; } diff --git a/app/javascript/styles/mastodon/footer.scss b/app/javascript/styles/mastodon/footer.scss index ba2a06954..dd3c1b688 100644 --- a/app/javascript/styles/mastodon/footer.scss +++ b/app/javascript/styles/mastodon/footer.scss @@ -4,7 +4,7 @@ font-size: 12px; color: $darker-text-color; - .domain { + .footer__domain { font-weight: 500; a { diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index 9260a81bc..a82f8974b 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -28,6 +28,7 @@ class UserSettingsDecorator user.settings['system_font_ui'] = system_font_ui_preference if change?('setting_system_font_ui') user.settings['noindex'] = noindex_preference if change?('setting_noindex') user.settings['theme'] = theme_preference if change?('setting_theme') + user.settings['hide_network'] = hide_network_preference if change?('setting_hide_network') end def merged_notification_emails @@ -78,6 +79,10 @@ class UserSettingsDecorator boolean_cast_setting 'setting_noindex' end + def hide_network_preference + boolean_cast_setting 'setting_hide_network' + end + def theme_preference settings['setting_theme'] end diff --git a/app/models/account.rb b/app/models/account.rb index 2b3ef5cdc..72e850aa7 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -136,6 +136,7 @@ class Account < ApplicationRecord :moderator?, :staff?, :locale, + :hides_network?, to: :user, prefix: true, allow_nil: true diff --git a/app/models/user.rb b/app/models/user.rb index 21c217e77..cfbae58ed 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -86,7 +86,7 @@ class User < ApplicationRecord has_many :session_activations, dependent: :destroy delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal, - :reduce_motion, :system_font_ui, :noindex, :theme, :display_sensitive_media, + :reduce_motion, :system_font_ui, :noindex, :theme, :display_sensitive_media, :hide_network, to: :settings, prefix: :setting, allow_nil: false attr_accessor :invite_code @@ -219,6 +219,10 @@ class User < ApplicationRecord settings.notification_emails['digest'] end + def hides_network? + @hides_network ||= settings.hide_network + end + def token_for_app(a) return nil if a.nil? || a.owner != self Doorkeeper::AccessToken diff --git a/app/views/accounts/_follow_grid.html.haml b/app/views/accounts/_follow_grid.html.haml index a6d0ee817..fdcef84be 100644 --- a/app/views/accounts/_follow_grid.html.haml +++ b/app/views/accounts/_follow_grid.html.haml @@ -1,5 +1,6 @@ -.accounts-grid +.accounts-grid{ class: accounts.empty? ? 'empty' : '' } - if accounts.empty? + = image_tag asset_pack_path('elephant_ui_greeting.svg'), alt: '', role: 'presentational' = render partial: 'accounts/nothing_here' - else = render partial: 'accounts/grid_card', collection: accounts, as: :account, cached: !user_signed_in? diff --git a/app/views/accounts/_follow_grid_hidden.html.haml b/app/views/accounts/_follow_grid_hidden.html.haml new file mode 100644 index 000000000..e970350e6 --- /dev/null +++ b/app/views/accounts/_follow_grid_hidden.html.haml @@ -0,0 +1,3 @@ +.accounts-grid.empty + = image_tag asset_pack_path('elephant_ui_greeting.svg'), alt: '', role: 'presentational' + %p.nothing-here= t('accounts.network_hidden') diff --git a/app/views/follower_accounts/index.html.haml b/app/views/follower_accounts/index.html.haml index a24e4ea20..65af81a5b 100644 --- a/app/views/follower_accounts/index.html.haml +++ b/app/views/follower_accounts/index.html.haml @@ -7,4 +7,7 @@ = render 'accounts/header', account: @account -= render 'accounts/follow_grid', follows: @follows, accounts: @follows.map(&:account) +- if @account.user_hides_network? + = render 'accounts/follow_grid_hidden' +- else + = render 'accounts/follow_grid', follows: @follows, accounts: @follows.map(&:account) diff --git a/app/views/following_accounts/index.html.haml b/app/views/following_accounts/index.html.haml index 67f6cfede..8fd95a0b4 100644 --- a/app/views/following_accounts/index.html.haml +++ b/app/views/following_accounts/index.html.haml @@ -7,4 +7,7 @@ = render 'accounts/header', account: @account -= render 'accounts/follow_grid', follows: @follows, accounts: @follows.map(&:target_account) +- if @account.user_hides_network? + = render 'accounts/follow_grid_hidden' +- else + = render 'accounts/follow_grid', follows: @follows, accounts: @follows.map(&:target_account) diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index be9648561..63cc3c7a7 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -8,9 +8,9 @@ %span.single-user-login = link_to t('auth.login'), new_user_session_path — - %span.domain= link_to site_hostname, about_path + %span.footer__domain= link_to site_hostname, about_path - else - %span.domain= link_to site_hostname, root_path + %span.footer__domain= link_to site_hostname, root_path %span.powered-by != t('generic.powered_by', link: link_to('Mastodon', 'https://joinmastodon.org')) diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml index fd66e13fb..d2e866373 100644 --- a/app/views/settings/preferences/show.html.haml +++ b/app/views/settings/preferences/show.html.haml @@ -26,6 +26,9 @@ .fields-group = f.input :setting_noindex, as: :boolean, wrapper: :with_label + .fields-group + = f.input :setting_hide_network, as: :boolean, wrapper: :with_label + %h4= t 'preferences.web' .fields-group diff --git a/config/locales/en.yml b/config/locales/en.yml index c074fa5b0..0257241cf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -40,6 +40,7 @@ en: following: Following media: Media moved_html: "%{name} has moved to %{new_profile_link}:" + network_hidden: This information is not available nothing_here: There is nothing here! people_followed_by: People whom %{name} follows people_who_follow: People who follow %{name} diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 7d6907ff5..85597e9a7 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -15,6 +15,7 @@ en: note: one: 1 character left other: %{count} characters left + setting_hide_network: Who you follow and who follows you will not be shown on your profile setting_noindex: Affects your public profile and status pages setting_theme: Affects how Mastodon looks when you're logged in from any device. imports: @@ -54,6 +55,7 @@ en: setting_default_sensitive: Always mark media as sensitive setting_delete_modal: Show confirmation dialog before deleting a toot setting_display_sensitive_media: Always show media marked as sensitive + setting_hide_network: Hide your network setting_noindex: Opt-out of search engine indexing setting_reduce_motion: Reduce motion in animations setting_system_font_ui: Use system's default font diff --git a/config/settings.yml b/config/settings.yml index dcf655008..3581d10a2 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -20,6 +20,7 @@ defaults: &defaults timeline_preview: true show_staff_badge: true default_sensitive: false + hide_network: false unfollow_modal: false boost_modal: false delete_modal: true -- cgit