create_spec.rb 30 KB

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