0
0
Fork 0
* Add structure for lists

* Add list timeline streaming API

* Add list APIs, bind list-account relation to follow relation

* Add API for adding/removing accounts from lists

* Add pagination to lists API

* Add pagination to list accounts API

* Adjust scopes for new APIs

- Creating and modifying lists merely requires "write" scope
- Fetching information about lists merely requires "read" scope

* Add test for wrong user context on list timeline

* Clean up tests
This commit is contained in:
Eugen Rochko 2017-11-18 00:16:48 +01:00 committed by GitHub
parent 4a2fc2d444
commit 24cafd73a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 855 additions and 224 deletions

View file

@ -3,7 +3,7 @@
#
# Table name: accounts
#
# id :bigint not null, primary key
# id :integer not null, primary key
# username :string default(""), not null
# domain :string
# secret :string default(""), not null
@ -53,6 +53,7 @@ class Account < ApplicationRecord
include AccountInteractions
include Attachmentable
include Remotable
include Paginable
enum protocol: [:ostatus, :activitypub]
@ -95,6 +96,10 @@ class Account < ApplicationRecord
has_many :account_moderation_notes, dependent: :destroy
has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy
# Lists
has_many :list_accounts, inverse_of: :account, dependent: :destroy
has_many :lists, through: :list_accounts
scope :remote, -> { where.not(domain: nil) }
scope :local, -> { where(domain: nil) }
scope :without_followers, -> { where(followers_count: 0) }

View file

@ -3,11 +3,11 @@
#
# Table name: account_domain_blocks
#
# id :integer not null, primary key
# domain :string
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint
# id :bigint not null, primary key
# account_id :integer
#
class AccountDomainBlock < ApplicationRecord

View file

@ -3,10 +3,10 @@
#
# Table name: account_moderation_notes
#
# id :bigint not null, primary key
# id :integer not null, primary key
# content :text not null
# account_id :bigint not null
# target_account_id :bigint not null
# account_id :integer not null
# target_account_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#

View file

@ -3,11 +3,11 @@
#
# Table name: blocks
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint not null
# id :bigint not null, primary key
# target_account_id :bigint not null
# account_id :integer not null
# target_account_id :integer not null
#
class Block < ApplicationRecord

View file

@ -3,7 +3,7 @@
#
# Table name: conversations
#
# id :bigint not null, primary key
# id :integer not null, primary key
# uri :string
# created_at :datetime not null
# updated_at :datetime not null

View file

@ -3,9 +3,9 @@
#
# Table name: conversation_mutes
#
# conversation_id :bigint not null
# account_id :bigint not null
# id :bigint not null, primary key
# id :integer not null, primary key
# conversation_id :integer not null
# account_id :integer not null
#
class ConversationMute < ApplicationRecord

View file

@ -3,7 +3,7 @@
#
# Table name: custom_emojis
#
# id :bigint not null, primary key
# id :integer not null, primary key
# shortcode :string default(""), not null
# domain :string
# image_file_name :string

View file

@ -3,12 +3,12 @@
#
# Table name: domain_blocks
#
# id :integer not null, primary key
# domain :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
# severity :integer default("silence")
# reject_media :boolean default(FALSE), not null
# id :bigint not null, primary key
#
class DomainBlock < ApplicationRecord

View file

@ -3,7 +3,7 @@
#
# Table name: email_domain_blocks
#
# id :bigint not null, primary key
# id :integer not null, primary key
# domain :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null

View file

@ -3,11 +3,11 @@
#
# Table name: favourites
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint not null
# id :bigint not null, primary key
# status_id :bigint not null
# account_id :integer not null
# status_id :integer not null
#
class Favourite < ApplicationRecord

View file

@ -1,36 +1,27 @@
# frozen_string_literal: true
class Feed
def initialize(type, account)
@type = type
@account = account
def initialize(type, id)
@type = type
@id = id
end
def get(limit, max_id = nil, since_id = nil)
if redis.exists("account:#{@account.id}:regeneration")
from_database(limit, max_id, since_id)
else
from_redis(limit, max_id, since_id)
end
from_redis(limit, max_id, since_id)
end
private
protected
def from_redis(limit, max_id, since_id)
max_id = '+inf' if max_id.blank?
since_id = '-inf' if since_id.blank?
unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)
Status.where(id: unhydrated).cache_ids
end
def from_database(limit, max_id, since_id)
Status.as_home_timeline(@account)
.paginate_by_max_id(limit, max_id, since_id)
.reject { |status| FeedManager.instance.filter?(:home, status, @account.id) }
end
def key
FeedManager.instance.key(@type, @account.id)
FeedManager.instance.key(@type, @id)
end
def redis

View file

@ -3,11 +3,11 @@
#
# Table name: follows
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint not null
# id :bigint not null, primary key
# target_account_id :bigint not null
# account_id :integer not null
# target_account_id :integer not null
#
class Follow < ApplicationRecord

View file

@ -3,11 +3,11 @@
#
# Table name: follow_requests
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint not null
# id :bigint not null, primary key
# target_account_id :bigint not null
# account_id :integer not null
# target_account_id :integer not null
#
class FollowRequest < ApplicationRecord

25
app/models/home_feed.rb Normal file
View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
class HomeFeed < Feed
def initialize(account)
@type = :home
@id = account.id
@account = account
end
def get(limit, max_id = nil, since_id = nil)
if redis.exists("account:#{@account.id}:regeneration")
from_database(limit, max_id, since_id)
else
super
end
end
private
def from_database(limit, max_id, since_id)
Status.as_home_timeline(@account)
.paginate_by_max_id(limit, max_id, since_id)
.reject { |status| FeedManager.instance.filter?(:home, status, @account.id) }
end
end

View file

@ -3,6 +3,7 @@
#
# Table name: imports
#
# id :integer not null, primary key
# type :integer not null
# approved :boolean default(FALSE), not null
# created_at :datetime not null
@ -11,8 +12,7 @@
# data_content_type :string
# data_file_size :integer
# data_updated_at :datetime
# account_id :bigint not null
# id :bigint not null, primary key
# account_id :integer not null
#
class Import < ApplicationRecord

22
app/models/list.rb Normal file
View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: lists
#
# id :integer not null, primary key
# account_id :integer
# title :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class List < ApplicationRecord
include Paginable
belongs_to :account
has_many :list_accounts, inverse_of: :list, dependent: :destroy
has_many :accounts, through: :list_accounts
validates :title, presence: true
end

View file

@ -0,0 +1,24 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: list_accounts
#
# id :integer not null, primary key
# list_id :integer not null
# account_id :integer not null
# follow_id :integer not null
#
class ListAccount < ApplicationRecord
belongs_to :list, required: true
belongs_to :account, required: true
belongs_to :follow, required: true
before_validation :set_follow
private
def set_follow
self.follow = Follow.find_by(account_id: list.account_id, target_account_id: account.id)
end
end

8
app/models/list_feed.rb Normal file
View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
class ListFeed < Feed
def initialize(list)
@type = :list
@id = list.id
end
end

View file

@ -3,19 +3,19 @@
#
# Table name: media_attachments
#
# id :bigint not null, primary key
# status_id :bigint
# id :integer not null, primary key
# status_id :integer
# file_file_name :string
# file_content_type :string
# file_file_size :integer
# file_updated_at :datetime
# remote_url :string default(""), not null
# account_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
# shortcode :string
# type :integer default("image"), not null
# file_meta :json
# account_id :integer
# description :text
#

View file

@ -3,11 +3,11 @@
#
# Table name: mentions
#
# status_id :bigint
# id :integer not null, primary key
# status_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint
# id :bigint not null, primary key
# account_id :integer
#
class Mention < ApplicationRecord

View file

@ -3,13 +3,13 @@
#
# Table name: notifications
#
# id :bigint not null, primary key
# account_id :bigint
# activity_id :bigint
# id :integer not null, primary key
# activity_id :integer
# activity_type :string
# created_at :datetime not null
# updated_at :datetime not null
# from_account_id :bigint
# account_id :integer
# from_account_id :integer
#
class Notification < ApplicationRecord

View file

@ -3,7 +3,7 @@
#
# Table name: preview_cards
#
# id :bigint not null, primary key
# id :integer not null, primary key
# url :string default(""), not null
# title :string default(""), not null
# description :string default(""), not null

View file

@ -3,15 +3,15 @@
#
# Table name: reports
#
# id :integer not null, primary key
# status_ids :integer default([]), not null, is an Array
# comment :text default(""), not null
# action_taken :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
# account_id :bigint not null
# action_taken_by_account_id :bigint
# id :bigint not null, primary key
# target_account_id :bigint not null
# account_id :integer not null
# action_taken_by_account_id :integer
# target_account_id :integer not null
#
class Report < ApplicationRecord

View file

@ -3,15 +3,15 @@
#
# Table name: session_activations
#
# id :bigint not null, primary key
# user_id :bigint not null
# id :integer not null, primary key
# session_id :string not null
# created_at :datetime not null
# updated_at :datetime not null
# user_agent :string default(""), not null
# ip :inet
# access_token_id :bigint
# web_push_subscription_id :bigint
# access_token_id :integer
# user_id :integer not null
# web_push_subscription_id :integer
#
# id :bigint not null, primary key

View file

@ -3,13 +3,13 @@
#
# Table name: settings
#
# id :integer not null, primary key
# var :string not null
# value :text
# thing_type :string
# created_at :datetime
# updated_at :datetime
# id :bigint not null, primary key
# thing_id :bigint
# thing_id :integer
#
class Setting < RailsSettings::Base

View file

@ -3,7 +3,7 @@
#
# Table name: site_uploads
#
# id :bigint not null, primary key
# id :integer not null, primary key
# var :string default(""), not null
# file_file_name :string
# file_content_type :string

View file

@ -3,26 +3,26 @@
#
# Table name: statuses
#
# id :bigint not null, primary key
# id :integer not null, primary key
# uri :string
# account_id :bigint not null
# text :text default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
# in_reply_to_id :bigint
# reblog_of_id :bigint
# in_reply_to_id :integer
# reblog_of_id :integer
# url :string
# sensitive :boolean default(FALSE), not null
# visibility :integer default("public"), not null
# in_reply_to_account_id :bigint
# application_id :bigint
# spoiler_text :text default(""), not null
# reply :boolean default(FALSE), not null
# favourites_count :integer default(0), not null
# reblogs_count :integer default(0), not null
# language :string
# conversation_id :bigint
# conversation_id :integer
# local :boolean
# account_id :integer not null
# application_id :integer
# in_reply_to_account_id :integer
#
class Status < ApplicationRecord

View file

@ -3,9 +3,9 @@
#
# Table name: status_pins
#
# id :bigint not null, primary key
# account_id :bigint not null
# status_id :bigint not null
# id :integer not null, primary key
# account_id :integer not null
# status_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#

View file

@ -3,13 +3,13 @@
#
# Table name: stream_entries
#
# activity_id :bigint
# id :integer not null, primary key
# activity_id :integer
# activity_type :string
# created_at :datetime not null
# updated_at :datetime not null
# hidden :boolean default(FALSE), not null
# account_id :bigint
# id :bigint not null, primary key
# account_id :integer
#
class StreamEntry < ApplicationRecord

View file

@ -3,6 +3,7 @@
#
# Table name: subscriptions
#
# id :integer not null, primary key
# callback_url :string default(""), not null
# secret :string
# expires_at :datetime
@ -11,8 +12,7 @@
# updated_at :datetime not null
# last_successful_delivery_at :datetime
# domain :string
# account_id :bigint not null
# id :bigint not null, primary key
# account_id :integer not null
#
class Subscription < ApplicationRecord

View file

@ -3,7 +3,7 @@
#
# Table name: tags
#
# id :bigint not null, primary key
# id :integer not null, primary key
# name :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null

View file

@ -3,7 +3,7 @@
#
# Table name: users
#
# id :bigint not null, primary key
# id :integer not null, primary key
# email :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
@ -30,7 +30,7 @@
# last_emailed_at :datetime
# otp_backup_codes :string is an Array
# filtered_languages :string default([]), not null, is an Array
# account_id :bigint not null
# account_id :integer not null
# disabled :boolean default(FALSE), not null
# moderator :boolean default(FALSE), not null
#

View file

@ -3,7 +3,7 @@
#
# Table name: web_push_subscriptions
#
# id :bigint not null, primary key
# id :integer not null, primary key
# endpoint :string not null
# key_p256dh :string not null
# key_auth :string not null

View file

@ -3,11 +3,11 @@
#
# Table name: web_settings
#
# id :integer not null, primary key
# data :json
# created_at :datetime not null
# updated_at :datetime not null
# id :bigint not null, primary key
# user_id :bigint
# user_id :integer
#
class Web::Setting < ApplicationRecord