-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix #4093
- Loading branch information
Showing
12 changed files
with
219 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::MarkersController < Api::BaseController | ||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:index] | ||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, except: [:index] | ||
|
||
before_action :require_user! | ||
|
||
def index | ||
@markers = current_user.markers.where(timeline: Array(params[:timeline])).each_with_object({}) { |marker, h| h[marker.timeline] = marker } | ||
render json: serialize_map(@markers) | ||
end | ||
|
||
def create | ||
Marker.transaction do | ||
@markers = {} | ||
|
||
resource_params.each_pair do |timeline, timeline_params| | ||
@markers[timeline] = current_user.markers.find_or_initialize_by(timeline: timeline) | ||
@markers[timeline].update!(timeline_params) | ||
end | ||
end | ||
|
||
render json: serialize_map(@markers) | ||
rescue ActiveRecord::StaleObjectError | ||
render json: { error: 'Conflict during update, please try again' }, status: 409 | ||
end | ||
|
||
private | ||
|
||
def serialize_map(map) | ||
serialized = {} | ||
|
||
map.each_pair do |key, value| | ||
serialized[key] = ActiveModelSerializers::SerializableResource.new(value, serializer: REST::MarkerSerializer).as_json | ||
end | ||
|
||
Oj.dump(serialized) | ||
end | ||
|
||
def resource_params | ||
params.slice(*Marker::TIMELINES).permit(*Marker::TIMELINES.map { |timeline| { timeline.to_sym => [:last_read_id] } }) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export const submitMarkers = () => (dispatch, getState) => { | ||
const accessToken = getState().getIn(['meta', 'access_token'], ''); | ||
const params = {}; | ||
|
||
const lastHomeId = getState().getIn(['timelines', 'home', 'items', 0]); | ||
const lastNotificationId = getState().getIn(['notifications', 'items', 0, 'id']); | ||
|
||
if (lastHomeId) { | ||
params.home = { | ||
last_read_id: lastHomeId, | ||
}; | ||
} | ||
|
||
if (lastNotificationId) { | ||
params.notifications = { | ||
last_read_id: lastNotificationId, | ||
}; | ||
} | ||
|
||
if (Object.keys(params).length === 0) { | ||
return; | ||
} | ||
|
||
const client = new XMLHttpRequest(); | ||
|
||
client.open('POST', '/api/v1/markers', false); | ||
client.setRequestHeader('Content-Type', 'application/json'); | ||
client.setRequestHeader('Authorization', `Bearer ${accessToken}`); | ||
client.send(JSON.stringify(params)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
# == Schema Information | ||
# | ||
# Table name: markers | ||
# | ||
# id :bigint(8) not null, primary key | ||
# user_id :bigint(8) | ||
# timeline :string default(""), not null | ||
# last_read_id :bigint(8) default(0), not null | ||
# lock_version :integer default(0), not null | ||
# created_at :datetime not null | ||
# updated_at :datetime not null | ||
# | ||
|
||
class Marker < ApplicationRecord | ||
TIMELINES = %w(home notifications).freeze | ||
|
||
belongs_to :user | ||
|
||
validates :timeline, :last_read_id, presence: true | ||
validates :timeline, inclusion: { in: TIMELINES } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# frozen_string_literal: true | ||
|
||
class REST::MarkerSerializer < ActiveModel::Serializer | ||
attributes :last_read_id, :version, :updated_at | ||
|
||
def last_read_id | ||
object.last_read_id.to_s | ||
end | ||
|
||
def version | ||
object.lock_version | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
class CreateMarkers < ActiveRecord::Migration[5.2] | ||
def change | ||
create_table :markers do |t| | ||
t.references :user, foreign_key: { on_delete: :cascade, index: false } | ||
t.string :timeline, default: '', null: false | ||
t.bigint :last_read_id, default: 0, null: false | ||
t.integer :lock_version, default: 0, null: false | ||
|
||
t.timestamps | ||
end | ||
|
||
add_index :markers, [:user_id, :timeline], unique: true | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe Api::V1::MarkersController, type: :controller do | ||
render_views | ||
|
||
let!(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } | ||
let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses write:statuses') } | ||
|
||
before { allow(controller).to receive(:doorkeeper_token) { token } } | ||
|
||
describe 'GET #index' do | ||
before do | ||
Fabricate(:marker, timeline: 'home', last_read_id: 123, user: user) | ||
Fabricate(:marker, timeline: 'notifications', last_read_id: 456, user: user) | ||
|
||
get :index, params: { timeline: %w(home notifications) } | ||
end | ||
|
||
it 'returns http success' do | ||
expect(response).to have_http_status(200) | ||
end | ||
|
||
it 'returns markers' do | ||
json = body_as_json | ||
|
||
expect(json.key?(:home)).to be true | ||
expect(json[:home][:last_read_id]).to eq '123' | ||
expect(json.key?(:notifications)).to be true | ||
expect(json[:notifications][:last_read_id]).to eq '456' | ||
end | ||
end | ||
|
||
describe 'POST #create' do | ||
context 'when no marker exists' do | ||
before do | ||
post :create, params: { home: { last_read_id: '69420' } } | ||
end | ||
|
||
it 'returns http success' do | ||
expect(response).to have_http_status(200) | ||
end | ||
|
||
it 'creates a marker' do | ||
expect(user.markers.first.timeline).to eq 'home' | ||
expect(user.markers.first.last_read_id).to eq 69420 | ||
end | ||
end | ||
|
||
context 'when a marker exists' do | ||
before do | ||
post :create, params: { home: { last_read_id: '69420' } } | ||
post :create, params: { home: { last_read_id: '70120' } } | ||
end | ||
|
||
it 'returns http success' do | ||
expect(response).to have_http_status(200) | ||
end | ||
|
||
it 'updates a marker' do | ||
expect(user.markers.first.timeline).to eq 'home' | ||
expect(user.markers.first.last_read_id).to eq 70120 | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Fabricator(:marker) do | ||
user | ||
timeline 'home' | ||
last_read_id 0 | ||
lock_version 0 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe Marker, type: :model do | ||
pending "add some examples to (or delete) #{__FILE__}" | ||
end |