@ -0,0 +1,17 @@ | |||
# frozen_string_literal: true | |||
class Api::V1::NotificationsController < ApiController | |||
before_action -> { doorkeeper_authorize! :read } | |||
before_action :require_user! | |||
respond_to :json | |||
def index | |||
@notifications = Notification.where(account: current_account).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) | |||
next_path = api_v1_notifications_url(max_id: @notifications.last.id) if @notifications.size == 20 | |||
prev_path = api_v1_notifications_url(since_id: @notifications.first.id) unless @notifications.empty? | |||
set_pagination_headers(next_path, prev_path) | |||
end | |||
end |
@ -0,0 +1,44 @@ | |||
# frozen_string_literal: true | |||
class Notification < ApplicationRecord | |||
include Paginable | |||
belongs_to :account | |||
belongs_to :activity, polymorphic: true | |||
belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id' | |||
belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id' | |||
belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id' | |||
belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id' | |||
STATUS_INCLUDES = [:account, :media_attachments, mentions: :account, reblog: [:account, mentions: :account]].freeze | |||
scope :with_includes, -> { includes(status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account) } | |||
def type | |||
case activity_type | |||
when 'Status' | |||
:reblog | |||
else | |||
activity_type.downcase.to_sym | |||
end | |||
end | |||
def from_account | |||
case type | |||
when :mention | |||
activity.status.account | |||
when :follow, :favourite, :reblog | |||
activity.account | |||
end | |||
end | |||
def target_status | |||
case type | |||
when :reblog | |||
activity.reblog | |||
when :favourite, :mention | |||
activity.status | |||
end | |||
end | |||
end |
@ -0,0 +1,36 @@ | |||
# frozen_string_literal: true | |||
class NotifyService < BaseService | |||
def call(recipient, activity) | |||
@recipient = recipient | |||
@activity = activity | |||
@notification = Notification.new(account: @recipient, activity: @activity) | |||
return if blocked? | |||
create_notification | |||
send_email if email_enabled? | |||
end | |||
private | |||
def blocked? | |||
blocked = false | |||
blocked ||= @recipient.id == @notification.from_account.id | |||
blocked ||= @recipient.blocking?(@notification.from_account) | |||
blocked | |||
end | |||
def create_notification | |||
@notification.save! | |||
FeedManager.instance.broadcast(@recipient.id, type: 'notification', message: FeedManager.instance.inline_render(@recipient, 'api/v1/notifications/show', @notification)) | |||
end | |||
def send_email | |||
NotificationMailer.send(@notification.type, @recipient, @notification).deliver_later | |||
end | |||
def email_enabled? | |||
@recipient.user.settings(:notification_emails).send(@notification.type) | |||
end | |||
end |
@ -0,0 +1,2 @@ | |||
collection @notifications | |||
extends 'api/v1/notifications/show' |
@ -0,0 +1,11 @@ | |||
object @notification | |||
attributes :id, :type | |||
child from_account: :account do | |||
extends 'api/v1/accounts/show' | |||
end | |||
node(:status, if: lambda { |n| [:favourite, :reblog, :mention].include?(n.type) }) do |n| | |||
partial 'api/v1/statuses/show', object: n.target_status | |||
end |
@ -0,0 +1,13 @@ | |||
class CreateNotifications < ActiveRecord::Migration[5.0] | |||
def change | |||
create_table :notifications do |t| | |||
t.integer :account_id | |||
t.integer :activity_id | |||
t.string :activity_type | |||
t.timestamps | |||
end | |||
add_index :notifications, :account_id | |||
end | |||
end |
@ -0,0 +1,4 @@ | |||
Fabricator(:notification) do | |||
activity_id 1 | |||
activity_type "MyString" | |||
end |
@ -0,0 +1,29 @@ | |||
require 'rails_helper' | |||
RSpec.describe Notification, type: :model do | |||
describe '#from_account' do | |||
pending | |||
end | |||
describe '#type' do | |||
it 'returns :reblog for a Status' do | |||
notification = Notification.new(activity: Status.new) | |||
expect(notification.type).to eq :reblog | |||
end | |||
it 'returns :mention for a Mention' do | |||
notification = Notification.new(activity: Mention.new) | |||
expect(notification.type).to eq :mention | |||
end | |||
it 'returns :favourite for a Favourite' do | |||
notification = Notification.new(activity: Favourite.new) | |||
expect(notification.type).to eq :favourite | |||
end | |||
it 'returns :follow for a Follow' do | |||
notification = Notification.new(activity: Follow.new) | |||
expect(notification.type).to eq :follow | |||
end | |||
end | |||
end |