Skip to content
Snippets Groups Projects
Commit 77e13c2b authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Removing failed push notification API, make context loads use cache

parent 19b9e1e2
No related branches found
No related tags found
No related merge requests found
# frozen_string_literal: true
class Api::V1::DevicesController < ApiController
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
respond_to :json
def register
Device.where(account: current_account, registration_id: params[:registration_id]).first_or_create!(account: current_account, registration_id: params[:registration_id])
render_empty
end
def unregister
Device.where(account: current_account, registration_id: params[:registration_id]).delete_all
render_empty
end
end
......@@ -14,7 +14,12 @@ class Api::V1::StatusesController < ApiController
end
def context
@context = OpenStruct.new(ancestors: @status.in_reply_to_id.nil? ? [] : @status.ancestors(current_account), descendants: @status.descendants(current_account))
ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(current_account)
descendants_results = @status.descendants(current_account)
loaded_ancestors = cache_collection(ancestors_results, Status)
loaded_descendants = cache_collection(descendants_results, Status)
@context = OpenStruct.new(ancestors: loaded_ancestors, descendants: loaded_descendants)
statuses = [@status] + @context[:ancestors] + @context[:descendants]
set_maps(statuses)
......
......@@ -14,8 +14,8 @@ class StreamEntriesController < ApplicationController
return gone if @stream_entry.activity.nil?
if @stream_entry.activity_type == 'Status'
@ancestors = @stream_entry.activity.ancestors(current_account)
@descendants = @stream_entry.activity.descendants(current_account)
@ancestors = @stream_entry.activity.reply? ? cache_collection(@stream_entry.activity.ancestors(current_account), Status) : []
@descendants = cache_collection(@stream_entry.activity.descendants(current_account), Status)
end
end
......
......@@ -5,7 +5,7 @@ class Favourite < ApplicationRecord
include Streamable
belongs_to :account, inverse_of: :favourites
belongs_to :status, inverse_of: :favourites, touch: true
belongs_to :status, inverse_of: :favourites
has_one :notification, as: :activity, dependent: :destroy
......
......@@ -14,7 +14,7 @@ class Status < ApplicationRecord
belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account'
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies
belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, touch: true
belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs
has_many :favourites, inverse_of: :status, dependent: :destroy
has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
......@@ -81,7 +81,7 @@ class Status < ApplicationRecord
def ancestors(account = nil)
ids = (Status.find_by_sql(['WITH RECURSIVE search_tree(id, in_reply_to_id, path) AS (SELECT id, in_reply_to_id, ARRAY[id] FROM statuses WHERE id = ? UNION ALL SELECT statuses.id, statuses.in_reply_to_id, path || statuses.id FROM search_tree JOIN statuses ON statuses.id = search_tree.in_reply_to_id WHERE NOT statuses.id = ANY(path)) SELECT id FROM search_tree ORDER BY path DESC', id]) - [self]).pluck(:id)
statuses = Status.where(id: ids).with_includes.group_by(&:id)
statuses = Status.where(id: ids).group_by(&:id)
results = ids.map { |id| statuses[id].first }
results = results.reject { |status| filter_from_context?(status, account) }
......@@ -90,7 +90,7 @@ class Status < ApplicationRecord
def descendants(account = nil)
ids = (Status.find_by_sql(['WITH RECURSIVE search_tree(id, path) AS (SELECT id, ARRAY[id] FROM statuses WHERE id = ? UNION ALL SELECT statuses.id, path || statuses.id FROM search_tree JOIN statuses ON statuses.in_reply_to_id = search_tree.id WHERE NOT statuses.id = ANY(path)) SELECT id FROM search_tree ORDER BY path', id]) - [self]).pluck(:id)
statuses = Status.where(id: ids).with_includes.group_by(&:id)
statuses = Status.where(id: ids).group_by(&:id)
results = ids.map { |id| statuses[id].first }
results = results.reject { |status| filter_from_context?(status, account) }
......@@ -180,6 +180,6 @@ class Status < ApplicationRecord
private
def filter_from_context?(status, account)
account&.blocking?(status.account) || !status.permitted?(account)
account&.blocking?(status.account_id) || !status.permitted?(account)
end
end
......@@ -117,9 +117,6 @@ Rails.application.routes.draw do
resources :blocks, only: [:index]
resources :favourites, only: [:index]
post '/devices/register', to: 'devices#register', as: :register_device
post '/devices/unregister', to: 'devices#unregister', as: :unregister_device
resources :follow_requests, only: [:index] do
member do
post :authorize
......
......@@ -222,22 +222,6 @@ Creates a new OAuth app. Returns `id`, `client_id` and `client_secret` which can
These values should be requested in the app itself from the API for each new app install + mastodon domain combo, and stored in the app for future requests.
**POST /api/v1/devices/register**
Form data:
- `registration_id`: Device token (also called registration token/registration ID)
Apps can use Firebase Cloud Messaging to receive push notifications from the instances, given that the instance admin has acquired a Firebase API key. More in [push notifications](Push-notifications.md). This method requires a user context, i.e. your app will receive notifications for the authorized user.
**POST /api/v1/devices/unregister**
Form data:
- `registration_id`: Device token (also called registration token/registration ID)
To remove the device from receiving push notifications for the user.
___
## Entities
......
......@@ -2,18 +2,3 @@ Push notifications
==================
**Note: This push notification design turned out to not be fully operational on the side of Firebase. A different approach is in consideration**
Mastodon can communicate with the Firebase Cloud Messaging API to send push notifications to apps on users' devices. For this to work, these conditions must be met:
* Responsibility of an instance owner: `FCM_API_KEY` set on the instance. This can be obtained on the Firebase dashboard, in project settings, under Cloud Messaging, as "server key"
* Responsibility of the app developer: Firebase added/enabled in the Android/iOS app. [See Guide](https://firebase.google.com/docs/cloud-messaging/)
When the app obtains/refreshes a registration ID from Firebase, it needs to send that ID to the `/api/v1/devices/register` endpoint of the authorized user's instance via a POST request. The app can opt out of notifications by sending a similiar request with `unregister` instead of `register`.
The push notifications will be triggered by the notifications of the type you can normally find in `/api/v1/notifications`. However, the push notifications will not contain any inline content. They will contain JSON data of this format ("12" is an example value):
```json
{ "notification_id": 12 }
```
Your app can then retrieve the actual content of the notification from the `/api/v1/notifications/12` API endpoint.
require 'rails_helper'
RSpec.describe Api::V1::DevicesController, type: :controller do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { double acceptable?: true, resource_owner_id: user.id }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #register' do
before do
post :register, params: { registration_id: 'foo123' }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'registers device' do
expect(Device.where(account: user.account, registration_id: 'foo123').first).to_not be_nil
end
end
describe 'POST #unregister' do
before do
post :unregister, params: { registration_id: 'foo123' }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'removes device' do
expect(Device.where(account: user.account, registration_id: 'foo123').first).to be_nil
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment