Skip to content

Commit

Permalink
Add feature circle
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 7b2ba61
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 16:03:52 2020 +0900

    Add the ability to change to a new circle by replying to a circle

commit 7013a22
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 16:10:57 2020 +0900

    fixup! add-limited-visibility-icon-to-status

commit 679aa8a
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 15:12:53 2020 +0900

    Fix 14666

commit b3addd8
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 11:44:12 2020 +0900

    Add Japanese translation for circle

commit b7f4b77
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 11:40:12 2020 +0900

    Squashed commit of the following:

    commit b85a468
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 10:50:03 2020 +0900

        Changed to remove restrictions on privacy options and allow users to switch circles when replying

    commit 0a8c014
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 09:33:07 2020 +0900

        Change limited visibility icon

    commit b64adf1
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Mon Aug 31 06:50:56 2020 +0900

        Fix a change to limited-visibility-bearcaps replies

    commit ed36140
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Aug 27 15:53:18 2020 +0900

        Fix composer text when change visibility

    commit 4da3add
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Aug 22 22:34:23 2020 +0900

        Fix wrong circle_id when changing visibility

    commit 752d7fc
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sun Aug 9 13:12:51 2020 +0900

        Add circle reply and redraft

    commit 5978bc0
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Mon Jul 27 01:07:52 2020 +0900

        Fix remove unused props

    commit 7970f69
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sun Jul 26 21:17:07 2020 +0900

        Separate circle choice from privacy

    commit 36f6a68
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Jul 23 10:54:25 2020 +0900

        Add UI for posting to circles

    commit 7ef4800
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Fri Jul 24 12:55:10 2020 +0900

        Fix silent mention by circle

commit 7a1caed
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 11:38:10 2020 +0900

    Squashed commit of the following:

    commit dca71fa
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 09:31:26 2020 +0900

        Revert "Add focus setting when opening the circle column"

        This reverts commit 3a93ac99312a13b68b7edc2b81313fb0ffb7bcdc.

    commit 0a1bc83
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 09:31:11 2020 +0900

        Change limited visibility icon

    commit 9784f8b
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Aug 13 21:52:07 2020 +0900

        Add focus setting when opening the circle column

    commit a84f680
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Aug 13 15:55:27 2020 +0900

        Fix message

    commit e3f11c4
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Mon Jul 27 01:01:23 2020 +0900

        Fix light-theme

    commit d7d96ed
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sun Jul 26 21:50:56 2020 +0900

        Fix circles loading in share page and followers search

    commit 10b821f
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Fri Jul 24 14:08:00 2020 +0900

        Refactor list items

    commit e020072
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Jul 23 20:15:38 2020 +0900

        Fixed a bug that circle name change is not reflected in the list

    commit 735bc41
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Wed Jul 22 08:49:47 2020 +0900

        Add UI for managing circle members

    commit d7c3145
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Wed Jul 22 07:34:52 2020 +0900

        Add the followers option to AccountSearchSercive

    commit 65e2b0c
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Wed Jul 22 07:05:56 2020 +0900

        Add CircleSerializer

commit a639e18
Author: noellabo <noel.yoshiba@gmail.com>
Date:   Sat Sep 5 11:37:30 2020 +0900

    Squashed commit of the following:

    commit 9cb3fb9d980e3ee066083076f508c5ab1447176a
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 07:15:19 2020 +0900

        Move the link to the mention list to the menu

    commit b32dd87b43f4e09b8e2c437f1fb5d3ebd6221215
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Sat Sep 5 00:56:12 2020 +0900

        Change limited visibility icon

    commit 8db0d024119d1c2cef8de849f2501496a166a2dd
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Tue Sep 1 01:42:13 2020 +0900

        Fix to disallow getting the list of mentions in limited replies

    commit 490a9d65a59a3dd0d86e81f6780e879dc4313dff
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Fri Jul 24 11:36:24 2020 +0900

        Add column to list mentioned accounts of limited status

    commit 62a423ac2729c16f26fafe111f257bc373218df2
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Thu Jul 23 13:30:17 2020 +0900

        Fix visibility compatibility more

    commit a5cfa54b259054f41e89037f299fa928a2361818
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Mon Jul 20 05:39:49 2020 +0900

        Fix visibility compatibility

    commit 7900ca5650c77565b86ddc594a221dfa3b5321b4
    Author: noellabo <noel.yoshiba@gmail.com>
    Date:   Mon Jul 20 02:01:27 2020 +0900

        Add limited visibility icon to status

commit 66b8396
Author: Eugen Rochko <eugen@zeonfederated.com>
Date:   Wed Aug 26 03:16:47 2020 +0200

    Add conversation-based forwarding for limited visibility statuses through bearcaps

commit 561abc6
Author: Eugen Rochko <eugen@zeonfederated.com>
Date:   Sun Jul 19 02:05:16 2020 +0200

    Add REST API for managing and posting to circles

    Circles are the conceptual opposite of lists. A list is a subdivision
    of your follows, a circle is a subdivision of your followers. Posting
    to a circle means making content available to only some of your
    followers. Circles have been internally supported in Mastodon for
    the purposes of federation since mastodon#8950, this adds the REST API
    necessary for making use of them in Mastodon itsef.
  • Loading branch information
noellabo committed Aug 19, 2021
1 parent f8fba21 commit 6e528cd
Show file tree
Hide file tree
Showing 104 changed files with 2,947 additions and 170 deletions.
16 changes: 16 additions & 0 deletions app/controllers/activitypub/contexts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class ActivityPub::ContextsController < ActivityPub::BaseController
before_action :set_conversation

def show
expires_in 3.minutes, public: public_fetch_mode?
render_with_cache json: @conversation, serializer: ActivityPub::ContextSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end

private

def set_conversation
@conversation = Conversation.local.find(params[:id])
end
end
18 changes: 18 additions & 0 deletions app/controllers/api/v1/accounts/circles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class Api::V1::Accounts::CirclesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:circles' }
before_action :require_user!
before_action :set_account

def index
@circles = @account.circles.where(account: current_account)
render json: @circles, each_serializer: REST::CircleSerializer
end

private

def set_account
@account = Account.find(params[:account_id])
end
end
1 change: 1 addition & 0 deletions app/controllers/api/v1/accounts/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def account_search
current_account,
limit: limit_param(DEFAULT_ACCOUNTS_LIMIT),
resolve: truthy_param?(:resolve),
followers: truthy_param?(:followers),
following: truthy_param?(:following),
group_only: truthy_param?(:group_only),
offset: params[:offset]
Expand Down
93 changes: 93 additions & 0 deletions app/controllers/api/v1/circles/accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

class Api::V1::Circles::AccountsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:circles' }, only: [:show]
before_action -> { doorkeeper_authorize! :write, :'write:circles' }, except: [:show]

before_action :require_user!
before_action :set_circle

after_action :insert_pagination_headers, only: :show

def show
@accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end

def create
ApplicationRecord.transaction do
circle_accounts.each do |account|
@circle.accounts << account
end
end

render_empty
end

def destroy
CircleAccount.where(circle: @circle, account_id: account_ids).destroy_all
render_empty
end

private

def set_circle
@circle = current_account.owned_circles.find(params[:circle_id])
end

def load_accounts
if unlimited?
@circle.accounts.includes(:account_stat).all
else
@circle.accounts.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
end
end

def circle_accounts
Account.find(account_ids)
end

def account_ids
Array(resource_params[:account_ids])
end

def resource_params
params.permit(account_ids: [])
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
return if unlimited?

api_v1_circle_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end

def prev_path
return if unlimited?

api_v1_circle_accounts_url(pagination_params(since_id: pagination_since_id)) unless @accounts.empty?
end

def pagination_max_id
@accounts.last.id
end

def pagination_since_id
@accounts.first.id
end

def records_continue?
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end

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

def unlimited?
params[:limit] == '0'
end
end
73 changes: 73 additions & 0 deletions app/controllers/api/v1/circles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

class Api::V1::CirclesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:circles' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write, :'write:circles' }, except: [:index, :show]

before_action :require_user!
before_action :set_circle, except: [:index, :create]

after_action :insert_pagination_headers, only: :index

def index
@circles = current_account.owned_circles.paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
render json: @circles, each_serializer: REST::CircleSerializer
end

def show
render json: @circle, serializer: REST::CircleSerializer
end

def create
@circle = current_account.owned_circles.create!(circle_params)
render json: @circle, serializer: REST::CircleSerializer
end

def update
@circle.update!(circle_params)
render json: @circle, serializer: REST::CircleSerializer
end

def destroy
@circle.destroy!
render_empty
end

private

def set_circle
@circle = current_account.owned_circles.find(params[:id])
end

def circle_params
params.permit(:title)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

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

def prev_path
api_v1_circles_url(pagination_params(since_id: pagination_since_id)) unless @circles.empty?
end

def pagination_max_id
@circles.last.id
end

def pagination_since_id
@circles.first.id
end

def records_continue?
@circles.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end

def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

class Api::V1::Statuses::MentionedByAccountsController < Api::BaseController
include Authorization

before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
before_action :set_status
after_action :insert_pagination_headers

def index
@accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end

private

def load_accounts
scope = default_accounts
scope.merge(paginated_mentions).to_a
end

def default_accounts
Account
.includes(:mentions, :account_stat)
.references(:mentions)
.where(mentions: { status_id: @status.id, silent: true })
end

def paginated_mentions
Mention.paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

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

def prev_path
api_v1_status_mentioned_by_index_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
end

def pagination_max_id
@accounts.last.mentions.last.id
end

def pagination_since_id
@accounts.first.mentions.first.id
end

def records_continue?
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end

def set_status
@status = Status.find(params[:status_id])
authorize @status, :show_mentions?
rescue Mastodon::NotPermittedError
not_found
end

def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params)
end
end
9 changes: 9 additions & 0 deletions app/controllers/api/v1/statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Api::V1::StatusesController < Api::BaseController
before_action :require_user!, except: [:show, :context]
before_action :set_status, only: [:show, :context]
before_action :set_thread, only: [:create]
before_action :set_circle, only: [:create]

override_rate_limit_headers :create, family: :statuses

Expand Down Expand Up @@ -39,6 +40,7 @@ def create
@status = PostStatusService.new.call(current_user.account,
text: status_params[:status],
thread: @thread,
circle: @circle,
media_ids: status_params[:media_ids],
sensitive: status_params[:sensitive],
spoiler_text: status_params[:spoiler_text],
Expand Down Expand Up @@ -81,10 +83,17 @@ def set_thread
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
end

def set_circle
@circle = status_params[:circle_id].blank? ? nil : current_account.owned_circles.find(status_params[:circle_id])
rescue ActiveRecord::RecordNotFound
render json: { error: I18n.t('statuses.errors.circle_not_found') }, status: 404
end

def status_params
params.permit(
:status,
:in_reply_to_id,
:circle_id,
:sensitive,
:spoiler_text,
:visibility,
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/cache_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def render_with_cache(**options)
end

def set_cache_headers
response.headers['Vary'] = public_fetch_mode? ? 'Accept' : 'Accept, Signature'
response.headers['Vary'] = public_fetch_mode? ? 'Accept, Authorization' : 'Accept, Signature, Authorization'
end

def cache_collection(raw, klass)
Expand Down
7 changes: 6 additions & 1 deletion app/controllers/statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@ def set_link_headers

def set_status
@status = @account.statuses.find(params[:id])
authorize @status, :show?

if request.authorization.present? && request.authorization.match(/^Bearer /i)
raise Mastodon::NotPermittedError unless @status.capability_tokens.find_by(token: request.authorization.gsub(/^Bearer /i, ''))
else
authorize @status, :show?
end
rescue Mastodon::NotPermittedError
not_found
end
Expand Down
4 changes: 3 additions & 1 deletion app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ def visibility_icon(status)
fa_icon('globe', title: I18n.t('statuses.visibilities.public'))
elsif status.unlisted_visibility?
fa_icon('unlock', title: I18n.t('statuses.visibilities.unlisted'))
elsif status.private_visibility? || status.limited_visibility?
elsif status.private_visibility?
fa_icon('lock', title: I18n.t('statuses.visibilities.private'))
elsif status.limited_visibility?
fa_icon('user-circle', title: I18n.t('statuses.visibilities.limited'))
elsif status.direct_visibility?
fa_icon('envelope', title: I18n.t('statuses.visibilities.direct'))
end
Expand Down
11 changes: 5 additions & 6 deletions app/helpers/jsonld_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,12 @@ def unsupported_uri_scheme?(uri)
!uri.start_with?('http://', 'https://')
end

def invalid_origin?(url)
return true if unsupported_uri_scheme?(url)

needle = Addressable::URI.parse(url).host
haystack = Addressable::URI.parse(@account.uri).host
def same_origin?(url_a, url_b)
Addressable::URI.parse(url_a).host.casecmp(Addressable::URI.parse(url_b).host).zero?
end

!haystack.casecmp(needle).zero?
def invalid_origin?(url)
unsupported_uri_scheme?(url) || !same_origin?(url, @account.uri)
end

def canonicalize(json)
Expand Down
Loading

0 comments on commit 6e528cd

Please sign in to comment.