You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1566 lines
61 KiB

  1. require 'rails_helper'
  2. RSpec.describe OStatus::AtomSerializer do
  3. shared_examples 'follow request salmon' do
  4. it 'appends author element with account' do
  5. account = Fabricate(:account, domain: nil, username: 'username')
  6. follow_request = Fabricate(:follow_request, account: account)
  7. follow_request_salmon = serialize(follow_request)
  8. expect(follow_request_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  9. end
  10. it 'appends activity:object-type element with activity type' do
  11. follow_request = Fabricate(:follow_request)
  12. follow_request_salmon = serialize(follow_request)
  13. object_type = follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  14. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  15. end
  16. it 'appends activity:verb element with request_friend type' do
  17. follow_request = Fabricate(:follow_request)
  18. follow_request_salmon = serialize(follow_request)
  19. verb = follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
  20. expect(verb.text).to eq OStatus::TagManager::VERBS[:request_friend]
  21. end
  22. it 'appends activity:object with target account' do
  23. target_account = Fabricate(:account, domain: 'domain', uri: 'https://domain/id')
  24. follow_request = Fabricate(:follow_request, target_account: target_account)
  25. follow_request_salmon = serialize(follow_request)
  26. object = follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
  27. expect(object.id.text).to eq 'https://domain/id'
  28. end
  29. end
  30. shared_examples 'namespaces' do
  31. it 'adds namespaces' do
  32. element = serialize
  33. expect(element['xmlns']).to eq OStatus::TagManager::XMLNS
  34. expect(element['xmlns:thr']).to eq OStatus::TagManager::THR_XMLNS
  35. expect(element['xmlns:activity']).to eq OStatus::TagManager::AS_XMLNS
  36. expect(element['xmlns:poco']).to eq OStatus::TagManager::POCO_XMLNS
  37. expect(element['xmlns:media']).to eq OStatus::TagManager::MEDIA_XMLNS
  38. expect(element['xmlns:ostatus']).to eq OStatus::TagManager::OS_XMLNS
  39. expect(element['xmlns:mastodon']).to eq OStatus::TagManager::MTDN_XMLNS
  40. end
  41. end
  42. shared_examples 'no namespaces' do
  43. it 'does not add namespaces' do
  44. expect(serialize['xmlns']).to eq nil
  45. end
  46. end
  47. shared_examples 'status attributes' do
  48. it 'appends summary element with spoiler text if present' do
  49. status = Fabricate(:status, language: :ca, spoiler_text: 'spoiler text')
  50. element = serialize(status)
  51. summary = element.summary
  52. expect(summary['xml:lang']).to eq 'ca'
  53. expect(summary.text).to eq 'spoiler text'
  54. end
  55. it 'does not append summary element with spoiler text if not present' do
  56. status = Fabricate(:status, spoiler_text: '')
  57. element = serialize(status)
  58. element.nodes.each { |node| expect(node.name).not_to eq 'summary' }
  59. end
  60. it 'appends content element with formatted status' do
  61. status = Fabricate(:status, language: :ca, text: 'text')
  62. element = serialize(status)
  63. content = element.content
  64. expect(content[:type]).to eq 'html'
  65. expect(content['xml:lang']).to eq 'ca'
  66. expect(content.text).to eq '<p>text</p>'
  67. end
  68. it 'appends link elements for mentioned accounts' do
  69. account = Fabricate(:account, username: 'username')
  70. status = Fabricate(:status)
  71. Fabricate(:mention, account: account, status: status)
  72. element = serialize(status)
  73. mentioned = element.nodes.find do |node|
  74. node.name == 'link' &&
  75. node[:rel] == 'mentioned' &&
  76. node['ostatus:object-type'] == OStatus::TagManager::TYPES[:person]
  77. end
  78. expect(mentioned[:href]).to eq 'https://cb6e6126.ngrok.io/users/username'
  79. end
  80. it 'appends link elements for emojis' do
  81. Fabricate(:custom_emoji)
  82. status = Fabricate(:status, text: ':coolcat:')
  83. element = serialize(status)
  84. emoji = element.nodes.find { |node| node.name == 'link' && node[:rel] == 'emoji' }
  85. expect(emoji[:name]).to eq 'coolcat'
  86. expect(emoji[:href]).to_not be_blank
  87. end
  88. end
  89. describe 'render' do
  90. it 'returns XML with emojis' do
  91. element = Ox::Element.new('tag')
  92. element << '💩'
  93. xml = OStatus::AtomSerializer.render(element)
  94. expect(xml).to eq "<?xml version=\"1.0\"?>\n<tag>💩</tag>\n"
  95. end
  96. it 'returns XML, stripping invalid characters like \b and \v' do
  97. element = Ox::Element.new('tag')
  98. element << "im l33t\b haxo\b\vr"
  99. xml = OStatus::AtomSerializer.render(element)
  100. expect(xml).to eq "<?xml version=\"1.0\"?>\n<tag>im l33t haxor</tag>\n"
  101. end
  102. end
  103. describe '#author' do
  104. context 'when note is present' do
  105. it 'appends poco:note element with note for local account' do
  106. account = Fabricate(:account, domain: nil, note: '<p>note</p>')
  107. author = OStatus::AtomSerializer.new.author(account)
  108. note = author.nodes.find { |node| node.name == 'poco:note' }
  109. expect(note.text).to eq '<p>note</p>'
  110. end
  111. it 'appends poco:note element with tags-stripped note for remote account' do
  112. account = Fabricate(:account, domain: 'remote', note: '<p>note</p>')
  113. author = OStatus::AtomSerializer.new.author(account)
  114. note = author.nodes.find { |node| node.name == 'poco:note' }
  115. expect(note.text).to eq 'note'
  116. end
  117. it 'appends summary element with type attribute and simplified note if present' do
  118. account = Fabricate(:account, note: 'note')
  119. author = OStatus::AtomSerializer.new.author(account)
  120. expect(author.summary.text).to eq '<p>note</p>'
  121. expect(author.summary[:type]).to eq 'html'
  122. end
  123. end
  124. context 'when note is not present' do
  125. it 'does not append poco:note element' do
  126. account = Fabricate(:account, note: '')
  127. author = OStatus::AtomSerializer.new.author(account)
  128. author.nodes.each { |node| expect(node.name).not_to eq 'poco:note' }
  129. end
  130. it 'does not append summary element' do
  131. account = Fabricate(:account, note: '')
  132. author = OStatus::AtomSerializer.new.author(account)
  133. author.nodes.each { |node| expect(node.name).not_to eq 'summary' }
  134. end
  135. end
  136. it 'returns author element' do
  137. account = Fabricate(:account)
  138. author = OStatus::AtomSerializer.new.author(account)
  139. expect(author.name).to eq 'author'
  140. end
  141. it 'appends activity:object-type element with person type' do
  142. account = Fabricate(:account, domain: nil, username: 'username')
  143. author = OStatus::AtomSerializer.new.author(account)
  144. object_type = author.nodes.find { |node| node.name == 'activity:object-type' }
  145. expect(object_type.text).to eq OStatus::TagManager::TYPES[:person]
  146. end
  147. it 'appends email element with username and domain for local account' do
  148. account = Fabricate(:account, username: 'username')
  149. author = OStatus::AtomSerializer.new.author(account)
  150. expect(author.email.text).to eq 'username@cb6e6126.ngrok.io'
  151. end
  152. it 'appends email element with username and domain for remote user' do
  153. account = Fabricate(:account, domain: 'domain', username: 'username')
  154. author = OStatus::AtomSerializer.new.author(account)
  155. expect(author.email.text).to eq 'username@domain'
  156. end
  157. it 'appends link element for an alternative' do
  158. account = Fabricate(:account, domain: nil, username: 'username')
  159. author = OStatus::AtomSerializer.new.author(account)
  160. link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
  161. expect(link[:type]).to eq 'text/html'
  162. expect(link[:rel]).to eq 'alternate'
  163. expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'
  164. end
  165. it 'has link element for avatar if present' do
  166. account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))
  167. author = OStatus::AtomSerializer.new.author(account)
  168. link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'avatar' }
  169. expect(link[:type]).to eq 'image/gif'
  170. expect(link['media:width']).to eq '120'
  171. expect(link['media:height']).to eq '120'
  172. expect(link[:href]).to match /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/avatars\/.+\/original\/avatar.gif/
  173. end
  174. it 'does not have link element for avatar if not present' do
  175. account = Fabricate(:account, avatar: nil)
  176. author = OStatus::AtomSerializer.new.author(account)
  177. author.nodes.each do |node|
  178. expect(node[:rel]).not_to eq 'avatar' if node.name == 'link'
  179. end
  180. end
  181. it 'appends link element for header if present' do
  182. account = Fabricate(:account, header: attachment_fixture('avatar.gif'))
  183. author = OStatus::AtomSerializer.new.author(account)
  184. link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'header' }
  185. expect(link[:type]).to eq 'image/gif'
  186. expect(link['media:width']).to eq '700'
  187. expect(link['media:height']).to eq '335'
  188. expect(link[:href]).to match /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/headers\/.+\/original\/avatar.gif/
  189. end
  190. it 'does not append link element for header if not present' do
  191. account = Fabricate(:account, header: nil)
  192. author = OStatus::AtomSerializer.new.author(account)
  193. author.nodes.each do |node|
  194. expect(node[:rel]).not_to eq 'header' if node.name == 'link'
  195. end
  196. end
  197. it 'appends poco:displayName element with display name if present' do
  198. account = Fabricate(:account, display_name: 'display name')
  199. author = OStatus::AtomSerializer.new.author(account)
  200. display_name = author.nodes.find { |node| node.name == 'poco:displayName' }
  201. expect(display_name.text).to eq 'display name'
  202. end
  203. it 'does not append poco:displayName element with display name if not present' do
  204. account = Fabricate(:account, display_name: '')
  205. author = OStatus::AtomSerializer.new.author(account)
  206. author.nodes.each { |node| expect(node.name).not_to eq 'poco:displayName' }
  207. end
  208. it "appends mastodon:scope element with 'private' if locked" do
  209. account = Fabricate(:account, locked: true)
  210. author = OStatus::AtomSerializer.new.author(account)
  211. scope = author.nodes.find { |node| node.name == 'mastodon:scope' }
  212. expect(scope.text).to eq 'private'
  213. end
  214. it "appends mastodon:scope element with 'public' if unlocked" do
  215. account = Fabricate(:account, locked: false)
  216. author = OStatus::AtomSerializer.new.author(account)
  217. scope = author.nodes.find { |node| node.name == 'mastodon:scope' }
  218. expect(scope.text).to eq 'public'
  219. end
  220. it 'includes URI' do
  221. account = Fabricate(:account, domain: nil, username: 'username')
  222. author = OStatus::AtomSerializer.new.author(account)
  223. expect(author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  224. expect(author.uri.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  225. end
  226. it 'includes username' do
  227. account = Fabricate(:account, username: 'username')
  228. author = OStatus::AtomSerializer.new.author(account)
  229. name = author.nodes.find { |node| node.name == 'name' }
  230. username = author.nodes.find { |node| node.name == 'poco:preferredUsername' }
  231. expect(name.text).to eq 'username'
  232. expect(username.text).to eq 'username'
  233. end
  234. end
  235. describe '#entry' do
  236. shared_examples 'not root' do
  237. include_examples 'no namespaces' do
  238. def serialize
  239. subject
  240. end
  241. end
  242. it 'does not append author element' do
  243. subject.nodes.each { |node| expect(node.name).not_to eq 'author' }
  244. end
  245. end
  246. context 'it is root' do
  247. include_examples 'namespaces' do
  248. def serialize
  249. stream_entry = Fabricate(:stream_entry)
  250. OStatus::AtomSerializer.new.entry(stream_entry, true)
  251. end
  252. end
  253. it 'appends author element' do
  254. account = Fabricate(:account, username: 'username')
  255. status = Fabricate(:status, account: account)
  256. entry = OStatus::AtomSerializer.new.entry(status.stream_entry, true)
  257. expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  258. end
  259. end
  260. context 'if status is present' do
  261. include_examples 'status attributes' do
  262. def serialize(status)
  263. OStatus::AtomSerializer.new.entry(status.stream_entry, true)
  264. end
  265. end
  266. it 'appends link element for the public collection if status is publicly visible' do
  267. status = Fabricate(:status, visibility: :public)
  268. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  269. mentioned_person = entry.nodes.find do |node|
  270. node.name == 'link' &&
  271. node[:rel] == 'mentioned' &&
  272. node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]
  273. end
  274. expect(mentioned_person[:href]).to eq OStatus::TagManager::COLLECTIONS[:public]
  275. end
  276. it 'does not append link element for the public collection if status is not publicly visible' do
  277. status = Fabricate(:status, visibility: :private)
  278. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  279. entry.nodes.each do |node|
  280. if node.name == 'link' &&
  281. node[:rel] == 'mentioned' &&
  282. node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]
  283. expect(mentioned_collection[:href]).not_to eq OStatus::TagManager::COLLECTIONS[:public]
  284. end
  285. end
  286. end
  287. it 'appends category elements for tags' do
  288. tag = Fabricate(:tag, name: 'tag')
  289. status = Fabricate(:status, tags: [ tag ])
  290. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  291. expect(entry.category[:term]).to eq 'tag'
  292. end
  293. it 'appends category element for NSFW if status is sensitive' do
  294. status = Fabricate(:status, sensitive: true)
  295. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  296. expect(entry.category[:term]).to eq 'nsfw'
  297. end
  298. it 'appends link elements for media attachments' do
  299. file = attachment_fixture('attachment.jpg')
  300. media_attachment = Fabricate(:media_attachment, file: file)
  301. status = Fabricate(:status, media_attachments: [ media_attachment ])
  302. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  303. enclosure = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'enclosure' }
  304. expect(enclosure[:type]).to eq 'image/jpeg'
  305. expect(enclosure[:href]).to match /^https:\/\/cb6e6126.ngrok.io\/system\/media_attachments\/files\/.+\/original\/attachment.jpg$/
  306. end
  307. it 'appends mastodon:scope element with visibility' do
  308. status = Fabricate(:status, visibility: :public)
  309. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  310. scope = entry.nodes.find { |node| node.name == 'mastodon:scope' }
  311. expect(scope.text).to eq 'public'
  312. end
  313. it 'returns element whose rendered view triggers creation when processed' do
  314. remote_account = Account.create!(username: 'username')
  315. remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z')
  316. entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true)
  317. entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test
  318. xml = OStatus::AtomSerializer.render(entry).gsub('cb6e6126.ngrok.io', 'remote')
  319. remote_status.destroy!
  320. remote_account.destroy!
  321. account = Account.create!(
  322. domain: 'remote',
  323. username: 'username',
  324. last_webfingered_at: Time.now.utc
  325. )
  326. ProcessFeedService.new.call(xml, account)
  327. expect(Status.find_by(uri: "https://remote/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status
  328. end
  329. end
  330. context 'if status is not present' do
  331. it 'appends content element saying status is deleted' do
  332. status = Fabricate(:status)
  333. status.destroy!
  334. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  335. expect(entry.content.text).to eq 'Deleted status'
  336. end
  337. it 'appends title element saying the status is deleted' do
  338. account = Fabricate(:account, username: 'username')
  339. status = Fabricate(:status, account: account)
  340. status.destroy!
  341. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  342. expect(entry.title.text).to eq 'username deleted status'
  343. end
  344. end
  345. context 'it is not root' do
  346. let(:stream_entry) { Fabricate(:stream_entry) }
  347. subject { OStatus::AtomSerializer.new.entry(stream_entry, false) }
  348. include_examples 'not root'
  349. end
  350. context 'without root parameter' do
  351. let(:stream_entry) { Fabricate(:stream_entry) }
  352. subject { OStatus::AtomSerializer.new.entry(stream_entry) }
  353. include_examples 'not root'
  354. end
  355. it 'returns entry element' do
  356. stream_entry = Fabricate(:stream_entry)
  357. entry = OStatus::AtomSerializer.new.entry(stream_entry)
  358. expect(entry.name).to eq 'entry'
  359. end
  360. it 'appends id element with unique tag' do
  361. status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z')
  362. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  363. expect(entry.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  364. end
  365. it 'appends published element with created date' do
  366. stream_entry = Fabricate(:stream_entry, created_at: '2000-01-01T00:00:00Z')
  367. entry = OStatus::AtomSerializer.new.entry(stream_entry)
  368. expect(entry.published.text).to eq '2000-01-01T00:00:00Z'
  369. end
  370. it 'appends updated element with updated date' do
  371. stream_entry = Fabricate(:stream_entry, updated_at: '2000-01-01T00:00:00Z')
  372. entry = OStatus::AtomSerializer.new.entry(stream_entry)
  373. expect(entry.updated.text).to eq '2000-01-01T00:00:00Z'
  374. end
  375. it 'appends title element with status title' do
  376. account = Fabricate(:account, username: 'username')
  377. status = Fabricate(:status, account: account, reblog_of_id: nil)
  378. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  379. expect(entry.title.text).to eq 'New status by username'
  380. end
  381. it 'appends activity:object-type element with object type' do
  382. status = Fabricate(:status)
  383. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  384. object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }
  385. expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]
  386. end
  387. it 'appends activity:verb element with object type' do
  388. status = Fabricate(:status)
  389. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  390. object_type = entry.nodes.find { |node| node.name == 'activity:verb' }
  391. expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]
  392. end
  393. it 'appends activity:object element with target if present' do
  394. reblogged = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
  395. reblog = Fabricate(:status, reblog: reblogged)
  396. entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry)
  397. object = entry.nodes.find { |node| node.name == 'activity:object' }
  398. expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}"
  399. end
  400. it 'does not append activity:object element if target is not present' do
  401. status = Fabricate(:status, reblog_of_id: nil)
  402. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  403. entry.nodes.each { |node| expect(node.name).not_to eq 'activity:object' }
  404. end
  405. it 'appends link element for an alternative' do
  406. account = Fabricate(:account, username: 'username')
  407. status = Fabricate(:status, account: account)
  408. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  409. link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
  410. expect(link[:type]).to eq 'text/html'
  411. expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
  412. end
  413. it 'appends link element for itself' do
  414. account = Fabricate(:account, username: 'username')
  415. status = Fabricate(:status, account: account)
  416. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  417. link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }
  418. expect(link[:type]).to eq 'application/atom+xml'
  419. expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}.atom"
  420. end
  421. it 'appends thr:in-reply-to element if threaded' do
  422. in_reply_to_status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reblog_of_id: nil)
  423. reply_status = Fabricate(:status, in_reply_to_id: in_reply_to_status.id)
  424. entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry)
  425. in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
  426. expect(in_reply_to[:ref]).to eq "https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}"
  427. end
  428. it 'does not append thr:in-reply-to element if not threaded' do
  429. status = Fabricate(:status)
  430. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  431. entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }
  432. end
  433. it 'appends ostatus:conversation if conversation id is present' do
  434. status = Fabricate(:status)
  435. status.conversation.update!(created_at: '2000-01-01T00:00:00Z')
  436. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  437. conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }
  438. expect(conversation[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation_id}:objectType=Conversation"
  439. end
  440. it 'does not append ostatus:conversation if conversation id is not present' do
  441. status = Fabricate.build(:status, conversation_id: nil)
  442. status.save!(validate: false)
  443. entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
  444. entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }
  445. end
  446. end
  447. describe '#feed' do
  448. include_examples 'namespaces' do
  449. def serialize
  450. account = Fabricate(:account)
  451. OStatus::AtomSerializer.new.feed(account, [])
  452. end
  453. end
  454. it 'returns feed element' do
  455. account = Fabricate(:account)
  456. feed = OStatus::AtomSerializer.new.feed(account, [])
  457. expect(feed.name).to eq 'feed'
  458. end
  459. it 'appends id element with account Atom URL' do
  460. account = Fabricate(:account, username: 'username')
  461. feed = OStatus::AtomSerializer.new.feed(account, [])
  462. expect(feed.id.text).to eq 'https://cb6e6126.ngrok.io/users/username.atom'
  463. end
  464. it 'appends title element with account display name if present' do
  465. account = Fabricate(:account, display_name: 'display name')
  466. feed = OStatus::AtomSerializer.new.feed(account, [])
  467. expect(feed.title.text).to eq 'display name'
  468. end
  469. it 'does not append title element with account username if account display name is not present' do
  470. account = Fabricate(:account, display_name: '', username: 'username')
  471. feed = OStatus::AtomSerializer.new.feed(account, [])
  472. expect(feed.title.text).to eq 'username'
  473. end
  474. it 'appends subtitle element with account note' do
  475. account = Fabricate(:account, note: 'note')
  476. feed = OStatus::AtomSerializer.new.feed(account, [])
  477. expect(feed.subtitle.text).to eq 'note'
  478. end
  479. it 'appends updated element with date account got updated' do
  480. account = Fabricate(:account, updated_at: '2000-01-01T00:00:00Z')
  481. feed = OStatus::AtomSerializer.new.feed(account, [])
  482. expect(feed.updated.text).to eq '2000-01-01T00:00:00Z'
  483. end
  484. it 'appends logo element with full asset URL for original account avatar' do
  485. account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))
  486. feed = OStatus::AtomSerializer.new.feed(account, [])
  487. expect(feed.logo.text).to match /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/avatars\/.+\/original\/avatar.gif/
  488. end
  489. it 'appends author element' do
  490. account = Fabricate(:account, username: 'username')
  491. feed = OStatus::AtomSerializer.new.feed(account, [])
  492. expect(feed.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  493. end
  494. it 'appends link element for an alternative' do
  495. account = Fabricate(:account, username: 'username')
  496. feed = OStatus::AtomSerializer.new.feed(account, [])
  497. link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
  498. expect(link[:type]).to eq 'text/html'
  499. expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'
  500. end
  501. it 'appends link element for itself' do
  502. account = Fabricate(:account, username: 'username')
  503. feed = OStatus::AtomSerializer.new.feed(account, [])
  504. link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }
  505. expect(link[:type]).to eq 'application/atom+xml'
  506. expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/users/username.atom'
  507. end
  508. it 'appends link element for the next if it has 20 stream entries' do
  509. account = Fabricate(:account, username: 'username')
  510. stream_entry = Fabricate(:stream_entry)
  511. feed = OStatus::AtomSerializer.new.feed(account, Array.new(20, stream_entry))
  512. link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'next' }
  513. expect(link[:type]).to eq 'application/atom+xml'
  514. expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username.atom?max_id=#{stream_entry.id}"
  515. end
  516. it 'does not append link element for the next if it does not have 20 stream entries' do
  517. account = Fabricate(:account, username: 'username')
  518. feed = OStatus::AtomSerializer.new.feed(account, [])
  519. feed.nodes.each do |node|
  520. expect(node[:rel]).not_to eq 'next' if node.name == 'link'
  521. end
  522. end
  523. it 'appends link element for hub' do
  524. account = Fabricate(:account, username: 'username')
  525. feed = OStatus::AtomSerializer.new.feed(account, [])
  526. link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'hub' }
  527. expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/api/push'
  528. end
  529. it 'appends link element for Salmon' do
  530. account = Fabricate(:account, username: 'username')
  531. feed = OStatus::AtomSerializer.new.feed(account, [])
  532. link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'salmon' }
  533. expect(link[:href]).to start_with 'https://cb6e6126.ngrok.io/api/salmon/'
  534. end
  535. it 'appends stream entries' do
  536. account = Fabricate(:account, username: 'username')
  537. status = Fabricate(:status, account: account)
  538. feed = OStatus::AtomSerializer.new.feed(account, [status.stream_entry])
  539. expect(feed.entry.title.text).to eq 'New status by username'
  540. end
  541. end
  542. describe '#block_salmon' do
  543. include_examples 'namespaces' do
  544. def serialize
  545. block = Fabricate(:block)
  546. OStatus::AtomSerializer.new.block_salmon(block)
  547. end
  548. end
  549. it 'returns entry element' do
  550. block = Fabricate(:block)
  551. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  552. expect(block_salmon.name).to eq 'entry'
  553. end
  554. it 'appends id element with unique tag' do
  555. block = Fabricate(:block)
  556. time_before = Time.now
  557. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  558. time_after = Time.now
  559. expect(block_salmon.id.text).to(
  560. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))
  561. .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))
  562. )
  563. end
  564. it 'appends title element with description' do
  565. account = Fabricate(:account, domain: nil, username: 'account')
  566. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  567. block = Fabricate(:block, account: account, target_account: target_account)
  568. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  569. expect(block_salmon.title.text).to eq 'account no longer wishes to interact with target_account@remote'
  570. end
  571. it 'appends author element with account' do
  572. account = Fabricate(:account, domain: nil, username: 'account')
  573. block = Fabricate(:block, account: account)
  574. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  575. expect(block_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'
  576. end
  577. it 'appends activity:object-type element with activity type' do
  578. block = Fabricate(:block)
  579. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  580. object_type = block_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  581. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  582. end
  583. it 'appends activity:verb element with block' do
  584. block = Fabricate(:block)
  585. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  586. verb = block_salmon.nodes.find { |node| node.name == 'activity:verb' }
  587. expect(verb.text).to eq OStatus::TagManager::VERBS[:block]
  588. end
  589. it 'appends activity:object element with target account' do
  590. target_account = Fabricate(:account, domain: 'domain', uri: 'https://domain/id')
  591. block = Fabricate(:block, target_account: target_account)
  592. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  593. object = block_salmon.nodes.find { |node| node.name == 'activity:object' }
  594. expect(object.id.text).to eq 'https://domain/id'
  595. end
  596. it 'returns element whose rendered view triggers block when processed' do
  597. block = Fabricate(:block)
  598. block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
  599. xml = OStatus::AtomSerializer.render(block_salmon)
  600. envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
  601. block.destroy!
  602. ProcessInteractionService.new.call(envelope, block.target_account)
  603. expect(block.account.blocking?(block.target_account)).to be true
  604. end
  605. end
  606. describe '#unblock_salmon' do
  607. include_examples 'namespaces' do
  608. def serialize
  609. block = Fabricate(:block)
  610. OStatus::AtomSerializer.new.unblock_salmon(block)
  611. end
  612. end
  613. it 'returns entry element' do
  614. block = Fabricate(:block)
  615. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  616. expect(unblock_salmon.name).to eq 'entry'
  617. end
  618. it 'appends id element with unique tag' do
  619. block = Fabricate(:block)
  620. time_before = Time.now
  621. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  622. time_after = Time.now
  623. expect(unblock_salmon.id.text).to(
  624. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))
  625. .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))
  626. )
  627. end
  628. it 'appends title element with description' do
  629. account = Fabricate(:account, domain: nil, username: 'account')
  630. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  631. block = Fabricate(:block, account: account, target_account: target_account)
  632. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  633. expect(unblock_salmon.title.text).to eq 'account no longer blocks target_account@remote'
  634. end
  635. it 'appends author element with account' do
  636. account = Fabricate(:account, domain: nil, username: 'account')
  637. block = Fabricate(:block, account: account)
  638. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  639. expect(unblock_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'
  640. end
  641. it 'appends activity:object-type element with activity type' do
  642. block = Fabricate(:block)
  643. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  644. object_type = unblock_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  645. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  646. end
  647. it 'appends activity:verb element with block' do
  648. block = Fabricate(:block)
  649. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  650. verb = unblock_salmon.nodes.find { |node| node.name == 'activity:verb' }
  651. expect(verb.text).to eq OStatus::TagManager::VERBS[:unblock]
  652. end
  653. it 'appends activity:object element with target account' do
  654. target_account = Fabricate(:account, domain: 'domain', uri: 'https://domain/id')
  655. block = Fabricate(:block, target_account: target_account)
  656. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  657. object = unblock_salmon.nodes.find { |node| node.name == 'activity:object' }
  658. expect(object.id.text).to eq 'https://domain/id'
  659. end
  660. it 'returns element whose rendered view triggers block when processed' do
  661. block = Fabricate(:block)
  662. unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
  663. xml = OStatus::AtomSerializer.render(unblock_salmon)
  664. envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
  665. ProcessInteractionService.new.call(envelope, block.target_account)
  666. expect{ block.reload }.to raise_error ActiveRecord::RecordNotFound
  667. end
  668. end
  669. describe '#favourite_salmon' do
  670. include_examples 'namespaces' do
  671. def serialize
  672. favourite = Fabricate(:favourite)
  673. OStatus::AtomSerializer.new.favourite_salmon(favourite)
  674. end
  675. end
  676. it 'returns entry element' do
  677. favourite = Fabricate(:favourite)
  678. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  679. expect(favourite_salmon.name).to eq 'entry'
  680. end
  681. it 'appends id element with unique tag' do
  682. favourite = Fabricate(:favourite, created_at: '2000-01-01T00:00:00Z')
  683. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  684. expect(favourite_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{favourite.id}:objectType=Favourite"
  685. end
  686. it 'appends author element with account' do
  687. account = Fabricate(:account, domain: nil, username: 'username')
  688. favourite = Fabricate(:favourite, account: account)
  689. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  690. expect(favourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  691. end
  692. it 'appends activity:object-type element with activity type' do
  693. favourite = Fabricate(:favourite)
  694. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  695. object_type = favourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  696. expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'
  697. end
  698. it 'appends activity:verb element with favorite' do
  699. favourite = Fabricate(:favourite)
  700. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  701. verb = favourite_salmon.nodes.find { |node| node.name == 'activity:verb' }
  702. expect(verb.text).to eq OStatus::TagManager::VERBS[:favorite]
  703. end
  704. it 'appends activity:object element with status' do
  705. status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
  706. favourite = Fabricate(:favourite, status: status)
  707. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  708. object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' }
  709. expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  710. end
  711. it 'appends thr:in-reply-to element for status' do
  712. status_account = Fabricate(:account, username: 'username')
  713. status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')
  714. favourite = Fabricate(:favourite, status: status)
  715. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  716. in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
  717. expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  718. expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
  719. end
  720. it 'includes description' do
  721. account = Fabricate(:account, domain: nil, username: 'account')
  722. status_account = Fabricate(:account, domain: 'remote', username: 'status_account')
  723. status = Fabricate(:status, account: status_account)
  724. favourite = Fabricate(:favourite, account: account, status: status)
  725. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  726. expect(favourite_salmon.title.text).to eq 'account favourited a status by status_account@remote'
  727. expect(favourite_salmon.content.text).to eq 'account favourited a status by status_account@remote'
  728. end
  729. it 'returns element whose rendered view triggers favourite when processed' do
  730. favourite = Fabricate(:favourite)
  731. favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
  732. xml = OStatus::AtomSerializer.render(favourite_salmon)
  733. envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
  734. favourite.destroy!
  735. ProcessInteractionService.new.call(envelope, favourite.status.account)
  736. expect(favourite.account.favourited?(favourite.status)).to be true
  737. end
  738. end
  739. describe '#unfavourite_salmon' do
  740. include_examples 'namespaces' do
  741. def serialize
  742. favourite = Fabricate(:favourite)
  743. OStatus::AtomSerializer.new.favourite_salmon(favourite)
  744. end
  745. end
  746. it 'returns entry element' do
  747. favourite = Fabricate(:favourite)
  748. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  749. expect(unfavourite_salmon.name).to eq 'entry'
  750. end
  751. it 'appends id element with unique tag' do
  752. favourite = Fabricate(:favourite)
  753. time_before = Time.now
  754. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  755. time_after = Time.now
  756. expect(unfavourite_salmon.id.text).to(
  757. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, favourite.id, 'Favourite'))
  758. .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, favourite.id, 'Favourite')))
  759. )
  760. end
  761. it 'appends author element with account' do
  762. account = Fabricate(:account, domain: nil, username: 'username')
  763. favourite = Fabricate(:favourite, account: account)
  764. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  765. expect(unfavourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  766. end
  767. it 'appends activity:object-type element with activity type' do
  768. favourite = Fabricate(:favourite)
  769. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  770. object_type = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  771. expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'
  772. end
  773. it 'appends activity:verb element with favorite' do
  774. favourite = Fabricate(:favourite)
  775. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  776. verb = unfavourite_salmon.nodes.find { |node| node.name == 'activity:verb' }
  777. expect(verb.text).to eq OStatus::TagManager::VERBS[:unfavorite]
  778. end
  779. it 'appends activity:object element with status' do
  780. status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
  781. favourite = Fabricate(:favourite, status: status)
  782. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  783. object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' }
  784. expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  785. end
  786. it 'appends thr:in-reply-to element for status' do
  787. status_account = Fabricate(:account, username: 'username')
  788. status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')
  789. favourite = Fabricate(:favourite, status: status)
  790. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  791. in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
  792. expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  793. expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
  794. end
  795. it 'includes description' do
  796. account = Fabricate(:account, domain: nil, username: 'account')
  797. status_account = Fabricate(:account, domain: 'remote', username: 'status_account')
  798. status = Fabricate(:status, account: status_account)
  799. favourite = Fabricate(:favourite, account: account, status: status)
  800. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  801. expect(unfavourite_salmon.title.text).to eq 'account no longer favourites a status by status_account@remote'
  802. expect(unfavourite_salmon.content.text).to eq 'account no longer favourites a status by status_account@remote'
  803. end
  804. it 'returns element whose rendered view triggers unfavourite when processed' do
  805. favourite = Fabricate(:favourite)
  806. unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
  807. xml = OStatus::AtomSerializer.render(unfavourite_salmon)
  808. envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
  809. ProcessInteractionService.new.call(envelope, favourite.status.account)
  810. expect { favourite.reload }.to raise_error ActiveRecord::RecordNotFound
  811. end
  812. end
  813. describe '#follow_salmon' do
  814. include_examples 'namespaces' do
  815. def serialize
  816. follow = Fabricate(:follow)
  817. OStatus::AtomSerializer.new.follow_salmon(follow)
  818. end
  819. end
  820. it 'returns entry element' do
  821. follow = Fabricate(:follow)
  822. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  823. expect(follow_salmon.name).to eq 'entry'
  824. end
  825. it 'appends id element with unique tag' do
  826. follow = Fabricate(:follow, created_at: '2000-01-01T00:00:00Z')
  827. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  828. expect(follow_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow.id}:objectType=Follow"
  829. end
  830. it 'appends author element with account' do
  831. account = Fabricate(:account, domain: nil, username: 'username')
  832. follow = Fabricate(:follow, account: account)
  833. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  834. expect(follow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  835. end
  836. it 'appends activity:object-type element with activity type' do
  837. follow = Fabricate(:follow)
  838. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  839. object_type = follow_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  840. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  841. end
  842. it 'appends activity:verb element with follow' do
  843. follow = Fabricate(:follow)
  844. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  845. verb = follow_salmon.nodes.find { |node| node.name == 'activity:verb' }
  846. expect(verb.text).to eq OStatus::TagManager::VERBS[:follow]
  847. end
  848. it 'appends activity:object element with target account' do
  849. target_account = Fabricate(:account, domain: 'domain', uri: 'https://domain/id')
  850. follow = Fabricate(:follow, target_account: target_account)
  851. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  852. object = follow_salmon.nodes.find { |node| node.name == 'activity:object' }
  853. expect(object.id.text).to eq 'https://domain/id'
  854. end
  855. it 'includes description' do
  856. account = Fabricate(:account, domain: nil, username: 'account')
  857. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  858. follow = Fabricate(:follow, account: account, target_account: target_account)
  859. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  860. expect(follow_salmon.title.text).to eq 'account started following target_account@remote'
  861. expect(follow_salmon.content.text).to eq 'account started following target_account@remote'
  862. end
  863. it 'returns element whose rendered view triggers follow when processed' do
  864. follow = Fabricate(:follow)
  865. follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
  866. xml = OStatus::AtomSerializer.render(follow_salmon)
  867. follow.destroy!
  868. envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
  869. ProcessInteractionService.new.call(envelope, follow.target_account)
  870. expect(follow.account.following?(follow.target_account)).to be true
  871. end
  872. end
  873. describe '#unfollow_salmon' do
  874. include_examples 'namespaces' do
  875. def serialize
  876. follow = Fabricate(:follow)
  877. follow.destroy!
  878. OStatus::AtomSerializer.new.unfollow_salmon(follow)
  879. end
  880. end
  881. it 'returns entry element' do
  882. follow = Fabricate(:follow)
  883. follow.destroy!
  884. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  885. expect(unfollow_salmon.name).to eq 'entry'
  886. end
  887. it 'appends id element with unique tag' do
  888. follow = Fabricate(:follow)
  889. follow.destroy!
  890. time_before = Time.now
  891. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  892. time_after = Time.now
  893. expect(unfollow_salmon.id.text).to(
  894. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow.id, 'Follow'))
  895. .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow.id, 'Follow')))
  896. )
  897. end
  898. it 'appends title element with description' do
  899. account = Fabricate(:account, domain: nil, username: 'account')
  900. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  901. follow = Fabricate(:follow, account: account, target_account: target_account)
  902. follow.destroy!
  903. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  904. expect(unfollow_salmon.title.text).to eq 'account is no longer following target_account@remote'
  905. end
  906. it 'appends content element with description' do
  907. account = Fabricate(:account, domain: nil, username: 'account')
  908. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  909. follow = Fabricate(:follow, account: account, target_account: target_account)
  910. follow.destroy!
  911. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  912. expect(unfollow_salmon.content.text).to eq 'account is no longer following target_account@remote'
  913. end
  914. it 'appends author element with account' do
  915. account = Fabricate(:account, domain: nil, username: 'username')
  916. follow = Fabricate(:follow, account: account)
  917. follow.destroy!
  918. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  919. expect(unfollow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  920. end
  921. it 'appends activity:object-type element with activity type' do
  922. follow = Fabricate(:follow)
  923. follow.destroy!
  924. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  925. object_type = unfollow_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  926. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  927. end
  928. it 'appends activity:verb element with follow' do
  929. follow = Fabricate(:follow)
  930. follow.destroy!
  931. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  932. verb = unfollow_salmon.nodes.find { |node| node.name == 'activity:verb' }
  933. expect(verb.text).to eq OStatus::TagManager::VERBS[:unfollow]
  934. end
  935. it 'appends activity:object element with target account' do
  936. target_account = Fabricate(:account, domain: 'domain', uri: 'https://domain/id')
  937. follow = Fabricate(:follow, target_account: target_account)
  938. follow.destroy!
  939. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  940. object = unfollow_salmon.nodes.find { |node| node.name == 'activity:object' }
  941. expect(object.id.text).to eq 'https://domain/id'
  942. end
  943. it 'returns element whose rendered view triggers unfollow when processed' do
  944. follow = Fabricate(:follow)
  945. follow.destroy!
  946. unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
  947. xml = OStatus::AtomSerializer.render(unfollow_salmon)
  948. follow.account.follow!(follow.target_account)
  949. envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
  950. ProcessInteractionService.new.call(envelope, follow.target_account)
  951. expect(follow.account.following?(follow.target_account)).to be false
  952. end
  953. end
  954. describe '#follow_request_salmon' do
  955. include_examples 'namespaces' do
  956. def serialize
  957. follow_request = Fabricate(:follow_request)
  958. OStatus::AtomSerializer.new.follow_request_salmon(follow_request)
  959. end
  960. end
  961. context do
  962. def serialize(follow_request)
  963. OStatus::AtomSerializer.new.follow_request_salmon(follow_request)
  964. end
  965. it_behaves_like 'follow request salmon'
  966. it 'appends id element with unique tag' do
  967. follow_request = Fabricate(:follow_request, created_at: '2000-01-01T00:00:00Z')
  968. follow_request_salmon = serialize(follow_request)
  969. expect(follow_request_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow_request.id}:objectType=FollowRequest"
  970. end
  971. it 'appends title element with description' do
  972. account = Fabricate(:account, domain: nil, username: 'account')
  973. target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
  974. follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
  975. follow_request_salmon = serialize(follow_request)
  976. expect(follow_request_salmon.title.text).to eq 'account requested to follow target_account@remote'
  977. end
  978. it 'returns element whose rendered view triggers follow request when processed' do
  979. follow_request = Fabricate(:follow_request)
  980. follow_request_salmon = serialize(follow_request)
  981. xml = OStatus::AtomSerializer.render(follow_request_salmon)
  982. envelope = OStatus2::Salmon.new.pack(xml, follow_request.account.keypair)
  983. follow_request.destroy!
  984. ProcessInteractionService.new.call(envelope, follow_request.target_account)
  985. expect(follow_request.account.requested?(follow_request.target_account)).to eq true
  986. end
  987. end
  988. end
  989. describe '#authorize_follow_request_salmon' do
  990. include_examples 'namespaces' do
  991. def serialize
  992. follow_request = Fabricate(:follow_request)
  993. OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  994. end
  995. end
  996. it_behaves_like 'follow request salmon' do
  997. def serialize(follow_request)
  998. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  999. authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
  1000. end
  1001. end
  1002. it 'appends id element with unique tag' do
  1003. follow_request = Fabricate(:follow_request)
  1004. time_before = Time.now
  1005. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  1006. time_after = Time.now
  1007. expect(authorize_follow_request_salmon.id.text).to(
  1008. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))
  1009. .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest')))
  1010. )
  1011. end
  1012. it 'appends title element with description' do
  1013. account = Fabricate(:account, domain: 'remote', username: 'account')
  1014. target_account = Fabricate(:account, domain: nil, username: 'target_account')
  1015. follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
  1016. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  1017. expect(authorize_follow_request_salmon.title.text).to eq 'target_account authorizes follow request by account@remote'
  1018. end
  1019. it 'appends activity:object-type element with activity type' do
  1020. follow_request = Fabricate(:follow_request)
  1021. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  1022. object_type = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  1023. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  1024. end
  1025. it 'appends activity:verb element with authorize' do
  1026. follow_request = Fabricate(:follow_request)
  1027. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  1028. verb = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
  1029. expect(verb.text).to eq OStatus::TagManager::VERBS[:authorize]
  1030. end
  1031. it 'returns element whose rendered view creates follow from follow request when processed' do
  1032. follow_request = Fabricate(:follow_request)
  1033. authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
  1034. xml = OStatus::AtomSerializer.render(authorize_follow_request_salmon)
  1035. envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
  1036. ProcessInteractionService.new.call(envelope, follow_request.account)
  1037. expect(follow_request.account.following?(follow_request.target_account)).to eq true
  1038. expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
  1039. end
  1040. end
  1041. describe '#reject_follow_request_salmon' do
  1042. include_examples 'namespaces' do
  1043. def serialize
  1044. follow_request = Fabricate(:follow_request)
  1045. OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1046. end
  1047. end
  1048. it_behaves_like 'follow request salmon' do
  1049. def serialize(follow_request)
  1050. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1051. reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
  1052. end
  1053. end
  1054. it 'appends id element with unique tag' do
  1055. follow_request = Fabricate(:follow_request)
  1056. time_before = Time.now
  1057. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1058. time_after = Time.now
  1059. expect(reject_follow_request_salmon.id.text).to(
  1060. eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))
  1061. .or(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest'))
  1062. )
  1063. end
  1064. it 'appends title element with description' do
  1065. account = Fabricate(:account, domain: 'remote', username: 'account')
  1066. target_account = Fabricate(:account, domain: nil, username: 'target_account')
  1067. follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
  1068. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1069. expect(reject_follow_request_salmon.title.text).to eq 'target_account rejects follow request by account@remote'
  1070. end
  1071. it 'appends activity:object-type element with activity type' do
  1072. follow_request = Fabricate(:follow_request)
  1073. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1074. object_type = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
  1075. expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
  1076. end
  1077. it 'appends activity:verb element with authorize' do
  1078. follow_request = Fabricate(:follow_request)
  1079. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1080. verb = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
  1081. expect(verb.text).to eq OStatus::TagManager::VERBS[:reject]
  1082. end
  1083. it 'returns element whose rendered view deletes follow request when processed' do
  1084. follow_request = Fabricate(:follow_request)
  1085. reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
  1086. xml = OStatus::AtomSerializer.render(reject_follow_request_salmon)
  1087. envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
  1088. ProcessInteractionService.new.call(envelope, follow_request.account)
  1089. expect(follow_request.account.following?(follow_request.target_account)).to eq false
  1090. expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
  1091. end
  1092. end
  1093. describe '#object' do
  1094. include_examples 'status attributes' do
  1095. def serialize(status)
  1096. OStatus::AtomSerializer.new.object(status)
  1097. end
  1098. end
  1099. it 'returns activity:object element' do
  1100. status = Fabricate(:status)
  1101. object = OStatus::AtomSerializer.new.object(status)
  1102. expect(object.name).to eq 'activity:object'
  1103. end
  1104. it 'appends id element with URL for status' do
  1105. status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
  1106. object = OStatus::AtomSerializer.new.object(status)
  1107. expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
  1108. end
  1109. it 'appends published element with created date' do
  1110. status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
  1111. object = OStatus::AtomSerializer.new.object(status)
  1112. expect(object.published.text).to eq '2000-01-01T00:00:00Z'
  1113. end
  1114. it 'appends updated element with updated date' do
  1115. status = Fabricate(:status)
  1116. status.updated_at = '2000-01-01T00:00:00Z'
  1117. object = OStatus::AtomSerializer.new.object(status)
  1118. expect(object.updated.text).to eq '2000-01-01T00:00:00Z'
  1119. end
  1120. it 'appends title element with title' do
  1121. account = Fabricate(:account, username: 'username')
  1122. status = Fabricate(:status, account: account)
  1123. object = OStatus::AtomSerializer.new.object(status)
  1124. expect(object.title.text).to eq 'New status by username'
  1125. end
  1126. it 'appends author element with account' do
  1127. account = Fabricate(:account, username: 'username')
  1128. status = Fabricate(:status, account: account)
  1129. entry = OStatus::AtomSerializer.new.object(status)
  1130. expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
  1131. end
  1132. it 'appends activity:object-type element with object type' do
  1133. status = Fabricate(:status)
  1134. entry = OStatus::AtomSerializer.new.object(status)
  1135. object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }
  1136. expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]
  1137. end
  1138. it 'appends activity:verb element with verb' do
  1139. status = Fabricate(:status)
  1140. entry = OStatus::AtomSerializer.new.object(status)
  1141. object_type = entry.nodes.find { |node| node.name == 'activity:verb' }
  1142. expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]
  1143. end
  1144. it 'appends link element for an alternative' do
  1145. account = Fabricate(:account, username: 'username')
  1146. status = Fabricate(:status, account: account)
  1147. entry = OStatus::AtomSerializer.new.object(status)
  1148. link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
  1149. expect(link[:type]).to eq 'text/html'
  1150. expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
  1151. end
  1152. it 'appends thr:in-reply-to element if it is a reply and thread is not nil' do
  1153. account = Fabricate(:account, username: 'username')
  1154. thread = Fabricate(:status, account: account, created_at: '2000-01-01T00:00:00Z')
  1155. reply = Fabricate(:status, thread: thread)
  1156. entry = OStatus::AtomSerializer.new.object(reply)
  1157. in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
  1158. expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}"
  1159. expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{thread.id}"
  1160. end
  1161. it 'does not append thr:in-reply-to element if thread is nil' do
  1162. status = Fabricate(:status, thread: nil)
  1163. entry = OStatus::AtomSerializer.new.object(status)
  1164. entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }
  1165. end
  1166. it 'does not append ostatus:conversation element if conversation_id is nil' do
  1167. status = Fabricate.build(:status, conversation_id: nil)
  1168. status.save!(validate: false)
  1169. entry = OStatus::AtomSerializer.new.object(status)
  1170. entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }
  1171. end
  1172. it 'appends ostatus:conversation element if conversation_id is not nil' do
  1173. status = Fabricate(:status)
  1174. status.conversation.update!(created_at: '2000-01-01T00:00:00Z')
  1175. entry = OStatus::AtomSerializer.new.object(status)
  1176. conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }
  1177. expect(conversation[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation.id}:objectType=Conversation"
  1178. end
  1179. end
  1180. end