Merge pull request #69 from kmycode/kb-draft-7.0

Bump version to 7.0
This commit is contained in:
KMY(雪あすか) 2023-10-11 12:25:45 +09:00 committed by GitHub
commit 285dc3fcf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 605 additions and 193 deletions

View file

@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file.
## [4.2.1] - UNRELEASED
## [4.2.1] - 2023-10-10
### Added
@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- Fix clicking on already-opened thread post scrolling to the top of the thread ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27331), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27338), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27350))
- Fix some remote posts getting truncated ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27307))
- Fix some cases of infinite scroll code trying to fetch inaccessible posts in a loop ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27286))
- Fix `Vary` headers not being set on some redirects ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27272))

View file

@ -15,6 +15,7 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
| Version | Supported |
| ------- | ---------------- |
| 4.2.x | Yes |
| 4.1.x | Yes |
| 4.0.x | Until 2023-10-31 |
| 3.5.x | Until 2023-12-31 |

View file

@ -35,7 +35,7 @@ module Admin
def update
authorize :friend_server, :update?
if @friend.update(resource_params)
if @friend.update(update_resource_params)
redirect_to admin_friend_servers_path
else
render action: :edit
@ -79,7 +79,11 @@ module Admin
end
def resource_params
params.require(:friend_domain).permit(:domain, :inbox_url, :available, :pseudo_relay, :unlocked, :allow_all_posts)
params.require(:friend_domain).permit(:domain, :inbox_url, :available, :pseudo_relay, :delivery_local, :unlocked, :allow_all_posts)
end
def update_resource_params
params.require(:friend_domain).permit(:inbox_url, :available, :pseudo_relay, :delivery_local, :unlocked, :allow_all_posts)
end
def warn_signatures_not_enabled!

View file

@ -475,9 +475,6 @@ class Status extends ImmutablePureComponent {
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div onClick={this.handleClick} className='status__info'>
<a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
{withReference}
{withExpiration}
{withLimited}
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
</a>

View file

@ -233,6 +233,8 @@ class Status extends ImmutablePureComponent {
componentDidMount () {
attachFullscreenListener(this.onFullScreenChange);
this._scrollStatusIntoView();
}
UNSAFE_componentWillReceiveProps (nextProps) {
@ -638,10 +640,10 @@ class Status extends ImmutablePureComponent {
this.node = c;
};
componentDidUpdate (prevProps) {
const { status, ancestorsIds, multiColumn } = this.props;
_scrollStatusIntoView () {
const { status, multiColumn } = this.props;
if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
if (status) {
window.requestAnimationFrame(() => {
this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true);
@ -658,6 +660,14 @@ class Status extends ImmutablePureComponent {
}
}
componentDidUpdate (prevProps) {
const { status, ancestorsIds } = this.props;
if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
this._scrollStatusIntoView();
}
}
componentWillUnmount () {
detachFullscreenListener(this.onFullScreenChange);
}
@ -666,6 +676,22 @@ class Status extends ImmutablePureComponent {
this.setState({ fullscreen: isFullscreen() });
};
shouldUpdateScroll = (prevRouterProps, { location }) => {
// Do not change scroll when opening a modal
if (location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
return false;
}
// Scroll to focused post if it is loaded
const child = this.node?.querySelector('.detailed-status__wrapper');
if (child) {
return [0, child.offsetTop];
}
// Do not scroll otherwise, `componentDidUpdate` will take care of that
return false;
};
render () {
let ancestors, descendants, references;
const { isLoading, status, ancestorsIds, descendantsIds, referenceIds, intl, domain, multiColumn, pictureInPicture } = this.props;
@ -723,7 +749,7 @@ class Status extends ImmutablePureComponent {
)}
/>
<ScrollContainer scrollKey='thread'>
<ScrollContainer scrollKey='thread' shouldUpdateScroll={this.shouldUpdateScroll}>
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
{references}
{ancestors}

View file

@ -102,7 +102,7 @@
"bundle_modal_error.message": "컴포넌트를 불러오는 중 문제가 발생했습니다.",
"bundle_modal_error.retry": "다시 시도",
"closed_registrations.other_server_instructions": "마스토돈은 분산화 되어 있기 때문에, 다른 서버에서 계정을 만들더라도 이 서버와 상호작용 할 수 있습니다.",
"closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 만약 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
"closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
"closed_registrations_modal.find_another_server": "다른 서버 찾기",
"closed_registrations_modal.preamble": "마스토돈은 분산화 되어 있습니다, 그렇기 때문에 어디에서 계정을 생성하든, 이 서버에 있는 누구와도 팔로우와 상호작용을 할 수 있습니다. 심지어는 스스로 서버를 만드는 것도 가능합니다!",
"closed_registrations_modal.title": "마스토돈에서 가입",

View file

@ -312,6 +312,7 @@
"home.hide_announcements": "ကြေညာချက်များကို ဖျောက်ပါ",
"home.pending_critical_update.body": "သင့် Mastodon ဆာဗာ အမြန်ဆုံး အပ်ဒိတ်လုပ်ပါ။",
"home.pending_critical_update.link": "အပ်ဒိတ်များကြည့်ရန်",
"home.pending_critical_update.title": "အရေးကြီးသည့် လုံခြုံရေးအပ်ဒိတ် ရနိုင်ပါမည်။",
"home.show_announcements": "ကြေညာချက်များကို ပြပါ",
"interaction_modal.description.favourite": "Mastodon အကောင့်ဖြင့် ဤပို့စ်ကို သင် favorite ပြုလုပ်ကြောင်း စာရေးသူအား အသိပေးပြီး နောက်ပိုင်းတွင် သိမ်းဆည်းနိုင်သည်။",
"interaction_modal.description.follow": "Mastodon အကောင့်ဖြင့် သင်၏ ပင်မစာမျက်နှာတွင် ၎င်းတို့၏ ပို့စ်များကို ရရှိရန်အတွက် {name} ကို စောင့်ကြည့်နိုင်ပါသည်။",
@ -594,6 +595,7 @@
"search_popout.options": "ရွေးချယ်ထားသည်များ ရှာဖွေရန်",
"search_popout.quick_actions": "အမြန်လုပ်ဆောင်မှုများ",
"search_popout.recent": "လတ်တလော ရှာဖွေမှုများ",
"search_popout.specific_date": "သီးခြားရက်စွဲ",
"search_popout.user": "အသုံးပြုသူ",
"search_results.accounts": "စာမျက်နှာ",
"search_results.all": "အားလုံး",

View file

@ -6,6 +6,7 @@
"about.rules": "සේවාදායකයේ නීති",
"account.account_note_header": "සටහන",
"account.add_or_remove_from_list": "ලැයිස්තු වලින් එකතු හෝ ඉවත් කරන්න",
"account.badges.bot": "ස්වයංක්‍රියයි",
"account.badges.group": "සමූහය",
"account.block": "@{name} අවහිර කරන්න",
"account.block_domain": "{domain} වසම අවහිර කරන්න",
@ -21,14 +22,15 @@
"account.follow": "අනුගමනය",
"account.followers": "අනුගාමිකයින්",
"account.followers.empty": "කිසිවෙක් අනුගමනය කර නැත.",
"account.following": "අනුගමනය",
"account.following_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
"account.followers_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
"account.following": "අනුගමන",
"account.following_counter": "{count, plural, one {අනුගමන {counter}} other {අනුගමන {counter}}}",
"account.follows.empty": "තවමත් කිසිවෙක් අනුගමනය නොකරයි.",
"account.follows_you": "ඔබව අනුගමනය කරයි",
"account.go_to_profile": "පැතිකඩට යන්න",
"account.joined_short": "එක් වූ දිනය",
"account.link_verified_on": "මෙම සබැඳියේ අයිතිය {date} දී පරීක්‍ෂා කෙරිණි",
"account.media": "මාධ්‍ය",
"account.media": "මාධ්‍ය",
"account.mention": "@{name} සඳහන් කරන්ක",
"account.mute": "@{name} නිහඬ කරන්න",
"account.mute_short": "නිහඬ",
@ -37,6 +39,7 @@
"account.posts_with_replies": "ලිපි සහ පිළිතුරු",
"account.report": "@{name} වාර්තා කරන්න",
"account.share": "@{name} ගේ පැතිකඩ බෙදාගන්න",
"account.statuses_counter": "{count, plural, one {ලිපි {counter}} other {ලිපි {counter}}}",
"account.unblock": "@{name} අනවහිර කරන්න",
"account.unblock_domain": "{domain} වසම අනවහිර කරන්න",
"account.unblock_short": "අනවහිර",
@ -53,11 +56,17 @@
"audio.hide": "හඬපටය සඟවන්න",
"autosuggest_hashtag.per_week": "සතියකට {count}",
"boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට {combo} එබීමට හැකිය",
"bundle_column_error.copy_stacktrace": "දෝෂ වාර්තාවේ පිටපතක්",
"bundle_column_error.error.title": "අපොයි!",
"bundle_column_error.network.title": "ජාලයේ දෝෂයකි",
"bundle_column_error.retry": "නැවත උත්සාහ කරන්න",
"bundle_column_error.return": "ආපසු මුලට යන්න",
"bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "වසන්න",
"bundle_modal_error.message": "මෙම සංරචකය පූරණයේ දී යම් දෙයක් වැරදී ඇත.",
"bundle_modal_error.retry": "නැවත උත්සාහ කරන්න",
"closed_registrations_modal.find_another_server": "වෙනත් සේවාදායක",
"closed_registrations_modal.title": "මාස්ටඩන් හි ලියාපදිංචි වන්න",
"column.about": "පිලිබඳව",
"column.blocks": "අවහිර කළ අය",
"column.bookmarks": "පොත්යොමු",
@ -159,7 +168,7 @@
"empty_column.domain_blocks": "අවහිර කරන ලද වසම් නැත.",
"empty_column.explore_statuses": "දැන් කිසිවක් නැඹුරු නොවේ. පසුව නැවත පරීක්ෂා කරන්න!",
"empty_column.follow_requests": "ඔබට තවමත් අනුගමන ඉල්ලීම් ලැබී නැත. ඉල්ලීමක් ලැබුණු විට, එය මෙහි පෙන්වනු ඇත.",
"empty_column.home": "ඔබගේ මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.",
"empty_column.home": "මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.",
"empty_column.lists": "ඔබට තවමත් ලැයිස්තු කිසිවක් නැත. ඔබ එකක් සාදන විට, එය මෙහි පෙන්වනු ඇත.",
"empty_column.mutes": "ඔබ තවමත් කිසිදු පරිශීලකයෙකු නිහඬ කර නැත.",
"empty_column.notifications": "ඔබට දැනුම්දීම් ලැබී නැත. අන් අය සහ ඔබ අතර අන්‍යෝන්‍ය බලපවත්වන දෑ මෙහි දිස්වනු ඇත.",
@ -264,7 +273,7 @@
"navigation_bar.favourites": "ප්‍රියතමයන්",
"navigation_bar.filters": "නිහඬ කළ වචන",
"navigation_bar.follow_requests": "අනුගමන ඉල්ලීම්",
"navigation_bar.follows_and_followers": "අනුගමන හා අනුගාමිකයින්",
"navigation_bar.follows_and_followers": "අනුගමන හා අනුගාමික",
"navigation_bar.lists": "ලැයිස්තු",
"navigation_bar.logout": "නික්මෙන්න",
"navigation_bar.mutes": "නිහඬ කළ අය",
@ -445,7 +454,7 @@
"time_remaining.seconds": "{number, plural, one {තත්පර #} other {තත්පර #}} ක් ඉතිරිය",
"timeline_hint.remote_resource_not_displayed": "වෙනත් සේවාදායකයන්ගෙන් {resource} දර්ශනය නොවේ.",
"timeline_hint.resources.followers": "අනුගාමිකයින්",
"timeline_hint.resources.follows": "අනුගමන",
"timeline_hint.resources.follows": "අනුගමන",
"timeline_hint.resources.statuses": "පරණ ලිපි",
"trends.trending_now": "දැන් නැගී එන",
"ui.beforeunload": "ඔබ මාස්ටඩන් හැර ගියහොත් කටුපිටපත අහිමි වේ.",

View file

@ -79,16 +79,16 @@
"admin.impact_report.instance_accounts": "Профілі облікових записів буде видалено",
"admin.impact_report.instance_followers": "Підписники, яких можуть втратити наші користувачі",
"admin.impact_report.instance_follows": "Підписники, яких можуть втратити їхні користувачі",
"admin.impact_report.title": "Наслідки",
"alert.rate_limited.message": "Спробуйте ще раз через {retry_time, time, medium}.",
"admin.impact_report.title": "Підсумки впливу",
"alert.rate_limited.message": "Спробуйте ще раз за {retry_time, time, medium}.",
"alert.rate_limited.title": "Швидкість обмежена",
"alert.unexpected.message": "Сталася неочікувана помилка.",
"alert.unexpected.title": "Ой!",
"announcement.announcement": "Оголошення",
"attachments_list.unprocessed": "(не оброблено)",
"audio.hide": "Сховати аудіо",
"autosuggest_hashtag.per_week": "{count} в тиждень",
"boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу",
"autosuggest_hashtag.per_week": "{count} на тиждень",
"boost_modal.combo": "Ви можете натиснути {combo}, щоби пропустити це наступного разу",
"bundle_column_error.copy_stacktrace": "Копіювати звіт про помилку",
"bundle_column_error.error.body": "Неможливо показати запитану сторінку. Це може бути спричинено помилкою у нашому коді, або через проблему сумісності з браузером.",
"bundle_column_error.error.title": "О, ні!",
@ -140,7 +140,7 @@
"compose.saved.body": "Допис збережено.",
"compose_form.direct_message_warning_learn_more": "Дізнатися більше",
"compose_form.encryption_warning": "Дописи на Mastodon не захищені шифруванням. Не поширюйте жодну делікатну інформацію.",
"compose_form.hashtag_warning": ей допис не буде зображений у жодній стрічці гештеґу, оскільки він прихований. Тільки публічні дописи можуть бути знайдені за гештеґом.",
"compose_form.hashtag_warning": ього допису не буде під жодним гештеґом, оскільки він не є загальнодоступним. За гештеґом можна шукати лише публічні дописи.",
"compose_form.lock_disclaimer": "Ваш обліковий запис не {locked}. Будь-який користувач може підписатися на вас та переглядати ваші дописи для підписників.",
"compose_form.lock_disclaimer.lock": "приватний",
"compose_form.placeholder": "Що у вас на думці?",
@ -151,7 +151,7 @@
"compose_form.poll.switch_to_multiple": "Дозволити вибір декількох відповідей",
"compose_form.poll.switch_to_single": "Перемкнути у режим вибору однієї відповіді",
"compose_form.publish": "Опублікувати",
"compose_form.publish_form": "Опублікувати",
"compose_form.publish_form": "Новий допис",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Зберегти зміни",
"compose_form.sensitive.hide": "{count, plural, one {Позначити медіа делікатним} other {Позначити медіа делікатними}}",
@ -206,7 +206,7 @@
"dismissable_banner.explore_tags": "Ці хештеги зараз набирають популярності серед людей на цьому та інших серверах децентралізованої мережі. Хештеги, які використовуються більшою кількістю людей, мають вищий рейтинг.",
"dismissable_banner.public_timeline": "Це найновіші загальнодоступні дописи від людей в соціальній мережі, на які підписані люди в {domain}.",
"embed.instructions": "Вбудуйте цей допис до вашого вебсайту, скопіювавши код нижче.",
"embed.preview": "Ось як він виглядатиме:",
"embed.preview": "Ось який вигляд це матиме:",
"emoji_button.activity": "Діяльність",
"emoji_button.clear": "Очистити",
"emoji_button.custom": "Власні",
@ -227,7 +227,7 @@
"empty_column.account_unavailable": "Профіль недоступний",
"empty_column.blocks": "Ви ще не заблокували жодного користувача.",
"empty_column.bookmarked_statuses": "У вас ще немає дописів у закладках. Коли ви щось додасте до закладок, воно з'явиться тут.",
"empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",
"empty_column.community": "Локальна стрічка порожня. Напишіть щось, щоб розігріти народ!",
"empty_column.direct": "У вас ще немає жодних особистих згадок. Коли ви надсилаєте чи отримуєте повідомлення, воно з'явиться тут.",
"empty_column.domain_blocks": "Тут поки немає прихованих доменів.",
"empty_column.explore_statuses": "Нема нічого популярного. Подивіться пізніше!",
@ -240,10 +240,10 @@
"empty_column.list": "Цей список порожній. Коли його учасники додадуть нові дописи, вони з'являться тут.",
"empty_column.lists": "У вас ще немає списків. Коли ви їх створите, вони з'являться тут.",
"empty_column.mutes": "Ви ще не приховали жодного користувача.",
"empty_column.notifications": "У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.",
"empty_column.notifications": "У вас ще немає сповіщень. Коли інші люди почнуть взаємодіяти з вами, ви побачите їх тут.",
"empty_column.public": "Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших серверів, щоб заповнити стрічку",
"error.unexpected_crash.explanation": "Через помилку у нашому коді або несумісність браузера, ця сторінка не може бути зображена коректно.",
"error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку викликано додатком браузера або автоматичним засобом перекладу.",
"error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку спричинило розширення браузера або автоматичний засіб перекладу.",
"error.unexpected_crash.next_steps": "Спробуйте перезавантажити сторінку. Якщо це не допоможе, ви все ще зможете використовувати Mastodon через інший браузер або рідний застосунок.",
"error.unexpected_crash.next_steps_addons": "Спробуйте їх вимкнути та оновити сторінку. Якщо це не допомагає, ви можете використовувати Mastodon через інший браузер або окремий застосунок.",
"errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну",
@ -394,7 +394,7 @@
"moved_to_account_banner.text": "Ваш обліковий запис {disabledAccount} наразі вимкнений, оскільки вас перенесено до {movedToAccount}.",
"mute_modal.duration": "Тривалість",
"mute_modal.hide_notifications": "Сховати сповіщення цього користувача?",
"mute_modal.indefinite": "Назавжди",
"mute_modal.indefinite": "Невизначений строк",
"navigation_bar.about": "Про застосунок",
"navigation_bar.advanced_interface": "Відкрити в розширеному вебінтерфейсі",
"navigation_bar.blocks": "Заблоковані користувачі",
@ -428,7 +428,7 @@
"notification.follow": "{name} підписалися на вас",
"notification.follow_request": "{name} відправили запит на підписку",
"notification.mention": "{name} згадали вас",
"notification.own_poll": "Ваше опитування завершено",
"notification.own_poll": "Ваше опитування завершилося",
"notification.poll": "Опитування, у якому ви голосували, скінчилося",
"notification.reblog": "{name} поширює ваш допис",
"notification.status": "{name} щойно дописує",
@ -480,7 +480,7 @@
"onboarding.follows.title": "Персоналізуйте домашню стрічку",
"onboarding.share.lead": "Розкажіть людям про те, як вони можуть знайти вас на Mastodon!",
"onboarding.share.message": "Я {username} на #Mastodon! Стежте за мною на {url}",
"onboarding.share.next_steps": "Можливі наступні кроки:",
"onboarding.share.next_steps": "Можливі такі кроки:",
"onboarding.share.title": "Поділитися своїм профілем",
"onboarding.start.lead": "Тепер ви — частина Mastodon, унікальної децентралізованої платформи соціальних медіа, де ви, а не алгоритми керують вашими вподобаннями. Розпочнімо роботу:",
"onboarding.start.skip": "Хочете пропустити?",
@ -694,7 +694,7 @@
"units.short.thousand": "{count} тис",
"upload_area.title": "Перетягніть сюди, щоб завантажити",
"upload_button.label": "Додати зображення, відео або аудіо",
"upload_error.limit": "Ліміт завантаження файлів перевищено.",
"upload_error.limit": "Ви перевищили ліміт завантаження файлів.",
"upload_error.poll": "Не можна завантажувати файли до опитувань.",
"upload_form.audio_description": "Опишіть для людей із вадами слуху",
"upload_form.description": "Опишіть для людей з вадами зору",
@ -713,7 +713,7 @@
"upload_modal.hint": "Клацніть або перетягніть коло на превʼю, щоб обрати точку, яку буде завжди видно на мініатюрах.",
"upload_modal.preparing_ocr": "Підготовка OCR…",
"upload_modal.preview_label": "Переглянути ({ratio})",
"upload_progress.label": "Завантаження...",
"upload_progress.label": "Вивантаження...",
"upload_progress.processing": "Обробка…",
"username.taken": "Це ім'я користувача вже зайнято. Спробуйте інше",
"video.close": "Закрити відео",

View file

@ -45,7 +45,7 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity
end
def accept_follow_for_friend
friend.update!(active_state: :accepted)
friend.update!(active_state: :accepted, passive_state: :idle)
end
def friend

View file

@ -114,7 +114,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def process_status_params
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object, account: @account)
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object, account: @account, friend_domain: friend_domain?)
@params = {
uri: @status_parser.uri,
@ -506,6 +506,10 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
FriendDomain.free_receivings.exists?(domain: @account.domain)
end
def friend_domain?
FriendDomain.enabled.find_by(domain: @account.domain)&.accepted?
end
def quote
@quote ||= @object['quote'] || @object['quoteUrl'] || @object['quoteURL'] || @object['_misskey_quote']
end

View file

@ -49,16 +49,20 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
already_accepted = false
if friend.present?
already_accepted = friend.they_are_accepted?
friend.update!(passive_state: :pending, passive_follow_activity_id: @json['id'])
already_accepted = friend.accepted?
friend.update!(passive_state: :pending, active_state: :idle, passive_follow_activity_id: @json['id'])
else
@friend = FriendDomain.create!(domain: @account.domain, passive_state: :pending, passive_follow_activity_id: @json['id'])
@friend = FriendDomain.new(domain: @account.domain, passive_state: :pending, passive_follow_activity_id: @json['id'])
@friend.initialize_inbox_url!
@friend.save!
end
if already_accepted || friend.unlocked || Setting.unlocked_friend
if already_accepted || Setting.unlocked_friend
friend.accept!
else
# Notify for admin even if unlocked
notify_staff_about_pending_friend_server! unless already_accepted
else
notify_staff_about_pending_friend_server!
end
end

View file

@ -57,6 +57,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
NotifyService.new.call(@original_status.account, :emoji_reaction, reaction)
forward_for_emoji_reaction
relay_for_emoji_reaction
relay_friend_for_emoji_reaction
end
rescue Seahorse::Client::NetworkingError
nil
@ -76,6 +77,14 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
end
end
def relay_friend_for_emoji_reaction
return unless @json['signature'].present? && @original_status.distributable_friend?
ActivityPub::DeliveryWorker.push_bulk(FriendDomain.distributables.pluck(:inbox_url)) do |inbox_url|
[Oj.dump(@json), @original_status.account.id, inbox_url]
end
end
def shortcode
return @shortcode if defined?(@shortcode)

View file

@ -39,7 +39,7 @@ class ActivityPub::Activity::Reject < ActivityPub::Activity
end
def reject_follow_for_friend
friend.update!(active_state: :rejected)
friend.update!(active_state: :rejected, passive_state: :idle)
end
def friend

View file

@ -103,7 +103,7 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
end
def remove_follow_from_friend
friend.update!(passive_state: :idle, passive_follow_activity_id: nil)
friend.destroy_without_signal!
end
def friend
@ -146,6 +146,7 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
if @original_status.account.local?
forward_for_undo_emoji_reaction
relay_for_undo_emoji_reaction
relay_friend_for_undo_emoji_reaction
end
end
else
@ -184,6 +185,14 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
end
end
def relay_friend_for_undo_emoji_reaction
return unless @json['signature'].present? && @original_status.distributable_friend?
ActivityPub::DeliveryWorker.push_bulk(FriendDomain.distributables.pluck(:inbox_url)) do |inbox_url|
[Oj.dump(@json), @original_status.account.id, inbox_url]
end
end
def shortcode
return @shortcode if defined?(@shortcode)

View file

@ -11,6 +11,7 @@ class ActivityPub::Parser::StatusParser
@object = magic_values[:object] || json['object'] || json
@magic_values = magic_values
@account = magic_values[:account]
@friend = magic_values[:friend_domain]
end
def uri
@ -76,11 +77,11 @@ class ActivityPub::Parser::StatusParser
def visibility
if audience_to.any? { |to| ActivityPub::TagManager.instance.public_collection?(to) }
:public
elsif audience_to.include?('LocalPublic')
elsif audience_to.include?('kmyblue:LocalPublic') && @friend
:public_unlisted
elsif audience_cc.any? { |cc| ActivityPub::TagManager.instance.public_collection?(cc) }
:unlisted
elsif audience_to.include?('as:LoginOnly') || audience_to.include?('LoginUser')
elsif audience_to.include?('kmyblue:LoginOnly') || audience_to.include?('as:LoginOnly') || audience_to.include?('LoginUser')
:login
elsif audience_to.include?(@magic_values[:followers_collection])
:private
@ -198,9 +199,9 @@ class ActivityPub::Parser::StatusParser
nil
elsif audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) }
:public
elsif audience_searchable_by.include?('as:Limited')
elsif audience_searchable_by.include?('kmyblue:Limited') || audience_searchable_by.include?('as:Limited')
:limited
elsif audience_searchable_by.include?('LocalPublic')
elsif audience_searchable_by.include?('kmyblue:LocalPublic') && @friend
:public_unlisted
elsif audience_searchable_by.include?(@account.followers_url)
:private

View file

@ -99,7 +99,7 @@ class ActivityPub::TagManager
when 'unlisted', 'public_unlisted', 'private'
[account_followers_url(status.account)]
when 'login'
[account_followers_url(status.account), 'as:LoginOnly', 'LoginUser']
[account_followers_url(status.account), 'as:LoginOnly', 'kmyblue:LoginOnly', 'LoginUser']
when 'direct'
if status.account.silenced?
# Only notify followers if the account is locally silenced
@ -128,7 +128,7 @@ class ActivityPub::TagManager
def to_for_friend(status)
to = to(status)
to << 'LocalPublic' if status.public_unlisted_visibility?
to << 'kmyblue:LocalPublic' if status.public_unlisted_visibility?
to
end
@ -249,7 +249,7 @@ class ActivityPub::TagManager
when 'direct'
status.conversation_id.present? ? [uri_for(status.conversation)] : []
when 'limited'
['as:Limited']
['as:Limited', 'kmyblue:Limited']
else
[]
end
@ -259,7 +259,7 @@ class ActivityPub::TagManager
def searchable_by_for_friend(status)
searchable = searchable_by(status)
searchable << 'LocalPublic' if status.compute_searchability_local == 'public_unlisted'
searchable << 'kmyblue:LocalPublic' if status.compute_searchability_local == 'public_unlisted'
searchable
end
@ -270,7 +270,7 @@ class ActivityPub::TagManager
when 'private', 'direct'
[account_followers_url(account)]
when 'limited'
['as:Limited']
['as:Limited', 'kmyblue:Limited']
else
[]
end

View file

@ -10,7 +10,7 @@ class StatusReachFinder
end
def inboxes
(reached_account_inboxes + followers_inboxes + relay_inboxes).uniq
(reached_account_inboxes + followers_inboxes + relay_inboxes + nolocal_friend_inboxes).uniq
end
def inboxes_for_misskey
@ -147,7 +147,15 @@ class StatusReachFinder
def friend_inboxes
if @status.public_visibility? || @status.public_unlisted_visibility? || (@status.unlisted_visibility? && (@status.public_searchability? || @status.public_unlisted_searchability?))
DeliveryFailureTracker.without_unavailable(FriendDomain.distributables.pluck(:inbox_url))
DeliveryFailureTracker.without_unavailable(FriendDomain.distributables.where(delivery_local: true).pluck(:inbox_url))
else
[]
end
end
def nolocal_friend_inboxes
if @status.public_visibility?
DeliveryFailureTracker.without_unavailable(FriendDomain.distributables.where(delivery_local: false).pluck(:inbox_url))
else
[]
end

View file

@ -43,6 +43,10 @@ class EmojiReaction < ApplicationRecord
custom_emoji? && !custom_emoji.local?
end
def sign?
status&.distributable_friend?
end
private
def refresh_cache

View file

@ -13,10 +13,10 @@
# passive_follow_activity_id :string
# available :boolean default(TRUE), not null
# pseudo_relay :boolean default(FALSE), not null
# unlocked :boolean default(FALSE), not null
# allow_all_posts :boolean default(TRUE), not null
# created_at :datetime not null
# updated_at :datetime not null
# delivery_local :boolean default(TRUE), not null
#
class FriendDomain < ApplicationRecord
@ -27,24 +27,31 @@ class FriendDomain < ApplicationRecord
enum passive_state: { idle: 0, pending: 1, accepted: 2, rejected: 3 }, _prefix: :they_are
scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) }
scope :enabled, -> { where(available: true) }
scope :mutuals, -> { enabled.where(active_state: :accepted, passive_state: :accepted) }
scope :distributables, -> { mutuals.where(pseudo_relay: true) }
scope :deliver_locals, -> { enabled.where(active_state: :accepted) }
scope :free_receivings, -> { mutuals.where(allow_all_posts: true) }
scope :enabled, -> { where(active_state: :accepted).or(FriendDomain.where(passive_state: :accepted)).where(available: true) }
scope :distributables, -> { enabled.where(pseudo_relay: true) }
scope :deliver_locals, -> { enabled.where(delivery_local: true) }
scope :free_receivings, -> { enabled.where(allow_all_posts: true) }
before_destroy :ensure_disabled
after_commit :set_default_inbox_url
def mutual?
i_am_accepted? && they_are_accepted?
def accepted?
i_am_accepted? || they_are_accepted?
end
def pending?
!accepted? && (i_am_pending? || they_are_pending?)
end
def idle?
(i_am_idle? || i_am_rejected?) && (they_are_idle? || they_are_rejected?)
end
def follow!
activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)
payload = Oj.dump(follow_activity(activity_id))
update!(active_state: :pending, active_follow_activity_id: activity_id)
update!(active_state: :pending, passive_state: :idle, active_follow_activity_id: activity_id)
DeliveryFailureTracker.reset!(inbox_url)
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
end
@ -53,7 +60,7 @@ class FriendDomain < ApplicationRecord
activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)
payload = Oj.dump(unfollow_activity(activity_id))
update!(active_state: :idle, active_follow_activity_id: nil)
update!(active_state: :idle, passive_state: :idle, active_follow_activity_id: nil)
DeliveryFailureTracker.reset!(inbox_url)
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
end
@ -64,7 +71,7 @@ class FriendDomain < ApplicationRecord
activity_id = passive_follow_activity_id
payload = Oj.dump(accept_follow_activity(activity_id))
update!(passive_state: :accepted)
update!(passive_state: :accepted, active_state: :idle)
DeliveryFailureTracker.reset!(inbox_url)
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
end
@ -75,11 +82,21 @@ class FriendDomain < ApplicationRecord
activity_id = passive_follow_activity_id
payload = Oj.dump(reject_follow_activity(activity_id))
update!(passive_state: :rejected, passive_follow_activity_id: nil)
update!(passive_state: :rejected, active_state: :idle, passive_follow_activity_id: nil)
DeliveryFailureTracker.reset!(inbox_url)
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
end
def destroy_without_signal!
self.active_state = :idle
self.passive_state = :idle
destroy!
end
def initialize_inbox_url!
self.inbox_url = default_inbox_url
end
private
def default_inbox_url
@ -154,7 +171,7 @@ class FriendDomain < ApplicationRecord
end
def ensure_disabled
delete_for_friend! unless i_am_idle? && they_are_idle?
delete_for_friend! unless id.nil? || (i_am_idle? && they_are_idle?)
end
def set_default_inbox_url

View file

@ -591,6 +591,10 @@ class Status < ApplicationRecord
end
end
def distributable_friend?
public_visibility? || public_unlisted_visibility? || (unlisted_visibility? && (public_searchability? || public_unlisted_searchability?))
end
private
def update_status_stat!(attrs)

View file

@ -25,7 +25,7 @@ class UserSettings
setting :default_privacy, default: nil, in: %w(public public_unlisted login unlisted private)
setting :stay_privacy, default: false
setting :default_reblog_privacy, default: nil
setting :default_searchability, default: :direct, in: %w(public private direct limited)
setting :default_searchability, default: :direct, in: %w(public private direct limited public_unlisted)
setting :default_searchability_of_search, default: :public, in: %w(public private direct limited)
setting :use_public_index, default: true
setting :disallow_unlisted_public_searchability, default: false

View file

@ -272,7 +272,7 @@ class ActivityPub::ProcessAccountService < BaseService
:public
elsif audience_searchable_by.include?(@account.followers_url)
:private
elsif audience_searchable_by.include?('as:Limited')
elsif audience_searchable_by.include?('kmyblue:Limited') || audience_searchable_by.include?('as:Limited')
:limited
else
:direct

View file

@ -14,6 +14,7 @@ class EmojiReactService < BaseService
def call(account, status, name)
status = status.reblog if status.reblog? && !status.reblog.nil?
authorize_with account, status, :emoji_reaction?
@status = status
emoji_reaction = nil
@ -36,6 +37,9 @@ class EmojiReactService < BaseService
notify_to_followers(emoji_reaction)
bump_potential_friendship(account, status)
write_stream(emoji_reaction)
forward_for_emoji_reaction!(emoji_reaction)
relay_for_emoji_reaction!(emoji_reaction)
relay_friend_for_emoji_reaction!(emoji_reaction)
emoji_reaction
end
@ -79,11 +83,33 @@ class EmojiReactService < BaseService
end
def build_json(emoji_reaction)
Oj.dump(serialize_payload(emoji_reaction, ActivityPub::EmojiReactionSerializer))
@build_json = Oj.dump(serialize_payload(emoji_reaction, ActivityPub::EmojiReactionSerializer, signer: emoji_reaction.account))
end
def render_emoji_reaction(emoji_group)
# @rendered_emoji_reaction ||= InlineRenderer.render(HashObject.new(emoji_group), nil, :emoji_reaction)
@render_emoji_reaction ||= Oj.dump(event: :emoji_reaction, payload: emoji_group.to_json)
end
def forward_for_emoji_reaction!(emoji_reaction)
return unless @status.local?
ActivityPub::RawDistributionWorker.perform_async(build_json(emoji_reaction), @status.account.id, [@status.account.preferred_inbox_url])
end
def relay_for_emoji_reaction!(emoji_reaction)
return unless @status.local? && @status.public_visibility?
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[build_json(emoji_reaction), @status.account.id, inbox_url]
end
end
def relay_friend_for_emoji_reaction!(emoji_reaction)
return unless @status.local? && @status.distributable_friend?
ActivityPub::DeliveryWorker.push_bulk(FriendDomain.distributables.pluck(:inbox_url)) do |inbox_url|
[build_json(emoji_reaction), @status.account.id, inbox_url]
end
end
end

View file

@ -57,7 +57,7 @@ class ReportService < BaseService
def forward_to_replied_to!
# Send report to servers to which the account was replying to, so they also have a chance to act
inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url]
inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url, @target_account.shared_inbox_url]
inbox_urls.each do |inbox_url|
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)

View file

@ -15,6 +15,10 @@ class UnEmojiReactService < BaseService
create_notification(emoji_reaction) if !@status.account.local? && @status.account.activitypub?
notify_to_followers(emoji_reaction) if @status.account.local?
write_stream(emoji_reaction)
forward_for_undo_emoji_reaction!(emoji_reaction)
relay_for_undo_emoji_reaction!(emoji_reaction)
relay_friend_for_undo_emoji_reaction!(emoji_reaction)
else
account = Account.find(account_id)
bulk(account, @status)
@ -52,11 +56,33 @@ class UnEmojiReactService < BaseService
end
def build_json(emoji_reaction)
Oj.dump(serialize_payload(emoji_reaction, ActivityPub::UndoEmojiReactionSerializer))
@build_json = Oj.dump(serialize_payload(emoji_reaction, ActivityPub::UndoEmojiReactionSerializer, signer: emoji_reaction.account))
end
def render_emoji_reaction(emoji_group)
# @rendered_emoji_reaction ||= InlineRenderer.render(emoji_group, nil, :emoji_reaction)
Oj.dump(event: :emoji_reaction, payload: emoji_group.to_json)
end
def forward_for_undo_emoji_reaction!(emoji_reaction)
return unless @status.local?
ActivityPub::RawDistributionWorker.perform_async(build_json(emoji_reaction), @status.account.id, [@status.account.preferred_inbox_url])
end
def relay_for_undo_emoji_reaction!(emoji_reaction)
return unless @status.local? && @status.public_visibility?
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[build_json(emoji_reaction), @status.account.id, inbox_url]
end
end
def relay_friend_for_undo_emoji_reaction!(emoji_reaction)
return unless @status.local? && @status.distributable_friend?
ActivityPub::DeliveryWorker.push_bulk(FriendDomain.distributables.pluck(:inbox_url)) do |inbox_url|
[build_json(emoji_reaction), @status.account.id, inbox_url]
end
end
end

View file

@ -7,7 +7,7 @@
= t 'admin.friend_servers.disabled'
%samp= friend.domain
%td
- if friend.i_am_accepted?
- if friend.accepted?
%span.positive-hint
= fa_icon('check')
= ' '
@ -16,21 +16,11 @@
= fa_icon('hourglass')
= ' '
= t 'admin.friend_servers.pending'
- else
%span.negative-hint
= fa_icon('times')
= ' '
= t 'admin.friend_servers.disabled'
%td
- if friend.they_are_accepted?
%span.positive-hint
= fa_icon('check')
= ' '
= t 'admin.friend_servers.enabled'
- elsif friend.they_are_pending?
%span.warning-hint
= fa_icon('hourglass')
= ' '
= t 'admin.friend_servers.pending'
= t 'admin.friend_servers.pending_you'
- else
%span.negative-hint
= fa_icon('times')

View file

@ -10,11 +10,11 @@
.fields-group
= f.input :available, as: :boolean, wrapper: :with_label, label: t('admin.friend_servers.edit.available')
.fields-group
= f.input :delivery_local, as: :boolean, wrapper: :with_label, label: t('admin.friend_servers.edit.delivery_local'), hint: t('admin.friend_servers.edit.delivery_local_hint')
.fields-group
= f.input :pseudo_relay, as: :boolean, wrapper: :with_label, label: t('admin.friend_servers.edit.pseudo_relay'), hint: t('admin.friend_servers.edit.pseudo_relay_hint')
.fields-group
= f.input :unlocked, as: :boolean, wrapper: :with_label, label: t('admin.friend_servers.edit.unlocked')
.fields-group
= f.input :allow_all_posts, as: :boolean, wrapper: :with_label, label: t('admin.friend_servers.edit.allow_all_posts'), hint: t('admin.friend_servers.edit.allow_all_posts_hint')

View file

@ -6,35 +6,14 @@
= render 'friend_fields', f: f, friend: @friend
.fields-group
%h4= t('admin.friend_servers.active_status')
%h4= t('admin.friend_servers.status')
.fields-group
- if @friend.i_am_accepted?
- if @friend.accepted?
%span.positive-hint
= fa_icon('check')
= ' '
= t 'admin.friend_servers.enabled'
- elsif @friend.i_am_pending?
= fa_icon('hourglass')
= ' '
= t 'admin.friend_servers.pending'
- else
%span.negative-hint
= fa_icon('times')
= ' '
= t 'admin.friend_servers.disabled'
.action-buttons
%div
= link_to t('admin.friend_servers.follow'), follow_admin_friend_server_path(@friend), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if @friend.i_am_idle? || @friend.i_am_rejected?
= link_to t('admin.friend_servers.unfollow'), unfollow_admin_friend_server_path(@friend), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if @friend.i_am_pending? || @friend.i_am_accepted?
%h4= t('admin.friend_servers.passive_status')
.fields-gtoup
- if @friend.they_are_accepted?
%span.positive-hint
= fa_icon('check')
= ' '
= t 'admin.friend_servers.enabled'
- elsif @friend.they_are_pending?
- elsif @friend.pending?
= fa_icon('hourglass')
= ' '
= t 'admin.friend_servers.pending'
@ -45,6 +24,7 @@
= t 'admin.friend_servers.disabled'
.action-buttons
%div
= link_to t('admin.friend_servers.follow'), follow_admin_friend_server_path(@friend), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if @friend.idle?
= link_to t('admin.friend_servers.accept'), accept_admin_friend_server_path(@friend), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if @friend.they_are_pending?
= link_to t('admin.friend_servers.reject'), reject_admin_friend_server_path(@friend), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if @friend.they_are_pending?

View file

@ -13,8 +13,7 @@
%thead
%tr
%th= t('admin.friend_servers.domain')
%th= t('admin.friend_servers.active_status')
%th= t('admin.friend_servers.passive_status')
%th= t('admin.friend_servers.status')
%th
%tbody
- @friends.each do |friend|

View file

@ -85,7 +85,7 @@ si:
signed_up_but_locked: ඔබ සාර්ථකව ලියාපදිංචි වී ඇත. කෙසේ වෙතත්, ඔබගේ ගිණුම අගුලු දමා ඇති නිසා අපට ඔබව පුරනය කිරීමට නොහැකි විය.
signed_up_but_pending: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්‍යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබ සබැඳිය ක්ලික් කළ පසු, අපි ඔබගේ අයදුම්පත සමාලෝචනය කරන්නෙමු. එය අනුමත වුවහොත් ඔබට දැනුම් දෙනු ලැබේ.
signed_up_but_unconfirmed: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්‍යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබගේ ගිණුම සක්‍රිය කිරීමට කරුණාකර සබැඳිය අනුගමනය කරන්න. ඔබට මෙම විද්‍යුත් තැපෑල නොලැබුනේ නම් කරුණාකර ඔබගේ අයාචිත තැපැල් ෆෝල්ඩරය පරීක්ෂා කරන්න.
update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය තහවුරු කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්‍ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය සත්‍යාපනය කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්‍ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
updated: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන කර ඇත.
sessions:
already_signed_out: සාර්ථකව නික්මිණි.

View file

@ -501,7 +501,6 @@ en:
unsuppress: Restore follow recommendation
friend_servers:
accept: Accept
active_status: My status
add_new: Add and make a new application
delete: Delete
description_html: <strong>フレンドサーバー</strong>とは、お互いのローカル公開・ローカル検索許可の投稿をそのまま交換するシステムです。
@ -511,6 +510,8 @@ en:
allow_all_posts: Receive all posts
allow_all_posts_hint: 通常は自分のサーバーの誰もフォローしていないアカウントの投稿は例外を除き受け入れがブロックされます。そのブロックを解除します。スパムが発生した場合など、いつでもブロックを再開できます。
available: Available
delivery_local: Deliver without changing public unlisted visibility and searchability
delivery_local_hint: Public unlisted posts will be added the friend's global timeline
description: フレンドサーバーは、登録と同時に相手方のサーバーへ申請されます。
domain: Domain
inbox_url: Friend server inbox URL
@ -521,8 +522,8 @@ en:
edit_friend: Edit
enabled: Enabled
follow: Request
passive_status: Partner status
pending: Pending
pending_you: Your review requested
reject: Reject
save_and_enable: Save and enable
setup: Add and make a new application

View file

@ -496,7 +496,6 @@ ja:
unsuppress: おすすめフォローを復元
friend_servers:
accept: 相手の申請を承認する
active_status: 自分の状態
add_new: フレンドサーバーを追加・申請
delete: 削除
description_html: <strong>フレンドサーバー</strong>とは、お互いのローカル公開・ローカル検索許可の投稿をそのまま交換するシステムです。
@ -506,6 +505,8 @@ ja:
allow_all_posts: このサーバーからの投稿を無条件で受け入れる
allow_all_posts_hint: 通常は自分のサーバーの誰もフォローしていないアカウントの投稿は例外を除き受け入れがブロックされます。そのブロックを解除します。スパムが発生した場合など、いつでもブロックを再開できます。
available: 有効にする
delivery_local: ローカル公開の公開範囲・検索許可を持った投稿をそのまま相手と共有する
delivery_local_hint: ローカル公開投稿は、通常は非収載に変換されて配送されます。その処理をせず、相手サーバーにもローカル公開と認識されるようにします。相手の連合タイムラインに掲載されます
description: フレンドサーバーは、登録と同時に相手方のサーバーへ申請されます。
domain: ドメイン
inbox_url: フレンドサーバーの inbox URL
@ -516,8 +517,8 @@ ja:
edit_friend: 編集
enabled: 有効
follow: こちらから申請する
passive_status: 相手の状態
pending: 承認待ち
pending_you: あなたの承認が必要
reject: 相手からの申請を却下する
save_and_enable: 保存して有効にする
setup: フレンドサーバーを追加・申請

View file

@ -10,7 +10,7 @@ si:
followers:
one: අනුගාමිකයා
other: අනුගාමිකයින්
following: අනුගමන
following: අනුගමන
instance_actor_flash: මෙම ගිණුම සේවාදායකයම නියෝජනය කිරීමට භාවිතා කරන අතථ්‍ය නළුවෙකු වන අතර කිසිදු තනි පරිශීලකයෙකු නොවේ. එය ෆෙඩරේෂන් අරමුණු සඳහා භාවිතා කරන අතර අත්හිටුවිය යුතු නොවේ.
last_active: අවසාන ක්රියාකාරී
link_verified_on: මෙම සබැඳියේ හිමිකාරිත්වය %{date}හි පරීක්ෂා කරන ලදී
@ -382,7 +382,7 @@ si:
status: තත්‍වය
suppress: අනුගමනය නිර්දේශය යටපත් කරන්න
suppressed: යටපත් කළා
title: නිර්දේශ අනුගමනය කරන්න
title: අනුගමනයට නිර්දේශ
unsuppress: නිර්දේශ පිළිපැදීම ප්‍රතිසාධනය කරන්න
instances:
availability:
@ -621,7 +621,7 @@ si:
history: අනුවාද ඉතිහාසය
language: භාෂාව
media:
title: මාධ්‍ය
title: මාධ්‍ය
metadata: පාරදත්ත
no_status_selected: කිසිවක් නොතේරූ බැවින් ලිපි කිසිවක් වෙනස් කර නැත
open: ලිපිය අරින්න
@ -787,7 +787,7 @@ si:
localization:
body: මාස්ටඩන් ස්වේච්ඡාවෙන් පරිවර්තනය කර ඇත.
guide_link: https://crowdin.com/project/mastodon
guide_link_text: සෑම කෙනෙකුටම දායක විය හැකිය.
guide_link_text: පරිවර්තකයින්ට දායක වීමට හැකිය.
sensitive_content: සංවේදී අන්තර්ගත
application_mailer:
notification_preferences: ඊමේල් මනාප වෙනස් කරන්න
@ -1191,7 +1191,7 @@ si:
relationships:
activity: ගිණුමේ ක්‍රියාකාරකම්
dormant: නිදිමතයි
follow_selected_followers: ෝරාගත් අනුගාමිකයින් අනුගමනය කරන්න
follow_selected_followers: ේරූ අනුගාමිකයින් අනුගමනය කරන්න
followers: අනුගාමිකයින්
following: අනුගමනය
invited: ආරාධනා කළා
@ -1201,9 +1201,9 @@ si:
mutual: අන්යෝන්ය
primary: ප්‍රාථමික
relationship: සම්බන්ධතාවය
remove_selected_domains: ෝරාගත් වසම් වලින් සියලුම අනුගාමිකයින් ඉවත් කරන්න
remove_selected_followers: ෝරාගත් අනුගාමිකයින් ඉවත් කරන්න
remove_selected_follows: ෝරාගත් පරිශීලකයින් අනුගමනය නොකරන්න
remove_selected_domains: ේරූ වසම් වල සියලුම අනුගාමිකයින් ඉවත් කරන්න
remove_selected_followers: ේරූ අනුගාමිකයින් ඉවත් කරන්න
remove_selected_follows: ේරූ අය අනුගමනය නොකරන්න
status: ගිණුමේ තත්‍වය
remote_follow:
missing_resource: ඔබගේ ගිණුම සඳහා අවශ්‍ය යළි-යොමුවීම් URL එක සොයා ගැනීමට නොහැකි විය
@ -1279,7 +1279,7 @@ si:
notifications: දැනුම්දීම්
preferences: අභිප්‍රේත
profile: ප්‍රසිද්ධ පැතිකඩ
relationships: අනුගමිකයින් සහ අනුගාමිකයින්
relationships: අනුගමන හා අනුගාමික
statuses_cleanup: ස්වයංක්‍රීය ලිපි මැකීම
two_factor_authentication: ද්වි සාධක Aut
webauthn_authentication: ආරක්‍ෂණ යතුරු
@ -1324,7 +1324,7 @@ si:
title: '%{name}: "%{quote}"'
visibilities:
direct: සෘජු
private: අනුගාමිකයින්-පමණි
private: අනුගාමිකයින් පමණි
private_long: අනුගාමිකයින්ට පමණක් පෙන්වන්න
public: ප්‍රසිද්ධ
public_long: හැමෝටම පේනවා
@ -1336,12 +1336,13 @@ si:
ignore_favs: ප්‍රියතමයන් නොසලකන්න
interaction_exceptions: අන්තර්ක්‍රියා මත පදනම් වූ ව්‍යතිරේක
keep_direct: සෘජු පණිවිඩ තබාගන්න
keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් මැකෙන්නේ නැත
keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් නොමැකෙයි
keep_media: මාධ්‍ය ඇමුණුම් සහිත ලිපි තබාගන්න
keep_media_hint: මාධ්‍ය ඇමුණුම් සහිත ඔබගේ ලිපි කිසිවක් මැකෙන්නේ නැත
keep_media_hint: මාධ්‍ය ඇමුණුම් සහිත ඔබගේ ලිපි කිසිවක් නොමැකෙයි
keep_pinned: ඇමිණූ ලිපි තබාගන්න
keep_pinned_hint: ඔබ ඇමිණූ ලිපි කිසිවක් නොමැකෙයි
keep_polls_hint: ඔබගේ මත විමසුම් මැකෙන්නේ නැත
keep_polls: මත විමසුම් තබාගන්න
keep_polls_hint: ඔබගේ මත විමසුම් නොමැකෙයි
keep_self_bookmark: ඔබ පොත්යොමු තැබූ ලිපි තබාගන්න
keep_self_bookmark_hint: ඔබගේම ලිපි වලට පොත්යොමු තබා ඇත්නම් ඒවා මකා නොදැමෙයි
keep_self_fav: ඔබ ප්‍රිය කළ ලිපි තබාගන්න
@ -1355,7 +1356,7 @@ si:
'604800': සති 1
'63113904': අවුරුදු 2
'7889238': මාස 3
min_age_label: වයස් සීමාව
min_age_label: කාල සීමාව
min_favs: අවම වශයෙන් ප්‍රිය කළ ලිපි තබාගන්න
stream_entries:
sensitive_content: සංවේදී අන්තර්ගතයකි

View file

@ -322,7 +322,7 @@ es-MX:
url: URL de Endpoint
'no': 'No'
not_recommended: No recomendado
overridden: Sobrescrito
overridden: Reemplazado
recommended: Recomendado
required:
mark: "*"

View file

@ -322,6 +322,7 @@ my:
url: URL ဆုံးမှတ်
'no': 'မလုပ်ပါ'
not_recommended: ထောက်ခံထားမှုမရှိ
overridden: ပယ်ဖျက်
recommended: ထောက်ခံထားပြီး
required:
mark: "*"

View file

@ -89,6 +89,8 @@ si:
fields:
name: නම්පත
value: අන්තර්ගතය
show_collections: අනුගමන හා අනුගාමිකයින් පැතිකඩෙහි පෙන්වන්න
unlocked: නව අනුගාමිකයින් ස්වයංක්‍රීයව පිළිගන්න
account_alias:
acct: පැරණි ගිණුමේ හැසිරවීම
account_migration:
@ -117,8 +119,9 @@ si:
appeal:
text: මෙම තීරණය ආපසු හැරවිය යුත්තේ මන්දැයි පැහැදිලි කරන්න
defaults:
autofollow: ඔබගේ ගිණුම අනුගමනය කිරීමට ආරාධනා කරන්න
autofollow: ඔබගේ ගිණුම අනුගමනයට ආරාධනා කරන්න
avatar: පැතිකඩ ඡායාරූපය
bot: මෙම ගිණුම ස්වයංක්‍රියයි
chosen_languages: භාෂා පෙරන්න
confirm_new_password: නව මුරපදය තහවුරු කරන්න
confirm_password: මුරපදය තහවුරු කරන්න
@ -139,7 +142,7 @@ si:
otp_attempt: ද්වි සාධක කේතය
password: මුරපදය
phrase: මූල පදය හෝ වාක්‍ය ඛණ්ඩය
setting_advanced_layout: උසස් වෙබ් අතුරු මුහුණත සබල කරන්න
setting_advanced_layout: සංකීර්ණ අතුරු මුහුණත සබල කරන්න
setting_always_send_emails: සෑම විටම විද්‍යුත් තැපැල් දැනුම්දීම් යවන්න
setting_auto_play_gif: සජීවිකරණ GIF ස්වයංක්‍රීයව ධාවනය කරන්න
setting_default_language: ලිපිවල භාෂාව

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
require Rails.root.join('lib', 'mastodon', 'migration_helpers')
class AddDeliveryLocalToFriendDomains < ActiveRecord::Migration[7.0]
include Mastodon::MigrationHelpers
disable_ddl_transaction!
def up
safety_assured do
add_column_with_default :friend_domains, :delivery_local, :boolean, default: true, allow_null: false
remove_column :friend_domains, :unlocked
end
end
def down
safety_assured do
remove_column :friend_domains, :delivery_local
add_column_with_default :friend_domains, :unlocked, :boolean, default: false, allow_null: false
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_10_07_090808) do
ActiveRecord::Schema[7.0].define(version: 2023_10_09_235215) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -686,10 +686,10 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_07_090808) do
t.string "passive_follow_activity_id"
t.boolean "available", default: true, null: false
t.boolean "pseudo_relay", default: false, null: false
t.boolean "unlocked", default: false, null: false
t.boolean "allow_all_posts", default: true, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "delivery_local", default: true, null: false
t.index ["domain"], name: "index_friend_domains_on_domain", unique: true
t.index ["inbox_url"], name: "index_friend_domains_on_inbox_url", unique: true
end

View file

@ -9,7 +9,7 @@ module Mastodon
end
def kmyblue_minor
1
0
end
def kmyblue_flag
@ -25,7 +25,7 @@ module Mastodon
end
def patch
0
1
end
def default_prerelease

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
Fabricator(:emoji_reaction) do
account { Fabricate.build(:account) }
status { Fabricate.build(:status) }
name '😀'
end

View file

@ -118,5 +118,26 @@ RSpec.describe ActivityPub::Activity::Accept do
subject.perform
expect(friend.reload.i_am_accepted?).to be true
end
it 'when the friend server is pending' do
friend.update(passive_state: :pending)
subject.perform
expect(friend.reload.they_are_idle?).to be true
expect(friend.i_am_accepted?).to be true
end
it 'when the friend server is accepted' do
friend.update(passive_state: :accepted)
subject.perform
expect(friend.reload.they_are_idle?).to be true
expect(friend.i_am_accepted?).to be true
end
it 'when my server is not pending' do
friend.update(active_state: :idle)
subject.perform
expect(friend.reload.i_am_idle?).to be true
expect(friend.they_are_idle?).to be true
end
end
end

View file

@ -30,9 +30,11 @@ RSpec.describe ActivityPub::Activity::Create do
let(:sender_software) { 'mastodon' }
let(:custom_before) { false }
let(:active_friend) { false }
before do
Fabricate(:instance_info, domain: 'example.com', software: sender_software)
Fabricate(:friend_domain, domain: 'example.com', active_state: :accepted) if active_friend
subject.perform unless custom_before
end
@ -234,17 +236,37 @@ RSpec.describe ActivityPub::Activity::Create do
end
end
context 'when public_unlisted with LocalPublic' do
context 'when public_unlisted with kmyblue:LocalPublic' do
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
to: ['http://example.com/followers', 'LocalPublic'],
to: ['http://example.com/followers', 'kmyblue:LocalPublic'],
cc: 'https://www.w3.org/ns/activitystreams#Public',
}
end
it 'creates status' do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.visibility).to eq 'unlisted'
end
end
context 'when public_unlisted with kmyblue:LocalPublic from friend-server' do
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
to: ['http://example.com/followers', 'kmyblue:LocalPublic'],
cc: 'https://www.w3.org/ns/activitystreams#Public',
}
end
let(:active_friend) { true }
it 'creates status' do
status = sender.statuses.first
@ -430,8 +452,20 @@ RSpec.describe ActivityPub::Activity::Create do
end
end
context 'with public_unlisted with LocalPublic' do
let(:searchable_by) { ['http://example.com/followers', 'LocalPublic'] }
context 'with public_unlisted with kmyblue:LocalPublic' do
let(:searchable_by) { ['http://example.com/followers', 'kmyblue:LocalPublic'] }
it 'create status' do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.searchability).to eq 'private'
end
end
context 'with public_unlisted with kmyblue:LocalPublic from friend-server' do
let(:searchable_by) { ['http://example.com/followers', 'kmyblue:LocalPublic'] }
let(:active_friend) { true }
it 'create status' do
status = sender.statuses.first
@ -475,6 +509,17 @@ RSpec.describe ActivityPub::Activity::Create do
end
context 'with limited' do
let(:searchable_by) { 'kmyblue:Limited' }
it 'create status' do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.searchability).to eq 'limited'
end
end
context 'with limited old spec' do
let(:searchable_by) { 'as:Limited' }
it 'create status' do
@ -600,7 +645,7 @@ RSpec.describe ActivityPub::Activity::Create do
context 'with misskey' do
let(:sender_software) { 'misskey' }
let(:searchable_by) { 'as:Limited' }
let(:searchable_by) { 'kmyblue:Limited' }
it 'create status' do
status = sender.statuses.first
@ -1495,11 +1540,7 @@ RSpec.describe ActivityPub::Activity::Create do
context 'when sender is in friend server' do
subject { described_class.new(json, sender, delivery: true) }
before do
Fabricate(:friend_domain, domain: sender.domain, active_state: :accepted, passive_state: :accepted)
subject.perform
end
let!(:friend) { Fabricate(:friend_domain, domain: sender.domain, active_state: :accepted) }
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
@ -1509,11 +1550,20 @@ RSpec.describe ActivityPub::Activity::Create do
end
it 'creates status' do
subject.perform
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.text).to eq 'Lorem ipsum'
end
it 'whey no-relay not creates status' do
friend.update(allow_all_posts: false)
subject.perform
status = sender.statuses.first
expect(status).to be_nil
end
end
context 'when the sender has no relevance to local activity' do

View file

@ -339,6 +339,37 @@ RSpec.describe ActivityPub::Activity::Follow do
expect(friend).to_not be_nil
expect(friend.they_are_pending?).to be true
expect(friend.passive_follow_activity_id).to eq 'foo'
expect(friend.inbox_url).to eq 'https://abc.com/inbox'
end
end
context 'when my server is pending' do
before do
friend.update(active_state: :pending)
end
it 'marks me as idle' do
subject.perform
expect(friend.reload.they_are_pending?).to be true
expect(friend.i_am_idle?).to be true
end
end
context 'when my server is already accepted' do
before do
friend.update(active_state: :accepted)
stub_request(:post, 'https://example.com/inbox')
end
it 'marks me as idle and the friend as accepted' do
subject.perform
expect(friend.reload.they_are_accepted?).to be true
expect(friend.i_am_idle?).to be true
expect(a_request(:post, 'https://example.com/inbox').with(body: hash_including({
id: 'foo#accepts/friends',
type: 'Accept',
object: 'foo',
}))).to have_been_made.once
end
end
@ -372,26 +403,6 @@ RSpec.describe ActivityPub::Activity::Follow do
end
end
context 'when unlocked' do
before do
friend.update(unlocked: true)
stub_request(:post, 'https://example.com/inbox')
end
it 'marks the friend as accepted' do
subject.perform
friend = FriendDomain.find_by(domain: 'abc.com')
expect(friend).to_not be_nil
expect(friend.they_are_accepted?).to be true
expect(a_request(:post, 'https://example.com/inbox').with(body: hash_including({
id: 'foo#accepts/friends',
type: 'Accept',
object: 'foo',
}))).to have_been_made.once
end
end
context 'when unlocked on admin settings' do
before do
Form::AdminSettings.new(unlocked_friend: '1').save

View file

@ -192,5 +192,19 @@ RSpec.describe ActivityPub::Activity::Reject do
subject.perform
expect(friend.reload.i_am_rejected?).to be true
end
it 'when the friend server is pending' do
friend.update(passive_state: :pending)
subject.perform
expect(friend.reload.they_are_idle?).to be true
expect(friend.i_am_rejected?).to be true
end
it 'when the friend server is accepted' do
friend.update(passive_state: :accepted)
subject.perform
expect(friend.reload.they_are_idle?).to be true
expect(friend.i_am_rejected?).to be true
end
end
end

View file

@ -149,7 +149,7 @@ RSpec.describe ActivityPub::Activity::Undo do
friend = Fabricate(:friend_domain, domain: sender.domain, passive_state: :accepted)
subject.perform
expect(sender.following?(recipient)).to be false
expect(friend.they_are_accepted?).to be true
expect(friend.reload.they_are_accepted?).to be true
end
context 'with only object uri' do
@ -175,8 +175,19 @@ RSpec.describe ActivityPub::Activity::Undo do
it 'deletes follow from this server to friend' do
subject.perform
expect(friend.reload.they_are_idle?).to be true
expect(friend.passive_follow_activity_id).to be_nil
expect(FriendDomain.exists?(domain: 'abc.com')).to be false
end
it 'when my server is pending' do
friend.update(active_state: :pending)
subject.perform
expect(FriendDomain.exists?(domain: 'abc.com')).to be false
end
it 'when my server is accepted' do
friend.update(active_state: :accepted)
subject.perform
expect(FriendDomain.exists?(domain: 'abc.com')).to be false
end
end
end
@ -202,5 +213,32 @@ RSpec.describe ActivityPub::Activity::Undo do
expect(sender.favourited?(status)).to be false
end
end
context 'with EmojiReact' do
let(:status) { Fabricate(:status) }
let(:content) { '😀' }
let(:object_json) do
{
id: 'bar',
type: 'Like',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: ActivityPub::TagManager.instance.uri_for(status),
content: content,
}
end
before do
Fabricate(:favourite, account: sender, status: status)
Fabricate(:emoji_reaction, account: sender, status: status, name: content)
end
it 'delete emoji reaction' do
subject.perform
reaction = EmojiReaction.find_by(account: sender, status: status)
expect(reaction).to be_nil
expect(sender.favourited?(status)).to be true
end
end
end
end

View file

@ -77,7 +77,7 @@ RSpec.describe ActivityPub::TagManager do
describe '#to_for_friend' do
it 'returns followers collection for public_unlisted status' do
status = Fabricate(:status, visibility: :public_unlisted)
expect(subject.to_for_friend(status)).to eq [account_followers_url(status.account), 'LocalPublic']
expect(subject.to_for_friend(status)).to eq [account_followers_url(status.account), 'kmyblue:LocalPublic']
end
it 'returns followers collection for unlisted status' do
@ -188,7 +188,7 @@ RSpec.describe ActivityPub::TagManager do
it 'returns as:Limited array for limited status' do
status = Fabricate(:status, searchability: :limited)
expect(subject.searchable_by(status)).to eq ['as:Limited']
expect(subject.searchable_by(status)).to eq ['as:Limited', 'kmyblue:Limited']
end
end
@ -200,7 +200,7 @@ RSpec.describe ActivityPub::TagManager do
it 'returns public collection for public_unlisted status' do
status = Fabricate(:status, account: Fabricate(:account, searchability: :public), searchability: :public_unlisted)
expect(subject.searchable_by_for_friend(status)).to eq [account_followers_url(status.account), 'LocalPublic']
expect(subject.searchable_by_for_friend(status)).to eq [account_followers_url(status.account), 'kmyblue:LocalPublic']
end
it 'returns followers collection for private status' do

View file

@ -99,7 +99,7 @@ describe StatusReachFinder do
let(:sender_software) { 'misskey' }
let(:searchability) { :public }
before { Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', available: true, active_state: :accepted, passive_state: :accepted, pseudo_relay: true) }
before { Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', available: true, active_state: :accepted, pseudo_relay: true) }
it 'send status without friend server' do
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
@ -114,7 +114,7 @@ describe StatusReachFinder do
context 'with follower' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', active_state: :accepted)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted)
bob.follow!(alice)
end
@ -124,9 +124,21 @@ describe StatusReachFinder do
end
end
context 'with non-follower' do
context 'with follower but not local-distributable' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', active_state: :accepted)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted, delivery_local: false)
bob.follow!(alice)
end
it 'send status' do
expect(subject.inboxes).to include 'https://foo.bar/inbox'
expect(subject.inboxes_for_friend).to_not include 'https://foo.bar/inbox'
end
end
context 'with non-follower and non-relay' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted)
end
it 'send status' do
@ -137,7 +149,7 @@ describe StatusReachFinder do
context 'with pending' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', active_state: :pending)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :pending)
bob.follow!(alice)
end
@ -147,9 +159,21 @@ describe StatusReachFinder do
end
end
context 'with unidirection from them' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :idle, passive_state: :accepted)
bob.follow!(alice)
end
it 'send status' do
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
expect(subject.inboxes_for_friend).to include 'https://foo.bar/inbox'
end
end
context 'when unavailable' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', active_state: :accepted, available: false)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted, available: false)
bob.follow!(alice)
end
@ -161,7 +185,18 @@ describe StatusReachFinder do
context 'when distributable' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', active_state: :accepted, passive_state: :accepted, pseudo_relay: true)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', passive_state: :accepted, pseudo_relay: true)
end
it 'send status' do
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
expect(subject.inboxes_for_friend).to include 'https://foo.bar/inbox'
end
end
context 'when distributable and following' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', passive_state: :accepted, pseudo_relay: true)
bob.follow!(alice)
end
@ -171,9 +206,9 @@ describe StatusReachFinder do
end
end
context 'when distributable and not following' do
context 'when distributable reverse' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted, passive_state: :accepted, pseudo_relay: true)
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', active_state: :accepted, pseudo_relay: true)
end
it 'send status' do
@ -181,10 +216,35 @@ describe StatusReachFinder do
expect(subject.inboxes_for_friend).to include 'https://foo.bar/inbox'
end
end
context 'when distributable but not local distributable' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', passive_state: :accepted, pseudo_relay: true, delivery_local: false)
end
it 'send status' do
expect(subject.inboxes).to include 'https://foo.bar/inbox'
expect(subject.inboxes_for_friend).to_not include 'https://foo.bar/inbox'
end
end
context 'when distributable and following but not local distributable' do
before do
Fabricate(:friend_domain, domain: 'foo.bar', passive_state: :accepted, pseudo_relay: true, delivery_local: false)
bob.follow!(alice)
end
it 'send status' do
expect(subject.inboxes).to include 'https://foo.bar/inbox'
expect(subject.inboxes_for_friend).to_not include 'https://foo.bar/inbox'
end
end
end
context 'when it contains distributable friend server' do
before { Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', available: true, active_state: :accepted, passive_state: :accepted, pseudo_relay: true) }
before do
Fabricate(:friend_domain, domain: 'foo.bar', inbox_url: 'https://foo.bar/inbox', passive_state: :accepted, pseudo_relay: true)
end
it 'includes the inbox of the mentioned account' do
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
@ -369,9 +429,11 @@ describe StatusReachFinder do
Fabricate(:friend_domain, domain: 'def.com', inbox_url: 'https://def.com/inbox', active_state: :accepted, passive_state: :accepted, pseudo_relay: true, available: true)
Fabricate(:friend_domain, domain: 'ghi.com', inbox_url: 'https://ghi.com/inbox', active_state: :accepted, passive_state: :accepted, pseudo_relay: true, available: false)
Fabricate(:friend_domain, domain: 'jkl.com', inbox_url: 'https://jkl.com/inbox', active_state: :accepted, passive_state: :accepted, pseudo_relay: false, available: true)
Fabricate(:friend_domain, domain: 'mno.com', inbox_url: 'https://mno.com/inbox', active_state: :accepted, passive_state: :pending, pseudo_relay: true, available: true)
Fabricate(:friend_domain, domain: 'mno.com', inbox_url: 'https://mno.com/inbox', active_state: :accepted, passive_state: :idle, pseudo_relay: true, available: true)
Fabricate(:friend_domain, domain: 'pqr.com', inbox_url: 'https://pqr.com/inbox', active_state: :accepted, passive_state: :accepted, pseudo_relay: true, available: true)
Fabricate(:unavailable_domain, domain: 'pqr.com')
Fabricate(:friend_domain, domain: 'stu.com', inbox_url: 'https://stu.com/inbox', active_state: :idle, passive_state: :accepted, pseudo_relay: true, available: true)
Fabricate(:friend_domain, domain: 'vwx.com', inbox_url: 'https://vwx.com/inbox', active_state: :idle, passive_state: :accepted, pseudo_relay: true, available: true, delivery_local: false)
end
it 'returns friend servers' do
@ -387,8 +449,13 @@ describe StatusReachFinder do
expect(subject).to_not include 'https://jkl.com/inbox'
end
it 'not contains no-mutual friends' do
expect(subject).to_not include 'https://mno.com/inbox'
it 'contains no-mutual friends' do
expect(subject).to include 'https://mno.com/inbox'
expect(subject).to include 'https://stu.com/inbox'
end
it 'not contains un local distable' do
expect(subject).to_not include 'https://vwx.com/inbox'
end
it 'not contains unavailable domain friends' do

View file

@ -11,9 +11,11 @@ describe FriendDomain do
describe '#follow!' do
it 'call inbox' do
friend.update(active_state: :accepted, passive_state: :accepted)
friend.follow!
expect(friend.active_follow_activity_id).to_not be_nil
expect(friend.i_am_pending?).to be true
expect(friend.they_are_idle?).to be true
expect(a_request(:post, 'https://foo.bar/inbox').with(body: hash_including({
id: friend.active_follow_activity_id,
type: 'Follow',
@ -25,10 +27,11 @@ describe FriendDomain do
describe '#unfollow!' do
it 'call inbox' do
friend.update(active_follow_activity_id: 'ohagi')
friend.update(active_follow_activity_id: 'ohagi', active_state: :accepted, passive_state: :accepted)
friend.unfollow!
expect(friend.active_follow_activity_id).to be_nil
expect(friend.i_am_idle?).to be true
expect(friend.they_are_idle?).to be true
expect(a_request(:post, 'https://foo.bar/inbox').with(body: hash_including({
type: 'Undo',
object: {
@ -43,9 +46,10 @@ describe FriendDomain do
describe '#accept!' do
it 'call inbox' do
friend.update(passive_follow_activity_id: 'ohagi', passive_state: :pending)
friend.update(passive_follow_activity_id: 'ohagi', active_state: :accepted, passive_state: :pending)
friend.accept!
expect(friend.they_are_accepted?).to be true
expect(friend.i_am_idle?).to be true
expect(a_request(:post, 'https://foo.bar/inbox').with(body: hash_including({
id: 'ohagi#accepts/friends',
type: 'Accept',
@ -57,9 +61,10 @@ describe FriendDomain do
describe '#reject!' do
it 'call inbox' do
friend.update(passive_follow_activity_id: 'ohagi', passive_state: :pending)
friend.update(passive_follow_activity_id: 'ohagi', active_state: :accepted, passive_state: :pending)
friend.reject!
expect(friend.they_are_rejected?).to be true
expect(friend.i_am_idle?).to be true
expect(a_request(:post, 'https://foo.bar/inbox').with(body: hash_including({
id: 'ohagi#rejects/friends',
type: 'Reject',

View file

@ -54,6 +54,14 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
end
context 'when limited' do
let(:searchable_by) { 'kmyblue:Limited' }
it 'searchability is limited' do
expect(subject.searchability).to eq 'limited'
end
end
context 'when limited old spec' do
let(:searchable_by) { 'as:Limited' }
it 'searchability is limited' do

View file

@ -295,6 +295,18 @@ RSpec.describe DeliveryAntennaService, type: :service do
end
end
context 'when public_unlisted searchability' do
let(:searchability) { :public_unlisted }
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
context 'when private searchability' do
let(:searchability) { :private }
@ -317,6 +329,15 @@ RSpec.describe DeliveryAntennaService, type: :service do
end
end
context 'when public_unlisted searchability' do
let(:searchability) { :public_unlisted }
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 private searchability' do
let(:searchability) { :private }

View file

@ -36,7 +36,7 @@ RSpec.describe ReportService, type: :service do
expect(report.uri).to_not be_nil
end
context 'when reporting a reply' do
context 'when reporting a reply on a different remote server' do
let(:remote_thread_account) { Fabricate(:account, domain: 'foo.com', protocol: :activitypub, inbox_url: 'http://foo.com/inbox') }
let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) }
@ -67,6 +67,25 @@ RSpec.describe ReportService, type: :service do
end
end
end
context 'when reporting a reply on the same remote server as the person being replied-to' do
let(:remote_thread_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) }
context 'when forward_to_domains includes both the replied-to domain and the origin domain' do
it 'sends ActivityPub payload only once' do
subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward, forward_to_domains: [remote_account.domain])
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
end
end
context 'when forward_to_domains does not include the replied-to domain' do
it 'sends ActivityPub payload only once' do
subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
end
end
end
end
context 'when forward is false' do