Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
gab-social
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
gab
social
gab-social
Commits
4de30bd8
Commit
4de30bd8
authored
Sep 18, 2019
by
Rob Colbert
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/revision-history' of
https://code.gab.com/gab/social/gab-social
into develop
parents
b340a49e
498630f2
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
319 additions
and
13 deletions
+319
-13
app/controllers/api/v1/statuses_controller.rb
app/controllers/api/v1/statuses_controller.rb
+4
-8
app/javascript/gabsocial/actions/status_revision_list.js
app/javascript/gabsocial/actions/status_revision_list.js
+16
-0
app/javascript/gabsocial/components/status.js
app/javascript/gabsocial/components/status.js
+4
-2
app/javascript/gabsocial/containers/status_container.js
app/javascript/gabsocial/containers/status_container.js
+4
-0
app/javascript/gabsocial/features/ui/components/modal_root.js
...javascript/gabsocial/features/ui/components/modal_root.js
+2
-0
app/javascript/gabsocial/features/ui/components/status_revision_list.js
.../gabsocial/features/ui/components/status_revision_list.js
+44
-0
app/javascript/gabsocial/features/ui/components/status_revision_modal.js
...gabsocial/features/ui/components/status_revision_modal.js
+40
-0
app/javascript/gabsocial/features/ui/containers/status_revision_list_container.js
.../features/ui/containers/status_revision_list_container.js
+27
-0
app/javascript/gabsocial/features/ui/util/async-components.js
...javascript/gabsocial/features/ui/util/async-components.js
+4
-0
app/javascript/gabsocial/reducers/index.js
app/javascript/gabsocial/reducers/index.js
+2
-0
app/javascript/gabsocial/reducers/status_revision_list.js
app/javascript/gabsocial/reducers/status_revision_list.js
+31
-0
app/javascript/styles/application.scss
app/javascript/styles/application.scss
+1
-0
app/javascript/styles/gabsocial/components/status-revisions.scss
...ascript/styles/gabsocial/components/status-revisions.scss
+72
-0
app/models/account_verification_request.rb
app/models/account_verification_request.rb
+1
-1
app/models/status.rb
app/models/status.rb
+2
-0
app/models/status_revision.rb
app/models/status_revision.rb
+13
-0
app/serializers/rest/status_revision_serializer.rb
app/serializers/rest/status_revision_serializer.rb
+5
-0
app/serializers/rest/status_serializer.rb
app/serializers/rest/status_serializer.rb
+1
-1
app/services/edit_status_service.rb
app/services/edit_status_service.rb
+22
-0
config/routes.rb
config/routes.rb
+1
-0
db/migrate/20190917135359_create_status_revisions.rb
db/migrate/20190917135359_create_status_revisions.rb
+9
-0
db/migrate/20190917141707_add_revised_at_to_statuses.rb
db/migrate/20190917141707_add_revised_at_to_statuses.rb
+5
-0
db/schema.rb
db/schema.rb
+9
-1
No files found.
app/controllers/api/v1/statuses_controller.rb
View file @
4de30bd8
...
...
@@ -6,7 +6,7 @@ class Api::V1::StatusesController < Api::BaseController
before_action
->
{
authorize_if_got_token!
:read
,
:'read:statuses'
},
except:
[
:create
,
:update
,
:destroy
]
before_action
->
{
doorkeeper_authorize!
:write
,
:'write:statuses'
},
only:
[
:create
,
:update
,
:destroy
]
before_action
:require_user!
,
except:
[
:show
,
:context
,
:card
]
before_action
:set_status
,
only:
[
:show
,
:context
,
:card
,
:update
]
before_action
:set_status
,
only:
[
:show
,
:context
,
:card
,
:update
,
:revisions
]
respond_to
:json
...
...
@@ -33,14 +33,10 @@ class Api::V1::StatusesController < Api::BaseController
render
json:
@context
,
serializer:
REST
::
ContextSerializer
,
relationships:
StatusRelationshipsPresenter
.
new
(
statuses
,
current_user
&
.
account_id
)
end
def
card
@
card
=
@status
.
preview_cards
.
first
def
revisions
@
revisions
=
@status
.
revisions
if
@card
.
nil?
render_empty
else
render
json:
@card
,
serializer:
REST
::
PreviewCardSerializer
end
render
json:
@revisions
,
each_serializer:
REST
::
StatusRevisionSerializer
end
def
create
...
...
app/javascript/gabsocial/actions/status_revision_list.js
0 → 100644
View file @
4de30bd8
import
api
from
'
../api
'
;
export
const
STATUS_REVISION_LIST_LOAD
=
'
STATUS_REVISION_LIST
'
;
export
const
STATUS_REVISION_LIST_LOAD_SUCCESS
=
'
STATUS_REVISION_LIST_SUCCESS
'
;
export
const
STATUS_REVISION_LIST_LOAD_FAIL
=
'
STATUS_REVISION_LIST_FAIL
'
;
const
loadSuccess
=
data
=>
({
type
:
STATUS_REVISION_LIST_LOAD_SUCCESS
,
payload
:
data
});
const
loadFail
=
e
=>
({
type
:
STATUS_REVISION_LIST_LOAD_FAIL
,
payload
:
e
});
export
function
load
(
statusId
)
{
return
(
dispatch
,
getState
)
=>
{
api
(
getState
).
get
(
`/api/v1/statuses/
${
statusId
}
/revisions`
)
.
then
(
res
=>
dispatch
(
loadSuccess
(
res
.
data
)))
.
catch
(
e
=>
dispatch
(
loadFail
(
e
)));
};
}
\ No newline at end of file
app/javascript/gabsocial/components/status.js
View file @
4de30bd8
...
...
@@ -67,6 +67,7 @@ class Status extends ImmutablePureComponent {
otherAccounts
:
ImmutablePropTypes
.
list
,
onClick
:
PropTypes
.
func
,
onReply
:
PropTypes
.
func
,
onShowRevisions
:
PropTypes
.
func
,
onQuote
:
PropTypes
.
func
,
onFavourite
:
PropTypes
.
func
,
onReblog
:
PropTypes
.
func
,
...
...
@@ -438,9 +439,10 @@ class Status extends ImmutablePureComponent {
<
/NavLink
>
<
/div
>
{
!
group
&&
status
.
get
(
'
group
'
)
&&
(
{
((
!
group
&&
status
.
get
(
'
group
'
))
||
status
.
get
(
'
revised_at
'
)
!==
null
)
&&
(
<
div
className
=
'
status__meta
'
>
Posted
in
<
NavLink
to
=
{
`/groups/
${
status
.
getIn
([
'
group
'
,
'
id
'
])}
`
}
>
{
status
.
getIn
([
'
group
'
,
'
title
'
])}
<
/NavLink
>
{
!
group
&&
status
.
get
(
'
group
'
)
&&
<
React
.
Fragment
>
Posted
in
<
NavLink
to
=
{
`/groups/
${
status
.
getIn
([
'
group
'
,
'
id
'
])}
`
}
>
{
status
.
getIn
([
'
group
'
,
'
title
'
])}
<
/NavLink></
React
.
Fragment
>
}
{
status
.
get
(
'
revised_at
'
)
!==
null
&&
<
a
onClick
=
{()
=>
other
.
onShowRevisions
(
status
)}
>
Edited
<
/a>
}
<
/div
>
)}
...
...
app/javascript/gabsocial/containers/status_container.js
View file @
4de30bd8
...
...
@@ -105,6 +105,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}
},
onShowRevisions
(
status
)
{
dispatch
(
openModal
(
'
STATUS_REVISION
'
,
{
status
}));
},
onFavourite
(
status
)
{
if
(
status
.
get
(
'
favourited
'
))
{
dispatch
(
unfavourite
(
status
));
...
...
app/javascript/gabsocial/features/ui/components/modal_root.js
View file @
4de30bd8
...
...
@@ -20,6 +20,7 @@ import {
EmbedModal
,
ListEditor
,
ListAdder
,
StatusRevisionModal
,
}
from
'
../../../features/ui/util/async-components
'
;
const
MODAL_COMPONENTS
=
{
...
...
@@ -35,6 +36,7 @@ const MODAL_COMPONENTS = {
'
FOCAL_POINT
'
:
()
=>
Promise
.
resolve
({
default
:
FocalPointModal
}),
'
LIST_ADDER
'
:
ListAdder
,
'
HOTKEYS
'
:
()
=>
Promise
.
resolve
({
default
:
HotkeysModal
}),
'
STATUS_REVISION
'
:
StatusRevisionModal
,
'
COMPOSE
'
:
()
=>
Promise
.
resolve
({
default
:
ComposeModal
}),
'
UNAUTHORIZED
'
:
()
=>
Promise
.
resolve
({
default
:
UnauthorizedModal
}),
};
...
...
app/javascript/gabsocial/features/ui/components/status_revision_list.js
0 → 100644
View file @
4de30bd8
import
React
from
'
react
'
;
import
{
injectIntl
}
from
'
react-intl
'
;
import
PropTypes
from
'
prop-types
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
ModalLoading
from
'
./modal_loading
'
;
import
RelativeTimestamp
from
'
../../../components/relative_timestamp
'
;
export
default
@
injectIntl
class
StatusRevisionsList
extends
ImmutablePureComponent
{
static
propTypes
=
{
loading
:
PropTypes
.
bool
.
isRequired
,
error
:
PropTypes
.
object
,
data
:
PropTypes
.
array
};
render
()
{
const
{
loading
,
error
,
data
}
=
this
.
props
;
if
(
loading
||
!
data
)
return
<
ModalLoading
/>
;
if
(
error
)
return
(
<
div
className
=
'
status-revisions-list
'
>
<
div
className
=
'
status-revisions-list__error
'
>
An
error
occured
<
/div
>
<
/div
>
);
return
(
<
div
className
=
'
status-revisions-list
'
>
{
data
.
map
((
revision
,
i
)
=>
(
<
div
key
=
{
i
}
className
=
'
status-revisions-list__item
'
>
<
div
className
=
'
status-revisions-list__item__timestamp
'
>
<
RelativeTimestamp
timestamp
=
{
revision
.
created_at
}
/
>
<
/div
>
<
div
className
=
'
status-revisions-list__item__text
'
>
{
revision
.
text
}
<
/div
>
<
/div
>
))}
<
/div
>
);
}
}
\ No newline at end of file
app/javascript/gabsocial/features/ui/components/status_revision_modal.js
0 → 100644
View file @
4de30bd8
import
React
from
'
react
'
;
import
{
defineMessages
,
injectIntl
,
FormattedMessage
}
from
'
react-intl
'
;
import
PropTypes
from
'
prop-types
'
;
import
ImmutablePropTypes
from
'
react-immutable-proptypes
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
IconButton
from
'
gabsocial/components/icon_button
'
;
import
StatusRevisionListContainer
from
'
../containers/status_revision_list_container
'
;
const
messages
=
defineMessages
({
close
:
{
id
:
'
lightbox.close
'
,
defaultMessage
:
'
Close
'
},
});
export
default
@
injectIntl
class
StatusRevisionModal
extends
ImmutablePureComponent
{
static
propTypes
=
{
intl
:
PropTypes
.
object
.
isRequired
,
onClose
:
PropTypes
.
func
.
isRequired
,
status
:
ImmutablePropTypes
.
map
.
isRequired
};
render
()
{
const
{
intl
,
onClose
,
status
}
=
this
.
props
;
return
(
<
div
className
=
'
modal-root__modal
'
>
<
div
className
=
'
status-revisions
'
>
<
div
className
=
'
status-revisions__header
'
>
<
h3
className
=
'
status-revisions__header__title
'
><
FormattedMessage
id
=
'
status_revisions.heading
'
defaultMessage
=
'
Revision History
'
/><
/h3
>
<
IconButton
className
=
'
status-revisions__close
'
title
=
{
intl
.
formatMessage
(
messages
.
close
)}
icon
=
'
times
'
onClick
=
{
onClose
}
size
=
{
20
}
/
>
<
/div
>
<
div
className
=
'
status-revisions__content
'
>
<
StatusRevisionListContainer
id
=
{
status
.
get
(
'
id
'
)}
/
>
<
/div
>
<
/div
>
<
/div
>
);
}
}
app/javascript/gabsocial/features/ui/containers/status_revision_list_container.js
0 → 100644
View file @
4de30bd8
import
React
from
'
react
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
load
}
from
'
../../../actions/status_revision_list
'
;
import
StatusRevisionList
from
'
../components/status_revision_list
'
;
class
StatusRevisionListContainer
extends
ImmutablePureComponent
{
componentDidMount
()
{
this
.
props
.
load
(
this
.
props
.
id
);
}
render
()
{
return
<
StatusRevisionList
{...
this
.
props
}
/>
;
}
}
const
mapStateToProps
=
state
=>
({
loading
:
state
.
getIn
([
'
status_revision_list
'
,
'
loading
'
]),
error
:
state
.
getIn
([
'
status_revision_list
'
,
'
error
'
]),
data
:
state
.
getIn
([
'
status_revision_list
'
,
'
data
'
]),
});
const
mapDispatchToProps
=
{
load
};
export
default
connect
(
mapStateToProps
,
mapDispatchToProps
)(
StatusRevisionListContainer
);
\ No newline at end of file
app/javascript/gabsocial/features/ui/util/async-components.js
View file @
4de30bd8
...
...
@@ -122,6 +122,10 @@ export function MuteModal () {
return
import
(
/* webpackChunkName: "modals/mute_modal" */
'
../components/mute_modal
'
);
}
export
function
StatusRevisionModal
()
{
return
import
(
/* webpackChunkName: "modals/mute_modal" */
'
../components/status_revision_modal
'
);
}
export
function
ReportModal
()
{
return
import
(
/* webpackChunkName: "modals/report_modal" */
'
../components/report_modal
'
);
}
...
...
app/javascript/gabsocial/reducers/index.js
View file @
4de30bd8
...
...
@@ -37,6 +37,7 @@ import group_relationships from './group_relationships';
import
group_lists
from
'
./group_lists
'
;
import
group_editor
from
'
./group_editor
'
;
import
sidebar
from
'
./sidebar
'
;
import
status_revision_list
from
'
./status_revision_list
'
;
const
reducers
=
{
dropdown_menu
,
...
...
@@ -77,6 +78,7 @@ const reducers = {
group_lists
,
group_editor
,
sidebar
,
status_revision_list
,
};
export
default
combineReducers
(
reducers
);
app/javascript/gabsocial/reducers/status_revision_list.js
0 → 100644
View file @
4de30bd8
import
{
Map
as
ImmutableMap
}
from
'
immutable
'
;
import
{
STATUS_REVISION_LIST_LOAD
,
STATUS_REVISION_LIST_LOAD_SUCCESS
,
STATUS_REVISION_LIST_LOAD_FAIL
}
from
'
../actions/status_revision_list
'
;
const
initialState
=
ImmutableMap
({
loading
:
false
,
error
:
null
,
data
:
null
});
export
default
function
statusRevisionList
(
state
=
initialState
,
action
)
{
switch
(
action
.
type
)
{
case
STATUS_REVISION_LIST_LOAD
:
return
initialState
;
case
STATUS_REVISION_LIST_LOAD_SUCCESS
:
return
state
.
withMutations
(
mutable
=>
{
mutable
.
set
(
'
loading
'
,
false
);
mutable
.
set
(
'
data
'
,
action
.
payload
);
});
case
STATUS_REVISION_LIST_LOAD_FAIL
:
return
state
.
withMutations
(
mutable
=>
{
mutable
.
set
(
'
loading
'
,
false
);
mutable
.
set
(
'
error
'
,
action
.
payload
);
});
default
:
return
state
;
}
};
app/javascript/styles/application.scss
View file @
4de30bd8
...
...
@@ -32,6 +32,7 @@
@import
'gabsocial/components/group-form'
;
@import
'gabsocial/components/group-sidebar-panel'
;
@import
'gabsocial/components/sidebar-menu'
;
@import
'gabsocial/components/status-revisions'
;
@import
'gabsocial/polls'
;
@import
'gabsocial/introduction'
;
...
...
app/javascript/styles/gabsocial/components/status-revisions.scss
0 → 100644
View file @
4de30bd8
.status-revisions
{
padding
:
8px
0
0
;
overflow
:
hidden
;
background-color
:
$classic-base-color
;
border-radius
:
6px
;
@media
screen
and
(
max-width
:
960px
)
{
height
:
90vh
;
}
&
__header
{
display
:
block
;
position
:
relative
;
border-bottom
:
1px
solid
lighten
(
$classic-base-color
,
8%
);
border-radius
:
6px
6px
0
0
;
padding-top
:
12px
;
padding-bottom
:
12px
;
&
__title
{
display
:
block
;
width
:
80%
;
margin
:
0
auto
;
font-size
:
18px
;
font-weight
:
bold
;
line-height
:
24px
;
color
:
$primary-text-color
;
text-align
:
center
;
}
}
&
__close
{
position
:
absolute
;
right
:
10px
;
top
:
10px
;
}
&
__content
{
display
:
flex
;
flex-direction
:
row
;
width
:
500px
;
flex-direction
:
column
;
overflow
:
hidden
;
overflow-y
:
scroll
;
height
:
calc
(
100%
-
80px
);
-webkit-overflow-scrolling
:
touch
;
widows
:
90%
;
}
&
-list
{
width
:
100%
;
&
__error
{
padding
:
15px
;
text-align
:
center
;
font-weight
:
bold
;
}
&
__item
{
padding
:
15px
;
border-bottom
:
1px
solid
lighten
(
$classic-base-color
,
8%
);
&
__timestamp
{
opacity
:
0
.5
;
font-size
:
13px
;
}
&
__text
{
font-size
:
15px
;
}
}
}
}
\ No newline at end of file
app/models/account_verification_request.rb
View file @
4de30bd8
...
...
@@ -6,7 +6,7 @@
# account_id :bigint(8)
# image_file_name :string
# image_content_type :string
# image_file_size :
bigint(8)
# image_file_size :
integer
# image_updated_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
...
...
app/models/status.rb
View file @
4de30bd8
...
...
@@ -24,6 +24,7 @@
# poll_id :bigint(8)
# group_id :integer
# quote_of_id :bigint(8)
# revised_at :datetime
#
class
Status
<
ApplicationRecord
...
...
@@ -61,6 +62,7 @@ class Status < ApplicationRecord
has_many
:mentions
,
dependent: :destroy
,
inverse_of: :status
has_many
:active_mentions
,
->
{
active
},
class_name:
'Mention'
,
inverse_of: :status
has_many
:media_attachments
,
dependent: :nullify
has_many
:revisions
,
class_name:
'StatusRevision'
,
dependent: :destroy
has_and_belongs_to_many
:tags
has_and_belongs_to_many
:preview_cards
...
...
app/models/status_revision.rb
0 → 100644
View file @
4de30bd8
# == Schema Information
#
# Table name: status_revisions
#
# id :bigint(8) not null, primary key
# status_id :bigint(8)
# text :string
# created_at :datetime not null
# updated_at :datetime not null
#
class
StatusRevision
<
ApplicationRecord
end
app/serializers/rest/status_revision_serializer.rb
0 → 100644
View file @
4de30bd8
# frozen_string_literal: true
class
REST::StatusRevisionSerializer
<
ActiveModel
::
Serializer
attributes
:created_at
,
:text
end
app/serializers/rest/status_serializer.rb
View file @
4de30bd8
# frozen_string_literal: true
class
REST::StatusSerializer
<
ActiveModel
::
Serializer
attributes
:id
,
:created_at
,
:in_reply_to_id
,
:in_reply_to_account_id
,
attributes
:id
,
:created_at
,
:
revised_at
,
:
in_reply_to_id
,
:in_reply_to_account_id
,
:sensitive
,
:spoiler_text
,
:visibility
,
:language
,
:uri
,
:url
,
:replies_count
,
:reblogs_count
,
:favourites_count
,
:quote_of_id
...
...
app/services/edit_status_service.rb
View file @
4de30bd8
...
...
@@ -25,9 +25,11 @@ class EditStatusService < BaseService
validate_media!
preprocess_attributes!
revision_text
=
prepare_revision_text
process_status!
postprocess_status!
create_revision!
revision_text
redis
.
setex
(
idempotency_key
,
3_600
,
@status
.
id
)
if
idempotency_given?
...
...
@@ -60,6 +62,25 @@ class EditStatusService < BaseService
LinkCrawlWorker
.
perform_async
(
@status
.
id
)
unless
@status
.
spoiler_text?
end
def
prepare_revision_text
text
=
@status
.
text
current_media_ids
=
@status
.
media_attachments
.
pluck
(
:id
)
new_media_ids
=
@options
[
:media_ids
].
take
(
4
).
map
(
&
:to_i
)
if
current_media_ids
.
sort
!=
new_media_ids
.
sort
text
=
""
if
text
==
@options
[
:text
]
text
+=
" [Media attachments changed]"
end
text
.
strip
()
end
def
create_revision!
(
text
)
@status
.
revisions
.
create!
({
text:
text
})
end
def
validate_media!
return
if
@options
[
:media_ids
].
blank?
||
!
@options
[
:media_ids
].
is_a?
(
Enumerable
)
...
...
@@ -100,6 +121,7 @@ class EditStatusService < BaseService
def
status_attributes
{
revised_at:
Time
.
now
,
text:
@text
,
media_attachments:
@media
||
[],
sensitive:
(
@options
[
:sensitive
].
nil?
?
@account
.
user
&
.
setting_default_sensitive
:
@options
[
:sensitive
])
||
@options
[
:spoiler_text
].
present?
,
...
...
config/routes.rb
View file @
4de30bd8
...
...
@@ -305,6 +305,7 @@ Rails.application.routes.draw do
member
do
get
:context
get
:card
get
:revisions
end
end
...
...
db/migrate/20190917135359_create_status_revisions.rb
0 → 100644
View file @
4de30bd8
class
CreateStatusRevisions
<
ActiveRecord
::
Migration
[
5.2
]
def
change
create_table
:status_revisions
do
|
t
|
t
.
bigint
:status_id
t
.
string
:text
t
.
timestamps
end
end
end
db/migrate/20190917141707_add_revised_at_to_statuses.rb
0 → 100644
View file @
4de30bd8
class
AddRevisedAtToStatuses
<
ActiveRecord
::
Migration
[
5.2
]
def
change
add_column
:statuses
,
:revised_at
,
:datetime
end
end
db/schema.rb
View file @
4de30bd8
...
...
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord
::
Schema
.
define
(
version:
2019_09_
03_162122
)
do
ActiveRecord
::
Schema
.
define
(
version:
2019_09_
17_141707
)
do
# These are extensions that must be enabled in order to support this database
enable_extension
"plpgsql"
...
...
@@ -672,6 +672,13 @@ ActiveRecord::Schema.define(version: 2019_09_03_162122) do
t
.
index
[
"account_id"
,
"status_id"
],
name:
"index_status_pins_on_account_id_and_status_id"
,
unique:
true
end
create_table
"status_revisions"
,
force: :cascade
do
|
t
|
t
.
bigint
"status_id"
t
.
string
"text"
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
end
create_table
"status_stats"
,
force: :cascade
do
|
t
|
t
.
bigint
"status_id"
,
null:
false
t
.
bigint
"replies_count"
,
default:
0
,
null:
false
...
...
@@ -703,6 +710,7 @@ ActiveRecord::Schema.define(version: 2019_09_03_162122) do
t
.
bigint
"poll_id"
t
.
integer
"group_id"
t
.
bigint
"quote_of_id"
t
.
datetime
"revised_at"
t
.
index
[
"account_id"
,
"id"
,
"visibility"
,
"updated_at"
],
name:
"index_statuses_20180106"
,
order:
{
id: :desc
}
t
.
index
[
"group_id"
],
name:
"index_statuses_on_group_id"
t
.
index
[
"in_reply_to_account_id"
],
name:
"index_statuses_on_in_reply_to_account_id"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment