Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scheduled statuses #9706

Merged
merged 1 commit into from
Jan 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/controllers/api/v1/scheduled_statuses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

class Api::V1::ScheduledStatusesController < Api::BaseController
include Authorization

before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, except: [:update, :destroy]
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:update, :destroy]

before_action :set_statuses, only: :index
before_action :set_status, except: :index

after_action :insert_pagination_headers, only: :index

def index
render json: @statuses, each_serializer: REST::ScheduledStatusSerializer
end

def show
render json: @status, serializer: REST::ScheduledStatusSerializer
end

def update
@status.update!(scheduled_status_params)
render json: @status, serializer: REST::ScheduledStatusSerializer
end

def destroy
@status.destroy!
render_empty
end

private

def set_statuses
@statuses = current_account.scheduled_statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))
end

def set_status
@status = current_account.scheduled_statuses.find(params[:id])
end

def scheduled_status_params
params.permit(:scheduled_at)
end

def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
if records_continue?
api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id)
end
end

def prev_path
unless @statuses.empty?
api_v1_scheduled_statuses_url pagination_params(min_id: pagination_since_id)
end
end

def records_continue?
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
end

def pagination_max_id
@statuses.last.id
end

def pagination_since_id
@statuses.first.id
end
end
9 changes: 5 additions & 4 deletions app/controllers/api/v1/statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@ def card

def create
@status = PostStatusService.new.call(current_user.account,
status_params[:status],
status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
text: status_params[:status],
thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
media_ids: status_params[:media_ids],
sensitive: status_params[:sensitive],
spoiler_text: status_params[:spoiler_text],
visibility: status_params[:visibility],
scheduled_at: status_params[:scheduled_at],
application: doorkeeper_token.application,
idempotency: request.headers['Idempotency-Key'])

render json: @status, serializer: REST::StatusSerializer
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
end

def destroy
Expand All @@ -77,7 +78,7 @@ def set_status
end

def status_params
params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, media_ids: [])
params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, :scheduled_at, media_ids: [])
end

def pagination_params(core_params)
Expand Down
1 change: 1 addition & 0 deletions app/models/concerns/account_associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module AccountAssociations
has_many :mentions, inverse_of: :account, dependent: :destroy
has_many :notifications, inverse_of: :account, dependent: :destroy
has_many :conversations, class_name: 'AccountConversation', dependent: :destroy, inverse_of: :account
has_many :scheduled_statuses, inverse_of: :account, dependent: :destroy

# Pinned statuses
has_many :status_pins, inverse_of: :account, dependent: :destroy
Expand Down
38 changes: 20 additions & 18 deletions app/models/media_attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
#
# Table name: media_attachments
#
# id :bigint(8) not null, primary key
# status_id :bigint(8)
# file_file_name :string
# file_content_type :string
# file_file_size :integer
# file_updated_at :datetime
# remote_url :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
# shortcode :string
# type :integer default("image"), not null
# file_meta :json
# account_id :bigint(8)
# description :text
# id :bigint(8) not null, primary key
# status_id :bigint(8)
# file_file_name :string
# file_content_type :string
# file_file_size :integer
# file_updated_at :datetime
# remote_url :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
# shortcode :string
# type :integer default("image"), not null
# file_meta :json
# account_id :bigint(8)
# description :text
# scheduled_status_id :bigint(8)
#

class MediaAttachment < ApplicationRecord
Expand Down Expand Up @@ -76,8 +77,9 @@ class MediaAttachment < ApplicationRecord
IMAGE_LIMIT = 8.megabytes
VIDEO_LIMIT = 40.megabytes

belongs_to :account, inverse_of: :media_attachments, optional: true
belongs_to :status, inverse_of: :media_attachments, optional: true
belongs_to :account, inverse_of: :media_attachments, optional: true
belongs_to :status, inverse_of: :media_attachments, optional: true
belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true

has_attached_file :file,
styles: ->(f) { file_styles f },
Expand All @@ -94,8 +96,8 @@ class MediaAttachment < ApplicationRecord
validates :account, presence: true
validates :description, length: { maximum: 420 }, if: :local?

scope :attached, -> { where.not(status_id: nil) }
scope :unattached, -> { where(status_id: nil) }
scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) }
scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) }
scope :local, -> { where(remote_url: '') }
scope :remote, -> { where.not(remote_url: '') }

Expand Down
39 changes: 39 additions & 0 deletions app/models/scheduled_status.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

# == Schema Information
#
# Table name: scheduled_statuses
#
# id :bigint(8) not null, primary key
# account_id :bigint(8)
# scheduled_at :datetime
# params :jsonb
#

class ScheduledStatus < ApplicationRecord
include Paginable

TOTAL_LIMIT = 300
DAILY_LIMIT = 25

belongs_to :account, inverse_of: :scheduled_statuses
has_many :media_attachments, inverse_of: :scheduled_status, dependent: :destroy

validate :validate_future_date
validate :validate_total_limit
validate :validate_daily_limit

private

def validate_future_date
errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET
end

def validate_total_limit
errors.add(:base, I18n.t('scheduled_statuses.over_total_limit', limit: TOTAL_LIMIT)) if account.scheduled_statuses.count >= TOTAL_LIMIT
end

def validate_daily_limit
errors.add(:base, I18n.t('scheduled_statuses.over_daily_limit', limit: DAILY_LIMIT)) if account.scheduled_statuses.where('scheduled_at::date = ?::date', scheduled_at).count >= DAILY_LIMIT
end
end
11 changes: 11 additions & 0 deletions app/serializers/rest/scheduled_status_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class REST::ScheduledStatusSerializer < ActiveModel::Serializer
attributes :id, :scheduled_at

has_many :media_attachments, serializer: REST::MediaAttachmentSerializer

def id
object.id.to_s
end
end
Loading