Add logging of admin actions (#5757)
* Add logging of admin actions * Update brakeman whitelist * Log creates, updates and destroys with history of changes * i18n: Update Polish translation (#5782) Signed-off-by: Marcin Mikołajczak <me@m4sk.in> * Split admin navigation into moderation and administration * Redesign audit log page * 🇵🇱 (#5795) * Add color coding to audit log * Change dismiss->resolve, log all outcomes of report as resolve * Update terminology (e-mail blacklist) (#5796) * Update terminology (e-mail blacklist) imho looks better * Update en.yml * Fix code style issues * i18n-tasks normalize
This commit is contained in:
		| @@ -21,7 +21,7 @@ module Admin | ||||
|  | ||||
|     def destroy | ||||
|       authorize @account_moderation_note, :destroy? | ||||
|       @account_moderation_note.destroy | ||||
|       @account_moderation_note.destroy! | ||||
|       redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg') | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -32,18 +32,21 @@ module Admin | ||||
|     def memorialize | ||||
|       authorize @account, :memorialize? | ||||
|       @account.memorialize! | ||||
|       log_action :memorialize, @account | ||||
|       redirect_to admin_account_path(@account.id) | ||||
|     end | ||||
|  | ||||
|     def enable | ||||
|       authorize @account.user, :enable? | ||||
|       @account.user.enable! | ||||
|       log_action :enable, @account.user | ||||
|       redirect_to admin_account_path(@account.id) | ||||
|     end | ||||
|  | ||||
|     def disable | ||||
|       authorize @account.user, :disable? | ||||
|       @account.user.disable! | ||||
|       log_action :disable, @account.user | ||||
|       redirect_to admin_account_path(@account.id) | ||||
|     end | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								app/controllers/admin/action_logs_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/controllers/admin/action_logs_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module Admin | ||||
|   class ActionLogsController < BaseController | ||||
|     def index | ||||
|       @action_logs = Admin::ActionLog.page(params[:page]) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -3,6 +3,7 @@ | ||||
| module Admin | ||||
|   class BaseController < ApplicationController | ||||
|     include Authorization | ||||
|     include AccountableConcern | ||||
|  | ||||
|     before_action :require_staff! | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ module Admin | ||||
|     def create | ||||
|       authorize @user, :confirm? | ||||
|       @user.confirm! | ||||
|       log_action :confirm, @user | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,7 @@ module Admin | ||||
|       @custom_emoji = CustomEmoji.new(resource_params) | ||||
|  | ||||
|       if @custom_emoji.save | ||||
|         log_action :create, @custom_emoji | ||||
|         redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.created_msg') | ||||
|       else | ||||
|         render :new | ||||
| @@ -30,6 +31,7 @@ module Admin | ||||
|       authorize @custom_emoji, :update? | ||||
|  | ||||
|       if @custom_emoji.update(resource_params) | ||||
|         log_action :update, @custom_emoji | ||||
|         redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg') | ||||
|       else | ||||
|         redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.update_failed_msg') | ||||
| @@ -38,7 +40,8 @@ module Admin | ||||
|  | ||||
|     def destroy | ||||
|       authorize @custom_emoji, :destroy? | ||||
|       @custom_emoji.destroy | ||||
|       @custom_emoji.destroy! | ||||
|       log_action :destroy, @custom_emoji | ||||
|       redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg') | ||||
|     end | ||||
|  | ||||
| @@ -49,6 +52,7 @@ module Admin | ||||
|       emoji.image = @custom_emoji.image | ||||
|  | ||||
|       if emoji.save | ||||
|         log_action :create, emoji | ||||
|         flash[:notice] = I18n.t('admin.custom_emojis.copied_msg') | ||||
|       else | ||||
|         flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') | ||||
| @@ -60,12 +64,14 @@ module Admin | ||||
|     def enable | ||||
|       authorize @custom_emoji, :enable? | ||||
|       @custom_emoji.update!(disabled: false) | ||||
|       log_action :enable, @custom_emoji | ||||
|       redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg') | ||||
|     end | ||||
|  | ||||
|     def disable | ||||
|       authorize @custom_emoji, :disable? | ||||
|       @custom_emoji.update!(disabled: true) | ||||
|       log_action :disable, @custom_emoji | ||||
|       redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg') | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,7 @@ module Admin | ||||
|  | ||||
|       if @domain_block.save | ||||
|         DomainBlockWorker.perform_async(@domain_block.id) | ||||
|         log_action :create, @domain_block | ||||
|         redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.created_msg') | ||||
|       else | ||||
|         render :new | ||||
| @@ -34,6 +35,7 @@ module Admin | ||||
|     def destroy | ||||
|       authorize @domain_block, :destroy? | ||||
|       UnblockDomainService.new.call(@domain_block, retroactive_unblock?) | ||||
|       log_action :destroy, @domain_block | ||||
|       redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg') | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,7 @@ module Admin | ||||
|       @email_domain_block = EmailDomainBlock.new(resource_params) | ||||
|  | ||||
|       if @email_domain_block.save | ||||
|         log_action :create, @email_domain_block | ||||
|         redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg') | ||||
|       else | ||||
|         render :new | ||||
| @@ -28,7 +29,8 @@ module Admin | ||||
|  | ||||
|     def destroy | ||||
|       authorize @email_domain_block, :destroy? | ||||
|       @email_domain_block.destroy | ||||
|       @email_domain_block.destroy! | ||||
|       log_action :destroy, @email_domain_block | ||||
|       redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg') | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ module Admin | ||||
|     def create | ||||
|       authorize :status, :update? | ||||
|  | ||||
|       @form         = Form::StatusBatch.new(form_status_batch_params) | ||||
|       @form         = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account)) | ||||
|       flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save | ||||
|  | ||||
|       redirect_to admin_report_path(@report) | ||||
| @@ -16,13 +16,15 @@ module Admin | ||||
|  | ||||
|     def update | ||||
|       authorize @status, :update? | ||||
|       @status.update(status_params) | ||||
|       @status.update!(status_params) | ||||
|       log_action :update, @status | ||||
|       redirect_to admin_report_path(@report) | ||||
|     end | ||||
|  | ||||
|     def destroy | ||||
|       authorize @status, :destroy? | ||||
|       RemovalWorker.perform_async(@status.id) | ||||
|       log_action :destroy, @status | ||||
|       render json: @status | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -25,12 +25,17 @@ module Admin | ||||
|     def process_report | ||||
|       case params[:outcome].to_s | ||||
|       when 'resolve' | ||||
|         @report.update(action_taken_by_current_attributes) | ||||
|         @report.update!(action_taken_by_current_attributes) | ||||
|         log_action :resolve, @report | ||||
|       when 'suspend' | ||||
|         Admin::SuspensionWorker.perform_async(@report.target_account.id) | ||||
|         log_action :resolve, @report | ||||
|         log_action :suspend, @report.target_account | ||||
|         resolve_all_target_account_reports | ||||
|       when 'silence' | ||||
|         @report.target_account.update(silenced: true) | ||||
|         @report.target_account.update!(silenced: true) | ||||
|         log_action :resolve, @report | ||||
|         log_action :silence, @report.target_account | ||||
|         resolve_all_target_account_reports | ||||
|       else | ||||
|         raise ActiveRecord::RecordNotFound | ||||
|   | ||||
| @@ -7,6 +7,7 @@ module Admin | ||||
|     def create | ||||
|       authorize @user, :reset_password? | ||||
|       @user.send_reset_password_instructions | ||||
|       log_action :reset_password, @user | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -7,12 +7,14 @@ module Admin | ||||
|     def promote | ||||
|       authorize @user, :promote? | ||||
|       @user.promote! | ||||
|       log_action :promote, @user | ||||
|       redirect_to admin_account_path(@user.account_id) | ||||
|     end | ||||
|  | ||||
|     def demote | ||||
|       authorize @user, :demote? | ||||
|       @user.demote! | ||||
|       log_action :demote, @user | ||||
|       redirect_to admin_account_path(@user.account_id) | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -6,13 +6,15 @@ module Admin | ||||
|  | ||||
|     def create | ||||
|       authorize @account, :silence? | ||||
|       @account.update(silenced: true) | ||||
|       @account.update!(silenced: true) | ||||
|       log_action :silence, @account | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|     def destroy | ||||
|       authorize @account, :unsilence? | ||||
|       @account.update(silenced: false) | ||||
|       @account.update!(silenced: false) | ||||
|       log_action :unsilence, @account | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ module Admin | ||||
|     def create | ||||
|       authorize :status, :update? | ||||
|  | ||||
|       @form         = Form::StatusBatch.new(form_status_batch_params) | ||||
|       @form         = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account)) | ||||
|       flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save | ||||
|  | ||||
|       redirect_to admin_account_statuses_path(@account.id, current_params) | ||||
| @@ -34,13 +34,15 @@ module Admin | ||||
|  | ||||
|     def update | ||||
|       authorize @status, :update? | ||||
|       @status.update(status_params) | ||||
|       @status.update!(status_params) | ||||
|       log_action :update, @status | ||||
|       redirect_to admin_account_statuses_path(@account.id, current_params) | ||||
|     end | ||||
|  | ||||
|     def destroy | ||||
|       authorize @status, :destroy? | ||||
|       RemovalWorker.perform_async(@status.id) | ||||
|       log_action :destroy, @status | ||||
|       render json: @status | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -7,12 +7,14 @@ module Admin | ||||
|     def create | ||||
|       authorize @account, :suspend? | ||||
|       Admin::SuspensionWorker.perform_async(@account.id) | ||||
|       log_action :suspend, @account | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|     def destroy | ||||
|       authorize @account, :unsuspend? | ||||
|       @account.unsuspend! | ||||
|       log_action :unsuspend, @account | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ module Admin | ||||
|     def destroy | ||||
|       authorize @user, :disable_2fa? | ||||
|       @user.disable_two_factor! | ||||
|       log_action :disable_2fa, @user | ||||
|       redirect_to admin_accounts_path | ||||
|     end | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								app/controllers/concerns/accountable_concern.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/controllers/concerns/accountable_concern.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module AccountableConcern | ||||
|   extend ActiveSupport::Concern | ||||
|  | ||||
|   def log_action(action, target) | ||||
|     Admin::ActionLog.create(account: current_account, action: action, target: target) | ||||
|   end | ||||
| end | ||||
							
								
								
									
										103
									
								
								app/helpers/admin/action_logs_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								app/helpers/admin/action_logs_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module Admin::ActionLogsHelper | ||||
|   def log_target(log) | ||||
|     if log.target | ||||
|       linkable_log_target(log.target) | ||||
|     else | ||||
|       log_target_from_history(log.target_type, log.recorded_changes) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def linkable_log_target(record) | ||||
|     case record.class.name | ||||
|     when 'Account' | ||||
|       link_to record.acct, admin_account_path(record.id) | ||||
|     when 'User' | ||||
|       link_to record.account.acct, admin_account_path(record.account_id) | ||||
|     when 'CustomEmoji' | ||||
|       record.shortcode | ||||
|     when 'Report' | ||||
|       link_to "##{record.id}", admin_report_path(record) | ||||
|     when 'DomainBlock', 'EmailDomainBlock' | ||||
|       link_to record.domain, "https://#{record.domain}" | ||||
|     when 'Status' | ||||
|       link_to record.account.acct, TagManager.instance.url_for(record) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def log_target_from_history(type, attributes) | ||||
|     case type | ||||
|     when 'CustomEmoji' | ||||
|       attributes['shortcode'] | ||||
|     when 'DomainBlock', 'EmailDomainBlock' | ||||
|       link_to attributes['domain'], "https://#{attributes['domain']}" | ||||
|     when 'Status' | ||||
|       tmp_status = Status.new(attributes) | ||||
|       link_to tmp_status.account.acct, TagManager.instance.url_for(tmp_status) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def relevant_log_changes(log) | ||||
|     if log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action) | ||||
|       log.recorded_changes.slice('domain') | ||||
|     elsif log.target_type == 'CustomEmoji' && log.action == :update | ||||
|       log.recorded_changes.slice('domain', 'visible_in_picker') | ||||
|     elsif log.target_type == 'User' && [:promote, :demote].include?(log.action) | ||||
|       log.recorded_changes.slice('moderator', 'admin') | ||||
|     elsif log.target_type == 'DomainBlock' | ||||
|       log.recorded_changes.slice('severity', 'reject_media') | ||||
|     elsif log.target_type == 'Status' && log.action == :update | ||||
|       log.recorded_changes.slice('sensitive') | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def log_extra_attributes(hash) | ||||
|     safe_join(hash.to_a.map { |key, value| safe_join([content_tag(:span, key, class: 'diff-key'), '=', log_change(value)]) }, ' ') | ||||
|   end | ||||
|  | ||||
|   def log_change(val) | ||||
|     return content_tag(:span, val, class: 'diff-neutral') unless val.is_a?(Array) | ||||
|     safe_join([content_tag(:span, val.first, class: 'diff-old'), content_tag(:span, val.last, class: 'diff-new')], '→') | ||||
|   end | ||||
|  | ||||
|   def icon_for_log(log) | ||||
|     case log.target_type | ||||
|     when 'Account', 'User' | ||||
|       'user' | ||||
|     when 'CustomEmoji' | ||||
|       'file' | ||||
|     when 'Report' | ||||
|       'flag' | ||||
|     when 'DomainBlock' | ||||
|       'lock' | ||||
|     when 'EmailDomainBlock' | ||||
|       'envelope' | ||||
|     when 'Status' | ||||
|       'pencil' | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def class_for_log_icon(log) | ||||
|     case log.action | ||||
|     when :enable, :unsuspend, :unsilence, :confirm, :promote, :resolve | ||||
|       'positive' | ||||
|     when :create | ||||
|       opposite_verbs?(log) ? 'negative' : 'positive' | ||||
|     when :update, :reset_password, :disable_2fa, :memorialize | ||||
|       'neutral' | ||||
|     when :demote, :silence, :disable, :suspend | ||||
|       'negative' | ||||
|     when :destroy | ||||
|       opposite_verbs?(log) ? 'positive' : 'negative' | ||||
|     else | ||||
|       '' | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def opposite_verbs?(log) | ||||
|     %w(DomainBlock EmailDomainBlock).include?(log.target_type) | ||||
|   end | ||||
| end | ||||
| @@ -347,3 +347,104 @@ | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .spacer { | ||||
|   flex: 1 1 auto; | ||||
| } | ||||
|  | ||||
| .log-entry { | ||||
|   margin-bottom: 8px; | ||||
|   line-height: 20px; | ||||
|  | ||||
|   &__header { | ||||
|     display: flex; | ||||
|     justify-content: flex-start; | ||||
|     align-items: center; | ||||
|     padding: 10px; | ||||
|     background: $ui-base-color; | ||||
|     color: $ui-primary-color; | ||||
|     border-radius: 4px 4px 0 0; | ||||
|     font-size: 14px; | ||||
|     position: relative; | ||||
|   } | ||||
|  | ||||
|   &__avatar { | ||||
|     margin-right: 10px; | ||||
|  | ||||
|     .avatar { | ||||
|       display: block; | ||||
|       margin: 0; | ||||
|       border-radius: 50%; | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &__title { | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|   } | ||||
|  | ||||
|   &__timestamp { | ||||
|     color: lighten($ui-base-color, 34%); | ||||
|   } | ||||
|  | ||||
|   &__extras { | ||||
|     background: lighten($ui-base-color, 6%); | ||||
|     border-radius: 0 0 4px 4px; | ||||
|     padding: 10px; | ||||
|     color: $ui-primary-color; | ||||
|     font-family: 'mastodon-font-monospace', monospace; | ||||
|     font-size: 12px; | ||||
|     white-space: nowrap; | ||||
|     min-height: 20px; | ||||
|   } | ||||
|  | ||||
|   &__icon { | ||||
|     font-size: 28px; | ||||
|     margin-right: 10px; | ||||
|     color: lighten($ui-base-color, 34%); | ||||
|   } | ||||
|  | ||||
|   &__icon__overlay { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     width: 10px; | ||||
|     height: 10px; | ||||
|     border-radius: 50%; | ||||
|  | ||||
|     &.positive { | ||||
|       background: $success-green; | ||||
|     } | ||||
|  | ||||
|     &.negative { | ||||
|       background: $error-red; | ||||
|     } | ||||
|  | ||||
|     &.neutral { | ||||
|       background: $ui-highlight-color; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   a, | ||||
|   .username, | ||||
|   .target { | ||||
|     color: $ui-secondary-color; | ||||
|     text-decoration: none; | ||||
|     font-weight: 500; | ||||
|   } | ||||
|  | ||||
|   .diff-old { | ||||
|     color: $error-red; | ||||
|   } | ||||
|  | ||||
|   .diff-neutral { | ||||
|     color: $ui-secondary-color; | ||||
|   } | ||||
|  | ||||
|   .diff-new { | ||||
|     color: $success-green; | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										7
									
								
								app/models/admin.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/models/admin.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module Admin | ||||
|   def self.table_name_prefix | ||||
|     'admin_' | ||||
|   end | ||||
| end | ||||
							
								
								
									
										40
									
								
								app/models/admin/action_log.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/models/admin/action_log.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| # frozen_string_literal: true | ||||
| # == Schema Information | ||||
| # | ||||
| # Table name: admin_action_logs | ||||
| # | ||||
| #  id               :integer          not null, primary key | ||||
| #  account_id       :integer | ||||
| #  action           :string           default(""), not null | ||||
| #  target_type      :string | ||||
| #  target_id        :integer | ||||
| #  recorded_changes :text             default(""), not null | ||||
| #  created_at       :datetime         not null | ||||
| #  updated_at       :datetime         not null | ||||
| # | ||||
|  | ||||
| class Admin::ActionLog < ApplicationRecord | ||||
|   serialize :recorded_changes | ||||
|  | ||||
|   belongs_to :account, required: true | ||||
|   belongs_to :target, required: true, polymorphic: true | ||||
|  | ||||
|   default_scope -> { order('id desc') } | ||||
|  | ||||
|   def action | ||||
|     super.to_sym | ||||
|   end | ||||
|  | ||||
|   before_validation :set_changes | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def set_changes | ||||
|     case action | ||||
|     when :destroy, :create | ||||
|       self.recorded_changes = target.attributes | ||||
|     when :update, :promote, :demote | ||||
|       self.recorded_changes = target.previous_changes | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -2,8 +2,9 @@ | ||||
|  | ||||
| class Form::StatusBatch | ||||
|   include ActiveModel::Model | ||||
|   include AccountableConcern | ||||
|  | ||||
|   attr_accessor :status_ids, :action | ||||
|   attr_accessor :status_ids, :action, :current_account | ||||
|  | ||||
|   ACTION_TYPE = %w(nsfw_on nsfw_off delete).freeze | ||||
|  | ||||
| @@ -20,11 +21,14 @@ class Form::StatusBatch | ||||
|  | ||||
|   def change_sensitive(sensitive) | ||||
|     media_attached_status_ids = MediaAttachment.where(status_id: status_ids).pluck(:status_id) | ||||
|  | ||||
|     ApplicationRecord.transaction do | ||||
|       Status.where(id: media_attached_status_ids).find_each do |status| | ||||
|         status.update!(sensitive: sensitive) | ||||
|         log_action :update, status | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     true | ||||
|   rescue ActiveRecord::RecordInvalid | ||||
|     false | ||||
| @@ -33,7 +37,9 @@ class Form::StatusBatch | ||||
|   def delete_statuses | ||||
|     Status.where(id: status_ids).find_each do |status| | ||||
|       RemovalWorker.perform_async(status.id) | ||||
|       log_action :destroy, status | ||||
|     end | ||||
|  | ||||
|     true | ||||
|   end | ||||
| end | ||||
|   | ||||
							
								
								
									
										15
									
								
								app/views/admin/action_logs/_action_log.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/views/admin/action_logs/_action_log.html.haml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| %li.log-entry | ||||
|   .log-entry__header | ||||
|     .log-entry__avatar | ||||
|       = image_tag action_log.account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar' | ||||
|     .log-entry__content | ||||
|       .log-entry__title | ||||
|         = t("admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}", name: content_tag(:span, action_log.account.username, class: 'username'), target: content_tag(:span, log_target(action_log), class: 'target')).html_safe | ||||
|       .log-entry__timestamp | ||||
|         %time= l action_log.created_at | ||||
|     .spacer | ||||
|     .log-entry__icon | ||||
|       = fa_icon icon_for_log(action_log) | ||||
|       .log-entry__icon__overlay{ class: class_for_log_icon(action_log) } | ||||
|   .log-entry__extras | ||||
|     = log_extra_attributes relevant_log_changes(action_log) | ||||
							
								
								
									
										7
									
								
								app/views/admin/action_logs/index.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/views/admin/action_logs/index.html.haml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| - content_for :page_title do | ||||
|   = t('admin.action_logs.title') | ||||
|  | ||||
| %ul | ||||
|   = render @action_logs | ||||
|  | ||||
| = paginate @action_logs | ||||
| @@ -7,10 +7,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 122, | ||||
|       "line": 143, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).inbox_url, Account.find(params[:id]).inbox_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -26,10 +26,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 128, | ||||
|       "line": 149, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).shared_inbox_url, Account.find(params[:id]).shared_inbox_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -45,10 +45,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 35, | ||||
|       "line": 54, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).url, Account.find(params[:id]).url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -76,6 +76,25 @@ | ||||
|       "confidence": "Weak", | ||||
|       "note": "" | ||||
|     }, | ||||
|     { | ||||
|       "warning_type": "Dynamic Render Path", | ||||
|       "warning_code": 15, | ||||
|       "fingerprint": "4b6a895e2805578d03ceedbe1d469cc75a0c759eba093722523edb4b8683c873", | ||||
|       "check_name": "Render", | ||||
|       "message": "Render path contains parameter value", | ||||
|       "file": "app/views/admin/action_logs/index.html.haml", | ||||
|       "line": 5, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", | ||||
|       "code": "render(action => Admin::ActionLog.page(params[:page]), {})", | ||||
|       "render_path": [{"type":"controller","class":"Admin::ActionLogsController","method":"index","line":7,"file":"app/controllers/admin/action_logs_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/action_logs/index" | ||||
|       }, | ||||
|       "user_input": "params[:page]", | ||||
|       "confidence": "Weak", | ||||
|       "note": "" | ||||
|     }, | ||||
|     { | ||||
|       "warning_type": "Cross-Site Scripting", | ||||
|       "warning_code": 4, | ||||
| @@ -83,10 +102,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 131, | ||||
|       "line": 152, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).followers_url, Account.find(params[:id]).followers_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -102,10 +121,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 106, | ||||
|       "line": 127, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).salmon_url, Account.find(params[:id]).salmon_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -124,7 +143,7 @@ | ||||
|       "line": 31, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", | ||||
|       "code": "render(action => filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]), {})", | ||||
|       "render_path": [{"type":"controller","class":"Admin::CustomEmojisController","method":"index","line":9,"file":"app/controllers/admin/custom_emojis_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::CustomEmojisController","method":"index","line":10,"file":"app/controllers/admin/custom_emojis_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/custom_emojis/index" | ||||
| @@ -163,7 +182,7 @@ | ||||
|       "line": 64, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", | ||||
|       "code": "render(action => filtered_accounts.page(params[:page]), {})", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"index","line":10,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"index","line":12,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/index" | ||||
| @@ -179,10 +198,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 95, | ||||
|       "line": 116, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).remote_url, Account.find(params[:id]).remote_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -221,7 +240,7 @@ | ||||
|       "line": 25, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", | ||||
|       "code": "render(action => filtered_reports.page(params[:page]), {})", | ||||
|       "render_path": [{"type":"controller","class":"Admin::ReportsController","method":"index","line":9,"file":"app/controllers/admin/reports_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::ReportsController","method":"index","line":10,"file":"app/controllers/admin/reports_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/reports/index" | ||||
| @@ -237,10 +256,10 @@ | ||||
|       "check_name": "LinkToHref", | ||||
|       "message": "Potentially unsafe model attribute in link_to href", | ||||
|       "file": "app/views/admin/accounts/show.html.haml", | ||||
|       "line": 125, | ||||
|       "line": 146, | ||||
|       "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", | ||||
|       "code": "link_to(Account.find(params[:id]).outbox_url, Account.find(params[:id]).outbox_url)", | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], | ||||
|       "location": { | ||||
|         "type": "template", | ||||
|         "template": "admin/accounts/show" | ||||
| @@ -269,6 +288,6 @@ | ||||
|       "note": "" | ||||
|     } | ||||
|   ], | ||||
|   "updated": "2017-10-20 00:00:54 +0900", | ||||
|   "updated": "2017-11-19 20:34:18 +0100", | ||||
|   "brakeman_version": "4.0.1" | ||||
| } | ||||
|   | ||||
| @@ -60,3 +60,4 @@ ignore_unused: | ||||
|   - 'activerecord.errors.models.doorkeeper/*' | ||||
|   - 'errors.429' | ||||
|   - 'admin.accounts.roles.*' | ||||
|   - 'admin.action_logs.actions.*' | ||||
|   | ||||
| @@ -133,6 +133,32 @@ en: | ||||
|       unsubscribe: Unsubscribe | ||||
|       username: Username | ||||
|       web: Web | ||||
|     action_logs: | ||||
|       actions: | ||||
|         confirm_user: "%{name} confirmed e-mail address of user %{target}" | ||||
|         create_custom_emoji: "%{name} uploaded new emoji %{target}" | ||||
|         create_domain_block: "%{name} blocked domain %{target}" | ||||
|         create_email_domain_block: "%{name} blacklisted e-mail domain %{target}" | ||||
|         demote_user: "%{name} demoted user %{target}" | ||||
|         destroy_domain_block: "%{name} unblocked domain %{target}" | ||||
|         destroy_email_domain_block: "%{name} whitelisted e-mail domain %{target}" | ||||
|         destroy_status: "%{name} removed status by %{target}" | ||||
|         disable_2fa_user: "%{name} disabled two factor requirement for user %{target}" | ||||
|         disable_custom_emoji: "%{name} disabled emoji %{target}" | ||||
|         disable_user: "%{name} disabled login for user %{target}" | ||||
|         enable_custom_emoji: "%{name} enabled emoji %{target}" | ||||
|         enable_user: "%{name} enabled login for user %{target}" | ||||
|         memorialize_account: "%{name} turned %{target}'s account into a memoriam page" | ||||
|         promote_user: "%{name} promoted user %{target}" | ||||
|         reset_password_user: "%{name} reset password of user %{target}" | ||||
|         resolve_report: "%{name} dismissed report %{target}" | ||||
|         silence_account: "%{name} silenced %{target}'s account" | ||||
|         suspend_account: "%{name} suspended %{target}'s account" | ||||
|         unsilence_account: "%{name} unsilenced %{target}'s account" | ||||
|         unsuspend_account: "%{name} unsuspended %{target}'s account" | ||||
|         update_custom_emoji: "%{name} updated emoji %{target}" | ||||
|         update_status: "%{name} updated status by %{target}" | ||||
|       title: Audit log | ||||
|     custom_emojis: | ||||
|       copied_msg: Successfully created local copy of the emoji | ||||
|       copy: Copy | ||||
| @@ -187,24 +213,24 @@ en: | ||||
|           suspend: Unsuspend all existing accounts from this domain | ||||
|         title: Undo domain block for %{domain} | ||||
|         undo: Undo | ||||
|       title: Domain Blocks | ||||
|       title: Domain blocks | ||||
|       undo: Undo | ||||
|     email_domain_blocks: | ||||
|       add_new: Add new | ||||
|       created_msg: Email domain block successfully created | ||||
|       created_msg: Successfully added e-mail domain to blacklist | ||||
|       delete: Delete | ||||
|       destroyed_msg: Email domain block successfully deleted | ||||
|       destroyed_msg: Successfully deleted e-mail domain from blacklist | ||||
|       domain: Domain | ||||
|       new: | ||||
|         create: Create block | ||||
|         title: New email domain block | ||||
|       title: Email Domain Block | ||||
|         create: Add domain | ||||
|         title: New e-mail blacklist entry | ||||
|       title: E-mail blacklist | ||||
|     instances: | ||||
|       account_count: Known accounts | ||||
|       domain_name: Domain | ||||
|       reset: Reset | ||||
|       search: Search | ||||
|       title: Known Instances | ||||
|       title: Known instances | ||||
|     reports: | ||||
|       action_taken_by: Action taken by | ||||
|       are_you_sure: Are you sure? | ||||
| @@ -265,7 +291,7 @@ en: | ||||
|       timeline_preview: | ||||
|         desc_html: Display public timeline on landing page | ||||
|         title: Timeline preview | ||||
|       title: Site Settings | ||||
|       title: Site settings | ||||
|     statuses: | ||||
|       back_to_account: Back to account page | ||||
|       batch: | ||||
| @@ -404,6 +430,8 @@ en: | ||||
|     validations: | ||||
|       images_and_video: Cannot attach a video to a status that already contains images | ||||
|       too_many: Cannot attach more than 4 files | ||||
|   moderation: | ||||
|     title: Moderation | ||||
|   notification_mailer: | ||||
|     digest: | ||||
|       body: 'Here is a brief summary of what you missed on %{instance} since your last visit on %{since}:' | ||||
|   | ||||
| @@ -49,6 +49,7 @@ pl: | ||||
|     reserved_username: Ta nazwa użytkownika jest zarezerwowana. | ||||
|     roles: | ||||
|       admin: Administrator | ||||
|       moderator: Moderator | ||||
|     unfollow: Przestań śledzić | ||||
|   admin: | ||||
|     account_moderation_notes: | ||||
| @@ -132,6 +133,32 @@ pl: | ||||
|       unsubscribe: Przestań subskrybować | ||||
|       username: Nazwa użytkownika | ||||
|       web: Sieć | ||||
|     action_logs: | ||||
|       actions: | ||||
|         confirm_user: "%{name} potwierdził adres e-mail użytkownika %{target}" | ||||
|         create_custom_emoji: "%{name} dodał nowe emoji %{target}" | ||||
|         create_domain_block: "%{name} zablokował domenę %{target}" | ||||
|         create_email_domain_block: "%{name} dodał domenę e-mail %{target} na czarną listę" | ||||
|         demote_user: "%{name} zdegradował użytkownika %{target}" | ||||
|         destroy_domain_block: "%{name} odblokował domenę %{target}" | ||||
|         destroy_email_domain_block: "%{name} usunął domenę e-mail %{target} z czarnej listy" | ||||
|         destroy_status: "%{name} usunął wpis użytkownika %{target}" | ||||
|         disable_2fa_user: "%{name} wyłączył uwierzytelnianie dwustopniowe użytkownikowi %{target}" | ||||
|         disable_custom_emoji: "%{name} wyłączył emoji %{target}" | ||||
|         disable_user: "%{name} zablokował możliwość logowania użytkownikowi %{target}" | ||||
|         enable_custom_emoji: "%{name} włączył emoji %{target}" | ||||
|         enable_user: "%{name} przywrócił możliwość logowania użytkownikowi %{target}" | ||||
|         memorialize_account: "%{name} nadał kontu %{target} status in memoriam" | ||||
|         promote_user: "%{name} podniósł uprawnienia użytkownikowi %{target}" | ||||
|         reset_password_user: "%{name} przywrócił hasło użytkownikowi %{target}" | ||||
|         resolve_report: "%{name} odrzucił zgłoszenie %{target}" | ||||
|         silence_account: "%{name} wyciszył konto %{target}" | ||||
|         suspend_account: "%{name} zawiesił konto %{target}" | ||||
|         unsilence_account: "%{name} cofnął wyciszenie konta %{target}" | ||||
|         unsuspend_account: "%{name} cofnął zawieszenie konta %{target}" | ||||
|         update_custom_emoji: "%{name} zaktualizował emoji %{target}" | ||||
|         update_status: "%{name} zaktualizował wpis użytkownika %{target}" | ||||
|       title: Dziennik działań administracyjnych | ||||
|     custom_emojis: | ||||
|       copied_msg: Pomyślnie utworzono lokalną kopię emoji | ||||
|       copy: Kopiuj | ||||
| @@ -148,6 +175,7 @@ pl: | ||||
|       listed: Widoczne | ||||
|       new: | ||||
|         title: Dodaj nowe niestandardowe emoji | ||||
|       overwrite: Zastąp | ||||
|       shortcode: Shortcode | ||||
|       shortcode_hint: Co najmniej 2 znaki, tylko znaki alfanumeryczne i podkreślniki | ||||
|       title: Niestandardowe emoji | ||||
| @@ -403,6 +431,8 @@ pl: | ||||
|     validations: | ||||
|       images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia | ||||
|       too_many: Nie możesz załączyć więcej niż 4 plików | ||||
|   moderation: | ||||
|     title: Moderacja | ||||
|   notification_mailer: | ||||
|     digest: | ||||
|       body: 'Oto krótkie podsumowanie co Cię ominęło na %{instance} od Twojej ostatniej wizyty (%{since}):' | ||||
|   | ||||
| @@ -20,17 +20,21 @@ SimpleNavigation::Configuration.run do |navigation| | ||||
|       development.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url, highlights_on: %r{/settings/applications} | ||||
|     end | ||||
|  | ||||
|     primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| | ||||
|     primary.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| | ||||
|       admin.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url | ||||
|       admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} | ||||
|       admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} | ||||
|       admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? } | ||||
|       admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } | ||||
|       admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}, if: -> { current_user.admin? } | ||||
|       admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? } | ||||
|       admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } | ||||
|       admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } | ||||
|     end | ||||
|  | ||||
|     primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), edit_admin_settings_url, if: proc { current_user.staff? } do |admin| | ||||
|       admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? } | ||||
|       admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis} | ||||
|       admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } | ||||
|       admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } | ||||
|       admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } | ||||
|     end | ||||
|  | ||||
|     primary.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_url, link_html: { 'data-method' => 'delete' } | ||||
|   | ||||
| @@ -110,6 +110,7 @@ Rails.application.routes.draw do | ||||
|     resources :subscriptions, only: [:index] | ||||
|     resources :domain_blocks, only: [:index, :new, :create, :show, :destroy] | ||||
|     resources :email_domain_blocks, only: [:index, :new, :create, :destroy] | ||||
|     resources :action_logs, only: [:index] | ||||
|     resource :settings, only: [:edit, :update] | ||||
|  | ||||
|     resources :instances, only: [:index] do | ||||
|   | ||||
							
								
								
									
										12
									
								
								db/migrate/20171119172437_create_admin_action_logs.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								db/migrate/20171119172437_create_admin_action_logs.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| class CreateAdminActionLogs < ActiveRecord::Migration[5.1] | ||||
|   def change | ||||
|     create_table :admin_action_logs do |t| | ||||
|       t.belongs_to :account, foreign_key: { on_delete: :cascade } | ||||
|       t.string :action, null: false, default: '' | ||||
|       t.references :target, polymorphic: true | ||||
|       t.text :recorded_changes, null: false, default: '' | ||||
|  | ||||
|       t.timestamps | ||||
|     end | ||||
|   end | ||||
| end | ||||
							
								
								
									
										15
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								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: 20171118012443) do | ||||
| ActiveRecord::Schema.define(version: 20171119172437) do | ||||
|  | ||||
|   # These are extensions that must be enabled in order to support this database | ||||
|   enable_extension "plpgsql" | ||||
| @@ -80,6 +80,18 @@ ActiveRecord::Schema.define(version: 20171118012443) do | ||||
|     t.index ["username", "domain"], name: "index_accounts_on_username_and_domain", unique: true | ||||
|   end | ||||
|  | ||||
|   create_table "admin_action_logs", force: :cascade do |t| | ||||
|     t.bigint "account_id" | ||||
|     t.string "action", default: "", null: false | ||||
|     t.string "target_type" | ||||
|     t.bigint "target_id" | ||||
|     t.text "recorded_changes", default: "", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_admin_action_logs_on_account_id" | ||||
|     t.index ["target_type", "target_id"], name: "index_admin_action_logs_on_target_type_and_target_id" | ||||
|   end | ||||
|  | ||||
|   create_table "blocks", force: :cascade do |t| | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
| @@ -488,6 +500,7 @@ ActiveRecord::Schema.define(version: 20171118012443) do | ||||
|   add_foreign_key "account_moderation_notes", "accounts" | ||||
|   add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id" | ||||
|   add_foreign_key "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify | ||||
|   add_foreign_key "admin_action_logs", "accounts", on_delete: :cascade | ||||
|   add_foreign_key "blocks", "accounts", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade | ||||
|   add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade | ||||
|   add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade | ||||
|   | ||||
							
								
								
									
										5
									
								
								spec/fabricators/admin_action_log_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/fabricators/admin_action_log_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| Fabricator('Admin::ActionLog') do | ||||
|   account nil | ||||
|   action  "MyString" | ||||
|   target  nil | ||||
| end | ||||
							
								
								
									
										5
									
								
								spec/models/admin/action_log_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/models/admin/action_log_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe Admin::ActionLog, type: :model do | ||||
|  | ||||
| end | ||||
		Reference in New Issue
	
	Block a user