Merge pull request #652 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
This commit is contained in:
		
						commit
						fe5b63f3e6
					
				
					 22 changed files with 108 additions and 28 deletions
				
			
		
							
								
								
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							|  | @ -10,6 +10,7 @@ gem 'rails', '~> 5.2.1' | ||||||
| 
 | 
 | ||||||
| gem 'hamlit-rails', '~> 0.2' | gem 'hamlit-rails', '~> 0.2' | ||||||
| gem 'pg', '~> 1.0' | gem 'pg', '~> 1.0' | ||||||
|  | gem 'makara', '~> 0.4' | ||||||
| gem 'pghero', '~> 2.1' | gem 'pghero', '~> 2.1' | ||||||
| gem 'dotenv-rails', '~> 2.2', '< 2.3' | gem 'dotenv-rails', '~> 2.2', '< 2.3' | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -324,6 +324,8 @@ GEM | ||||||
|       nokogiri (>= 1.5.9) |       nokogiri (>= 1.5.9) | ||||||
|     mail (2.7.0) |     mail (2.7.0) | ||||||
|       mini_mime (>= 0.1.1) |       mini_mime (>= 0.1.1) | ||||||
|  |     makara (0.4.0) | ||||||
|  |       activerecord (>= 3.0.0) | ||||||
|     marcel (0.3.2) |     marcel (0.3.2) | ||||||
|       mimemagic (~> 0.3.2) |       mimemagic (~> 0.3.2) | ||||||
|     mario-redis-lock (1.2.1) |     mario-redis-lock (1.2.1) | ||||||
|  | @ -700,6 +702,7 @@ DEPENDENCIES | ||||||
|   letter_opener_web (~> 1.3) |   letter_opener_web (~> 1.3) | ||||||
|   link_header (~> 0.0) |   link_header (~> 0.0) | ||||||
|   lograge (~> 0.10) |   lograge (~> 0.10) | ||||||
|  |   makara (~> 0.4) | ||||||
|   mario-redis-lock (~> 1.2) |   mario-redis-lock (~> 1.2) | ||||||
|   memory_profiler |   memory_profiler | ||||||
|   microformats (~> 4.0) |   microformats (~> 4.0) | ||||||
|  |  | ||||||
|  | @ -30,6 +30,12 @@ module Admin | ||||||
|       redirect_to admin_invites_path |       redirect_to admin_invites_path | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     def deactivate_all | ||||||
|  |       authorize :invite, :deactivate_all? | ||||||
|  |       Invite.available.in_batches.update_all(expires_at: Time.now.utc) | ||||||
|  |       redirect_to admin_invites_path | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|     def resource_params |     def resource_params | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ module StreamEntriesHelper | ||||||
|           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('settings.edit_profile')]) |           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('settings.edit_profile')]) | ||||||
|         end |         end | ||||||
|       elsif current_account.following?(account) || current_account.requested?(account) |       elsif current_account.following?(account) || current_account.requested?(account) | ||||||
|         link_to account_unfollow_path(account), class: 'button logo-button', data: { method: :post } do |         link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do | ||||||
|           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.unfollow')]) |           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.unfollow')]) | ||||||
|         end |         end | ||||||
|       else |       else | ||||||
|  |  | ||||||
|  | @ -140,7 +140,7 @@ export function redraft(status) { | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export function deleteStatus(id, withRedraft = false) { | export function deleteStatus(id, router, withRedraft = false) { | ||||||
|   return (dispatch, getState) => { |   return (dispatch, getState) => { | ||||||
|     const status = getState().getIn(['statuses', id]); |     const status = getState().getIn(['statuses', id]); | ||||||
| 
 | 
 | ||||||
|  | @ -153,6 +153,10 @@ export function deleteStatus(id, withRedraft = false) { | ||||||
| 
 | 
 | ||||||
|       if (withRedraft) { |       if (withRedraft) { | ||||||
|         dispatch(redraft(status)); |         dispatch(redraft(status)); | ||||||
|  | 
 | ||||||
|  |         if (!getState().getIn(['compose', 'mounted'])) { | ||||||
|  |           router.push('/statuses/new'); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }).catch(error => { |     }).catch(error => { | ||||||
|       dispatch(deleteStatusFail(id, error)); |       dispatch(deleteStatusFail(id, error)); | ||||||
|  |  | ||||||
|  | @ -96,11 +96,11 @@ export default class StatusActionBar extends ImmutablePureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleDeleteClick = () => { |   handleDeleteClick = () => { | ||||||
|     this.props.onDelete(this.props.status); |     this.props.onDelete(this.props.status, this.context.router.history); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleRedraftClick = () => { |   handleRedraftClick = () => { | ||||||
|     this.props.onDelete(this.props.status, true); |     this.props.onDelete(this.props.status, this.context.router.history, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handlePinClick = () => { |   handlePinClick = () => { | ||||||
|  |  | ||||||
|  | @ -93,14 +93,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ | ||||||
|     })); |     })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onDelete (status, withRedraft = false) { |   onDelete (status, history, withRedraft = false) { | ||||||
|     if (!deleteModal) { |     if (!deleteModal) { | ||||||
|       dispatch(deleteStatus(status.get('id'), withRedraft)); |       dispatch(deleteStatus(status.get('id'), history, withRedraft)); | ||||||
|     } else { |     } else { | ||||||
|       dispatch(openModal('CONFIRM', { |       dispatch(openModal('CONFIRM', { | ||||||
|         message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), |         message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), | ||||||
|         confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), |         confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), | ||||||
|         onConfirm: () => dispatch(deleteStatus(status.get('id'), withRedraft)), |         onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)), | ||||||
|       })); |       })); | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ export default class Upload extends ImmutablePureComponent { | ||||||
|     onUndo: PropTypes.func.isRequired, |     onUndo: PropTypes.func.isRequired, | ||||||
|     onDescriptionChange: PropTypes.func.isRequired, |     onDescriptionChange: PropTypes.func.isRequired, | ||||||
|     onOpenFocalPoint: PropTypes.func.isRequired, |     onOpenFocalPoint: PropTypes.func.isRequired, | ||||||
|  |     onSubmit: PropTypes.func.isRequired, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   state = { |   state = { | ||||||
|  | @ -28,6 +29,17 @@ export default class Upload extends ImmutablePureComponent { | ||||||
|     dirtyDescription: null, |     dirtyDescription: null, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   handleKeyDown = (e) => { | ||||||
|  |     if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { | ||||||
|  |       this.handleSubmit(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   handleSubmit = () => { | ||||||
|  |     this.handleInputBlur(); | ||||||
|  |     this.props.onSubmit(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   handleUndoClick = () => { |   handleUndoClick = () => { | ||||||
|     this.props.onUndo(this.props.media.get('id')); |     this.props.onUndo(this.props.media.get('id')); | ||||||
|   } |   } | ||||||
|  | @ -93,6 +105,7 @@ export default class Upload extends ImmutablePureComponent { | ||||||
|                     onFocus={this.handleInputFocus} |                     onFocus={this.handleInputFocus} | ||||||
|                     onChange={this.handleInputChange} |                     onChange={this.handleInputChange} | ||||||
|                     onBlur={this.handleInputBlur} |                     onBlur={this.handleInputBlur} | ||||||
|  |                     onKeyDown={this.handleKeyDown} | ||||||
|                   /> |                   /> | ||||||
|                 </label> |                 </label> | ||||||
|               </div> |               </div> | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import { connect } from 'react-redux'; | ||||||
| import Upload from '../components/upload'; | import Upload from '../components/upload'; | ||||||
| import { undoUploadCompose, changeUploadCompose } from '../../../actions/compose'; | import { undoUploadCompose, changeUploadCompose } from '../../../actions/compose'; | ||||||
| import { openModal } from '../../../actions/modal'; | import { openModal } from '../../../actions/modal'; | ||||||
|  | import { submitCompose } from '../../../actions/compose'; | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = (state, { id }) => ({ | const mapStateToProps = (state, { id }) => ({ | ||||||
|   media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id), |   media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id), | ||||||
|  | @ -21,6 +22,10 @@ const mapDispatchToProps = dispatch => ({ | ||||||
|     dispatch(openModal('FOCAL_POINT', { id })); |     dispatch(openModal('FOCAL_POINT', { id })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|  |   onSubmit () { | ||||||
|  |     dispatch(submitCompose()); | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default connect(mapStateToProps, mapDispatchToProps)(Upload); | export default connect(mapStateToProps, mapDispatchToProps)(Upload); | ||||||
|  |  | ||||||
|  | @ -139,6 +139,7 @@ export default class GettingStarted extends ImmutablePureComponent { | ||||||
|             {multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>} |             {multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>} | ||||||
|             <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li> |             <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li> | ||||||
|             <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li> |             <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li> | ||||||
|  |             <li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li> | ||||||
|             <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li> |             <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li> | ||||||
|             <li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li> |             <li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li> | ||||||
|             <li><a href='https://github.com/tootsuite/documentation#documentation' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li> |             <li><a href='https://github.com/tootsuite/documentation#documentation' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li> | ||||||
|  |  | ||||||
|  | @ -65,11 +65,11 @@ export default class ActionBar extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleDeleteClick = () => { |   handleDeleteClick = () => { | ||||||
|     this.props.onDelete(this.props.status); |     this.props.onDelete(this.props.status, this.context.router.history); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleRedraftClick = () => { |   handleRedraftClick = () => { | ||||||
|     this.props.onDelete(this.props.status, true); |     this.props.onDelete(this.props.status, this.context.router.history, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleDirectClick = () => { |   handleDirectClick = () => { | ||||||
|  |  | ||||||
|  | @ -174,16 +174,16 @@ export default class Status extends ImmutablePureComponent { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   handleDeleteClick = (status, withRedraft = false) => { |   handleDeleteClick = (status, history, withRedraft = false) => { | ||||||
|     const { dispatch, intl } = this.props; |     const { dispatch, intl } = this.props; | ||||||
| 
 | 
 | ||||||
|     if (!deleteModal) { |     if (!deleteModal) { | ||||||
|       dispatch(deleteStatus(status.get('id'), withRedraft)); |       dispatch(deleteStatus(status.get('id'), history, withRedraft)); | ||||||
|     } else { |     } else { | ||||||
|       dispatch(openModal('CONFIRM', { |       dispatch(openModal('CONFIRM', { | ||||||
|         message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), |         message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), | ||||||
|         confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), |         confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), | ||||||
|         onConfirm: () => dispatch(deleteStatus(status.get('id'), withRedraft)), |         onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)), | ||||||
|       })); |       })); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -35,6 +35,17 @@ | ||||||
|     transition: all 200ms ease-out; |     transition: all 200ms ease-out; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   &--destructive { | ||||||
|  |     transition: none; | ||||||
|  | 
 | ||||||
|  |     &:active, | ||||||
|  |     &:focus, | ||||||
|  |     &:hover { | ||||||
|  |       background-color: $error-red; | ||||||
|  |       transition: none; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   &:disabled { |   &:disabled { | ||||||
|     background-color: $ui-primary-color; |     background-color: $ui-primary-color; | ||||||
|     cursor: default; |     cursor: default; | ||||||
|  |  | ||||||
|  | @ -110,6 +110,18 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   &.button--destructive { | ||||||
|  |     &:active, | ||||||
|  |     &:focus, | ||||||
|  |     &:hover { | ||||||
|  |       background: $error-red; | ||||||
|  | 
 | ||||||
|  |       svg path:last-child { | ||||||
|  |         fill: $error-red; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @media screen and (max-width: $no-gap-breakpoint) { |   @media screen and (max-width: $no-gap-breakpoint) { | ||||||
|     svg { |     svg { | ||||||
|       display: none; |       display: none; | ||||||
|  |  | ||||||
|  | @ -42,7 +42,14 @@ class User < ApplicationRecord | ||||||
|   include Settings::Extend |   include Settings::Extend | ||||||
|   include Omniauthable |   include Omniauthable | ||||||
| 
 | 
 | ||||||
|   ACTIVE_DURATION = 7.days |   # The home and list feeds will be stored in Redis for this amount | ||||||
|  |   # of time, and status fan-out to followers will include only people | ||||||
|  |   # within this time frame. Lowering the duration may improve performance | ||||||
|  |   # if lots of people sign up, but not a lot of them check their feed | ||||||
|  |   # every day. Raising the duration reduces the amount of expensive | ||||||
|  |   # RegenerationWorker jobs that need to be run when those people come | ||||||
|  |   # to check their feed | ||||||
|  |   ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days | ||||||
| 
 | 
 | ||||||
|   devise :two_factor_authenticatable, |   devise :two_factor_authenticatable, | ||||||
|          otp_secret_encryption_key: Rails.configuration.x.otp_secret |          otp_secret_encryption_key: Rails.configuration.x.otp_secret | ||||||
|  |  | ||||||
|  | @ -9,6 +9,10 @@ class InvitePolicy < ApplicationPolicy | ||||||
|     min_required_role? |     min_required_role? | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def deactivate_all? | ||||||
|  |     admin? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def destroy? |   def destroy? | ||||||
|     owner? || (Setting.min_invite_role == 'admin' ? admin? : staff?) |     owner? || (Setting.min_invite_role == 'admin' ? admin? : staff?) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ class ProcessMentionsService < BaseService | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       next match if mention_undeliverable?(mentioned_account) |       next match if mention_undeliverable?(mentioned_account) || mentioned_account&.suspended | ||||||
| 
 | 
 | ||||||
|       mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status) |       mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,14 +9,17 @@ | ||||||
|       %li= filter_link_to t('admin.invites.filter.available'), available: 1, expired: nil |       %li= filter_link_to t('admin.invites.filter.available'), available: 1, expired: nil | ||||||
|       %li= filter_link_to t('admin.invites.filter.expired'), available: nil, expired: 1 |       %li= filter_link_to t('admin.invites.filter.expired'), available: nil, expired: 1 | ||||||
| 
 | 
 | ||||||
|  | %hr.spacer/ | ||||||
|  | 
 | ||||||
| - if policy(:invite).create? | - if policy(:invite).create? | ||||||
|   %p= t('invites.prompt') |   %p= t('invites.prompt') | ||||||
| 
 | 
 | ||||||
|   = render 'invites/form' |   = render 'invites/form' | ||||||
| 
 | 
 | ||||||
|   %hr/ |   %hr.spacer/ | ||||||
| 
 | 
 | ||||||
| %table.table | .table-wrapper | ||||||
|  |   %table.table | ||||||
|     %thead |     %thead | ||||||
|       %tr |       %tr | ||||||
|         %th |         %th | ||||||
|  | @ -28,3 +31,6 @@ | ||||||
|       = render @invites |       = render @invites | ||||||
| 
 | 
 | ||||||
| = paginate @invites | = paginate @invites | ||||||
|  | 
 | ||||||
|  | - if policy(:invite).deactivate_all? | ||||||
|  |   = link_to t('admin.invites.deactivate_all'), deactivate_all_admin_invites_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' | ||||||
|  |  | ||||||
|  | @ -42,6 +42,6 @@ | ||||||
|             %h4= t 'footer.more' |             %h4= t 'footer.more' | ||||||
|             %ul |             %ul | ||||||
|               %li= link_to t('about.source_code'), Mastodon::Version.source_url |               %li= link_to t('about.source_code'), Mastodon::Version.source_url | ||||||
|               %li= link_to 'joinmastodon.org', 'https://joinmastodon.org' |               %li= link_to t('about.apps'), 'https://joinmastodon.org/apps' | ||||||
| 
 | 
 | ||||||
| = render template: 'layouts/application' | = render template: 'layouts/application' | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ en: | ||||||
|     about_this: About |     about_this: About | ||||||
|     administered_by: 'Administered by:' |     administered_by: 'Administered by:' | ||||||
|     api: API |     api: API | ||||||
|  |     apps: Mobile apps | ||||||
|     closed_registrations: Registrations are currently closed on this instance. However! You can find a different instance to make an account on and get access to the very same network from there. |     closed_registrations: Registrations are currently closed on this instance. However! You can find a different instance to make an account on and get access to the very same network from there. | ||||||
|     contact: Contact |     contact: Contact | ||||||
|     contact_missing: Not set |     contact_missing: Not set | ||||||
|  | @ -281,6 +282,7 @@ en: | ||||||
|       search: Search |       search: Search | ||||||
|       title: Known instances |       title: Known instances | ||||||
|     invites: |     invites: | ||||||
|  |       deactivate_all: Deactivate all | ||||||
|       filter: |       filter: | ||||||
|         all: All |         all: All | ||||||
|         available: Available |         available: Available | ||||||
|  |  | ||||||
|  | @ -137,7 +137,12 @@ Rails.application.routes.draw do | ||||||
|     resources :email_domain_blocks, only: [:index, :new, :create, :destroy] |     resources :email_domain_blocks, only: [:index, :new, :create, :destroy] | ||||||
|     resources :action_logs, only: [:index] |     resources :action_logs, only: [:index] | ||||||
|     resource :settings, only: [:edit, :update] |     resource :settings, only: [:edit, :update] | ||||||
|     resources :invites, only: [:index, :create, :destroy] | 
 | ||||||
|  |     resources :invites, only: [:index, :create, :destroy] do | ||||||
|  |       collection do | ||||||
|  |         post :deactivate_all | ||||||
|  |       end | ||||||
|  |     end | ||||||
| 
 | 
 | ||||||
|     resources :relays, only: [:index, :new, :create, :destroy] do |     resources :relays, only: [:index, :new, :create, :destroy] do | ||||||
|       member do |       member do | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ class CopyStatusStats < ActiveRecord::Migration[5.2] | ||||||
| 
 | 
 | ||||||
|   def up |   def up | ||||||
|     safety_assured do |     safety_assured do | ||||||
|       Status.where.not(id: StatusStat.select('status_id')).select('id').find_in_batches do |statuses| |       Status.unscoped.select('id').find_in_batches(batch_size: 5_000) do |statuses| | ||||||
|         execute <<-SQL.squish |         execute <<-SQL.squish | ||||||
|           INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at) |           INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at) | ||||||
|           SELECT id, reblogs_count, favourites_count, created_at, updated_at |           SELECT id, reblogs_count, favourites_count, created_at, updated_at | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue