@ -0,0 +1,13 @@ | |||||
Mastodon | |||||
======== | |||||
Mastodon is a federated microblogging engine. An alternative implementation of the GNU Social project. Based on ActivityStreams, Webfinger, PubsubHubbub and Salmon. | |||||
The core ideals of this project are: | |||||
- Independence of legacy Twitter APIs - we don't want to be compatible with Twitter clients, we want our own clients | |||||
- In that vein, a strong and clean REST API and OAuth2 | |||||
- Minimalism. Just because you can do almost anything with ActivityStreams doesn't mean you should. Limit the set of possible functions to what makes sense in a microblogging engine. This will make federation as well as UI design a lot easier | |||||
- Ease of deployment. The end-goal of this project is to be distributable as a Docker image. | |||||
**Current status of the project is early development. Documentation, licensing information &co will be added later** |
@ -1,28 +0,0 @@ | |||||
== README | |||||
This README would normally document whatever steps are necessary to get the | |||||
application up and running. | |||||
Things you may want to cover: | |||||
* Ruby version | |||||
* System dependencies | |||||
* Configuration | |||||
* Database creation | |||||
* Database initialization | |||||
* How to run the test suite | |||||
* Services (job queues, cache servers, search engines, etc.) | |||||
* Deployment instructions | |||||
* ... | |||||
Please feel free to use a different markup language if you do not plan to run | |||||
<tt>rake doc:app</tt>. |
@ -1,5 +1,101 @@ | |||||
module AtomHelper | module AtomHelper | ||||
def stream_updated_at | def stream_updated_at | ||||
@account.stream_entries.last ? @account.stream_entries.last.created_at.iso8601 : @account.updated_at.iso8601 | |||||
@account.stream_entries.last ? @account.stream_entries.last.created_at : @account.updated_at | |||||
end | |||||
def entry(xml, is_root, &block) | |||||
if is_root | |||||
root_tag(xml, :entry, &block) | |||||
else | |||||
xml.entry &block | |||||
end | |||||
end | |||||
def feed(xml, &block) | |||||
root_tag(xml, :feed, &block) | |||||
end | |||||
def unique_id(xml, date, id, type) | |||||
xml.id_ unique_tag(date, id, type) | |||||
end | |||||
def simple_id(xml, id) | |||||
xml.id_ id | |||||
end | |||||
def published_at(xml, date) | |||||
xml.published date.iso8601 | |||||
end | |||||
def updated_at(xml, date) | |||||
xml.updated date.iso8601 | |||||
end | |||||
def verb(xml, verb) | |||||
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{verb}") | |||||
end | |||||
def content(xml, content) | |||||
xml.content({ type: 'html' }, content) | |||||
end | |||||
def title(xml, title) | |||||
xml.title title | |||||
end | |||||
def author(xml, &block) | |||||
xml.author &block | |||||
end | |||||
def target(xml, &block) | |||||
xml['activity'].object &block | |||||
end | |||||
def object_type(xml, type) | |||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{type}") | |||||
end | |||||
def uri(xml, uri) | |||||
xml.uri uri | |||||
end | |||||
def name(xml, name) | |||||
xml.name name | |||||
end | |||||
def summary(xml, summary) | |||||
xml.summary summary | |||||
end | |||||
def subtitle(xml, subtitle) | |||||
xml.subtitle subtitle | |||||
end | |||||
def link_alternate(xml, url) | |||||
xml.link(rel: 'alternate', type: 'text/html', href: url) | |||||
end | |||||
def link_self(xml, url) | |||||
xml.link(rel: 'self', type: 'application/atom+xml', href: url) | |||||
end | |||||
def link_hub(xml, url) | |||||
xml.link(rel: 'hub', href: url) | |||||
end | |||||
def link_salmon(xml, url) | |||||
xml.link(rel: 'salmon', href: url) | |||||
end | |||||
def portable_contact(xml, account) | |||||
xml['poco'].preferredUsername account.username | |||||
xml['poco'].displayName account.display_name | |||||
xml['poco'].note account.note | |||||
end | |||||
private | |||||
def root_tag(xml, tag, &block) | |||||
xml.send(tag, {xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0'}, &block) | |||||
end | end | ||||
end | end |
@ -1,39 +1,37 @@ | |||||
Nokogiri::XML::Builder.new do |xml| | Nokogiri::XML::Builder.new do |xml| | ||||
xml.entry(xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0') do | |||||
xml.id_ unique_tag(@entry.created_at, @entry.activity_id, @entry.activity_type) | |||||
entry(xml, true) do | |||||
unique_id xml, @entry.created_at, @entry.activity_id, @entry.activity_type | |||||
published_at xml, @entry.activity.created_at | |||||
updated_at xml, @entry.activity.updated_at | |||||
title xml, @entry.title | |||||
content xml, @entry.content | |||||
verb xml, @entry.verb | |||||
xml.published @entry.activity.created_at.iso8601 | |||||
xml.updated @entry.activity.updated_at.iso8601 | |||||
xml.title @entry.title | |||||
xml.content({ type: 'html' }, @entry.content) | |||||
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{@entry.verb}") | |||||
xml.author do | |||||
xml['activity'].send('object-type', 'http://activitystrea.ms/schema/1.0/person') | |||||
xml.uri profile_url(name: @entry.account.username) | |||||
xml.name @entry.account.username | |||||
xml.summary @entry.account.note | |||||
xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @entry.account.username)) | |||||
xml['poco'].preferredUsername @entry.account.username | |||||
xml['poco'].displayName @entry.account.display_name | |||||
xml['poco'].note @entry.account.note | |||||
author(xml) do | |||||
object_type xml, :person | |||||
uri xml, profile_url(name: @entry.account.username) | |||||
name xml, @entry.account.username | |||||
summary xml, @entry.account.note | |||||
link_alternate xml, profile_url(name: @entry.account.username) | |||||
portable_contact xml, @entry.account | |||||
end | end | ||||
if @entry.targeted? | if @entry.targeted? | ||||
xml['activity'].send('object') do | |||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{@entry.target.object_type}") | |||||
xml.id_ @entry.target.uri | |||||
xml.title @entry.target.title | |||||
xml.summary @entry.target.summary | |||||
xml.link(rel: 'alternate', type: 'text/html', href: @entry.target.uri) | |||||
target(xml) do | |||||
object_type xml, @entry.target.object_type | |||||
simple_id xml, @entry.target.uri | |||||
title xml, @entry.target.title | |||||
summary xml, @entry.target.summary | |||||
link_alternate xml, @entry.target.uri | |||||
if @entry.target.object_type == :person | |||||
portable_contact xml, @entry.target | |||||
end | |||||
end | end | ||||
else | else | ||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{@entry.object_type}") | |||||
object_type xml, @entry.object_type | |||||
end | end | ||||
xml.link(rel: 'self', type: 'application/atom+xml', href: atom_entry_url(id: @entry.id)) | |||||
link_self xml, atom_entry_url(id: @entry.id) | |||||
end | end | ||||
end.to_xml | |||||
end |
@ -1,52 +1,49 @@ | |||||
Nokogiri::XML::Builder.new do |xml| | Nokogiri::XML::Builder.new do |xml| | ||||
xml.feed(xmlns: 'http://www.w3.org/2005/Atom', 'xmlns:thr': 'http://purl.org/syndication/thread/1.0', 'xmlns:activity': 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco': 'http://portablecontacts.net/spec/1.0') do | |||||
xml.id_ atom_user_stream_url(id: @account.id) | |||||
xml.title @account.display_name | |||||
xml.subtitle @account.note | |||||
xml.updated stream_updated_at | |||||
xml.author do | |||||
xml['activity'].send('object-type', 'http://activitystrea.ms/schema/1.0/person') | |||||
xml.uri profile_url(name: @account.username) | |||||
xml.name @account.username | |||||
xml.summary @account.note | |||||
xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username)) | |||||
xml['poco'].preferredUsername @account.username | |||||
xml['poco'].displayName @account.display_name | |||||
xml['poco'].note @account.note | |||||
feed(xml) do | |||||
simple_id xml, atom_user_stream_url(id: @account.id) | |||||
title xml, @account.display_name | |||||
subtitle xml, @account.note | |||||
updated_at xml, stream_updated_at | |||||
author(xml) do | |||||
object_type xml, :person | |||||
uri xml, profile_url(name: @account.username) | |||||
name xml, @account.username | |||||
summary xml, @account.note | |||||
link_alternate xml, profile_url(name: @account.username) | |||||
portable_contact xml, @account | |||||
end | end | ||||
xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username)) | |||||
xml.link(rel: 'hub', href: HUB_URL) | |||||
xml.link(rel: 'salmon', href: salmon_url(@account)) | |||||
xml.link(rel: 'self', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id)) | |||||
link_alternate xml, profile_url(name: @account.username) | |||||
link_self xml, atom_user_stream_url(id: @account.id) | |||||
link_hub xml, HUB_URL | |||||
link_salmon xml, salmon_url(@account) | |||||
@account.stream_entries.order('id desc').each do |stream_entry| | @account.stream_entries.order('id desc').each do |stream_entry| | ||||
xml.entry do | |||||
xml.id_ unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type) | |||||
xml.published stream_entry.activity.created_at.iso8601 | |||||
xml.updated stream_entry.activity.updated_at.iso8601 | |||||
xml.title stream_entry.title | |||||
xml.content({ type: 'html' }, stream_entry.content) | |||||
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{stream_entry.verb}") | |||||
entry(xml, false) do | |||||
unique_id xml, stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type | |||||
published_at xml, stream_entry.activity.created_at | |||||
updated_at xml, stream_entry.activity.updated_at | |||||
title xml, stream_entry.title | |||||
content xml, stream_entry.content | |||||
verb xml, stream_entry.verb | |||||
link_self xml, atom_entry_url(id: stream_entry.id) | |||||
if stream_entry.targeted? | if stream_entry.targeted? | ||||
xml['activity'].send('object') do | |||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.target.object_type}") | |||||
xml.id_ stream_entry.target.uri | |||||
xml.title stream_entry.target.title | |||||
xml.summary stream_entry.target.summary | |||||
xml.link(rel: 'alternate', type: 'text/html', href: stream_entry.target.uri) | |||||
target(xml) do | |||||
object_type xml, stream_entry.target.object_type | |||||
simple_id xml, stream_entry.target.uri | |||||
title xml, stream_entry.target.title | |||||
summary xml, stream_entry.target.summary | |||||
link_alternate xml, stream_entry.target.uri | |||||
if stream_entry.target.object_type == :person | |||||
portable_contact xml, stream_entry.target | |||||
end | |||||
end | end | ||||
else | else | ||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}") | |||||
object_type xml, stream_entry.object_type | |||||
end | end | ||||
xml.link(rel: 'self', type: 'application/atom+xml', href: atom_entry_url(id: stream_entry.id)) | |||||
end | end | ||||
end | end | ||||
end | end | ||||