mirror of
https://github.com/lunaisnotaboy/mastodon.git
synced 2024-11-07 15:34:55 +00:00
Merge pull request #291 from glitch-soc/merge-upstream
Merge with upstream @ f4b80e6511
This commit is contained in:
commit
d817c0a958
|
@ -3,6 +3,7 @@
|
||||||
module Admin
|
module Admin
|
||||||
class CustomEmojisController < BaseController
|
class CustomEmojisController < BaseController
|
||||||
before_action :set_custom_emoji, except: [:index, :new, :create]
|
before_action :set_custom_emoji, except: [:index, :new, :create]
|
||||||
|
before_action :set_filter_params
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :custom_emoji, :index?
|
authorize :custom_emoji, :index?
|
||||||
|
@ -32,23 +33,26 @@ module Admin
|
||||||
|
|
||||||
if @custom_emoji.update(resource_params)
|
if @custom_emoji.update(resource_params)
|
||||||
log_action :update, @custom_emoji
|
log_action :update, @custom_emoji
|
||||||
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg')
|
flash[:notice] = I18n.t('admin.custom_emojis.updated_msg')
|
||||||
else
|
else
|
||||||
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.update_failed_msg')
|
flash[:alert] = I18n.t('admin.custom_emojis.update_failed_msg')
|
||||||
end
|
end
|
||||||
|
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @custom_emoji, :destroy?
|
authorize @custom_emoji, :destroy?
|
||||||
@custom_emoji.destroy!
|
@custom_emoji.destroy!
|
||||||
log_action :destroy, @custom_emoji
|
log_action :destroy, @custom_emoji
|
||||||
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg')
|
flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg')
|
||||||
|
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def copy
|
def copy
|
||||||
authorize @custom_emoji, :copy?
|
authorize @custom_emoji, :copy?
|
||||||
|
|
||||||
emoji = CustomEmoji.find_or_initialize_by(domain: nil, shortcode: @custom_emoji.shortcode)
|
emoji = CustomEmoji.find_or_initialize_by(domain: nil,
|
||||||
|
shortcode: @custom_emoji.shortcode)
|
||||||
emoji.image = @custom_emoji.image
|
emoji.image = @custom_emoji.image
|
||||||
|
|
||||||
if emoji.save
|
if emoji.save
|
||||||
|
@ -58,21 +62,23 @@ module Admin
|
||||||
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
|
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to admin_custom_emojis_path(page: params[:page])
|
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable
|
def enable
|
||||||
authorize @custom_emoji, :enable?
|
authorize @custom_emoji, :enable?
|
||||||
@custom_emoji.update!(disabled: false)
|
@custom_emoji.update!(disabled: false)
|
||||||
log_action :enable, @custom_emoji
|
log_action :enable, @custom_emoji
|
||||||
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg')
|
flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg')
|
||||||
|
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable
|
def disable
|
||||||
authorize @custom_emoji, :disable?
|
authorize @custom_emoji, :disable?
|
||||||
@custom_emoji.update!(disabled: true)
|
@custom_emoji.update!(disabled: true)
|
||||||
log_action :disable, @custom_emoji
|
log_action :disable, @custom_emoji
|
||||||
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg')
|
flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg')
|
||||||
|
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -81,6 +87,10 @@ module Admin
|
||||||
@custom_emoji = CustomEmoji.find(params[:id])
|
@custom_emoji = CustomEmoji.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_filter_params
|
||||||
|
@filter_params = filter_params.to_hash.symbolize_keys
|
||||||
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
|
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,8 @@ module Admin
|
||||||
bootstrap_timeline_accounts
|
bootstrap_timeline_accounts
|
||||||
thumbnail
|
thumbnail
|
||||||
min_invite_role
|
min_invite_role
|
||||||
|
activity_api_enabled
|
||||||
|
peers_api_enabled
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
BOOLEAN_SETTINGS = %w(
|
BOOLEAN_SETTINGS = %w(
|
||||||
|
@ -24,6 +26,8 @@ module Admin
|
||||||
open_deletion
|
open_deletion
|
||||||
timeline_preview
|
timeline_preview
|
||||||
show_staff_badge
|
show_staff_badge
|
||||||
|
activity_api_enabled
|
||||||
|
peers_api_enabled
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
UPLOAD_SETTINGS = %w(
|
UPLOAD_SETTINGS = %w(
|
||||||
|
|
36
app/controllers/api/v1/instances/activity_controller.rb
Normal file
36
app/controllers/api/v1/instances/activity_controller.rb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Instances::ActivityController < Api::BaseController
|
||||||
|
before_action :require_enabled_api!
|
||||||
|
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def show
|
||||||
|
render_cached_json('api:v1:instances:activity:show', expires_in: 1.day) { activity }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def activity
|
||||||
|
weeks = []
|
||||||
|
|
||||||
|
12.times do |i|
|
||||||
|
day = i.weeks.ago.to_date
|
||||||
|
week_id = day.cweek
|
||||||
|
week = Date.commercial(day.cwyear, week_id)
|
||||||
|
|
||||||
|
weeks << {
|
||||||
|
week: week.to_time.to_i.to_s,
|
||||||
|
statuses: Redis.current.get("activity:statuses:local:#{week_id}") || 0,
|
||||||
|
logins: Redis.current.pfcount("activity:logins:#{week_id}"),
|
||||||
|
registrations: Redis.current.get("activity:accounts:local:#{week_id}") || 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
weeks
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_enabled_api!
|
||||||
|
head 404 unless Setting.activity_api_enabled
|
||||||
|
end
|
||||||
|
end
|
17
app/controllers/api/v1/instances/peers_controller.rb
Normal file
17
app/controllers/api/v1/instances/peers_controller.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Instances::PeersController < Api::BaseController
|
||||||
|
before_action :require_enabled_api!
|
||||||
|
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def index
|
||||||
|
render_cached_json('api:v1:instances:peers:index', expires_in: 1.day) { Account.remote.domains }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def require_enabled_api!
|
||||||
|
head 404 unless Setting.peers_api_enabled
|
||||||
|
end
|
||||||
|
end
|
|
@ -196,4 +196,13 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_cached_json(cache_key, **options)
|
||||||
|
data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do
|
||||||
|
yield.to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
expires_in options[:expires_in], public: true
|
||||||
|
render json: data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,13 +2,8 @@
|
||||||
|
|
||||||
class Auth::ConfirmationsController < Devise::ConfirmationsController
|
class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
layout 'auth'
|
layout 'auth'
|
||||||
before_action :set_pack
|
|
||||||
|
|
||||||
def show
|
before_action :set_pack
|
||||||
super do |user|
|
|
||||||
BootstrapTimelineWorker.perform_async(user.account_id) if user.errors.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ module UserTrackingConcern
|
||||||
|
|
||||||
# Mark as signed-in today
|
# Mark as signed-in today
|
||||||
current_user.update_tracked_fields!(request)
|
current_user.update_tracked_fields!(request)
|
||||||
|
ActivityTracker.record('activity:logins', current_user.id)
|
||||||
|
|
||||||
# Regenerate feed if needed
|
# Regenerate feed if needed
|
||||||
regenerate_feed! if user_needs_feed_update?
|
regenerate_feed! if user_needs_feed_update?
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module WellKnown
|
module WellKnown
|
||||||
class HostMetaController < ApplicationController
|
class HostMetaController < ActionController::Base
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
|
before_action { response.headers['Vary'] = 'Accept' }
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.xml { render content_type: 'application/xrd+xml' }
|
format.xml { render content_type: 'application/xrd+xml' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
expires_in(3.days, public: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module WellKnown
|
module WellKnown
|
||||||
class WebfingerController < ApplicationController
|
class WebfingerController < ActionController::Base
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
|
before_action { response.headers['Vary'] = 'Accept' }
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@account = Account.find_local!(username_from_resource)
|
@account = Account.find_local!(username_from_resource)
|
||||||
|
|
||||||
|
@ -16,6 +18,8 @@ module WellKnown
|
||||||
render content_type: 'application/xrd+xml'
|
render content_type: 'application/xrd+xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
expires_in(3.days, public: true)
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
head 404
|
head 404
|
||||||
end
|
end
|
||||||
|
|
BIN
app/javascript/images/mastodon-drawer.png
Normal file
BIN
app/javascript/images/mastodon-drawer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 45 KiB |
BIN
app/javascript/images/wave-drawer.png
Normal file
BIN
app/javascript/images/wave-drawer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -51,7 +51,7 @@ const sendSubscriptionToBackend = (subscription, me) => {
|
||||||
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
||||||
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
|
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
|
||||||
|
|
||||||
export default function register () {
|
export function register () {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(setBrowserSupport(supportsPushNotifications));
|
dispatch(setBrowserSupport(supportsPushNotifications));
|
||||||
const me = getState().getIn(['meta', 'me']);
|
const me = getState().getIn(['meta', 'me']);
|
||||||
|
|
|
@ -94,6 +94,7 @@ export default class Compose extends React.PureComponent {
|
||||||
<div className='drawer__inner' onFocus={this.onFocus}>
|
<div className='drawer__inner' onFocus={this.onFocus}>
|
||||||
<NavigationContainer onClose={this.onBlur} />
|
<NavigationContainer onClose={this.onBlur} />
|
||||||
<ComposeFormContainer />
|
<ComposeFormContainer />
|
||||||
|
<div className='mastodon' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||||
|
|
|
@ -98,19 +98,17 @@ export default class GettingStarted extends ImmutablePureComponent {
|
||||||
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='getting-started__footer scrollable optionally-scrollable'>
|
<div className='static-content getting-started'>
|
||||||
<div className='static-content getting-started'>
|
<p>
|
||||||
<p>
|
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a>
|
||||||
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a>
|
</p>
|
||||||
</p>
|
<p>
|
||||||
<p>
|
<FormattedMessage
|
||||||
<FormattedMessage
|
id='getting_started.open_source_notice'
|
||||||
id='getting_started.open_source_notice'
|
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
||||||
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }}
|
||||||
values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }}
|
/>
|
||||||
/>
|
</p>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
@ -213,6 +213,7 @@
|
||||||
"search_popout.tips.user": "유저",
|
"search_popout.tips.user": "유저",
|
||||||
"search_results.total": "{count, number}건의 결과",
|
"search_results.total": "{count, number}건의 결과",
|
||||||
"standalone.public_title": "A look inside...",
|
"standalone.public_title": "A look inside...",
|
||||||
|
"status.block": "@{name} 차단",
|
||||||
"status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다",
|
"status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다",
|
||||||
"status.delete": "삭제",
|
"status.delete": "삭제",
|
||||||
"status.embed": "공유하기",
|
"status.embed": "공유하기",
|
||||||
|
@ -221,6 +222,7 @@
|
||||||
"status.media_hidden": "미디어 숨겨짐",
|
"status.media_hidden": "미디어 숨겨짐",
|
||||||
"status.mention": "답장",
|
"status.mention": "답장",
|
||||||
"status.more": "자세히",
|
"status.more": "자세히",
|
||||||
|
"status.mute": "@{name} 뮤트",
|
||||||
"status.mute_conversation": "이 대화를 뮤트",
|
"status.mute_conversation": "이 대화를 뮤트",
|
||||||
"status.open": "상세 정보 표시",
|
"status.open": "상세 정보 표시",
|
||||||
"status.pin": "고정",
|
"status.pin": "고정",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { register as registerPushNotifications } from './actions/push_notifications';
|
import * as registerPushNotifications from './actions/push_notifications';
|
||||||
import { default as Mastodon, store } from './containers/mastodon';
|
import { default as Mastodon, store } from './containers/mastodon';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
|
@ -1758,7 +1758,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: lighten($ui-base-color, 13%);
|
background: lighten($ui-base-color, 13%) url('~images/wave-drawer.png') no-repeat bottom / 100% auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1771,6 +1771,11 @@
|
||||||
&.darker {
|
&.darker {
|
||||||
background: $ui-base-color;
|
background: $ui-base-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .mastodon {
|
||||||
|
background: url('~images/mastodon-drawer.png') no-repeat left bottom / contain;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pseudo-drawer {
|
.pseudo-drawer {
|
||||||
|
@ -2072,15 +2077,8 @@
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.getting-started__footer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.getting-started {
|
.getting-started {
|
||||||
box-sizing: border-box;
|
background: $ui-base-color;
|
||||||
padding-bottom: 235px;
|
|
||||||
background: url('~images/mastodon-getting-started.png') no-repeat 0 100%;
|
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|
31
app/lib/activity_tracker.rb
Normal file
31
app/lib/activity_tracker.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityTracker
|
||||||
|
EXPIRE_AFTER = 90.days.seconds
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def increment(prefix)
|
||||||
|
key = [prefix, current_week].join(':')
|
||||||
|
|
||||||
|
redis.incrby(key, 1)
|
||||||
|
redis.expire(key, EXPIRE_AFTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
def record(prefix, value)
|
||||||
|
key = [prefix, current_week].join(':')
|
||||||
|
|
||||||
|
redis.pfadd(key, value)
|
||||||
|
redis.expire(key, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def redis
|
||||||
|
Redis.current
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_week
|
||||||
|
Time.zone.today.cweek
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -29,7 +29,7 @@ class ProviderDiscovery < OEmbed::ProviderDiscovery
|
||||||
end
|
end
|
||||||
|
|
||||||
if format.nil? || format == :xml
|
if format.nil? || format == :xml
|
||||||
provider_endpoint ||= html.at_xpath('//link[@type="application/xml+oembed"]')&.attribute('href')&.value
|
provider_endpoint ||= html.at_xpath('//link[@type="text/xml+oembed"]')&.attribute('href')&.value
|
||||||
format ||= :xml if provider_endpoint
|
format ||= :xml if provider_endpoint
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,10 @@ class Form::AdminSettings
|
||||||
:bootstrap_timeline_accounts=,
|
:bootstrap_timeline_accounts=,
|
||||||
:min_invite_role,
|
:min_invite_role,
|
||||||
:min_invite_role=,
|
:min_invite_role=,
|
||||||
|
:activity_api_enabled,
|
||||||
|
:activity_api_enabled=,
|
||||||
|
:peers_api_enabled,
|
||||||
|
:peers_api_enabled=,
|
||||||
to: Setting
|
to: Setting
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -138,6 +138,7 @@ class Status < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
after_create_commit :store_uri, if: :local?
|
after_create_commit :store_uri, if: :local?
|
||||||
|
after_create_commit :update_statistics, if: :local?
|
||||||
|
|
||||||
around_create Mastodon::Snowflake::Callbacks
|
around_create Mastodon::Snowflake::Callbacks
|
||||||
|
|
||||||
|
@ -336,4 +337,9 @@ class Status < ApplicationRecord
|
||||||
def set_local
|
def set_local
|
||||||
self.local = account.local?
|
self.local = account.local?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_statistics
|
||||||
|
return unless public_visibility? || unlisted_visibility?
|
||||||
|
ActivityTracker.increment('activity:statuses:local')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -122,9 +122,19 @@ class User < ApplicationRecord
|
||||||
update!(disabled: false)
|
update!(disabled: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
return if confirmed?
|
||||||
|
|
||||||
|
super
|
||||||
|
update_statistics!
|
||||||
|
end
|
||||||
|
|
||||||
def confirm!
|
def confirm!
|
||||||
|
return if confirmed?
|
||||||
|
|
||||||
skip_confirmation!
|
skip_confirmation!
|
||||||
save!
|
save!
|
||||||
|
update_statistics!
|
||||||
end
|
end
|
||||||
|
|
||||||
def promote!
|
def promote!
|
||||||
|
@ -202,4 +212,9 @@ class User < ApplicationRecord
|
||||||
def sanitize_languages
|
def sanitize_languages
|
||||||
filtered_languages.reject!(&:blank?)
|
filtered_languages.reject!(&:blank?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_statistics!
|
||||||
|
BootstrapTimelineWorker.perform_async(account_id)
|
||||||
|
ActivityTracker.increment('activity:accounts:local')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,18 +11,18 @@
|
||||||
%td
|
%td
|
||||||
- if custom_emoji.local?
|
- if custom_emoji.local?
|
||||||
- if custom_emoji.visible_in_picker
|
- if custom_emoji.visible_in_picker
|
||||||
= table_link_to 'eye', t('admin.custom_emojis.listed'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: false }), method: :patch
|
= table_link_to 'eye', t('admin.custom_emojis.listed'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: false }, page: params[:page], **@filter_params), method: :patch
|
||||||
- else
|
- else
|
||||||
= table_link_to 'eye-slash', t('admin.custom_emojis.unlisted'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: true }), method: :patch
|
= table_link_to 'eye-slash', t('admin.custom_emojis.unlisted'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: true }, page: params[:page], **@filter_params), method: :patch
|
||||||
- else
|
- else
|
||||||
- if custom_emoji.local_counterpart.present?
|
- if custom_emoji.local_counterpart.present?
|
||||||
= link_to safe_join([custom_emoji_tag(custom_emoji.local_counterpart), t('admin.custom_emojis.overwrite')]), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post, class: 'table-action-link'
|
= link_to safe_join([custom_emoji_tag(custom_emoji.local_counterpart), t('admin.custom_emojis.overwrite')]), copy_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, class: 'table-action-link'
|
||||||
- else
|
- else
|
||||||
= table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post
|
= table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post
|
||||||
%td
|
%td
|
||||||
- if custom_emoji.disabled?
|
- if custom_emoji.disabled?
|
||||||
= table_link_to 'power-off', t('admin.custom_emojis.enable'), enable_admin_custom_emoji_path(custom_emoji), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
= table_link_to 'power-off', t('admin.custom_emojis.enable'), enable_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
- else
|
- else
|
||||||
= table_link_to 'power-off', t('admin.custom_emojis.disable'), disable_admin_custom_emoji_path(custom_emoji), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
= table_link_to 'power-off', t('admin.custom_emojis.disable'), disable_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
%td
|
%td
|
||||||
= table_link_to 'times', t('admin.custom_emojis.delete'), admin_custom_emoji_path(custom_emoji), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
= table_link_to 'times', t('admin.custom_emojis.delete'), admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
%button= t('admin.accounts.search')
|
%button= t('admin.accounts.search')
|
||||||
= link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'
|
= link_to t('admin.accounts.reset'), admin_custom_emojis_path, class: 'button negative'
|
||||||
|
|
||||||
.table-wrapper
|
.table-wrapper
|
||||||
%table.table
|
%table.table
|
||||||
|
|
|
@ -46,5 +46,13 @@
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :bootstrap_timeline_accounts, wrapper: :with_block_label, label: t('admin.settings.bootstrap_timeline_accounts.title'), hint: t('admin.settings.bootstrap_timeline_accounts.desc_html')
|
= f.input :bootstrap_timeline_accounts, wrapper: :with_block_label, label: t('admin.settings.bootstrap_timeline_accounts.title'), hint: t('admin.settings.bootstrap_timeline_accounts.desc_html')
|
||||||
|
|
||||||
|
%hr/
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :activity_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.activity_api_enabled.title'), hint: t('admin.settings.activity_api_enabled.desc_html')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :peers_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.peers_api_enabled.title'), hint: t('admin.settings.peers_api_enabled.desc_html')
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('generic.save_changes'), type: :submit
|
= f.button :button, t('generic.save_changes'), type: :submit
|
||||||
|
|
|
@ -265,12 +265,18 @@ en:
|
||||||
unresolved: Unresolved
|
unresolved: Unresolved
|
||||||
view: View
|
view: View
|
||||||
settings:
|
settings:
|
||||||
|
activity_api_enabled:
|
||||||
|
desc_html: Counts of locally posted statuses, active users, and new registrations in weekly buckets
|
||||||
|
title: Publish aggregate statistics about user activity
|
||||||
bootstrap_timeline_accounts:
|
bootstrap_timeline_accounts:
|
||||||
desc_html: Separate multiple usernames by comma. Only local and unlocked accounts will work. Default when empty is all local admins.
|
desc_html: Separate multiple usernames by comma. Only local and unlocked accounts will work. Default when empty is all local admins.
|
||||||
title: Default follows for new users
|
title: Default follows for new users
|
||||||
contact_information:
|
contact_information:
|
||||||
email: Business e-mail
|
email: Business e-mail
|
||||||
username: Contact username
|
username: Contact username
|
||||||
|
peers_api_enabled:
|
||||||
|
desc_html: Domain names this instance has encountered in the fediverse
|
||||||
|
title: Publish list of discovered instances
|
||||||
registrations:
|
registrations:
|
||||||
closed_message:
|
closed_message:
|
||||||
desc_html: Displayed on frontpage when registrations are closed. You can use HTML tags
|
desc_html: Displayed on frontpage when registrations are closed. You can use HTML tags
|
||||||
|
|
|
@ -265,12 +265,18 @@ ko:
|
||||||
unresolved: 미해결
|
unresolved: 미해결
|
||||||
view: 표시
|
view: 표시
|
||||||
settings:
|
settings:
|
||||||
|
activity_api_enabled:
|
||||||
|
desc_html: 주별 로컬에 게시 된 글, 활성 사용자 및 새로운 가입자 수
|
||||||
|
title: 유저 활동에 대한 통계 발행
|
||||||
bootstrap_timeline_accounts:
|
bootstrap_timeline_accounts:
|
||||||
desc_html: 콤마로 여러 유저명을 구분. 로컬의 잠기지 않은 계정만 가능합니다. 비워 둘 경우 모든 로컬 관리자가 기본으로 사용 됩니다.
|
desc_html: 콤마로 여러 유저명을 구분. 로컬의 잠기지 않은 계정만 가능합니다. 비워 둘 경우 모든 로컬 관리자가 기본으로 사용 됩니다.
|
||||||
title: 새 유저가 팔로우 할 계정들
|
title: 새 유저가 팔로우 할 계정들
|
||||||
contact_information:
|
contact_information:
|
||||||
email: 공개할 메일 주소를 입력
|
email: 공개할 메일 주소를 입력
|
||||||
username: 아이디를 입력
|
username: 아이디를 입력
|
||||||
|
peers_api_enabled:
|
||||||
|
desc_html: 이 인스턴스가 페디버스에서 만났던 도메인 네임들
|
||||||
|
title: 발견 된 인스턴스들의 리스트 발행
|
||||||
registrations:
|
registrations:
|
||||||
closed_message:
|
closed_message:
|
||||||
desc_html: 신규 등록을 받지 않을 때 프론트 페이지에 표시됩니다. <br>HTML 태그를 사용할 수 있습니다.
|
desc_html: 신규 등록을 받지 않을 때 프론트 페이지에 표시됩니다. <br>HTML 태그를 사용할 수 있습니다.
|
||||||
|
|
|
@ -255,7 +255,11 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :apps, only: [:create]
|
resources :apps, only: [:create]
|
||||||
|
|
||||||
resource :instance, only: [:show]
|
resource :instance, only: [:show] do
|
||||||
|
resources :peers, only: [:index], controller: 'instances/peers'
|
||||||
|
resource :activity, only: [:show], controller: 'instances/activity'
|
||||||
|
end
|
||||||
|
|
||||||
resource :domain_blocks, only: [:show, :create, :destroy]
|
resource :domain_blocks, only: [:show, :create, :destroy]
|
||||||
|
|
||||||
resources :follow_requests, only: [:index] do
|
resources :follow_requests, only: [:index] do
|
||||||
|
|
|
@ -49,7 +49,8 @@ defaults: &defaults
|
||||||
- webmaster
|
- webmaster
|
||||||
- administrator
|
- administrator
|
||||||
bootstrap_timeline_accounts: ''
|
bootstrap_timeline_accounts: ''
|
||||||
|
activity_api_enabled: true
|
||||||
|
peers_api_enabled: true
|
||||||
development:
|
development:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
|
|
||||||
|
|
8
spec/fixtures/requests/oembed_json_xml.html
vendored
8
spec/fixtures/requests/oembed_json_xml.html
vendored
|
@ -1,8 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<!--
|
||||||
|
oEmbed
|
||||||
|
https://oembed.com/
|
||||||
|
> The type attribute must contain either application/json+oembed for JSON
|
||||||
|
> responses, or text/xml+oembed for XML.
|
||||||
|
-->
|
||||||
<link href='https://host/provider.json' rel='alternate' type='application/json+oembed'>
|
<link href='https://host/provider.json' rel='alternate' type='application/json+oembed'>
|
||||||
<link href='https://host/provider.xml' rel='alternate' type='application/xml+oembed'>
|
<link href='https://host/provider.xml' rel='alternate' type='text/xml+oembed'>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
</html>
|
</html>
|
||||||
|
|
8
spec/fixtures/requests/oembed_xml.html
vendored
8
spec/fixtures/requests/oembed_xml.html
vendored
|
@ -1,7 +1,13 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link href='https://host/provider.xml' rel='alternate' type='application/xml+oembed'>
|
<!--
|
||||||
|
oEmbed
|
||||||
|
https://oembed.com/
|
||||||
|
> The type attribute must contain either application/json+oembed for JSON
|
||||||
|
> responses, or text/xml+oembed for XML.
|
||||||
|
-->
|
||||||
|
<link href='https://host/provider.xml' rel='alternate' type='text/xml+oembed'>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue