Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
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:
 | 
			
		||||
@@ -412,6 +438,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
 | 
			
		||||
@@ -411,6 +439,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}):'
 | 
			
		||||
 
 | 
			
		||||
@@ -21,17 +21,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' }
 | 
			
		||||
 
 | 
			
		||||
@@ -117,6 +117,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
 | 
			
		||||
@@ -499,6 +511,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