interactions_spec.rb 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe Account::Interactions do
  4. let(:account) { Fabricate(:account) }
  5. let(:account_id) { account.id }
  6. let(:account_ids) { [account_id] }
  7. let(:target_account) { Fabricate(:account) }
  8. let(:target_account_id) { target_account.id }
  9. let(:target_account_ids) { [target_account_id] }
  10. describe '.following_map' do
  11. subject { Account.following_map(target_account_ids, account_id) }
  12. context 'when Account with Follow' do
  13. it 'returns { target_account_id => true }' do
  14. Fabricate(:follow, account: account, target_account: target_account)
  15. expect(subject).to eq(target_account_id => { reblogs: true, notify: false, languages: nil })
  16. end
  17. end
  18. context 'when Account without Follow' do
  19. it 'returns {}' do
  20. expect(subject).to eq({})
  21. end
  22. end
  23. end
  24. describe '.followed_by_map' do
  25. subject { Account.followed_by_map(target_account_ids, account_id) }
  26. context 'when Account with Follow' do
  27. it 'returns { target_account_id => true }' do
  28. Fabricate(:follow, account: target_account, target_account: account)
  29. expect(subject).to eq(target_account_id => true)
  30. end
  31. end
  32. context 'when Account without Follow' do
  33. it 'returns {}' do
  34. expect(subject).to eq({})
  35. end
  36. end
  37. end
  38. describe '.blocking_map' do
  39. subject { Account.blocking_map(target_account_ids, account_id) }
  40. context 'when Account with Block' do
  41. it 'returns { target_account_id => true }' do
  42. Fabricate(:block, account: account, target_account: target_account)
  43. expect(subject).to eq(target_account_id => true)
  44. end
  45. end
  46. context 'when Account without Block' do
  47. it 'returns {}' do
  48. expect(subject).to eq({})
  49. end
  50. end
  51. end
  52. describe '.muting_map' do
  53. subject { Account.muting_map(target_account_ids, account_id) }
  54. context 'when Account with Mute' do
  55. before do
  56. Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)
  57. end
  58. context 'when Mute#hide_notifications?' do
  59. let(:hide) { true }
  60. it 'returns { target_account_id => { notifications: true } }' do
  61. expect(subject).to eq(target_account_id => { notifications: true })
  62. end
  63. end
  64. context 'when not Mute#hide_notifications?' do
  65. let(:hide) { false }
  66. it 'returns { target_account_id => { notifications: false } }' do
  67. expect(subject).to eq(target_account_id => { notifications: false })
  68. end
  69. end
  70. end
  71. context 'when Account without Mute' do
  72. it 'returns {}' do
  73. expect(subject).to eq({})
  74. end
  75. end
  76. end
  77. describe '#follow!' do
  78. it 'creates and returns Follow' do
  79. expect do
  80. expect(account.follow!(target_account)).to be_a Follow
  81. end.to change { account.following.count }.by 1
  82. end
  83. end
  84. describe '#block' do
  85. it 'creates and returns Block' do
  86. expect do
  87. expect(account.block!(target_account)).to be_a Block
  88. end.to change { account.block_relationships.count }.by 1
  89. end
  90. end
  91. describe '#mute!' do
  92. subject { account.mute!(target_account, notifications: arg_notifications) }
  93. context 'when Mute does not exist yet' do
  94. context 'when arg :notifications is nil' do
  95. let(:arg_notifications) { nil }
  96. it 'creates Mute, and returns Mute' do
  97. expect do
  98. expect(subject).to be_a Mute
  99. end.to change { account.mute_relationships.count }.by 1
  100. end
  101. end
  102. context 'when arg :notifications is false' do
  103. let(:arg_notifications) { false }
  104. it 'creates Mute, and returns Mute' do
  105. expect do
  106. expect(subject).to be_a Mute
  107. end.to change { account.mute_relationships.count }.by 1
  108. end
  109. end
  110. context 'when arg :notifications is true' do
  111. let(:arg_notifications) { true }
  112. it 'creates Mute, and returns Mute' do
  113. expect do
  114. expect(subject).to be_a Mute
  115. end.to change { account.mute_relationships.count }.by 1
  116. end
  117. end
  118. end
  119. context 'when Mute already exists' do
  120. before do
  121. account.mute_relationships << mute
  122. end
  123. let(:mute) do
  124. Fabricate(:mute,
  125. account: account,
  126. target_account: target_account,
  127. hide_notifications: hide_notifications)
  128. end
  129. context 'when mute.hide_notifications is true' do
  130. let(:hide_notifications) { true }
  131. context 'when arg :notifications is nil' do
  132. let(:arg_notifications) { nil }
  133. it 'returns Mute without updating mute.hide_notifications' do
  134. expect do
  135. expect(subject).to be_a Mute
  136. end.to_not change { mute.reload.hide_notifications? }.from(true)
  137. end
  138. end
  139. context 'when arg :notifications is false' do
  140. let(:arg_notifications) { false }
  141. it 'returns Mute, and updates mute.hide_notifications false' do
  142. expect do
  143. expect(subject).to be_a Mute
  144. end.to change { mute.reload.hide_notifications? }.from(true).to(false)
  145. end
  146. end
  147. context 'when arg :notifications is true' do
  148. let(:arg_notifications) { true }
  149. it 'returns Mute without updating mute.hide_notifications' do
  150. expect do
  151. expect(subject).to be_a Mute
  152. end.to_not change { mute.reload.hide_notifications? }.from(true)
  153. end
  154. end
  155. end
  156. context 'when mute.hide_notifications is false' do
  157. let(:hide_notifications) { false }
  158. context 'when arg :notifications is nil' do
  159. let(:arg_notifications) { nil }
  160. it 'returns Mute, and updates mute.hide_notifications true' do
  161. expect do
  162. expect(subject).to be_a Mute
  163. end.to change { mute.reload.hide_notifications? }.from(false).to(true)
  164. end
  165. end
  166. context 'when arg :notifications is false' do
  167. let(:arg_notifications) { false }
  168. it 'returns Mute without updating mute.hide_notifications' do
  169. expect do
  170. expect(subject).to be_a Mute
  171. end.to_not change { mute.reload.hide_notifications? }.from(false)
  172. end
  173. end
  174. context 'when arg :notifications is true' do
  175. let(:arg_notifications) { true }
  176. it 'returns Mute, and updates mute.hide_notifications true' do
  177. expect do
  178. expect(subject).to be_a Mute
  179. end.to change { mute.reload.hide_notifications? }.from(false).to(true)
  180. end
  181. end
  182. end
  183. end
  184. end
  185. describe '#mute_conversation!' do
  186. subject { account.mute_conversation!(conversation) }
  187. let(:conversation) { Fabricate(:conversation) }
  188. it 'creates and returns ConversationMute' do
  189. expect do
  190. expect(subject).to be_a ConversationMute
  191. end.to change { account.conversation_mutes.count }.by 1
  192. end
  193. end
  194. describe '#block_domain!' do
  195. subject { account.block_domain!(domain) }
  196. let(:domain) { 'example.com' }
  197. it 'creates and returns AccountDomainBlock' do
  198. expect do
  199. expect(subject).to be_a AccountDomainBlock
  200. end.to change { account.domain_blocks.count }.by 1
  201. end
  202. end
  203. describe '#block_idna_domain!' do
  204. subject do
  205. [
  206. account.block_domain!(idna_domain),
  207. account.block_domain!(punycode_domain),
  208. ]
  209. end
  210. let(:idna_domain) { '대한민국.한국' }
  211. let(:punycode_domain) { 'xn--3e0bs9hfvinn1a.xn--3e0b707e' }
  212. it 'creates single AccountDomainBlock' do
  213. expect do
  214. expect(subject).to all(be_a AccountDomainBlock)
  215. end.to change { account.domain_blocks.count }.by 1
  216. end
  217. end
  218. describe '#unfollow!' do
  219. subject { account.unfollow!(target_account) }
  220. context 'when following target_account' do
  221. it 'returns destroyed Follow' do
  222. account.active_relationships.create(target_account: target_account)
  223. expect(subject).to be_a Follow
  224. expect(subject).to be_destroyed
  225. end
  226. end
  227. context 'when not following target_account' do
  228. it 'returns nil' do
  229. expect(subject).to be_nil
  230. end
  231. end
  232. end
  233. describe '#unblock!' do
  234. subject { account.unblock!(target_account) }
  235. context 'when blocking target_account' do
  236. it 'returns destroyed Block' do
  237. account.block_relationships.create(target_account: target_account)
  238. expect(subject).to be_a Block
  239. expect(subject).to be_destroyed
  240. end
  241. end
  242. context 'when not blocking target_account' do
  243. it 'returns nil' do
  244. expect(subject).to be_nil
  245. end
  246. end
  247. end
  248. describe '#unmute!' do
  249. subject { account.unmute!(target_account) }
  250. context 'when muting target_account' do
  251. it 'returns destroyed Mute' do
  252. account.mute_relationships.create(target_account: target_account)
  253. expect(subject).to be_a Mute
  254. expect(subject).to be_destroyed
  255. end
  256. end
  257. context 'when not muting target_account' do
  258. it 'returns nil' do
  259. expect(subject).to be_nil
  260. end
  261. end
  262. end
  263. describe '#unmute_conversation!' do
  264. subject { account.unmute_conversation!(conversation) }
  265. let(:conversation) { Fabricate(:conversation) }
  266. context 'when muting the conversation' do
  267. it 'returns destroyed ConversationMute' do
  268. account.conversation_mutes.create(conversation: conversation)
  269. expect(subject).to be_a ConversationMute
  270. expect(subject).to be_destroyed
  271. end
  272. end
  273. context 'when not muting the conversation' do
  274. it 'returns nil' do
  275. expect(subject).to be_nil
  276. end
  277. end
  278. end
  279. describe '#unblock_domain!' do
  280. subject { account.unblock_domain!(domain) }
  281. let(:domain) { 'example.com' }
  282. context 'when blocking the domain' do
  283. it 'returns destroyed AccountDomainBlock' do
  284. account_domain_block = Fabricate(:account_domain_block, domain: domain)
  285. account.domain_blocks << account_domain_block
  286. expect(subject).to be_a AccountDomainBlock
  287. expect(subject).to be_destroyed
  288. end
  289. end
  290. context 'when unblocking the domain' do
  291. it 'returns nil' do
  292. expect(subject).to be_nil
  293. end
  294. end
  295. end
  296. describe '#unblock_idna_domain!' do
  297. subject { account.unblock_domain!(punycode_domain) }
  298. let(:idna_domain) { '대한민국.한국' }
  299. let(:punycode_domain) { 'xn--3e0bs9hfvinn1a.xn--3e0b707e' }
  300. context 'when blocking the domain' do
  301. it 'returns destroyed AccountDomainBlock' do
  302. account_domain_block = Fabricate(:account_domain_block, domain: idna_domain)
  303. account.domain_blocks << account_domain_block
  304. expect(subject).to be_a AccountDomainBlock
  305. expect(subject).to be_destroyed
  306. end
  307. end
  308. context 'when unblocking idna domain' do
  309. it 'returns nil' do
  310. expect(subject).to be_nil
  311. end
  312. end
  313. end
  314. describe '#following?' do
  315. subject { account.following?(target_account) }
  316. context 'when following target_account' do
  317. it 'returns true' do
  318. account.active_relationships.create(target_account: target_account)
  319. expect(subject).to be true
  320. end
  321. end
  322. context 'when not following target_account' do
  323. it 'returns false' do
  324. expect(subject).to be false
  325. end
  326. end
  327. end
  328. describe '#followed_by?' do
  329. subject { account.followed_by?(target_account) }
  330. context 'when followed by target_account' do
  331. it 'returns true' do
  332. account.passive_relationships.create(account: target_account)
  333. expect(subject).to be true
  334. end
  335. end
  336. context 'when not followed by target_account' do
  337. it 'returns false' do
  338. expect(subject).to be false
  339. end
  340. end
  341. end
  342. describe '#blocking?' do
  343. subject { account.blocking?(target_account) }
  344. context 'when blocking target_account' do
  345. it 'returns true' do
  346. account.block_relationships.create(target_account: target_account)
  347. expect(subject).to be true
  348. end
  349. end
  350. context 'when not blocking target_account' do
  351. it 'returns false' do
  352. expect(subject).to be false
  353. end
  354. end
  355. end
  356. describe '#domain_blocking?' do
  357. subject { account.domain_blocking?(domain) }
  358. let(:domain) { 'example.com' }
  359. context 'when blocking the domain' do
  360. it 'returns true' do
  361. account_domain_block = Fabricate(:account_domain_block, domain: domain)
  362. account.domain_blocks << account_domain_block
  363. expect(subject).to be true
  364. end
  365. end
  366. context 'when not blocking the domain' do
  367. it 'returns false' do
  368. expect(subject).to be false
  369. end
  370. end
  371. end
  372. describe '#muting?' do
  373. subject { account.muting?(target_account) }
  374. context 'when muting target_account' do
  375. it 'returns true' do
  376. mute = Fabricate(:mute, account: account, target_account: target_account)
  377. account.mute_relationships << mute
  378. expect(subject).to be true
  379. end
  380. end
  381. context 'when not muting target_account' do
  382. it 'returns false' do
  383. expect(subject).to be false
  384. end
  385. end
  386. end
  387. describe '#muting_conversation?' do
  388. subject { account.muting_conversation?(conversation) }
  389. let(:conversation) { Fabricate(:conversation) }
  390. context 'when muting the conversation' do
  391. it 'returns true' do
  392. account.conversation_mutes.create(conversation: conversation)
  393. expect(subject).to be true
  394. end
  395. end
  396. context 'when not muting the conversation' do
  397. it 'returns false' do
  398. expect(subject).to be false
  399. end
  400. end
  401. end
  402. describe '#muting_notifications?' do
  403. subject { account.muting_notifications?(target_account) }
  404. before do
  405. mute = Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)
  406. account.mute_relationships << mute
  407. end
  408. context 'when muting notifications of target_account' do
  409. let(:hide) { true }
  410. it 'returns true' do
  411. expect(subject).to be true
  412. end
  413. end
  414. context 'when not muting notifications of target_account' do
  415. let(:hide) { false }
  416. it 'returns false' do
  417. expect(subject).to be false
  418. end
  419. end
  420. end
  421. describe '#requested?' do
  422. subject { account.requested?(target_account) }
  423. context 'with requested by target_account' do
  424. it 'returns true' do
  425. Fabricate(:follow_request, account: account, target_account: target_account)
  426. expect(subject).to be true
  427. end
  428. end
  429. context 'when not requested by target_account' do
  430. it 'returns false' do
  431. expect(subject).to be false
  432. end
  433. end
  434. end
  435. describe '#favourited?' do
  436. subject { account.favourited?(status) }
  437. let(:status) { Fabricate(:status, account: account, favourites: favourites) }
  438. context 'when favorited' do
  439. let(:favourites) { [Fabricate(:favourite, account: account)] }
  440. it 'returns true' do
  441. expect(subject).to be true
  442. end
  443. end
  444. context 'when not favorited' do
  445. let(:favourites) { [] }
  446. it 'returns false' do
  447. expect(subject).to be false
  448. end
  449. end
  450. end
  451. describe '#reblogged?' do
  452. subject { account.reblogged?(status) }
  453. let(:status) { Fabricate(:status, account: account, reblogs: reblogs) }
  454. context 'with reblogged' do
  455. let(:reblogs) { [Fabricate(:status, account: account)] }
  456. it 'returns true' do
  457. expect(subject).to be true
  458. end
  459. end
  460. context 'when not reblogged' do
  461. let(:reblogs) { [] }
  462. it 'returns false' do
  463. expect(subject).to be false
  464. end
  465. end
  466. end
  467. describe '#pinned?' do
  468. subject { account.pinned?(status) }
  469. let(:status) { Fabricate(:status, account: account) }
  470. context 'when pinned' do
  471. it 'returns true' do
  472. Fabricate(:status_pin, account: account, status: status)
  473. expect(subject).to be true
  474. end
  475. end
  476. context 'when not pinned' do
  477. it 'returns false' do
  478. expect(subject).to be false
  479. end
  480. end
  481. end
  482. describe '#remote_followers_hash' do
  483. let(:me) { Fabricate(:account, username: 'Me') }
  484. let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
  485. let(:remote_bob) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
  486. let(:remote_instance_actor) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') }
  487. let(:remote_eve) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
  488. before do
  489. remote_alice.follow!(me)
  490. remote_bob.follow!(me)
  491. remote_instance_actor.follow!(me)
  492. remote_eve.follow!(me)
  493. me.follow!(remote_alice)
  494. end
  495. it 'returns correct hash for remote domains' do
  496. expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
  497. expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e'
  498. expect(me.remote_followers_hash('https://foo.org.evil.com/')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
  499. expect(me.remote_followers_hash('https://foo')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
  500. end
  501. it 'invalidates cache as needed when removing or adding followers' do
  502. expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
  503. remote_instance_actor.unfollow!(me)
  504. expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
  505. remote_alice.unfollow!(me)
  506. expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
  507. remote_alice.follow!(me)
  508. expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
  509. end
  510. end
  511. describe '#local_followers_hash' do
  512. let(:me) { Fabricate(:account, username: 'Me') }
  513. let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
  514. before do
  515. me.follow!(remote_alice)
  516. end
  517. it 'returns correct hash for local users' do
  518. expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
  519. end
  520. it 'invalidates cache as needed when removing or adding followers' do
  521. expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
  522. me.unfollow!(remote_alice)
  523. expect(remote_alice.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
  524. me.follow!(remote_alice)
  525. expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
  526. end
  527. end
  528. describe 'muting an account' do
  529. let(:me) { Fabricate(:account, username: 'Me') }
  530. let(:you) { Fabricate(:account, username: 'You') }
  531. context 'with the notifications option unspecified' do
  532. before do
  533. me.mute!(you)
  534. end
  535. it 'defaults to muting notifications' do
  536. expect(me.muting_notifications?(you)).to be true
  537. end
  538. end
  539. context 'with the notifications option set to false' do
  540. before do
  541. me.mute!(you, notifications: false)
  542. end
  543. it 'does not mute notifications' do
  544. expect(me.muting_notifications?(you)).to be false
  545. end
  546. end
  547. context 'with the notifications option set to true' do
  548. before do
  549. me.mute!(you, notifications: true)
  550. end
  551. it 'does mute notifications' do
  552. expect(me.muting_notifications?(you)).to be true
  553. end
  554. end
  555. end
  556. describe 'ignoring reblogs from an account' do
  557. let!(:me) { Fabricate(:account, username: 'Me') }
  558. let!(:you) { Fabricate(:account, username: 'You') }
  559. context 'with the reblogs option unspecified' do
  560. before do
  561. me.follow!(you)
  562. end
  563. it 'defaults to showing reblogs' do
  564. expect(me.muting_reblogs?(you)).to be(false)
  565. end
  566. end
  567. context 'with the reblogs option set to false' do
  568. before do
  569. me.follow!(you, reblogs: false)
  570. end
  571. it 'does mute reblogs' do
  572. expect(me.muting_reblogs?(you)).to be(true)
  573. end
  574. end
  575. context 'with the reblogs option set to true' do
  576. before do
  577. me.follow!(you, reblogs: true)
  578. end
  579. it 'does not mute reblogs' do
  580. expect(me.muting_reblogs?(you)).to be(false)
  581. end
  582. end
  583. end
  584. describe '#lists_for_local_distribution' do
  585. let(:account) { Fabricate(:user, current_sign_in_at: Time.now.utc).account }
  586. let!(:inactive_follower_user) { Fabricate(:user, current_sign_in_at: 5.years.ago) }
  587. let!(:follower_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
  588. let!(:follow_request_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
  589. let!(:inactive_follower_list) { Fabricate(:list, account: inactive_follower_user.account) }
  590. let!(:follower_list) { Fabricate(:list, account: follower_user.account) }
  591. let!(:follow_request_list) { Fabricate(:list, account: follow_request_user.account) }
  592. let!(:self_list) { Fabricate(:list, account: account) }
  593. before do
  594. inactive_follower_user.account.follow!(account)
  595. follower_user.account.follow!(account)
  596. follow_request_user.account.follow_requests.create!(target_account: account)
  597. inactive_follower_list.accounts << account
  598. follower_list.accounts << account
  599. follow_request_list.accounts << account
  600. self_list.accounts << account
  601. end
  602. it 'includes only the list from the active follower and from oneself' do
  603. expect(account.lists_for_local_distribution.to_a).to contain_exactly(follower_list, self_list)
  604. end
  605. end
  606. end