diff options
author | Starfall <us@starfall.systems> | 2022-06-06 13:35:20 -0500 |
---|---|---|
committer | Starfall <us@starfall.systems> | 2022-06-06 13:35:20 -0500 |
commit | 78266a002b4735caaef07098ba66419fd71f47c1 (patch) | |
tree | 4ba2bc330d5ed4b6a3a926ab9a03a89f56bc8843 /app/lib | |
parent | e9b2e11520056d0ec822ac0862923d00c6a1289c (diff) | |
parent | 434b08e95b1a440bf9ae563b72600d1590106260 (diff) |
Merge remote-tracking branch 'glitch/main'
Diffstat (limited to 'app/lib')
-rw-r--r-- | app/lib/activitypub/activity.rb | 17 | ||||
-rw-r--r-- | app/lib/activitypub/activity/announce.rb | 2 | ||||
-rw-r--r-- | app/lib/activitypub/activity/create.rb | 4 | ||||
-rw-r--r-- | app/lib/activitypub/activity/delete.rb | 6 | ||||
-rw-r--r-- | app/lib/advanced_text_formatter.rb | 2 | ||||
-rw-r--r-- | app/lib/application_extension.rb | 4 | ||||
-rw-r--r-- | app/lib/emoji_formatter.rb | 28 | ||||
-rw-r--r-- | app/lib/importer/accounts_index_importer.rb | 30 | ||||
-rw-r--r-- | app/lib/importer/base_importer.rb | 87 | ||||
-rw-r--r-- | app/lib/importer/statuses_index_importer.rb | 89 | ||||
-rw-r--r-- | app/lib/importer/tags_index_importer.rb | 26 | ||||
-rw-r--r-- | app/lib/rss/builder.rb | 33 | ||||
-rw-r--r-- | app/lib/rss/channel.rb | 49 | ||||
-rw-r--r-- | app/lib/rss/element.rb | 24 | ||||
-rw-r--r-- | app/lib/rss/item.rb | 45 | ||||
-rw-r--r-- | app/lib/rss/media_content.rb | 35 | ||||
-rw-r--r-- | app/lib/rss/serializer.rb | 55 | ||||
-rw-r--r-- | app/lib/rss_builder.rb | 130 | ||||
-rw-r--r-- | app/lib/user_settings_decorator.rb | 5 |
19 files changed, 452 insertions, 219 deletions
diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 3c51a7a51..7ff06ea39 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -3,6 +3,7 @@ class ActivityPub::Activity include JsonLdHelper include Redisable + include Lockable SUPPORTED_TYPES = %w(Note Question).freeze CONVERTED_TYPES = %w(Image Audio Video Article Page Event).freeze @@ -157,22 +158,6 @@ class ActivityPub::Activity end end - def lock_or_return(key, expire_after = 2.hours.seconds) - yield if redis.set(key, true, nx: true, ex: expire_after) - ensure - redis.del(key) - end - - def lock_or_fail(key, expire_after = 15.minutes.seconds) - RedisLock.acquire({ redis: redis, key: key, autorelease: expire_after }) do |lock| - if lock.acquired? - yield - else - raise Mastodon::RaceConditionError - end - end - end - def fetch? !@options[:delivery] end diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb index 0674b1083..e6674be8a 100644 --- a/app/lib/activitypub/activity/announce.rb +++ b/app/lib/activitypub/activity/announce.rb @@ -4,7 +4,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity def perform return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? - lock_or_fail("announce:#{@object['id']}") do + with_lock("announce:#{value_or_id(@object)}") do original_status = status_from_object return reject_payload! if original_status.nil? || !announceable?(original_status) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 09fe08d45..ebae12973 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -47,7 +47,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def create_status return reject_payload! if unsupported_object_type? || invalid_origin?(object_uri) || tombstone_exists? || !related_to_local_activity? - lock_or_fail("create:#{object_uri}") do + with_lock("create:#{object_uri}") do return if delete_arrived_first?(object_uri) || poll_vote? @status = find_existing_status @@ -315,7 +315,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity poll = replied_to_status.preloadable_poll already_voted = true - lock_or_fail("vote:#{replied_to_status.poll_id}:#{@account.id}") do + with_lock("vote:#{replied_to_status.poll_id}:#{@account.id}") do already_voted = poll.votes.where(account: @account).exists? poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: object_uri) end diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb index f5ef863f3..871eb3966 100644 --- a/app/lib/activitypub/activity/delete.rb +++ b/app/lib/activitypub/activity/delete.rb @@ -12,7 +12,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity private def delete_person - lock_or_return("delete_in_progress:#{@account.id}") do + with_lock("delete_in_progress:#{@account.id}", autorelease: 2.hours, raise_on_failure: false) do DeleteAccountService.new.call(@account, reserve_username: false, skip_activitypub: true) end end @@ -20,14 +20,14 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity def delete_note return if object_uri.nil? - lock_or_return("delete_status_in_progress:#{object_uri}", 5.minutes.seconds) do + with_lock("delete_status_in_progress:#{object_uri}", raise_on_failure: false) do unless invalid_origin?(object_uri) # This lock ensures a concurrent `ActivityPub::Activity::Create` either # does not create a status at all, or has finished saving it to the # database before we try to load it. # Without the lock, `delete_later!` could be called after `delete_arrived_first?` # and `Status.find` before `Status.create!` - lock_or_fail("create:#{object_uri}") { delete_later!(object_uri) } + with_lock("create:#{object_uri}") { delete_later!(object_uri) } Tombstone.find_or_create_by(uri: object_uri, account: @account) end diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb index 728400819..dcaf34b91 100644 --- a/app/lib/advanced_text_formatter.rb +++ b/app/lib/advanced_text_formatter.rb @@ -8,7 +8,7 @@ class AdvancedTextFormatter < TextFormatter end def block_code(code, _language) - <<~HTML.squish + <<~HTML <pre><code>#{ERB::Util.h(code).gsub("\n", '<br/>')}</code></pre> HTML end diff --git a/app/lib/application_extension.rb b/app/lib/application_extension.rb index a1fea6430..d61ec0e6e 100644 --- a/app/lib/application_extension.rb +++ b/app/lib/application_extension.rb @@ -12,4 +12,8 @@ module ApplicationExtension def most_recently_used_access_token @most_recently_used_access_token ||= access_tokens.where.not(last_used_at: nil).order(last_used_at: :desc).first end + + def confirmation_redirect_uri + redirect_uri.lines.first.strip + end end diff --git a/app/lib/emoji_formatter.rb b/app/lib/emoji_formatter.rb index f808f3a22..194849c23 100644 --- a/app/lib/emoji_formatter.rb +++ b/app/lib/emoji_formatter.rb @@ -11,6 +11,7 @@ class EmojiFormatter # @param [Array<CustomEmoji>] custom_emojis # @param [Hash] options # @option options [Boolean] :animate + # @option options [String] :style def initialize(html, custom_emojis, options = {}) raise ArgumentError unless html.html_safe? @@ -85,14 +86,29 @@ class EmojiFormatter def image_for_emoji(shortcode, emoji) original_url, static_url = emoji - if animate? - image_tag(original_url, draggable: false, class: 'emojione', alt: ":#{shortcode}:", title: ":#{shortcode}:") - else - image_tag(original_url, draggable: false, class: 'emojione custom-emoji', alt: ":#{shortcode}:", title: ":#{shortcode}:", data: { original: original_url, static: static_url }) - end + image_tag( + animate? ? original_url : static_url, + image_attributes.merge(alt: ":#{shortcode}:", title: ":#{shortcode}:", data: image_data_attributes(original_url, static_url)) + ) + end + + def image_attributes + { rel: 'emoji', draggable: false, width: 16, height: 16, class: image_class_names, style: image_style } + end + + def image_data_attributes(original_url, static_url) + { original: original_url, static: static_url } unless animate? + end + + def image_class_names + animate? ? 'emojione' : 'emojione custom-emoji' + end + + def image_style + @options[:style] end def animate? - @options[:animate] + @options[:animate] || @options.key?(:style) end end diff --git a/app/lib/importer/accounts_index_importer.rb b/app/lib/importer/accounts_index_importer.rb new file mode 100644 index 000000000..792a31b1b --- /dev/null +++ b/app/lib/importer/accounts_index_importer.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Importer::AccountsIndexImporter < Importer::BaseImporter + def import! + scope.includes(:account_stat).find_in_batches(batch_size: @batch_size) do |tmp| + in_work_unit(tmp) do |accounts| + bulk = Chewy::Index::Import::BulkBuilder.new(index, to_index: accounts).bulk_body + + indexed = bulk.select { |entry| entry[:index] }.size + deleted = bulk.select { |entry| entry[:delete] }.size + + Chewy::Index::Import::BulkRequest.new(index).perform(bulk) + + [indexed, deleted] + end + end + + wait! + end + + private + + def index + AccountsIndex + end + + def scope + Account.searchable + end +end diff --git a/app/lib/importer/base_importer.rb b/app/lib/importer/base_importer.rb new file mode 100644 index 000000000..ea522c600 --- /dev/null +++ b/app/lib/importer/base_importer.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +class Importer::BaseImporter + # @param [Integer] batch_size + # @param [Concurrent::ThreadPoolExecutor] executor + def initialize(batch_size:, executor:) + @batch_size = batch_size + @executor = executor + @wait_for = Concurrent::Set.new + end + + # Callback to run when a concurrent work unit completes + # @param [Proc] + def on_progress(&block) + @on_progress = block + end + + # Callback to run when a concurrent work unit fails + # @param [Proc] + def on_failure(&block) + @on_failure = block + end + + # Reduce resource usage during and improve speed of indexing + def optimize_for_import! + Chewy.client.indices.put_settings index: index.index_name, body: { index: { refresh_interval: -1 } } + end + + # Restore original index settings + def optimize_for_search! + Chewy.client.indices.put_settings index: index.index_name, body: { index: { refresh_interval: index.settings_hash[:settings][:index][:refresh_interval] } } + end + + # Estimate the amount of documents that would be indexed. Not exact! + # @returns [Integer] + def estimate! + ActiveRecord::Base.connection_pool.with_connection { |connection| connection.select_one("SELECT reltuples AS estimate FROM pg_class WHERE relname = '#{index.adapter.target.table_name}'")['estimate'].to_i } + end + + # Import data from the database into the index + def import! + raise NotImplementedError + end + + # Remove documents from the index that no longer exist in the database + def clean_up! + index.scroll_batches do |documents| + ids = documents.map { |doc| doc['_id'] } + existence_map = index.adapter.target.where(id: ids).pluck(:id).each_with_object({}) { |id, map| map[id.to_s] = true } + tmp = ids.reject { |id| existence_map[id] } + + next if tmp.empty? + + in_work_unit(tmp) do |deleted_ids| + bulk = Chewy::Index::Import::BulkBuilder.new(index, delete: deleted_ids).bulk_body + + Chewy::Index::Import::BulkRequest.new(index).perform(bulk) + + [0, bulk.size] + end + end + + wait! + end + + protected + + def in_work_unit(*args, &block) + work_unit = Concurrent::Promises.future_on(@executor, *args, &block) + + work_unit.on_fulfillment!(&@on_progress) + work_unit.on_rejection!(&@on_failure) + work_unit.on_resolution! { @wait_for.delete(work_unit) } + + @wait_for << work_unit + rescue Concurrent::RejectedExecutionError + sleep(0.1) && retry # Backpressure + end + + def wait! + Concurrent::Promises.zip(*@wait_for).wait + end + + def index + raise NotImplementedError + end +end diff --git a/app/lib/importer/statuses_index_importer.rb b/app/lib/importer/statuses_index_importer.rb new file mode 100644 index 000000000..7c6532560 --- /dev/null +++ b/app/lib/importer/statuses_index_importer.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +class Importer::StatusesIndexImporter < Importer::BaseImporter + def import! + # The idea is that instead of iterating over all statuses in the database + # and calculating the searchable_by for each of them (majority of which + # would be empty), we approach the index from the other end + + scopes.each do |scope| + # We could be tempted to keep track of status IDs we have already processed + # from a different scope to avoid indexing them multiple times, but that + # could end up being a very large array + + scope.find_in_batches(batch_size: @batch_size) do |tmp| + in_work_unit(tmp.map(&:status_id)) do |status_ids| + bulk = ActiveRecord::Base.connection_pool.with_connection do + Chewy::Index::Import::BulkBuilder.new(index, to_index: Status.includes(:media_attachments, :preloadable_poll).where(id: status_ids)).bulk_body + end + + indexed = 0 + deleted = 0 + + # We can't use the delete_if proc to do the filtering because delete_if + # is called before rendering the data and we need to filter based + # on the results of the filter, so this filtering happens here instead + bulk.map! do |entry| + new_entry = begin + if entry[:index] && entry.dig(:index, :data, 'searchable_by').blank? + { delete: entry[:index].except(:data) } + else + entry + end + end + + if new_entry[:index] + indexed += 1 + else + deleted += 1 + end + + new_entry + end + + Chewy::Index::Import::BulkRequest.new(index).perform(bulk) + + [indexed, deleted] + end + end + end + + wait! + end + + private + + def index + StatusesIndex + end + + def scopes + [ + local_statuses_scope, + local_mentions_scope, + local_favourites_scope, + local_votes_scope, + local_bookmarks_scope, + ] + end + + def local_mentions_scope + Mention.where(account: Account.local, silent: false).select(:id, :status_id) + end + + def local_favourites_scope + Favourite.where(account: Account.local).select(:id, :status_id) + end + + def local_bookmarks_scope + Bookmark.select(:id, :status_id) + end + + def local_votes_scope + Poll.joins(:votes).where(votes: { account: Account.local }).select('polls.id, polls.status_id') + end + + def local_statuses_scope + Status.local.select('id, coalesce(reblog_of_id, id) as status_id') + end +end diff --git a/app/lib/importer/tags_index_importer.rb b/app/lib/importer/tags_index_importer.rb new file mode 100644 index 000000000..f5bd8f052 --- /dev/null +++ b/app/lib/importer/tags_index_importer.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Importer::TagsIndexImporter < Importer::BaseImporter + def import! + index.adapter.default_scope.find_in_batches(batch_size: @batch_size) do |tmp| + in_work_unit(tmp) do |tags| + bulk = Chewy::Index::Import::BulkBuilder.new(index, to_index: tags).bulk_body + + indexed = bulk.select { |entry| entry[:index] }.size + deleted = bulk.select { |entry| entry[:delete] }.size + + Chewy::Index::Import::BulkRequest.new(index).perform(bulk) + + [indexed, deleted] + end + end + + wait! + end + + private + + def index + TagsIndex + end +end diff --git a/app/lib/rss/builder.rb b/app/lib/rss/builder.rb new file mode 100644 index 000000000..a9b3f08c5 --- /dev/null +++ b/app/lib/rss/builder.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class RSS::Builder + attr_reader :dsl + + def self.build + new.tap do |builder| + yield builder.dsl + end.to_xml + end + + def initialize + @dsl = RSS::Channel.new + end + + def to_xml + ('<?xml version="1.0" encoding="UTF-8"?>'.dup << Ox.dump(wrap_in_document, effort: :tolerant)).force_encoding('UTF-8') + end + + private + + def wrap_in_document + Ox::Document.new(version: '1.0').tap do |document| + document << Ox::Element.new('rss').tap do |rss| + rss['version'] = '2.0' + rss['xmlns:webfeeds'] = 'http://webfeeds.org/rss/1.0' + rss['xmlns:media'] = 'http://search.yahoo.com/mrss/' + + rss << @dsl.to_element + end + end + end +end diff --git a/app/lib/rss/channel.rb b/app/lib/rss/channel.rb new file mode 100644 index 000000000..1dba94e47 --- /dev/null +++ b/app/lib/rss/channel.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class RSS::Channel < RSS::Element + def initialize + super() + + @root = create_element('channel') + end + + def title(str) + append_element('title', str) + end + + def link(str) + append_element('link', str) + end + + def last_build_date(date) + append_element('lastBuildDate', date.to_formatted_s(:rfc822)) + end + + def image(url, title, link) + append_element('image') do |image| + image << create_element('url', url) + image << create_element('title', title) + image << create_element('link', link) + end + end + + def description(str) + append_element('description', str) + end + + def generator(str) + append_element('generator', str) + end + + def icon(str) + append_element('webfeeds:icon', str) + end + + def logo(str) + append_element('webfeeds:logo', str) + end + + def item(&block) + @root << RSS::Item.with(&block) + end +end diff --git a/app/lib/rss/element.rb b/app/lib/rss/element.rb new file mode 100644 index 000000000..7142fa039 --- /dev/null +++ b/app/lib/rss/element.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class RSS::Element + def self.with(*args, &block) + new(*args).tap(&block).to_element + end + + def create_element(name, content = nil) + Ox::Element.new(name).tap do |element| + yield element if block_given? + element << content if content.present? + end + end + + def append_element(name, content = nil) + @root << create_element(name, content).tap do |element| + yield element if block_given? + end + end + + def to_element + @root + end +end diff --git a/app/lib/rss/item.rb b/app/lib/rss/item.rb new file mode 100644 index 000000000..c02991ace --- /dev/null +++ b/app/lib/rss/item.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class RSS::Item < RSS::Element + def initialize + super() + + @root = create_element('item') + end + + def title(str) + append_element('title', str) + end + + def link(str) + append_element('guid', str) do |guid| + guid['isPermaLink'] = 'true' + end + + append_element('link', str) + end + + def pub_date(date) + append_element('pubDate', date.to_formatted_s(:rfc822)) + end + + def description(str) + append_element('description', str) + end + + def category(str) + append_element('category', str) + end + + def enclosure(url, type, size) + append_element('enclosure') do |enclosure| + enclosure['url'] = url + enclosure['length'] = size + enclosure['type'] = type + end + end + + def media_content(url, type, size, &block) + @root << RSS::MediaContent.with(url, type, size, &block) + end +end diff --git a/app/lib/rss/media_content.rb b/app/lib/rss/media_content.rb new file mode 100644 index 000000000..f281fe29e --- /dev/null +++ b/app/lib/rss/media_content.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class RSS::MediaContent < RSS::Element + def initialize(url, type, size) + super() + + @root = create_element('media:content') do |content| + content['url'] = url + content['type'] = type + content['fileSize'] = size + end + end + + def medium(str) + @root['medium'] = str + end + + def rating(str) + append_element('media:rating', str) do |rating| + rating['scheme'] = 'urn:simple' + end + end + + def description(str) + append_element('media:description', str) do |description| + description['type'] = 'plain' + end + end + + def thumbnail(str) + append_element('media:thumbnail') do |thumbnail| + thumbnail['url'] = str + end + end +end diff --git a/app/lib/rss/serializer.rb b/app/lib/rss/serializer.rb deleted file mode 100644 index d44e94221..000000000 --- a/app/lib/rss/serializer.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -class RSS::Serializer - include FormattingHelper - - private - - def render_statuses(builder, statuses) - statuses.each do |status| - builder.item do |item| - item.title(status_title(status)) - .link(ActivityPub::TagManager.instance.url_for(status)) - .pub_date(status.created_at) - .description(status_description(status)) - - status.ordered_media_attachments.each do |media| - item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, media.file.size) - end - end - end - end - - def status_title(status) - preview = status.proper.spoiler_text.presence || status.proper.text - - if preview.length > 30 || preview[0, 30].include?("\n") - preview = preview[0, 30] - preview = preview[0, preview.index("\n").presence || 30] + '…' - end - - preview = "#{status.proper.spoiler_text.present? ? 'CW ' : ''}“#{preview}”#{status.proper.sensitive? ? ' (sensitive)' : ''}" - - if status.reblog? - "#{status.account.acct} boosted #{status.reblog.account.acct}: #{preview}" - else - "#{status.account.acct}: #{preview}" - end - end - - def status_description(status) - if status.proper.spoiler_text? - status.proper.spoiler_text - else - html = status_content_format(status.proper).to_str - after_html = '' - - if status.proper.preloadable_poll - poll_options_html = status.proper.preloadable_poll.options.map { |o| "[ ] #{o}" }.join('<br />') - after_html = "<p>#{poll_options_html}</p>" - end - - "#{html}#{after_html}" - end - end -end diff --git a/app/lib/rss_builder.rb b/app/lib/rss_builder.rb deleted file mode 100644 index 63ddba2e8..000000000 --- a/app/lib/rss_builder.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -class RSSBuilder - class ItemBuilder - def initialize - @item = Ox::Element.new('item') - end - - def title(str) - @item << (Ox::Element.new('title') << str) - - self - end - - def link(str) - @item << Ox::Element.new('guid').tap do |guid| - guid['isPermalink'] = 'true' - guid << str - end - - @item << (Ox::Element.new('link') << str) - - self - end - - def pub_date(date) - @item << (Ox::Element.new('pubDate') << date.to_formatted_s(:rfc822)) - - self - end - - def description(str) - @item << (Ox::Element.new('description') << str) - - self - end - - def enclosure(url, type, size) - @item << Ox::Element.new('enclosure').tap do |enclosure| - enclosure['url'] = url - enclosure['length'] = size - enclosure['type'] = type - end - - self - end - - def to_element - @item - end - end - - def initialize - @document = Ox::Document.new(version: '1.0') - @channel = Ox::Element.new('channel') - - @document << (rss << @channel) - end - - def title(str) - @channel << (Ox::Element.new('title') << str) - - self - end - - def link(str) - @channel << (Ox::Element.new('link') << str) - - self - end - - def image(str) - @channel << Ox::Element.new('image').tap do |image| - image << (Ox::Element.new('url') << str) - image << (Ox::Element.new('title') << '') - image << (Ox::Element.new('link') << '') - end - - @channel << (Ox::Element.new('webfeeds:icon') << str) - - self - end - - def cover(str) - @channel << Ox::Element.new('webfeeds:cover').tap do |cover| - cover['image'] = str - end - - self - end - - def logo(str) - @channel << (Ox::Element.new('webfeeds:logo') << str) - - self - end - - def accent_color(str) - @channel << (Ox::Element.new('webfeeds:accentColor') << str) - - self - end - - def description(str) - @channel << (Ox::Element.new('description') << str) - - self - end - - def item - @channel << ItemBuilder.new.tap do |item| - yield item - end.to_element - - self - end - - def to_xml - ('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(@document, effort: :tolerant)).force_encoding('UTF-8') - end - - private - - def rss - Ox::Element.new('rss').tap do |rss| - rss['version'] = '2.0' - rss['xmlns:webfeeds'] = 'http://webfeeds.org/rss/1.0' - end - end -end diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index d339e078c..1d70ed36a 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -34,7 +34,6 @@ class UserSettingsDecorator user.settings['noindex'] = noindex_preference if change?('setting_noindex') user.settings['flavour'] = flavour_preference if change?('setting_flavour') user.settings['skin'] = skin_preference if change?('setting_skin') - user.settings['hide_network'] = hide_network_preference if change?('setting_hide_network') user.settings['aggregate_reblogs'] = aggregate_reblogs_preference if change?('setting_aggregate_reblogs') user.settings['show_application'] = show_application_preference if change?('setting_show_application') user.settings['advanced_layout'] = advanced_layout_preference if change?('setting_advanced_layout') @@ -118,10 +117,6 @@ class UserSettingsDecorator settings['setting_skin'] end - def hide_network_preference - boolean_cast_setting 'setting_hide_network' - end - def show_application_preference boolean_cast_setting 'setting_show_application' end |