diff --git a/INSTALL.md b/INSTALL.md
index 91729e336c..0311120436 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -33,58 +33,10 @@ Sudachiインストール終了後、追加で`/etc/elasticsearch/sudachi/config
}
```
-## 新規インストールの場合
+## インストール手順
-1. 本家Mastodonとセットアップ手順はほとんど一緒です。kmyblueが独自に必須ソフトウェアを追加したわけではありません。ただしkmyblueはMastodonの開発中コードを取り込んでいるので、Rubyなどのバージョンアップ作業が必要になる場合があります。Mastodon公式のセットアップ手順を盲信せず、画面の指示に従ってインストールを進めてください。CloudFlareを組み合わせてセットアップしたとき、サーバーに接続すると400が出るなどのトラブルが出ることがありますが、大抵はMastodon本家由来のトラブルだと思われるので基本サポートはしません
-2. ただひとつ差異があります。Gitリポジトリはこのkmyblueに向けてください。`kb_development`ブランチの最新コミットではなく、`kb`で始まる最新のタグを取り込むことを強くおすすめします
+[Wiki](https://github.com/kmycode/mastodon/wiki/Installation)を参照してください
-## 本家Mastodonからのマイグレーションの場合
+## アップデート手順
-kmyblueから本家Mastodonに戻りたい場合もあると思いますので、**必ずデータベースのバックアップをとってください**。
-
-1. kmyblueのリリースノートに、kmyblueバージョンに対応した本家Mastodonのバージョンが記載されています。それを参照して、まず本家Mastodonをそのバージョンまでバージョンアップしてください
-2. Gitのリモートにkmyblueを追加して、そのままチェックアウトしてください
-3. データベースのマイグレーションなどを行ってください
-
-```
-sudo systemctl stop mastodon-*
-
-bundle install
-yarn install
-RAILS_ENV=production bin/rails db:migrate
-RAILS_ENV=production bin/rails assets:clobber
-RAILS_ENV=production bin/rails assets:precompile
-
-# ElasticSearchを使用する場合
-RAILS_ENV=production bin/tootctl search deploy
-
-RAILS_ENV=production bin/tootctl cache clear
-sudo systemctl start mastodon-web mastodon-streaming mastodon-sidekiq
-```
-
-## kmyblueのバージョンをアップデートする
-
-リリースノートを参照して、自分に必要な作業を特定してください。面倒な場合は毎回全部実行してしまっても問題ありません。(プリコンパイルが失敗する可能性があるのでご注意ください)
-
-```
-# Rubyパッケージアップデート
-bundle intall
-
-# JSパッケージアップデート
-yarn install
-
-# DBマイグレーション
-RAILS_ENV=production bin/rails db:migrate
-
-# プリコンパイル
-# うまくいかない場合(エラーは出ないのにWeb表示が崩れる)はclobberしてからprecompile
-# それでもうまくいかない場合はsudo systemctl stop mastodon-webしてから試す
-# それでもうまくいかない場合はサーバーOSを再起動してから試す
-RAILS_ENV=production bin/rails assets:clobber # プリコンパイルがうまくいかない場合
-RAILS_ENV=production bin/rails assets:precompile
-
-# サーバー再起動
-sudo systemctl restart mastodon-web
-sudo systemctl restart mastodon-streaming
-sudo systemctl restart mastodon-sidekiq
-```
+[Wiki](https://github.com/kmycode/mastodon/wiki/Updation)を参照してください
diff --git a/app/controllers/api/v1/statuses/emoji_reactioned_by_accounts_controller.rb b/app/controllers/api/v1/statuses/emoji_reactioned_by_accounts_controller.rb
index 92cd5228cc..9c2fb3d4a5 100644
--- a/app/controllers/api/v1/statuses/emoji_reactioned_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/emoji_reactioned_by_accounts_controller.rb
@@ -33,7 +33,7 @@ class Api::V1::Statuses::EmojiReactionedByAccountsController < Api::BaseControll
def paginated_emoji_reactions
EmojiReaction.paginate_by_max_id(
- limit_param(1000), # limit_param(DEFAULT_ACCOUNTS_LIMIT),
+ limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index 3ea159f019..1f682d1321 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -785,11 +785,12 @@ export function insertExpirationCompose(position, data) {
};
}
-export function insertReferenceCompose(position, url) {
+export function insertReferenceCompose(position, url, attributeType) {
return {
type: COMPOSE_REFERENCE_INSERT,
position,
url,
+ attributeType,
};
}
diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js
index a5f6729f41..b361809309 100644
--- a/app/javascript/mastodon/actions/interactions.js
+++ b/app/javascript/mastodon/actions/interactions.js
@@ -51,6 +51,10 @@ export const EMOJI_REACTIONS_FETCH_REQUEST = 'EMOJI_REACTIONS_FETCH_REQUEST';
export const EMOJI_REACTIONS_FETCH_SUCCESS = 'EMOJI_REACTIONS_FETCH_SUCCESS';
export const EMOJI_REACTIONS_FETCH_FAIL = 'EMOJI_REACTIONS_FETCH_FAIL';
+export const EMOJI_REACTIONS_EXPAND_REQUEST = 'EMOJI_REACTIONS_EXPAND_REQUEST';
+export const EMOJI_REACTIONS_EXPAND_SUCCESS = 'EMOJI_REACTIONS_EXPAND_SUCCESS';
+export const EMOJI_REACTIONS_EXPAND_FAIL = 'EMOJI_REACTIONS_EXPAND_FAIL';
+
export const PIN_REQUEST = 'PIN_REQUEST';
export const PIN_SUCCESS = 'PIN_SUCCESS';
export const PIN_FAIL = 'PIN_FAIL';
@@ -547,8 +551,9 @@ export function fetchEmojiReactions(id) {
dispatch(fetchEmojiReactionsRequest(id));
api(getState).get(`/api/v1/statuses/${id}/emoji_reactioned_by`).then(response => {
+ const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(importFetchedAccounts(response.data.map((er) => er.account)));
- dispatch(fetchEmojiReactionsSuccess(id, response.data));
+ dispatch(fetchEmojiReactionsSuccess(id, response.data, next ? next.uri : null));
}).catch(error => {
dispatch(fetchEmojiReactionsFail(id, error));
});
@@ -562,11 +567,12 @@ export function fetchEmojiReactionsRequest(id) {
};
}
-export function fetchEmojiReactionsSuccess(id, accounts) {
+export function fetchEmojiReactionsSuccess(id, accounts, next) {
return {
type: EMOJI_REACTIONS_FETCH_SUCCESS,
id,
accounts,
+ next,
};
}
@@ -577,6 +583,48 @@ export function fetchEmojiReactionsFail(id, error) {
};
}
+export function expandEmojiReactions(id) {
+ return (dispatch, getState) => {
+ const url = getState().getIn(['user_lists', 'emoji_reactioned_by', id, 'next']);
+ if (url === null) {
+ return;
+ }
+
+ dispatch(expandEmojiReactionsRequest(id));
+
+ api(getState).get(url).then(response => {
+ const next = getLinks(response).refs.find(link => link.rel === 'next');
+
+ dispatch(importFetchedAccounts(response.data.map((er) => er.account)));
+ dispatch(expandEmojiReactionsSuccess(id, response.data, next ? next.uri : null));
+ }).catch(error => dispatch(expandEmojiReactionsFail(id, error)));
+ };
+}
+
+export function expandEmojiReactionsRequest(id) {
+ return {
+ type: EMOJI_REACTIONS_EXPAND_REQUEST,
+ id,
+ };
+}
+
+export function expandEmojiReactionsSuccess(id, accounts, next) {
+ return {
+ type: EMOJI_REACTIONS_EXPAND_SUCCESS,
+ id,
+ accounts,
+ next,
+ };
+}
+
+export function expandEmojiReactionsFail(id, error) {
+ return {
+ type: EMOJI_REACTIONS_EXPAND_FAIL,
+ id,
+ error,
+ };
+}
+
export function fetchStatusReferences(id) {
return (dispatch, getState) => {
dispatch(fetchStatusReferencesRequest(id));
diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx
index d689b1ed03..02a42a92dd 100644
--- a/app/javascript/mastodon/components/status_action_bar.jsx
+++ b/app/javascript/mastodon/components/status_action_bar.jsx
@@ -52,6 +52,7 @@ const messages = defineMessages({
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to post' },
reference: { id: 'status.reference', defaultMessage: 'Add reference' },
+ quote: { id: 'status.quote', defaultMessage: 'Add ref (quote in other servers)' },
hide: { id: 'status.hide', defaultMessage: 'Hide post' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
@@ -97,6 +98,8 @@ class StatusActionBar extends ImmutablePureComponent {
onBookmarkCategoryAdder: PropTypes.func,
onFilter: PropTypes.func,
onAddFilter: PropTypes.func,
+ onReference: PropTypes.func,
+ onQuote: PropTypes.func,
onInteractionModal: PropTypes.func,
withDismiss: PropTypes.bool,
withCounters: PropTypes.bool,
@@ -271,6 +274,10 @@ class StatusActionBar extends ImmutablePureComponent {
this.props.onReference(this.props.status);
};
+ handleQuote = () => {
+ this.props.onQuote(this.props.status);
+ };
+
handleHideClick = () => {
this.props.onFilter();
};
@@ -316,6 +323,7 @@ class StatusActionBar extends ImmutablePureComponent {
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference });
+ menu.push({ text: intl.formatMessage(messages.quote), action: this.handleQuote });
}
menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClickOriginal });
diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx
index 5023b7ef03..da3058334b 100644
--- a/app/javascript/mastodon/containers/status_container.jsx
+++ b/app/javascript/mastodon/containers/status_container.jsx
@@ -203,7 +203,11 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
},
onReference (status) {
- dispatch(insertReferenceCompose(0, status.get('url')));
+ dispatch(insertReferenceCompose(0, status.get('url'), 'BT'));
+ },
+
+ onQuote (status) {
+ dispatch(insertReferenceCompose(0, status.get('url'), 'QT'));
},
onTranslate (status) {
diff --git a/app/javascript/mastodon/features/emoji_reactions/index.jsx b/app/javascript/mastodon/features/emoji_reactions/index.jsx
index 78d088e947..5ab2a34958 100644
--- a/app/javascript/mastodon/features/emoji_reactions/index.jsx
+++ b/app/javascript/mastodon/features/emoji_reactions/index.jsx
@@ -8,7 +8,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
-import { fetchEmojiReactions } from 'mastodon/actions/interactions';
+import { debounce } from 'lodash';
+
+import { fetchEmojiReactions, expandEmojiReactions } from 'mastodon/actions/interactions';
import ColumnHeader from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon';
import ScrollableList from 'mastodon/components/scrollable_list';
@@ -25,7 +27,9 @@ const messages = defineMessages({
const mapStateToProps = (state, props) => {
return {
- accountIds: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId]),
+ accountIds: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'items']),
+ hasMore: !!state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'next']),
+ isLoading: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'isLoading'], true),
};
};
@@ -35,6 +39,8 @@ class EmojiReactions extends ImmutablePureComponent {
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
+ hasMore: PropTypes.bool,
+ isLoading: PropTypes.bool,
multiColumn: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
@@ -45,18 +51,16 @@ class EmojiReactions extends ImmutablePureComponent {
}
}
- componentWillReceiveProps (nextProps) {
- if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
- this.props.dispatch(fetchEmojiReactions(nextProps.params.statusId));
- }
- }
-
handleRefresh = () => {
this.props.dispatch(fetchEmojiReactions(this.props.params.statusId));
};
+ handleLoadMore = debounce(() => {
+ this.props.dispatch(expandEmojiReactions(this.props.params.statusId));
+ }, 300, { leading: true });
+
render () {
- const { intl, accountIds, multiColumn } = this.props;
+ const { intl, accountIds, hasMore, isLoading, multiColumn } = this.props;
if (!accountIds) {
return (
@@ -68,7 +72,7 @@ class EmojiReactions extends ImmutablePureComponent {
let groups = {};
for (const emoji_reaction of accountIds) {
- const key = emoji_reaction.account.id;
+ const key = emoji_reaction.account_id;
const value = emoji_reaction;
if (!groups[key]) groups[key] = [value];
else groups[key].push(value);
@@ -82,12 +86,15 @@ class EmojiReactions extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
-
+
)}
/>
diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx
index e80a83c907..56086075fc 100644
--- a/app/javascript/mastodon/features/status/components/action_bar.jsx
+++ b/app/javascript/mastodon/features/status/components/action_bar.jsx
@@ -46,6 +46,7 @@ const messages = defineMessages({
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to post' },
reference: { id: 'status.reference', defaultMessage: 'Add reference' },
+ quote: { id: 'status.quote', defaultMessage: 'Add ref (quote in other servers)' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
@@ -74,6 +75,7 @@ class ActionBar extends PureComponent {
onFavourite: PropTypes.func.isRequired,
onEmojiReact: PropTypes.func.isRequired,
onReference: PropTypes.func.isRequired,
+ onQuote: PropTypes.func.isRequired,
onBookmark: PropTypes.func.isRequired,
onBookmarkCategoryAdder: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
@@ -208,6 +210,10 @@ class ActionBar extends PureComponent {
this.props.onReference(this.props.status);
};
+ handleQuote = () => {
+ this.props.onQuote(this.props.status);
+ };
+
handleEmojiPick = (data) => {
this.props.onEmojiReact(this.props.status, data);
};
@@ -248,6 +254,7 @@ class ActionBar extends PureComponent {
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference });
+ menu.push({ text: intl.formatMessage(messages.quote), action: this.handleQuote });
}
menu.push({ text: intl.formatMessage(messages.bookmark_category), action: this.handleBookmarkCategoryAdderClick });
diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx
index cf4c2bd6ce..03a721d9c8 100644
--- a/app/javascript/mastodon/features/status/index.jsx
+++ b/app/javascript/mastodon/features/status/index.jsx
@@ -363,7 +363,11 @@ class Status extends ImmutablePureComponent {
};
handleReference = (status) => {
- this.props.dispatch(insertReferenceCompose(0, status.get('url')));
+ this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'BT'));
+ };
+
+ handleQuote = (status) => {
+ this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'QT'));
};
handleBookmarkClick = (status) => {
@@ -750,6 +754,7 @@ class Status extends ImmutablePureComponent {
onReblog={this.handleReblogClick}
onReblogForceModal={this.handleReblogForceModalClick}
onReference={this.handleReference}
+ onQuote={this.handleQuote}
onBookmark={this.handleBookmarkClick}
onBookmarkCategoryAdder={this.handleBookmarkCategoryAdderClick}
onDelete={this.handleDeleteClick}
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 9de9b72162..b986b45b30 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -683,6 +683,7 @@
"status.open": "Expand this post",
"status.pin": "Pin on profile",
"status.pinned": "Pinned post",
+ "status.quote": "Ref (quote in other servers)",
"status.read_more": "Read more",
"status.reblog": "Boost",
"status.reblog_private": "Boost with original visibility",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index d294d85e0b..e598512178 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -769,6 +769,7 @@
"status.open": "詳細を表示",
"status.pin": "プロフィールに固定表示",
"status.pinned": "固定された投稿",
+ "status.quote": "参照 (他サーバーで引用扱い)",
"status.read_more": "もっと見る",
"status.reblog": "ブースト",
"status.reblog_private": "ブースト",
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index 59be1ae6da..612ee01d9b 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -252,10 +252,11 @@ const insertExpiration = (state, position, data) => {
});
};
-const insertReference = (state, url) => {
+const insertReference = (state, url, attributeType) => {
const oldText = state.get('text');
+ const attribute = attributeType || 'BT';
- if (oldText.indexOf(`BT ${url}`) >= 0) {
+ if (oldText.indexOf(`${attribute} ${url}`) >= 0) {
return state;
}
@@ -271,12 +272,12 @@ const insertReference = (state, url) => {
if (oldText.length > 0) {
const lastLine = oldText.slice(oldText.lastIndexOf('\n') + 1, oldText.length - 1);
- if (lastLine.startsWith('BT ')) {
+ if (lastLine.startsWith(`${attribute} `)) {
newLine = '\n';
}
}
- const referenceText = `${newLine}BT ${url}`;
+ const referenceText = `${newLine}${attribute} ${url}`;
const text = `${oldText}${referenceText}`;
return state.merge({
@@ -526,7 +527,7 @@ export default function compose(state = initialState, action) {
case COMPOSE_EXPIRATION_INSERT:
return insertExpiration(state, action.position, action.data);
case COMPOSE_REFERENCE_INSERT:
- return insertReference(state, action.url);
+ return insertReference(state, action.url, action.attributeType);
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
return state
.set('is_changing_upload', false)
diff --git a/app/javascript/mastodon/reducers/user_lists.js b/app/javascript/mastodon/reducers/user_lists.js
index edc83bd3d4..2cb41cd03d 100644
--- a/app/javascript/mastodon/reducers/user_lists.js
+++ b/app/javascript/mastodon/reducers/user_lists.js
@@ -57,7 +57,12 @@ import {
FAVOURITES_EXPAND_REQUEST,
FAVOURITES_EXPAND_SUCCESS,
FAVOURITES_EXPAND_FAIL,
+ EMOJI_REACTIONS_FETCH_REQUEST,
EMOJI_REACTIONS_FETCH_SUCCESS,
+ EMOJI_REACTIONS_FETCH_FAIL,
+ EMOJI_REACTIONS_EXPAND_REQUEST,
+ EMOJI_REACTIONS_EXPAND_SUCCESS,
+ EMOJI_REACTIONS_EXPAND_FAIL,
STATUS_REFERENCES_FETCH_SUCCESS,
} from '../actions/interactions';
import {
@@ -101,12 +106,33 @@ const normalizeList = (state, path, accounts, next) => {
}));
};
+const normalizeEmojiReactionList = (state, path, rows, next) => {
+ return state.setIn(path, ImmutableMap({
+ next,
+ items: ImmutableList(rows.map(normalizeEmojiReactionRow)),
+ isLoading: false,
+ }));
+};
+
const appendToList = (state, path, accounts, next) => {
return state.updateIn(path, map => {
return map.set('next', next).set('isLoading', false).update('items', list => list.concat(accounts.map(item => item.id)));
});
};
+const appendToEmojiReactionList = (state, path, rows, next) => {
+ return state.updateIn(path, map => {
+ return map.set('next', next).set('isLoading', false).update('items', list => list.concat(rows.map(normalizeEmojiReactionRow)));
+ });
+};
+
+const normalizeEmojiReactionRow = (row) => {
+ const accountId = row.account ? row.account.id : 0;
+ delete row.account;
+ row.account_id = accountId;
+ return row;
+};
+
const normalizeFollowRequest = (state, notification) => {
return state.updateIn(['follow_requests', 'items'], list => {
return list.filterNot(item => item === notification.account.id).unshift(notification.account.id);
@@ -167,8 +193,16 @@ export default function userLists(state = initialState, action) {
case FAVOURITES_FETCH_FAIL:
case FAVOURITES_EXPAND_FAIL:
return state.setIn(['favourited_by', action.id, 'isLoading'], false);
+ case EMOJI_REACTIONS_FETCH_REQUEST:
+ case EMOJI_REACTIONS_EXPAND_REQUEST:
+ return state.setIn(['emoji_reactioned_by', action.id, 'isLoading'], true);
+ case EMOJI_REACTIONS_FETCH_FAIL:
+ case EMOJI_REACTIONS_EXPAND_FAIL:
+ return state.setIn(['emoji_reactioned_by', action.id, 'isLoading'], false);
case EMOJI_REACTIONS_FETCH_SUCCESS:
- return state.setIn(['emoji_reactioned_by', action.id], ImmutableList(action.accounts));
+ return normalizeEmojiReactionList(state, ['emoji_reactioned_by', action.id], action.accounts, action.next);
+ case EMOJI_REACTIONS_EXPAND_SUCCESS:
+ return appendToEmojiReactionList(state, ['emoji_reactioned_by', action.id], action.accounts, action.next);
case STATUS_REFERENCES_FETCH_SUCCESS:
return state.setIn(['referred_by', action.id], ImmutableList(action.statuses.map(item => item.id)));
case NOTIFICATIONS_UPDATE:
diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb
index 57cd9ca415..08b546561d 100644
--- a/app/models/form/admin_settings.rb
+++ b/app/models/form/admin_settings.rb
@@ -46,6 +46,7 @@ class Form::AdminSettings
receive_other_servers_emoji_reaction
streaming_other_servers_emoji_reaction
enable_emoji_reaction
+ check_lts_version_only
).freeze
INTEGER_KEYS = %i(
@@ -72,6 +73,7 @@ class Form::AdminSettings
receive_other_servers_emoji_reaction
streaming_other_servers_emoji_reaction
enable_emoji_reaction
+ check_lts_version_only
).freeze
UPLOAD_KEYS = %i(
diff --git a/app/models/software_update.rb b/app/models/software_update.rb
index cb3a6df2ae..4aeb7e665b 100644
--- a/app/models/software_update.rb
+++ b/app/models/software_update.rb
@@ -36,5 +36,13 @@ class SoftwareUpdate < ApplicationRecord
def urgent_pending?
pending_to_a.any?(&:urgent?)
end
+
+ def major_pending?
+ pending_to_a.any?(&:major_type?)
+ end
+
+ def patch_pending?
+ pending_to_a.any?(&:patch_type?)
+ end
end
end
diff --git a/app/models/status.rb b/app/models/status.rb
index f9587b3c71..9f0299a511 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -226,6 +226,10 @@ class Status < ApplicationRecord
!reblog_of_id.nil?
end
+ def quote
+ reference_objects.where(attribute_type: 'QT').first&.target_status
+ end
+
def within_realtime_window?
created_at >= REAL_TIME_WINDOW.ago
end
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index 109f8115df..d8f7a328ed 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -17,7 +17,6 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
attribute :quote_uri, if: :quote?
attribute :misskey_quote, key: :_misskey_quote, if: :quote?
- attribute :misskey_content, key: :_misskey_content, if: :quote?
has_many :virtual_attachments, key: :attachment
has_many :virtual_tags, key: :tag
@@ -172,21 +171,21 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
end
def quote?
- object.references.count == 1 && object.account.user&.settings&.[]('single_ref_to_quote')
+ @quote ||= (object.reference_objects.count == 1 && object.account.user&.settings&.[]('single_ref_to_quote')) || object.reference_objects.where(attribute_type: 'QT').count == 1
+ end
+
+ def quote_post
+ @quote_post ||= object.quote || object.references.first
end
def quote_uri
- ActivityPub::TagManager.instance.uri_for(object.references.first)
+ ActivityPub::TagManager.instance.uri_for(quote_post)
end
def misskey_quote
quote_uri
end
- def misskey_content
- object.text
- end
-
def poll_options
object.preloadable_poll.loaded_options
end
diff --git a/app/services/delivery_antenna_service.rb b/app/services/delivery_antenna_service.rb
index e494321917..53bcc226e7 100644
--- a/app/services/delivery_antenna_service.rb
+++ b/app/services/delivery_antenna_service.rb
@@ -47,8 +47,8 @@ class DeliveryAntennaService
end
antennas = antennas.where(account_id: Account.without_suspended.joins(:user).select('accounts.id').where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago))
- antennas = antennas.where(account: @status.account.followers) if [:public, :public_unlisted, :login, :limited].exclude?(@status.visibility.to_sym) && !@status.public_searchability?
- antennas = antennas.where(account: @status.mentioned_accounts) if @status.visibility.to_sym == :limited
+ antennas = antennas.where(account: @status.account.followers) if followers_only?
+ antennas = antennas.where(account: @status.mentioned_accounts) if mentioned_users_only?
antennas = antennas.where(with_media_only: false) unless @status.with_media?
antennas = antennas.where(ignore_reblog: false) if @status.reblog?
antennas = antennas.where(stl: false, ltl: false)
@@ -116,6 +116,26 @@ class DeliveryAntennaService
collection.deliver!
end
+ def followers_only?
+ case @status.visibility.to_sym
+ when :public, :public_unlisted, :login, :limited
+ false
+ when :unlisted
+ if @status.local?
+ !@status.public_searchability?
+ else
+ info = InstanceInfo.find_by(domain: @status.account.domain)
+ info&.software == 'firefish' || !@status.public_searchability?
+ end
+ else
+ true
+ end
+ end
+
+ def mentioned_users_only?
+ @status.visibility.to_sym == :limited
+ end
+
class AntennaCollection
def initialize(status, update, stl_home = false) # rubocop:disable Style/OptionalBooleanParameter
@status = status
diff --git a/app/services/process_references_service.rb b/app/services/process_references_service.rb
index 05aa5ef345..faf5965a7a 100644
--- a/app/services/process_references_service.rb
+++ b/app/services/process_references_service.rb
@@ -58,11 +58,11 @@ class ProcessReferencesService < BaseService
private
def references
- @references = @reference_parameters + scan_text!
+ @references ||= @reference_parameters + scan_text!
end
def old_references
- @old_references = @status.references.pluck(:id)
+ @old_references ||= @status.references.pluck(:id)
end
def added_references
@@ -112,7 +112,7 @@ class ProcessReferencesService < BaseService
def create_notifications!
return if @added_objects.blank?
- local_reference_objects = @added_objects.filter { |ref| ref.target_status.account.local? }
+ local_reference_objects = @added_objects.filter { |ref| ref.target_status.account.local? && StatusPolicy.new(ref.target_status.account, ref.status).show? }
return if local_reference_objects.empty?
LocalNotificationWorker.push_bulk(local_reference_objects) do |ref|
diff --git a/app/services/software_update_check_service.rb b/app/services/software_update_check_service.rb
index 49b92f104d..b20fb8611b 100644
--- a/app/services/software_update_check_service.rb
+++ b/app/services/software_update_check_service.rb
@@ -27,11 +27,18 @@ class SoftwareUpdateCheckService < BaseService
end
def api_url
- ENV.fetch('UPDATE_CHECK_URL', 'https://api.joinmastodon.org/update-check')
+ ENV.fetch('UPDATE_CHECK_URL', 'https://kmy.blue/update-check')
end
def version
- @version ||= Mastodon::Version.to_s.split('+')[0]
+ if ENV.fetch('UPDATE_CHECK_SOURCE', 'kmyblue') == 'kmyblue'
+ @version = "#{Mastodon::Version.kmyblue_major}.#{Mastodon::Version.kmyblue_minor}"
+ @version += '-lts' if Setting.check_lts_version_only
+ else
+ @version = Mastodon::Version.to_s.split('+')[0]
+ end
+
+ @version
end
def process_update_notices!(update_notices)
diff --git a/app/views/admin/settings/discovery/show.html.haml b/app/views/admin/settings/discovery/show.html.haml
index 60443e6877..6ea9e4fb4b 100644
--- a/app/views/admin/settings/discovery/show.html.haml
+++ b/app/views/admin/settings/discovery/show.html.haml
@@ -55,6 +55,9 @@
.fields-group
= f.input :authorized_fetch, as: :boolean, wrapper: :with_label, label: t('admin.settings.security.authorized_fetch'), warning_hint: authorized_fetch_overridden? ? t('admin.settings.security.authorized_fetch_overridden_hint') : nil, hint: t('admin.settings.security.authorized_fetch_hint'), disabled: authorized_fetch_overridden?, recommended: authorized_fetch_overridden? ? :overridden : nil
+ .fields-group
+ = f.input :check_lts_version_only, as: :boolean, wrapper: :with_label, kmyblue: true, hint: false
+
%h4= t('admin.settings.discovery.follow_recommendations')
.fields-group
diff --git a/app/views/settings/preferences/reaching/show.html.haml b/app/views/settings/preferences/reaching/show.html.haml
index b3d22e8052..cfeaeff68e 100644
--- a/app/views/settings/preferences/reaching/show.html.haml
+++ b/app/views/settings/preferences/reaching/show.html.haml
@@ -31,7 +31,7 @@
.fields-row
.fields-group.fields-row__column.fields-row__column-12
- = ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |searchability| safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability')
+ = ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |searchability| safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_default_searchability')
.fields-group
= ff.input :disallow_unlisted_public_searchability, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_disallow_unlisted_public_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_disallow_unlisted_public_searchability')
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d9d0bb084a..4e477ba146 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -997,6 +997,9 @@ en:
other: Used by %{count} people over the last week
title: Trends
trending: Trending
+ update-pendings:
+ major: Major update pending
+ patch: Patch update pending
warning_presets:
add_new: Add new
delete: Delete
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 286e19d42f..4d6d4e4c6a 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -991,6 +991,9 @@ ja:
other: 週間%{count}人に使用されました
title: トレンド
trending: トレンド
+ update_pendings:
+ major: メジャーアップデートあり
+ patch: パッチアップデートあり
warning_presets:
add_new: 追加
delete: 削除
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 738e5f39c2..aa17a42816 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -62,6 +62,7 @@ en:
setting_aggregate_reblogs: Do not show new boosts for posts that have been recently boosted (only affects newly-received boosts)
setting_always_send_emails: Normally e-mail notifications won't be sent when you are actively using Mastodon
setting_bookmark_category_needed: When removing from all category, unbookmarked automatically
+ setting_default_searchability: kmyblue・Fedibirdでは検索許可設定に基づき検索されます。Misskeyでは当設定に関係なく、全ての公開・ローカル公開・未収載投稿が検索されます。Mastodon・Firefishでは検索許可の代わりにプロフィール設定の「公開投稿を他のサーバーで自由に検索できるようにする」設定が適用されます
setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click
setting_display_media_default: Hide media marked as sensitive
setting_display_media_hide_all: Always hide media
@@ -315,6 +316,7 @@ en:
activity_api_enabled: Publish aggregate statistics about user activity in the API
backups_retention_period: User archive retention period
bootstrap_timeline_accounts: Always recommend these accounts to new users
+ check_lts_version_only: Check kmyblue LTS version only when update check
closed_registrations_message: Custom message when sign-ups are not available
content_cache_retention_period: Content cache retention period
custom_css: Custom CSS
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index 5c72720a33..e255c43cd4 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -65,6 +65,7 @@ ja:
setting_always_send_emails: 通常、Mastodon からメール通知は行われません。
setting_bookmark_category_needed: すべてのカテゴリから削除したとき、ブックマークが自動で外れるようになります
setting_boost_modal: ブーストの公開範囲が指定できるようになります
+ setting_default_searchability: kmyblue・Fedibirdでは検索許可設定に基づき検索されます。Misskeyでは当設定に関係なく、全ての公開・ローカル公開・未収載投稿が検索されます。Mastodon・Firefishでは検索許可の代わりにプロフィール設定の「公開投稿を他のサーバーで自由に検索できるようにする」設定が適用されます
setting_default_sensitive: 閲覧注意状態のメディアはデフォルトでは内容が伏せられ、クリックして初めて閲覧できるようになります
setting_disallow_unlisted_public_searchability: この設定を有効にすると、未収載投稿と検索範囲「誰でも」は両立できず不特定多数からの検索が不可になります。Fedibirdと同じ挙動になります
setting_display_media_default: 閲覧注意としてマークされたメディアは隠す
@@ -330,6 +331,7 @@ ja:
activity_api_enabled: APIでユーザーアクティビティに関する集計統計を公開する
backups_retention_period: ユーザーアーカイブの保持期間
bootstrap_timeline_accounts: おすすめユーザーに常に表示するアカウント
+ check_lts_version_only: 更新チェックの時、LTSバージョンのみ確認する
closed_registrations_message: アカウント作成を停止している時のカスタムメッセージ
content_cache_retention_period: コンテンツキャッシュの保持期間
custom_css: カスタムCSS
diff --git a/config/navigation.rb b/config/navigation.rb
index ce8c44d542..bdb86f06a7 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -4,7 +4,11 @@ SimpleNavigation::Configuration.run do |navigation|
navigation.items do |n|
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path
- n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
+ if ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops)
+ n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
+ n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.update_pendings.major')]), admin_software_updates_path, if: -> { !SoftwareUpdate.urgent_pending? && SoftwareUpdate.major_pending? }, html: { class: 'warning' }
+ n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.update_pendings.patch')]), admin_software_updates_path, if: -> { !SoftwareUpdate.urgent_pending? && SoftwareUpdate.patch_pending? }, html: { class: 'warning' }
+ end
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
diff --git a/config/settings.yml b/config/settings.yml
index 0042b5822e..69b3ed1ee3 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -41,6 +41,7 @@ defaults: &defaults
receive_other_servers_emoji_reaction: false
streaming_other_servers_emoji_reaction: false
enable_emoji_reaction: true
+ check_lts_version_only: true
development:
<<: *defaults
diff --git a/db/post_migrate/20230803082451_add_unique_index_on_preview_cards_statuses.rb b/db/post_migrate/20230803082451_add_unique_index_on_preview_cards_statuses.rb
index 3e9ab134b7..d29d7847c5 100644
--- a/db/post_migrate/20230803082451_add_unique_index_on_preview_cards_statuses.rb
+++ b/db/post_migrate/20230803082451_add_unique_index_on_preview_cards_statuses.rb
@@ -18,7 +18,7 @@ class AddUniqueIndexOnPreviewCardsStatuses < ActiveRecord::Migration[6.1]
def supports_concurrent_reindex?
@supports_concurrent_reindex ||= begin
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
- version >= 12_000
+ version >= 120_000
end
end
diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb
index 4a43f67c27..c382b5fbd5 100644
--- a/lib/mastodon/migration_helpers.rb
+++ b/lib/mastodon/migration_helpers.rb
@@ -202,7 +202,7 @@ module Mastodon
def supports_add_column_with_default?
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
- version >= 11_000
+ version >= 110_000
end
# Adds a foreign key with only minimal locking on the tables involved.
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index 0086555a4e..e5d7b0ae8f 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -62,7 +62,11 @@ module Mastodon
end
def gem_version
- @gem_version ||= Gem::Version.new(to_s.split('+')[0])
+ @gem_version ||= if ENV.fetch('UPDATE_CHECK_SOURCE', 'kmyblue') == 'kmyblue'
+ Gem::Version.new("#{kmyblue_major}.#{kmyblue_minor}")
+ else
+ Gem::Version.new(to_s.split('+')[0])
+ end
end
def repository
diff --git a/public/robots.txt b/public/robots.txt
index 6672eeba1f..3bd45adaef 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -3,6 +3,9 @@
User-agent: GPTBot
Disallow: /
+User-agent: CCBot
+Disallow: /
+
User-agent: *
Disallow: /media_proxy/
Disallow: /interact/
diff --git a/spec/serializers/activitypub/note_serializer_spec.rb b/spec/serializers/activitypub/note_serializer_spec.rb
index f4248e548e..0425e2e66b 100644
--- a/spec/serializers/activitypub/note_serializer_spec.rb
+++ b/spec/serializers/activitypub/note_serializer_spec.rb
@@ -73,7 +73,6 @@ describe ActivityPub::NoteSerializer do
expect(subject['quoteUri']).to_not be_nil
expect(subject['quoteUri']).to eq referred.uri
expect(subject['_misskey_quote']).to eq referred.uri
- expect(subject['_misskey_content']).to eq referred.text
expect(subject['references']['first']['items']).to include referred.uri
end
end
diff --git a/spec/services/delivery_antenna_service_spec.rb b/spec/services/delivery_antenna_service_spec.rb
index 26c23eb930..e9620dc083 100644
--- a/spec/services/delivery_antenna_service_spec.rb
+++ b/spec/services/delivery_antenna_service_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe DeliveryAntennaService, type: :service do
let(:domain) { nil }
let(:spoiler_text) { '' }
let(:tags) { Tag.find_or_create_by_names(['hoge']) }
+ let(:software) { nil }
let(:status) do
url = domain.present? ? 'https://example.com/status' : nil
status = Fabricate(:status, account: alice, spoiler_text: spoiler_text, visibility: visibility, searchability: searchability, text: 'Hello my body #hoge', url: url)
@@ -30,6 +31,8 @@ RSpec.describe DeliveryAntennaService, type: :service do
let(:mode) { :home }
before do
+ Fabricate(:instance_info, domain: domain, software: software) if domain.present? && software.present?
+
bob.follow!(alice)
alice.block!(ohagi)
@@ -359,4 +362,42 @@ RSpec.describe DeliveryAntennaService, type: :service do
expect(antenna_feed_of(antenna)).to include status.id
end
end
+
+ context 'with federated unlisted post' do
+ let(:visibility) { :unlisted }
+ let(:searchability) { :public }
+ let(:domain) { 'fast.example.com' }
+ let!(:antenna) { antenna_with_keyword(bob, 'body') }
+ let!(:empty_antenna) { antenna_with_keyword(tom, 'body') }
+
+ context 'when unknown domain' do
+ let(:software) { nil }
+
+ it 'detecting antenna' do
+ expect(antenna_feed_of(antenna)).to include status.id
+ expect(antenna_feed_of(empty_antenna)).to include status.id
+ end
+ end
+
+ context 'when misskey domain' do
+ let(:software) { 'misskey' }
+
+ it 'detecting antenna' do
+ expect(antenna_feed_of(antenna)).to include status.id
+ expect(antenna_feed_of(empty_antenna)).to include status.id
+ end
+ end
+
+ context 'when firefish domain' do
+ let(:software) { 'firefish' }
+
+ it 'detecting antenna' do
+ expect(antenna_feed_of(antenna)).to include status.id
+ end
+
+ it 'not detecting antenna' do
+ expect(antenna_feed_of(empty_antenna)).to_not include status.id
+ end
+ end
+ end
end
diff --git a/spec/services/process_references_service_spec.rb b/spec/services/process_references_service_spec.rb
index e9099fb935..c41144a2aa 100644
--- a/spec/services/process_references_service_spec.rb
+++ b/spec/services/process_references_service_spec.rb
@@ -6,10 +6,16 @@ RSpec.describe ProcessReferencesService, type: :service do
let(:text) { 'Hello' }
let(:account) { Fabricate(:user).account }
let(:visibility) { :public }
+ let(:target_status_visibility) { :public }
let(:status) { Fabricate(:status, account: account, text: text, visibility: visibility) }
- let(:target_status) { Fabricate(:status, account: Fabricate(:user).account) }
+ let(:target_status) { Fabricate(:status, account: Fabricate(:user).account, visibility: target_status_visibility) }
let(:target_status_uri) { ActivityPub::TagManager.instance.uri_for(target_status) }
+ def notify?(target_status_id = nil)
+ target_status_id ||= target_status.id
+ StatusReference.exists?(id: Notification.where(type: 'status_reference').select(:activity_id), target_status_id: target_status_id)
+ end
+
describe 'posting new status' do
subject do
described_class.new.call(status, reference_parameters, urls: urls, fetch_remote: fetch_remote)
@@ -27,6 +33,7 @@ RSpec.describe ProcessReferencesService, type: :service do
expect(subject.size).to eq 1
expect(subject.pluck(0)).to include target_status.id
expect(subject.pluck(1)).to include 'RT'
+ expect(notify?).to be true
end
end
@@ -39,6 +46,59 @@ RSpec.describe ProcessReferencesService, type: :service do
expect(subject.size).to eq 2
expect(subject).to include [target_status.id, 'RT']
expect(subject).to include [target_status2.id, 'BT']
+ expect(notify?).to be true
+ expect(notify?(target_status2.id)).to be true
+ end
+ end
+
+ context 'when private post' do
+ let(:text) { "Hello RT #{target_status_uri}" }
+ let(:visibility) { :private }
+
+ it 'post status' do
+ expect(subject.size).to eq 1
+ expect(subject.pluck(0)).to include target_status.id
+ expect(subject.pluck(1)).to include 'RT'
+ expect(notify?).to be false
+ end
+ end
+
+ context 'when cannot show private post' do
+ let(:text) { "Hello RT #{target_status_uri}" }
+ let(:target_status_visibility) { :private }
+
+ it 'post status' do
+ expect(subject.size).to eq 0
+ expect(notify?).to be false
+ end
+ end
+
+ context 'with quote' do
+ let(:text) { "Hello QT #{target_status_uri}" }
+
+ it 'post status' do
+ expect(subject.size).to eq 1
+ expect(subject.pluck(0)).to include target_status.id
+ expect(subject.pluck(1)).to include 'QT'
+ expect(status.quote).to_not be_nil
+ expect(status.quote.id).to eq target_status.id
+ expect(notify?).to be true
+ end
+ end
+
+ context 'with quote and reference' do
+ let(:target_status2) { Fabricate(:status) }
+ let(:target_status2_uri) { ActivityPub::TagManager.instance.uri_for(target_status2) }
+ let(:text) { "Hello QT #{target_status_uri}\nBT #{target_status2_uri}" }
+
+ it 'post status' do
+ expect(subject.size).to eq 2
+ expect(subject).to include [target_status.id, 'QT']
+ expect(subject).to include [target_status2.id, 'BT']
+ expect(status.quote).to_not be_nil
+ expect(status.quote.id).to eq target_status.id
+ expect(notify?).to be true
+ expect(notify?(target_status2.id)).to be true
end
end
@@ -47,6 +107,7 @@ RSpec.describe ProcessReferencesService, type: :service do
it 'post status' do
expect(subject.size).to eq 0
+ expect(notify?).to be false
end
end
@@ -143,6 +204,7 @@ RSpec.describe ProcessReferencesService, type: :service do
it 'post status' do
expect(subject.size).to eq 1
expect(subject).to include target_status.id
+ expect(notify?).to be true
end
end
@@ -154,6 +216,7 @@ RSpec.describe ProcessReferencesService, type: :service do
expect(subject.size).to eq 2
expect(subject).to include target_status.id
expect(subject).to include target_status2.id
+ expect(notify?(target_status2.id)).to be true
end
end
@@ -173,6 +236,7 @@ RSpec.describe ProcessReferencesService, type: :service do
it 'post status' do
expect(subject.size).to eq 0
+ expect(notify?).to be false
end
end
@@ -183,6 +247,7 @@ RSpec.describe ProcessReferencesService, type: :service do
it 'post status' do
expect(subject.size).to eq 1
expect(subject).to include target_status2.id
+ expect(notify?(target_status2.id)).to be true
end
end
end
diff --git a/spec/services/software_update_check_service_spec.rb b/spec/services/software_update_check_service_spec.rb
index c8821348ac..7cc99bb09c 100644
--- a/spec/services/software_update_check_service_spec.rb
+++ b/spec/services/software_update_check_service_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe SoftwareUpdateCheckService, type: :service do
subject { described_class.new }
shared_examples 'when the feature is enabled' do
- let(:full_update_check_url) { "#{update_check_url}?version=#{Mastodon::Version.to_s.split('+')[0]}" }
+ let(:full_update_check_url) { "#{update_check_url}?version=#{Mastodon::Version.kmyblue_major}.#{Mastodon::Version.kmyblue_minor}-lts" }
let(:devops_role) { Fabricate(:user_role, name: 'DevOps', permissions: UserRole::FLAGS[:view_devops]) }
let(:owner_user) { Fabricate(:user, role: UserRole.find_by(name: 'Owner')) }
@@ -139,7 +139,7 @@ RSpec.describe SoftwareUpdateCheckService, type: :service do
end
context 'when using the default update checking API' do
- let(:update_check_url) { 'https://api.joinmastodon.org/update-check' }
+ let(:update_check_url) { 'https://kmy.blue/update-check' }
it_behaves_like 'when the feature is enabled'
end