create_spec.rb 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe ActivityPub::Activity::Create do
  4. let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor') }
  5. let(:json) do
  6. {
  7. '@context': 'https://www.w3.org/ns/activitystreams',
  8. id: [ActivityPub::TagManager.instance.uri_for(sender), '#foo'].join,
  9. type: 'Create',
  10. actor: ActivityPub::TagManager.instance.uri_for(sender),
  11. object: object_json,
  12. }.with_indifferent_access
  13. end
  14. before do
  15. sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
  16. stub_request(:get, 'http://example.com/attachment.png').to_return(request_fixture('avatar.txt'))
  17. stub_request(:get, 'http://example.com/emoji.png').to_return(body: attachment_fixture('emojo.png'))
  18. stub_request(:get, 'http://example.com/emojib.png').to_return(body: attachment_fixture('emojo.png'), headers: { 'Content-Type' => 'application/octet-stream' })
  19. end
  20. describe 'processing posts received out of order' do
  21. let(:follower) { Fabricate(:account, username: 'bob') }
  22. let(:object_json) do
  23. {
  24. id: [ActivityPub::TagManager.instance.uri_for(sender), 'post1'].join('/'),
  25. type: 'Note',
  26. to: [
  27. 'https://www.w3.org/ns/activitystreams#Public',
  28. ActivityPub::TagManager.instance.uri_for(follower),
  29. ],
  30. content: '@bob lorem ipsum',
  31. published: 1.hour.ago.utc.iso8601,
  32. updated: 1.hour.ago.utc.iso8601,
  33. tag: {
  34. type: 'Mention',
  35. href: ActivityPub::TagManager.instance.uri_for(follower),
  36. },
  37. }
  38. end
  39. let(:reply_json) do
  40. {
  41. id: [ActivityPub::TagManager.instance.uri_for(sender), 'reply'].join('/'),
  42. type: 'Note',
  43. inReplyTo: object_json[:id],
  44. to: [
  45. 'https://www.w3.org/ns/activitystreams#Public',
  46. ActivityPub::TagManager.instance.uri_for(follower),
  47. ],
  48. content: '@bob lorem ipsum',
  49. published: Time.now.utc.iso8601,
  50. updated: Time.now.utc.iso8601,
  51. tag: {
  52. type: 'Mention',
  53. href: ActivityPub::TagManager.instance.uri_for(follower),
  54. },
  55. }
  56. end
  57. let(:invalid_mention_json) do
  58. {
  59. id: [ActivityPub::TagManager.instance.uri_for(sender), 'post2'].join('/'),
  60. type: 'Note',
  61. to: [
  62. 'https://www.w3.org/ns/activitystreams#Public',
  63. ActivityPub::TagManager.instance.uri_for(follower),
  64. ],
  65. content: '@bob lorem ipsum',
  66. published: 1.hour.ago.utc.iso8601,
  67. updated: 1.hour.ago.utc.iso8601,
  68. tag: {
  69. type: 'Mention',
  70. href: 'http://notexisting.dontexistingtld/actor',
  71. },
  72. }
  73. end
  74. def activity_for_object(json)
  75. {
  76. '@context': 'https://www.w3.org/ns/activitystreams',
  77. id: [json[:id], 'activity'].join('/'),
  78. type: 'Create',
  79. actor: ActivityPub::TagManager.instance.uri_for(sender),
  80. object: json,
  81. }.with_indifferent_access
  82. end
  83. before do
  84. follower.follow!(sender)
  85. end
  86. it 'correctly processes posts and inserts them in timelines', :aggregate_failures do
  87. # Simulate a temporary failure preventing from fetching the parent post
  88. stub_request(:get, object_json[:id]).to_return(status: 500)
  89. # When receiving the reply…
  90. described_class.new(activity_for_object(reply_json), sender, delivery: true).perform
  91. # NOTE: Refering explicitly to the workers is a bit awkward
  92. DistributionWorker.drain
  93. FeedInsertWorker.drain
  94. # …it creates a status with an unknown parent
  95. reply = Status.find_by(uri: reply_json[:id])
  96. expect(reply.reply?).to be true
  97. expect(reply.in_reply_to_id).to be_nil
  98. # …and creates a notification
  99. expect(LocalNotificationWorker.jobs.size).to eq 1
  100. # …but does not insert it into timelines
  101. expect(redis.zscore(FeedManager.instance.key(:home, follower.id), reply.id)).to be_nil
  102. # When receiving the parent…
  103. described_class.new(activity_for_object(object_json), sender, delivery: true).perform
  104. Sidekiq::Worker.drain_all
  105. # …it creates a status and insert it into timelines
  106. parent = Status.find_by(uri: object_json[:id])
  107. expect(parent.reply?).to be false
  108. expect(parent.in_reply_to_id).to be_nil
  109. expect(reply.reload.in_reply_to_id).to eq parent.id
  110. # Check that the both statuses have been inserted into the home feed
  111. expect(redis.zscore(FeedManager.instance.key(:home, follower.id), parent.id)).to be_within(0.1).of(parent.id.to_f)
  112. expect(redis.zscore(FeedManager.instance.key(:home, follower.id), reply.id)).to be_within(0.1).of(reply.id.to_f)
  113. # Creates two notifications
  114. expect(Notification.count).to eq 2
  115. end
  116. it 'ignores unprocessable mention', :aggregate_failures do
  117. stub_request(:get, invalid_mention_json[:tag][:href]).to_raise(HTTP::ConnectionError)
  118. # When receiving the post that contains an invalid mention…
  119. described_class.new(activity_for_object(invalid_mention_json), sender, delivery: true).perform
  120. # NOTE: Refering explicitly to the workers is a bit awkward
  121. DistributionWorker.drain
  122. FeedInsertWorker.drain
  123. # …it creates a status
  124. status = Status.find_by(uri: invalid_mention_json[:id])
  125. # Check the process did not crash
  126. expect(status.nil?).to be false
  127. # It has queued a mention resolve job
  128. expect(MentionResolveWorker).to have_enqueued_sidekiq_job(status.id, invalid_mention_json[:tag][:href], anything)
  129. end
  130. end
  131. describe '#perform' do
  132. context 'when fetching' do
  133. subject { described_class.new(json, sender) }
  134. before do
  135. subject.perform
  136. end
  137. context 'when object publication date is below ISO8601 range' do
  138. let(:object_json) do
  139. {
  140. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  141. type: 'Note',
  142. content: 'Lorem ipsum',
  143. published: '-0977-11-03T08:31:22Z',
  144. }
  145. end
  146. it 'creates status with a valid creation date', :aggregate_failures do
  147. status = sender.statuses.first
  148. expect(status).to_not be_nil
  149. expect(status.text).to eq 'Lorem ipsum'
  150. expect(status.created_at).to be_within(30).of(Time.now.utc)
  151. end
  152. end
  153. context 'when object publication date is above ISO8601 range' do
  154. let(:object_json) do
  155. {
  156. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  157. type: 'Note',
  158. content: 'Lorem ipsum',
  159. published: '10000-11-03T08:31:22Z',
  160. }
  161. end
  162. it 'creates status with a valid creation date', :aggregate_failures do
  163. status = sender.statuses.first
  164. expect(status).to_not be_nil
  165. expect(status.text).to eq 'Lorem ipsum'
  166. expect(status.created_at).to be_within(30).of(Time.now.utc)
  167. end
  168. end
  169. context 'when object has been edited' do
  170. let(:object_json) do
  171. {
  172. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  173. type: 'Note',
  174. content: 'Lorem ipsum',
  175. published: '2022-01-22T15:00:00Z',
  176. updated: '2022-01-22T16:00:00Z',
  177. }
  178. end
  179. it 'creates status with appropriate creation and edition dates', :aggregate_failures do
  180. status = sender.statuses.first
  181. expect(status).to_not be_nil
  182. expect(status.text).to eq 'Lorem ipsum'
  183. expect(status.created_at).to eq '2022-01-22T15:00:00Z'.to_datetime
  184. expect(status.edited?).to be true
  185. expect(status.edited_at).to eq '2022-01-22T16:00:00Z'.to_datetime
  186. end
  187. end
  188. context 'when object has update date equal to creation date' do
  189. let(:object_json) do
  190. {
  191. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  192. type: 'Note',
  193. content: 'Lorem ipsum',
  194. published: '2022-01-22T15:00:00Z',
  195. updated: '2022-01-22T15:00:00Z',
  196. }
  197. end
  198. it 'creates status' do
  199. status = sender.statuses.first
  200. expect(status).to_not be_nil
  201. expect(status.text).to eq 'Lorem ipsum'
  202. end
  203. it 'does not mark status as edited' do
  204. status = sender.statuses.first
  205. expect(status).to_not be_nil
  206. expect(status.edited?).to be false
  207. end
  208. end
  209. context 'with an unknown object type' do
  210. let(:object_json) do
  211. {
  212. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  213. type: 'Banana',
  214. content: 'Lorem ipsum',
  215. }
  216. end
  217. it 'does not create a status' do
  218. expect(sender.statuses.count).to be_zero
  219. end
  220. end
  221. context 'with a standalone' do
  222. let(:object_json) do
  223. {
  224. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  225. type: 'Note',
  226. content: 'Lorem ipsum',
  227. }
  228. end
  229. it 'creates status' do
  230. status = sender.statuses.first
  231. expect(status).to_not be_nil
  232. expect(status.text).to eq 'Lorem ipsum'
  233. end
  234. it 'missing to/cc defaults to direct privacy' do
  235. status = sender.statuses.first
  236. expect(status).to_not be_nil
  237. expect(status.visibility).to eq 'direct'
  238. end
  239. end
  240. context 'when public with explicit public address' do
  241. let(:object_json) do
  242. {
  243. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  244. type: 'Note',
  245. content: 'Lorem ipsum',
  246. to: 'https://www.w3.org/ns/activitystreams#Public',
  247. }
  248. end
  249. it 'creates status' do
  250. status = sender.statuses.first
  251. expect(status).to_not be_nil
  252. expect(status.visibility).to eq 'public'
  253. end
  254. end
  255. context 'when public with as:Public' do
  256. let(:object_json) do
  257. {
  258. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  259. type: 'Note',
  260. content: 'Lorem ipsum',
  261. to: 'as:Public',
  262. }
  263. end
  264. it 'creates status' do
  265. status = sender.statuses.first
  266. expect(status).to_not be_nil
  267. expect(status.visibility).to eq 'public'
  268. end
  269. end
  270. context 'when public with Public' do
  271. let(:object_json) do
  272. {
  273. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  274. type: 'Note',
  275. content: 'Lorem ipsum',
  276. to: 'Public',
  277. }
  278. end
  279. it 'creates status' do
  280. status = sender.statuses.first
  281. expect(status).to_not be_nil
  282. expect(status.visibility).to eq 'public'
  283. end
  284. end
  285. context 'when unlisted with explicit public address' do
  286. let(:object_json) do
  287. {
  288. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  289. type: 'Note',
  290. content: 'Lorem ipsum',
  291. cc: 'https://www.w3.org/ns/activitystreams#Public',
  292. }
  293. end
  294. it 'creates status' do
  295. status = sender.statuses.first
  296. expect(status).to_not be_nil
  297. expect(status.visibility).to eq 'unlisted'
  298. end
  299. end
  300. context 'when unlisted with as:Public' do
  301. let(:object_json) do
  302. {
  303. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  304. type: 'Note',
  305. content: 'Lorem ipsum',
  306. cc: 'as:Public',
  307. }
  308. end
  309. it 'creates status' do
  310. status = sender.statuses.first
  311. expect(status).to_not be_nil
  312. expect(status.visibility).to eq 'unlisted'
  313. end
  314. end
  315. context 'when unlisted with Public' do
  316. let(:object_json) do
  317. {
  318. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  319. type: 'Note',
  320. content: 'Lorem ipsum',
  321. cc: 'Public',
  322. }
  323. end
  324. it 'creates status' do
  325. status = sender.statuses.first
  326. expect(status).to_not be_nil
  327. expect(status.visibility).to eq 'unlisted'
  328. end
  329. end
  330. context 'when private' do
  331. let(:object_json) do
  332. {
  333. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  334. type: 'Note',
  335. content: 'Lorem ipsum',
  336. to: 'http://example.com/followers',
  337. }
  338. end
  339. it 'creates status' do
  340. status = sender.statuses.first
  341. expect(status).to_not be_nil
  342. expect(status.visibility).to eq 'private'
  343. end
  344. end
  345. context 'when private with inlined Collection in audience' do
  346. let(:object_json) do
  347. {
  348. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  349. type: 'Note',
  350. content: 'Lorem ipsum',
  351. to: {
  352. type: 'OrderedCollection',
  353. id: 'http://example.com/followers',
  354. first: 'http://example.com/followers?page=true',
  355. },
  356. }
  357. end
  358. it 'creates status' do
  359. status = sender.statuses.first
  360. expect(status).to_not be_nil
  361. expect(status.visibility).to eq 'private'
  362. end
  363. end
  364. context 'when limited' do
  365. let(:recipient) { Fabricate(:account) }
  366. let(:object_json) do
  367. {
  368. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  369. type: 'Note',
  370. content: 'Lorem ipsum',
  371. to: ActivityPub::TagManager.instance.uri_for(recipient),
  372. }
  373. end
  374. it 'creates status' do
  375. status = sender.statuses.first
  376. expect(status).to_not be_nil
  377. expect(status.visibility).to eq 'limited'
  378. end
  379. it 'creates silent mention' do
  380. status = sender.statuses.first
  381. expect(status.mentions.first).to be_silent
  382. end
  383. end
  384. context 'when direct' do
  385. let(:recipient) { Fabricate(:account) }
  386. let(:object_json) do
  387. {
  388. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  389. type: 'Note',
  390. content: 'Lorem ipsum',
  391. to: ActivityPub::TagManager.instance.uri_for(recipient),
  392. tag: {
  393. type: 'Mention',
  394. href: ActivityPub::TagManager.instance.uri_for(recipient),
  395. },
  396. }
  397. end
  398. it 'creates status' do
  399. status = sender.statuses.first
  400. expect(status).to_not be_nil
  401. expect(status.visibility).to eq 'direct'
  402. end
  403. end
  404. context 'with a reply' do
  405. let(:original_status) { Fabricate(:status) }
  406. let(:object_json) do
  407. {
  408. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  409. type: 'Note',
  410. content: 'Lorem ipsum',
  411. inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),
  412. }
  413. end
  414. it 'creates status' do
  415. status = sender.statuses.first
  416. expect(status).to_not be_nil
  417. expect(status.thread).to eq original_status
  418. expect(status.reply?).to be true
  419. expect(status.in_reply_to_account).to eq original_status.account
  420. expect(status.conversation).to eq original_status.conversation
  421. end
  422. end
  423. context 'with mentions' do
  424. let(:recipient) { Fabricate(:account) }
  425. let(:object_json) do
  426. {
  427. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  428. type: 'Note',
  429. content: 'Lorem ipsum',
  430. tag: [
  431. {
  432. type: 'Mention',
  433. href: ActivityPub::TagManager.instance.uri_for(recipient),
  434. },
  435. ],
  436. }
  437. end
  438. it 'creates status' do
  439. status = sender.statuses.first
  440. expect(status).to_not be_nil
  441. expect(status.mentions.map(&:account)).to include(recipient)
  442. end
  443. end
  444. context 'with mentions missing href' do
  445. let(:object_json) do
  446. {
  447. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  448. type: 'Note',
  449. content: 'Lorem ipsum',
  450. tag: [
  451. {
  452. type: 'Mention',
  453. },
  454. ],
  455. }
  456. end
  457. it 'creates status' do
  458. status = sender.statuses.first
  459. expect(status).to_not be_nil
  460. end
  461. end
  462. context 'with media attachments' do
  463. let(:object_json) do
  464. {
  465. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  466. type: 'Note',
  467. content: 'Lorem ipsum',
  468. attachment: [
  469. {
  470. type: 'Document',
  471. mediaType: 'image/png',
  472. url: 'http://example.com/attachment.png',
  473. },
  474. {
  475. type: 'Document',
  476. mediaType: 'image/png',
  477. url: 'http://example.com/emoji.png',
  478. },
  479. ],
  480. }
  481. end
  482. it 'creates status with correctly-ordered media attachments' do
  483. status = sender.statuses.first
  484. expect(status).to_not be_nil
  485. expect(status.ordered_media_attachments.map(&:remote_url)).to eq ['http://example.com/attachment.png', 'http://example.com/emoji.png']
  486. expect(status.ordered_media_attachment_ids).to be_present
  487. end
  488. end
  489. context 'with media attachments with long description' do
  490. let(:object_json) do
  491. {
  492. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  493. type: 'Note',
  494. content: 'Lorem ipsum',
  495. attachment: [
  496. {
  497. type: 'Document',
  498. mediaType: 'image/png',
  499. url: 'http://example.com/attachment.png',
  500. name: '*' * 1500,
  501. },
  502. ],
  503. }
  504. end
  505. it 'creates status' do
  506. status = sender.statuses.first
  507. expect(status).to_not be_nil
  508. expect(status.media_attachments.map(&:description)).to include('*' * 1500)
  509. end
  510. end
  511. context 'with media attachments with long description as summary' do
  512. let(:object_json) do
  513. {
  514. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  515. type: 'Note',
  516. content: 'Lorem ipsum',
  517. attachment: [
  518. {
  519. type: 'Document',
  520. mediaType: 'image/png',
  521. url: 'http://example.com/attachment.png',
  522. summary: '*' * 1500,
  523. },
  524. ],
  525. }
  526. end
  527. it 'creates status' do
  528. status = sender.statuses.first
  529. expect(status).to_not be_nil
  530. expect(status.media_attachments.map(&:description)).to include('*' * 1500)
  531. end
  532. end
  533. context 'with media attachments with focal points' do
  534. let(:object_json) do
  535. {
  536. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  537. type: 'Note',
  538. content: 'Lorem ipsum',
  539. attachment: [
  540. {
  541. type: 'Document',
  542. mediaType: 'image/png',
  543. url: 'http://example.com/attachment.png',
  544. focalPoint: [0.5, -0.7],
  545. },
  546. ],
  547. }
  548. end
  549. it 'creates status' do
  550. status = sender.statuses.first
  551. expect(status).to_not be_nil
  552. expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7')
  553. end
  554. end
  555. context 'with media attachments missing url' do
  556. let(:object_json) do
  557. {
  558. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  559. type: 'Note',
  560. content: 'Lorem ipsum',
  561. attachment: [
  562. {
  563. type: 'Document',
  564. mediaType: 'image/png',
  565. },
  566. ],
  567. }
  568. end
  569. it 'creates status' do
  570. status = sender.statuses.first
  571. expect(status).to_not be_nil
  572. end
  573. end
  574. context 'with hashtags' do
  575. let(:object_json) do
  576. {
  577. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  578. type: 'Note',
  579. content: 'Lorem ipsum',
  580. tag: [
  581. {
  582. type: 'Hashtag',
  583. href: 'http://example.com/blah',
  584. name: '#test',
  585. },
  586. ],
  587. }
  588. end
  589. it 'creates status' do
  590. status = sender.statuses.first
  591. expect(status).to_not be_nil
  592. expect(status.tags.map(&:name)).to include('test')
  593. end
  594. end
  595. context 'with hashtags missing name' do
  596. let(:object_json) do
  597. {
  598. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  599. type: 'Note',
  600. content: 'Lorem ipsum',
  601. tag: [
  602. {
  603. type: 'Hashtag',
  604. href: 'http://example.com/blah',
  605. },
  606. ],
  607. }
  608. end
  609. it 'creates status' do
  610. status = sender.statuses.first
  611. expect(status).to_not be_nil
  612. end
  613. end
  614. context 'with hashtags invalid name' do
  615. let(:object_json) do
  616. {
  617. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  618. type: 'Note',
  619. content: 'Lorem ipsum',
  620. tag: [
  621. {
  622. type: 'Hashtag',
  623. href: 'http://example.com/blah',
  624. name: 'foo, #eh !',
  625. },
  626. ],
  627. }
  628. end
  629. it 'creates status' do
  630. status = sender.statuses.first
  631. expect(status).to_not be_nil
  632. end
  633. end
  634. context 'with emojis' do
  635. let(:object_json) do
  636. {
  637. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  638. type: 'Note',
  639. content: 'Lorem ipsum :tinking:',
  640. tag: [
  641. {
  642. type: 'Emoji',
  643. icon: {
  644. url: 'http://example.com/emoji.png',
  645. },
  646. name: 'tinking',
  647. },
  648. ],
  649. }
  650. end
  651. it 'creates status' do
  652. status = sender.statuses.first
  653. expect(status).to_not be_nil
  654. expect(status.emojis.map(&:shortcode)).to include('tinking')
  655. end
  656. end
  657. context 'with emojis served with invalid content-type' do
  658. let(:object_json) do
  659. {
  660. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  661. type: 'Note',
  662. content: 'Lorem ipsum :tinkong:',
  663. tag: [
  664. {
  665. type: 'Emoji',
  666. icon: {
  667. url: 'http://example.com/emojib.png',
  668. },
  669. name: 'tinkong',
  670. },
  671. ],
  672. }
  673. end
  674. it 'creates status' do
  675. status = sender.statuses.first
  676. expect(status).to_not be_nil
  677. expect(status.emojis.map(&:shortcode)).to include('tinkong')
  678. end
  679. end
  680. context 'with emojis missing name' do
  681. let(:object_json) do
  682. {
  683. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  684. type: 'Note',
  685. content: 'Lorem ipsum :tinking:',
  686. tag: [
  687. {
  688. type: 'Emoji',
  689. icon: {
  690. url: 'http://example.com/emoji.png',
  691. },
  692. },
  693. ],
  694. }
  695. end
  696. it 'creates status' do
  697. status = sender.statuses.first
  698. expect(status).to_not be_nil
  699. end
  700. end
  701. context 'with emojis missing icon' do
  702. let(:object_json) do
  703. {
  704. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  705. type: 'Note',
  706. content: 'Lorem ipsum :tinking:',
  707. tag: [
  708. {
  709. type: 'Emoji',
  710. name: 'tinking',
  711. },
  712. ],
  713. }
  714. end
  715. it 'creates status' do
  716. status = sender.statuses.first
  717. expect(status).to_not be_nil
  718. end
  719. end
  720. context 'with poll' do
  721. let(:object_json) do
  722. {
  723. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  724. type: 'Question',
  725. content: 'Which color was the submarine?',
  726. oneOf: [
  727. {
  728. name: 'Yellow',
  729. replies: {
  730. type: 'Collection',
  731. totalItems: 10,
  732. },
  733. },
  734. {
  735. name: 'Blue',
  736. replies: {
  737. type: 'Collection',
  738. totalItems: 3,
  739. },
  740. },
  741. ],
  742. }
  743. end
  744. it 'creates status' do
  745. status = sender.statuses.first
  746. expect(status).to_not be_nil
  747. expect(status.poll).to_not be_nil
  748. end
  749. it 'creates a poll' do
  750. poll = sender.polls.first
  751. expect(poll).to_not be_nil
  752. expect(poll.status).to_not be_nil
  753. expect(poll.options).to eq %w(Yellow Blue)
  754. expect(poll.cached_tallies).to eq [10, 3]
  755. end
  756. end
  757. context 'when a vote to a local poll' do
  758. let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) }
  759. let!(:local_status) { Fabricate(:status, poll: poll) }
  760. let(:object_json) do
  761. {
  762. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  763. type: 'Note',
  764. name: 'Yellow',
  765. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
  766. }
  767. end
  768. it 'adds a vote to the poll with correct uri' do
  769. vote = poll.votes.first
  770. expect(vote).to_not be_nil
  771. expect(vote.uri).to eq object_json[:id]
  772. expect(poll.reload.cached_tallies).to eq [1, 0]
  773. end
  774. end
  775. context 'when a vote to an expired local poll' do
  776. let(:poll) do
  777. poll = Fabricate.build(:poll, options: %w(Yellow Blue), expires_at: 1.day.ago)
  778. poll.save(validate: false)
  779. poll
  780. end
  781. let!(:local_status) { Fabricate(:status, poll: poll) }
  782. let(:object_json) do
  783. {
  784. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  785. type: 'Note',
  786. name: 'Yellow',
  787. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
  788. }
  789. end
  790. it 'does not add a vote to the poll' do
  791. expect(poll.votes.first).to be_nil
  792. end
  793. end
  794. context 'with counts' do
  795. let(:object_json) do
  796. {
  797. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  798. type: 'Note',
  799. content: 'Lorem ipsum',
  800. likes: {
  801. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/likes'].join,
  802. type: 'Collection',
  803. totalItems: 50,
  804. },
  805. shares: {
  806. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/shares'].join,
  807. type: 'Collection',
  808. totalItems: 100,
  809. },
  810. }
  811. end
  812. it 'uses the counts from the created object' do
  813. status = sender.statuses.first
  814. expect(status.untrusted_favourites_count).to eq 50
  815. expect(status.untrusted_reblogs_count).to eq 100
  816. end
  817. end
  818. end
  819. context 'when object URI uses bearcaps' do
  820. subject { described_class.new(json, sender) }
  821. let(:token) { 'foo' }
  822. let(:json) do
  823. {
  824. '@context': 'https://www.w3.org/ns/activitystreams',
  825. id: [ActivityPub::TagManager.instance.uri_for(sender), '#foo'].join,
  826. type: 'Create',
  827. actor: ActivityPub::TagManager.instance.uri_for(sender),
  828. object: Addressable::URI.new(scheme: 'bear', query_values: { t: token, u: object_json[:id] }).to_s,
  829. }.with_indifferent_access
  830. end
  831. let(:object_json) do
  832. {
  833. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  834. type: 'Note',
  835. content: 'Lorem ipsum',
  836. to: 'https://www.w3.org/ns/activitystreams#Public',
  837. }
  838. end
  839. before do
  840. stub_request(:get, object_json[:id])
  841. .with(headers: { Authorization: "Bearer #{token}" })
  842. .to_return(body: Oj.dump(object_json), headers: { 'Content-Type': 'application/activity+json' })
  843. subject.perform
  844. end
  845. it 'creates status' do
  846. status = sender.statuses.first
  847. expect(status).to_not be_nil
  848. expect(status).to have_attributes(
  849. visibility: 'public',
  850. text: 'Lorem ipsum'
  851. )
  852. end
  853. end
  854. context 'when sender is followed by local users' do
  855. subject { described_class.new(json, sender, delivery: true) }
  856. before do
  857. Fabricate(:account).follow!(sender)
  858. subject.perform
  859. end
  860. let(:object_json) do
  861. {
  862. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  863. type: 'Note',
  864. content: 'Lorem ipsum',
  865. }
  866. end
  867. it 'creates status' do
  868. status = sender.statuses.first
  869. expect(status).to_not be_nil
  870. expect(status.text).to eq 'Lorem ipsum'
  871. end
  872. end
  873. context 'when sender replies to local status' do
  874. subject { described_class.new(json, sender, delivery: true) }
  875. let!(:local_status) { Fabricate(:status) }
  876. let(:object_json) do
  877. {
  878. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  879. type: 'Note',
  880. content: 'Lorem ipsum',
  881. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
  882. }
  883. end
  884. before do
  885. subject.perform
  886. end
  887. it 'creates status' do
  888. status = sender.statuses.first
  889. expect(status).to_not be_nil
  890. expect(status.text).to eq 'Lorem ipsum'
  891. end
  892. end
  893. context 'when sender targets a local user' do
  894. subject { described_class.new(json, sender, delivery: true) }
  895. let!(:local_account) { Fabricate(:account) }
  896. let(:object_json) do
  897. {
  898. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  899. type: 'Note',
  900. content: 'Lorem ipsum',
  901. to: ActivityPub::TagManager.instance.uri_for(local_account),
  902. }
  903. end
  904. before do
  905. subject.perform
  906. end
  907. it 'creates status' do
  908. status = sender.statuses.first
  909. expect(status).to_not be_nil
  910. expect(status.text).to eq 'Lorem ipsum'
  911. end
  912. end
  913. context 'when sender cc\'s a local user' do
  914. subject { described_class.new(json, sender, delivery: true) }
  915. let!(:local_account) { Fabricate(:account) }
  916. let(:object_json) do
  917. {
  918. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  919. type: 'Note',
  920. content: 'Lorem ipsum',
  921. cc: ActivityPub::TagManager.instance.uri_for(local_account),
  922. }
  923. end
  924. before do
  925. subject.perform
  926. end
  927. it 'creates status' do
  928. status = sender.statuses.first
  929. expect(status).to_not be_nil
  930. expect(status.text).to eq 'Lorem ipsum'
  931. end
  932. end
  933. context 'when the sender has no relevance to local activity' do
  934. subject { described_class.new(json, sender, delivery: true) }
  935. before do
  936. subject.perform
  937. end
  938. let(:object_json) do
  939. {
  940. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  941. type: 'Note',
  942. content: 'Lorem ipsum',
  943. }
  944. end
  945. it 'does not create anything' do
  946. expect(sender.statuses.count).to eq 0
  947. end
  948. end
  949. end
  950. end