34 Commits

Author SHA1 Message Date
253ab26520 Adding more tests for helpers 2016-03-20 13:50:22 +01:00
b640f35621 Writing out more tests, fixed some bugs 2016-03-20 13:03:06 +01:00
e14b76c7cb On following/followers pages, show most recent first 2016-03-19 22:54:40 +01:00
7e53efae31 Fix for incoming favourites 2016-03-19 22:46:58 +01:00
f4ad2fb35a Strip out HTML in plain text notification e-mails. Oh, and fix #14 2016-03-19 19:34:31 +01:00
2b116131d7 Adding e-mail notifications about mentions, follows, favourites and reblogs. Fixing another mention recording bug 2016-03-19 19:20:07 +01:00
e2b846f630 Adding letter opener for development and Rack::Attack for future rate limiting implementations 2016-03-19 14:57:30 +01:00
5d72b92271 Improving account grid cards layout for longer usernames and notes 2016-03-19 14:11:09 +01:00
71ae4dd3d2 Adding public following and followers pages, fix #3 2016-03-19 14:02:30 +01:00
c349200761 Removing some unused gems, adding pagination to profiles, fix #10 2016-03-19 12:49:34 +01:00
d4892ace62 Adding more test stubs 2016-03-19 12:13:47 +01:00
66a2107527 Turns out that replies don't have to have the type comment. Changed handling
of those to depend on presence of <thr:in-reply-to /> instead
2016-03-19 11:59:23 +01:00
111f2a1d48 Adding section on updating to the latest version
[ci skip]
2016-03-19 01:14:55 +01:00
f97fc9744f Use FanOutOnWriteService AFTER processing mentions 2016-03-19 00:41:29 +01:00
47d1cb4e21 TIL a return from a block seems to return from the whole method rather than
the block, even though the last line of a block is an implicit return. I am
confused to say the least
2016-03-19 00:23:46 +01:00
071f64d317 Fix #13, Atom feeds now contain formatted post content 2016-03-19 00:16:04 +01:00
580b91c387 Fix more subtle bugs with first_or_create 2016-03-19 00:02:39 +01:00
48aeacd5f9 Fixed ANOTHER first_or_create bug. Seriously who came up with that API smh 2016-03-18 23:47:02 +01:00
7837afbb5f Removing autogenerated test stubs that were not needed 2016-03-18 23:36:54 +01:00
94eb142ab8 Updating Travis CI file to setup the test environment correctly 2016-03-18 23:31:07 +01:00
9a7485d034 Fix typo on /api/accounts/:id/statuses, fix potential case-sensitivity issue
when registering incoming status mentions, add Travis CI file
2016-03-18 23:23:19 +01:00
15476d505d Adding favicon 2016-03-18 12:36:57 +01:00
323474c97e Fix #2, add rake task for PuSH-unsubscribing from remote users who have no
local followers. Remote users' usernames SHOULD be case-sensitive
2016-03-17 12:02:45 +01:00
af7ae348d7 Include AtomBuilderHelper (which declared url_for_target) to all services 2016-03-16 22:44:04 +01:00
e239fc3050 Fix error when unfollowing somebody who wasn't followed in the first place 2016-03-16 21:23:40 +01:00
d022975444 Fixing small bug with FollowRemoteAccountService usage 2016-03-16 21:20:50 +01:00
086d487145 Fix unfollows 2016-03-16 21:14:39 +01:00
9cb690c706 Access tokens no longer expire, case-insensitive local username validation, as well as case-insensitive Webfinger look-up 2016-03-16 18:29:52 +01:00
786397e15d Adjusted todo list 2016-03-16 13:02:17 +01:00
55ca59a66c Improved readme 2016-03-16 13:00:25 +01:00
48d66a2055 Fixing the docker container setup (with assets compilation &co) 2016-03-16 12:57:01 +01:00
2c374cd97c Adding e-mail configuration 2016-03-16 12:13:40 +01:00
8767a98fbb Adding CSS for form errors, adding missing indices 2016-03-16 11:46:25 +01:00
a9db42a956 Validations for local profiles 2016-03-16 11:18:09 +01:00
106 changed files with 2020 additions and 274 deletions

View File

@ -1,5 +1,23 @@
# Service dependencies
REDIS_HOST=redis
REDIS_PORT=6379
DB_HOST=db
DB_USER=postgres
DB_NAME=postgres
DB_PASS=
DB_PORT=5432
# Federation
LOCAL_DOMAIN=example.com
LOCAL_HTTPS=true
# Application secrets
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
# E-mail configuration
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=notifications@example.com

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
language: ruby
cache: bundler
env:
global:
- LOCAL_DOMAIN=example.com
- LOCAL_HTTPS=false
addons:
postgresql: 9.4
rvm:
- 2.2.4
services:
- redis-server
bundler_args: --without development --retry=3 --jobs=3
before_script:
- bundle exec rake db:create db:migrate
script: bundle exec rspec

View File

@ -2,7 +2,7 @@ FROM ruby:2.2.4
ENV RAILS_ENV=production
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
RUN mkdir /mastodon
WORKDIR /mastodon
@ -13,3 +13,5 @@ ADD Gemfile.lock /mastodon/Gemfile.lock
RUN bundle install --deployment --without test --without development
ADD . /mastodon
VOLUME ["/mastodon/public/system", "/mastodon/public/assets"]

View File

@ -1,7 +1,6 @@
source 'https://rubygems.org'
gem 'rails', '4.2.5.1'
gem 'sqlite3'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
@ -18,7 +17,6 @@ gem 'font-awesome-rails'
gem 'paranoia', '~> 2.0'
gem 'paperclip', '~> 4.3'
gem 'backport_new_renderer'
gem 'http'
gem 'addressable'
@ -36,6 +34,8 @@ gem 'fast_blank'
gem 'htmlentities'
gem 'onebox'
gem 'simple_form'
gem 'will_paginate', '~> 3.0.6'
gem 'rack-attack'
group :development, :test do
gem 'rspec-rails'
@ -56,6 +56,7 @@ group :development do
gem 'better_errors'
gem 'binding_of_caller'
gem 'rack-mini-profiler'
gem 'letter_opener'
end
group :production do

View File

@ -39,8 +39,6 @@ GEM
addressable (2.4.0)
arel (6.0.3)
ast (2.2.0)
backport_new_renderer (1.0.0)
rails
bcrypt (3.1.11)
better_errors (2.1.1)
coderay (>= 1.0.0)
@ -131,6 +129,10 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.4.1)
launchy (~> 2.2)
libv8 (3.16.14.13)
loofah (2.0.3)
nokogiri (>= 1.5.9)
@ -182,6 +184,8 @@ GEM
rabl (0.12.0)
activesupport (>= 2.3.14)
rack (1.6.4)
rack-attack (4.4.1)
rack
rack-mini-profiler (0.9.9.2)
rack (>= 1.2.0)
rack-test (0.6.3)
@ -283,7 +287,6 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.11)
therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
ref
@ -310,13 +313,13 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
will_paginate (3.0.7)
PLATFORMS
ruby
DEPENDENCIES
addressable
backport_new_renderer
better_errors
binding_of_caller
coffee-rails (~> 4.1.0)
@ -334,6 +337,7 @@ DEPENDENCIES
http
jbuilder (~> 2.0)
jquery-rails
letter_opener
nokogiri
oj
onebox
@ -345,6 +349,7 @@ DEPENDENCIES
puma
quiet_assets
rabl
rack-attack
rack-mini-profiler
rails (= 4.2.5.1)
rails_12factor
@ -356,11 +361,11 @@ DEPENDENCIES
sdoc (~> 0.4.0)
simple_form
simplecov
sqlite3
therubyracer
uglifier (>= 1.3.0)
web-console (~> 2.0)
webmock
will_paginate (~> 3.0.6)
BUNDLED WITH
1.11.2

View File

@ -1,6 +1,8 @@
Mastodon
========
[![Build Status](https://travis-ci.org/Gargron/mastodon.svg?branch=master)](https://travis-ci.org/Gargron/mastodon)
Mastodon is a federated microblogging engine. An alternative implementation of the GNU Social project. Based on ActivityStreams, Webfinger, PubsubHubbub and Salmon.
**Current status of the project is early development. Documentation &co will be added later**
@ -18,18 +20,14 @@ Mastodon is a federated microblogging engine. An alternative implementation of t
- Upload header image for profile page
- Deleting statuses, deletion propagation
Missing:
- Media attachments (photos, videos)
- UI to post, reblog, favourite, follow and unfollow
- Streaming API
## Configuration
- `LOCAL_DOMAIN` should be the domain/hostname of your instance. This is **absolutely required** as it is used for generating unique IDs for everything federation-related
- `LOCAL_HTTPS` set it to `true` if HTTPS works on your website. This is used to generate canonical URLs, which is also important when generating and parsing federation-related IDs
- `HUB_URL` should be the URL of the PubsubHubbub service that your instance is going to use. By default it is the open service of Superfeedr
Consult the example configuration file, `.env.production.sample` for the full list.
## Requirements
- PostgreSQL
@ -37,14 +35,36 @@ Missing:
## Running with Docker and Docker-Compose
The project now includes a Dockerfile and a docker-compose.yml. You need to turn .env.production sample into .env.production with all the variables set before you can:
The project now includes a `Dockerfile` and a `docker-compose.yml`. You need to turn `.env.production.sample` into `.env.production` with all the variables set before you can:
docker-compose build
And finally
docker-compose up
docker-compose up -d
As usual, the first thing you would need to do would be to run migrations:
docker-compose run web rake db:migrate
And since the instance running in the container will be running in production mode, you need to pre-compile assets:
docker-compose run web rake assets:precompile
The container has two volumes, for the assets and for user uploads. The default docker-compose.yml maps them to the repository's `public/assets` and `public/system` directories, you may wish to put them somewhere else. Likewise, the PostgreSQL and Redis images have data containers that you may wish to map somewhere where you know how to find them and back them up.
### Updating
This approach makes updating to the latest version a real breeze.
git pull
To pull down the updates, re-run
docker-compose build
And finally,
docker-compose up -d
Which will re-create the updated containers, leaving databases and data as is. Depending on what files have been updated, you might need to re-run migrations and asset compilation.

View File

@ -2,7 +2,7 @@
background: #282c37;
background-size: cover;
padding: 60px 0;
padding-bottom: 10px;
padding-bottom: 0;
border-radius: 4px 4px 0 0;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
overflow: hidden;
@ -64,8 +64,45 @@
width: 80px;
color: #9baec8;
padding: 0 10px;
margin-bottom: 10px;
border-right: 1px solid #9baec8;
cursor: default;
position: relative;
a {
display: block;
}
&:after {
display: block;
content: "";
position: absolute;
bottom: -10px;
left: 0;
width: 100%;
border-bottom: 4px solid #9baec8;
opacity: 0.5;
transition: all 0.8s ease;
}
&.active {
&:after {
border-bottom: 4px solid #2b90d9;
opacity: 1;
}
}
&:hover {
&:after {
opacity: 1;
transition-duration: 0.2s;
}
}
a {
text-decoration: none;
color: inherit;
}
.counter-label {
font-size: 12px;
@ -89,3 +126,146 @@
color: #d9e1e8;
}
}
.pagination {
padding: 30px 0;
text-align: center;
overflow: hidden;
a, .current, .next_page, .previous_page, .gap {
font-size: 14px;
color: #fff;
font-weight: 500;
display: inline-block;
padding: 6px 10px;
text-decoration: none;
}
.current {
background: #fff;
border-radius: 100px;
color: #282c37;
cursor: default;
}
.gap {
cursor: default;
}
.previous_page, .next_page {
text-transform: uppercase;
color: #d9e1e8;
}
.previous_page {
float: left;
padding-left: 0;
.fa {
display: inline-block;
margin-right: 5px;
}
}
.next_page {
float: right;
padding-right: 0;
.fa {
display: inline-block;
margin-left: 5px;
}
}
.disabled {
cursor: default;
color: lighten(#282c37, 10%);
}
}
.accounts-grid {
clear: both;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
background: #fff;
border-radius: 0 0 4px 4px;
padding: 20px 10px;
padding-bottom: 10px;
overflow: hidden;
.account-grid-card {
box-sizing: border-box;
width: 335px;
float: left;
border: 1px solid #d9e1e8;
border-radius: 4px;
color: #282c37;
height: 160px;
margin-bottom: 10px;
&:nth-child(odd) {
margin-right: 10px;
}
.account-grid-card__header {
overflow: hidden;
padding: 10px;
border-bottom: 1px solid #d9e1e8;
}
.avatar {
width: 60px;
height: 60px;
float: left;
margin-right: 15px;
img {
display: block;
width: 60px;
height: 60px;
border-radius: 60px;
}
}
.name {
width: 333-20-60-15px;
float: left;
padding-top: 10px;
a {
display: block;
color: #282c37;
text-decoration: none;
&:hover {
.display_name {
text-decoration: underline;
}
}
}
}
.display_name {
font-size: 14px;
display: block;
}
.username {
color: #2b90d9;
}
.note {
padding: 10px;
padding-top: 15px;
color: #9baec8;
}
}
}
.nothing-here {
color: #9baec8;
font-size: 14px;
font-weight: 500;
text-align: center;
padding: 15px 0;
cursor: default;
}

View File

@ -1,3 +0,0 @@
// Place all the styles related to the Api::Accounts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the API::Follows controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the API::Salmon controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the API::Statuses controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the API::Subscriptions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,12 +1,3 @@
$primary-color: #ff7473;
$secondary-color: #ffc952;
$tertiary-color: #47b8e0;
$quaternary-color: #34314c;
$background-color: #fff;
$darker-background-color: #e3dede;
$text-color: #333030;
$lighter-text-color: #8b8687;
@import url(https://fonts.googleapis.com/css?family=Roboto:400,500,400italic);
@import url(https://fonts.googleapis.com/css?family=Roboto+Mono:400,500);
@import "font-awesome";

View File

@ -214,6 +214,12 @@
text-align: center;
}
.error_notification {
color: #df405a;
font-weight: 500;
margin-bottom: 15px;
}
.input {
margin-bottom: 15px;
@ -238,7 +244,7 @@
font-size: 14px;
font-family: 'Roboto', sans-serif;
&:focus {
&:focus, &:active {
border-bottom: 2px solid #2b90d9;
padding-bottom: 5px;
}
@ -253,6 +259,24 @@
margin-top: 5px;
color: lighten(#282c37, 25%);
}
&.field_with_errors {
input[type=text], input[type=email], input[type=password], textarea {
border-bottom: 2px solid #df405a;
padding-bottom: 5px;
&:focus, &:active {
border-bottom: 2px solid #2b90d9;
padding-bottom: 5px;
}
}
.error {
display: block;
margin-top: 5px;
color: #df405a;
}
}
}
}

View File

@ -1,3 +0,0 @@
// Place all the styles related to the oauth::applications controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -8,11 +8,19 @@ class AccountsController < ApplicationController
@statuses = @account.statuses.order('id desc').with_includes.with_counters
respond_to do |format|
format.html
format.html { @statuses = @statuses.paginate(page: params[:page], per_page: 10)}
format.atom
end
end
def followers
@followers = @account.followers.order('follows.created_at desc').paginate(page: params[:page], per_page: 6)
end
def following
@following = @account.following.order('follows.created_at desc').paginate(page: params[:page], per_page: 6)
end
private
def set_account

View File

@ -15,16 +15,21 @@ class Api::AccountsController < ApiController
end
def statuses
@statuses = @account.statuses.with_includes.with_counts.order('created_at desc')
@statuses = @account.statuses.with_includes.with_counters.order('created_at desc')
end
def follow
@follow = current_user.account.follow!(@account)
if @account.local?
@follow = current_user.account.follow!(@account)
else
@follow = FollowService.new.(current_user.account, @account.acct)
end
render action: :show
end
def unfollow
@unfollow = current_user.account.unfollow!(@account)
@unfollow = UnfollowService.new.(current_user.account, @account)
render action: :show
end

View File

@ -12,7 +12,7 @@ class Api::SubscriptionsController < ApiController
def update
body = request.body.read
if @account.subscription(api_subscription_url(@account.id)).verify(body, env['HTTP_X_HUB_SIGNATURE'])
if @account.subscription(api_subscription_url(@account.id)).verify(body, request.headers['HTTP_X_HUB_SIGNATURE'])
ProcessFeedService.new.(body, @account)
render nothing: true, status: 201
else

View File

@ -1,5 +1,6 @@
class ApiController < ApplicationController
protect_from_forgery with: :null_session
skip_before_filter :verify_authenticity_token
protected

View File

@ -6,7 +6,7 @@ class XrdController < ApplicationController
end
def webfinger
@account = Account.find_by!(username: username_from_resource, domain: nil)
@account = Account.find_local!(username_from_resource)
@canonical_account_uri = "acct:#{@account.username}@#{Rails.configuration.x.local_domain}"
@magic_key = pem_to_magic_key(@account.keypair.public_key)
rescue ActiveRecord::RecordNotFound
@ -21,10 +21,10 @@ class XrdController < ApplicationController
end
def username_from_resource
if params[:resource].start_with?('acct:')
params[:resource].split('@').first.gsub('acct:', '')
if resource_param.start_with?('acct:')
resource_param.split('@').first.gsub('acct:', '')
else
url = Addressable::URI.parse(params[:resource])
url = Addressable::URI.parse(resource_param)
url.path.gsub('/users/', '')
end
end
@ -43,4 +43,8 @@ class XrdController < ApplicationController
(["RSA"] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
end
def resource_param
params.require(:resource)
end
end

View File

@ -1,3 +1,5 @@
module AccountsHelper
def pagination_options
{ previous_label: "#{fa_icon('chevron-left')} Prev".html_safe, next_label: "Next #{fa_icon('chevron-right')}".html_safe, inner_window: 2 }
end
end

View File

@ -12,6 +12,17 @@ module ApplicationHelper
id.start_with?("tag:#{Rails.configuration.x.local_domain}")
end
def linkify(status)
mention_hash = {}
status.mentions.each { |m| mention_hash[m.acct] = m }
coder = HTMLEntities.new
auto_link(coder.encode(status.text), link: :urls, html: { rel: 'nofollow noopener' }).gsub(Account::MENTION_RE) do |m|
account = mention_hash[Account::MENTION_RE.match(m)[1]]
"#{m.split('@').first}<a href=\"#{url_for_target(account)}\" class=\"mention\">@<span>#{account.acct}</span></a>"
end.html_safe
end
def active_nav_class(path)
current_page?(path) ? 'active' : ''
end

View File

@ -3,7 +3,7 @@ module AtomBuilderHelper
@account.stream_entries.last ? (@account.updated_at > @account.stream_entries.last.created_at ? @account.updated_at : @account.stream_entries.last.created_at) : @account.updated_at
end
def entry(xml, is_root, &block)
def entry(xml, is_root = false, &block)
if is_root
root_tag(xml, :entry, &block)
else
@ -135,6 +135,22 @@ module AtomBuilderHelper
xml.logo url
end
def conditionally_formatted(activity)
if activity.is_a?(Status)
if activity.reblog? && activity.reblog.local?
linkify(activity.reblog)
elsif activity.local?
linkify(activity)
else
activity.content
end
elsif activity.nil?
''
else
activity.content
end
end
def include_author(xml, account)
object_type xml, :person
uri xml, url_for_target(account)
@ -150,7 +166,7 @@ module AtomBuilderHelper
published_at xml, stream_entry.created_at
updated_at xml, stream_entry.updated_at
title xml, stream_entry.title
content xml, stream_entry.content
content xml, conditionally_formatted(stream_entry.activity)
verb xml, stream_entry.verb
link_self xml, account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom')
object_type xml, stream_entry.object_type
@ -176,7 +192,7 @@ module AtomBuilderHelper
# Statuses have content
if [:note, :comment].include? stream_entry.target.object_type
content xml, stream_entry.target.content
content xml, conditionally_formatted(stream_entry.target)
end
end
end

View File

@ -20,17 +20,6 @@ module StreamEntriesHelper
date < 5.days.ago ? date.strftime("%d.%m.%Y") : "#{time_ago_in_words(date)} ago"
end
def linkify(status)
mention_hash = {}
status.mentions.each { |m| mention_hash[m.acct] = m }
coder = HTMLEntities.new
auto_link(coder.encode(status.text), link: :urls, html: { target: '_blank', rel: 'nofollow' }).gsub(Account::MENTION_RE) do |m|
account = mention_hash[Account::MENTION_RE.match(m)[1]]
"#{m.split('@').first}<a href=\"#{url_for_target(account)}\" class=\"mention\">@<span>#{account.acct}</span></a>"
end.html_safe
end
def reblogged_by_me_class(status)
user_signed_in? && current_user.account.reblogged?(status) ? 'reblogged' : ''
end

View File

@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: (ENV['SMTP_FROM_ADDRESS'] || 'notifications@localhost')
layout 'mailer'
end

View File

@ -0,0 +1,34 @@
class NotificationMailer < ApplicationMailer
helper StreamEntriesHelper
helper AtomBuilderHelper
def mention(mentioned_account, status)
@me = mentioned_account
@status = status
mail to: @me.user.email, subject: "You were mentioned by #{@status.account.acct}"
end
def follow(followed_account, follower)
@me = followed_account
@account = follower
mail to: @me.user.email, subject: "#{@account.acct} is now following you"
end
def favourite(target_status, from_account)
@me = target_status.account
@account = from_account
@status = target_status
mail to: @me.user.email, subject: "#{@account.acct} favourited your status"
end
def reblog(target_status, from_account)
@me = target_status.account
@account = from_account
@status = target_status
mail to: @me.user.email, subject: "#{@account.acct} reblogged your status"
end
end

View File

@ -1,7 +1,8 @@
class Account < ActiveRecord::Base
# Local users
has_one :user, inverse_of: :account
validates :username, uniqueness: { scope: :domain }
validates :username, uniqueness: { scope: :domain, case_sensitive: false }, if: 'local?'
validates :username, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?'
# Avatar upload
attr_reader :avatar_remote_url
@ -12,6 +13,10 @@ class Account < ActiveRecord::Base
has_attached_file :header, styles: { medium: '700x335#' }
validates_attachment_content_type :header, content_type: /\Aimage\/.*\Z/
# Local user profile validations
validates :display_name, length: { maximum: 30 }, if: 'local?'
validates :note, length: { maximum: 124 }, if: 'local?'
# Timelines
has_many :stream_entries, inverse_of: :account
has_many :statuses, inverse_of: :account
@ -32,7 +37,8 @@ class Account < ActiveRecord::Base
end
def unfollow!(other_account)
self.active_relationships.find_by(target_account: other_account).destroy
follow = self.active_relationships.find_by(target_account: other_account)
follow.destroy unless follow.nil?
end
def following?(other_account)
@ -93,6 +99,17 @@ class Account < ActiveRecord::Base
self.username
end
def self.find_local!(username)
table = self.arel_table
self.where(table[:username].matches(username)).where(domain: nil).take!
end
def self.find_local(username)
self.find_local!(username)
rescue ActiveRecord::RecordNotFound
nil
end
before_create do
if local?
keypair = OpenSSL::PKey::RSA.new(Rails.env.test? ? 1024 : 2048)

View File

@ -2,7 +2,7 @@ class Favourite < ActiveRecord::Base
belongs_to :account, inverse_of: :favourites
belongs_to :status, inverse_of: :favourites
has_one :stream_entry, as: :activity, dependent: :destroy
has_one :stream_entry, as: :activity
def verb
:favorite

View File

@ -2,7 +2,7 @@ class Follow < ActiveRecord::Base
belongs_to :account
belongs_to :target_account, class_name: 'Account'
has_one :stream_entry, as: :activity, dependent: :destroy
has_one :stream_entry, as: :activity
validates :account, :target_account, presence: true
validates :account_id, uniqueness: { scope: :target_account_id }

View File

@ -78,6 +78,5 @@ class Status < ActiveRecord::Base
after_create do
self.account.stream_entries.create!(activity: self)
FanOutOnWriteService.new.(self)
end
end

View File

@ -1,4 +1,6 @@
class BaseService
include RoutingHelper
include ActionView::Helpers::TextHelper
include ApplicationHelper
include AtomBuilderHelper
end

View File

@ -16,7 +16,8 @@ class FanOutOnWriteService < BaseService
end
# Deliver to local mentioned
status.mentions.each do |mentioned_account|
status.mentioned_accounts.each do |mention|
mentioned_account = mention.account
next unless mentioned_account.local?
push(:mentions, mentioned_account.id, status)
end

View File

@ -6,8 +6,13 @@ class FavouriteService < BaseService
def call(account, status)
favourite = Favourite.create!(account: account, status: status)
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
return favourite if status.local?
send_interaction_service.(favourite.stream_entry, status.account)
if status.local?
NotificationMailer.favourite(status, account).deliver_later
else
send_interaction_service.(favourite.stream_entry, status.account)
end
favourite
end

View File

@ -7,6 +7,7 @@ class PostStatusService < BaseService
def call(account, text, in_reply_to = nil)
status = account.statuses.create!(text: text, thread: in_reply_to)
process_mentions_service.(status)
fan_out_on_write_service.(status)
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
status
end
@ -16,4 +17,8 @@ class PostStatusService < BaseService
def process_mentions_service
@process_mentions_service ||= ProcessMentionsService.new
end
def fan_out_on_write_service
@fan_out_on_write_service ||= FanOutOnWriteService.new
end
end

View File

@ -17,7 +17,7 @@ class ProcessFeedService < BaseService
status = Status.find_by(uri: activity_id(entry))
# If we already have a post and the verb is now "delete", we gotta delete it and move on!
if verb(entry) == :delete
if !status.nil? && verb(entry) == :delete
delete_post!(status)
next
end
@ -26,12 +26,14 @@ class ProcessFeedService < BaseService
status = Status.new(uri: activity_id(entry), url: activity_link(entry), account: account, text: content(entry), created_at: published(entry), updated_at: updated(entry))
if object_type(entry) == :comment && verb(entry) == :post
add_reply!(entry, status)
elsif verb(entry) == :share
if verb(entry) == :share
add_reblog!(entry, status)
elsif verb(entry) == :post
add_post!(entry, status)
if thread_id(entry).nil?
add_post!(entry, status)
else
add_reply!(entry, status)
end
end
# If we added a status, go through accounts it mentions and create respective relations
@ -45,13 +47,16 @@ class ProcessFeedService < BaseService
href = Addressable::URI.parse(mention_link.attribute('href').value)
if href.host == Rails.configuration.x.local_domain
mentioned_account = Account.find_by(username: href.path.gsub('/users/', ''), domain: nil)
mentioned_account = Account.find_local(href.path.gsub('/users/', ''))
unless mentioned_account.nil?
mentioned_account.mentions.first_or_create(status: status)
mentioned_account.mentions.where(status: status).first_or_create(status: status)
NotificationMailer.mention(mentioned_account, status).deliver_later
end
end
end
fan_out_on_write_service.(status)
end
end
end
@ -69,7 +74,10 @@ class ProcessFeedService < BaseService
status.reblog = fetch_remote_status(entry)
end
status.save! unless status.reblog.nil?
if !status.reblog.nil?
status.save!
NotificationMailer.reblog(status.reblog, status.account).deliver_later
end
end
def add_reply!(entry, status)
@ -98,7 +106,7 @@ class ProcessFeedService < BaseService
account = Account.find_by(username: username, domain: domain)
if account.nil?
account = follow_remote_account_service.("acct:#{username}@#{domain}", false)
account = follow_remote_account_service.("#{username}@#{domain}", false)
return nil if account.nil?
end
@ -166,4 +174,8 @@ class ProcessFeedService < BaseService
def update_remote_profile_service
@update_remote_profile_service ||= UpdateRemoteProfileService.new
end
def fan_out_on_write_service
@fan_out_on_write_service ||= FanOutOnWriteService.new
end
end

View File

@ -14,7 +14,7 @@ class ProcessInteractionService < BaseService
account = Account.find_by(username: username, domain: domain)
if account.nil?
account = follow_remote_account_service.("acct:#{username}@#{domain}", false)
account = follow_remote_account_service.("#{username}@#{domain}", false)
return if account.nil?
end
@ -48,13 +48,14 @@ class ProcessInteractionService < BaseService
end
def verb(xml)
xml.at_xpath('//activity:verb').content.gsub('http://activitystrea.ms/schema/1.0/', '').to_sym
xml.at_xpath('//activity:verb').content.gsub('http://activitystrea.ms/schema/1.0/', '').gsub('http://ostatus.org/schema/1.0/', '').to_sym
rescue
:post
end
def follow!(account, target_account)
account.follow!(target_account)
NotificationMailer.follow(target_account, account).deliver_later
end
def unfollow!(account, target_account)
@ -62,7 +63,9 @@ class ProcessInteractionService < BaseService
end
def favourite!(xml, from_account)
status(xml).favourites.first_or_create!(account: from_account)
current_status = status(xml)
current_status.favourites.where(account: from_account).first_or_create!(account: from_account)
NotificationMailer.favourite(current_status, from_account).deliver_later
end
def add_post!(body, account)
@ -74,7 +77,7 @@ class ProcessInteractionService < BaseService
end
def activity_id(xml)
xml.at_xpath('/xmlns:entry/xmlns:id').content
xml.at_xpath('./activity:object/xmlns:id').content
end
def salmon

View File

@ -10,16 +10,22 @@ class ProcessMentionsService < BaseService
username, domain = match.first.split('@')
mentioned_account = Account.find_by(username: username, domain: domain)
if mentioned_account.nil?
mentioned_account = follow_remote_account_service.("acct:#{match.first}")
if mentioned_account.nil? && !domain.nil?
mentioned_account = follow_remote_account_service.("#{match.first}")
next if mentioned_account.nil?
end
mentioned_account.mentions.first_or_create(status: status)
mentioned_account.mentions.where(status: status).first_or_create(status: status)
end
status.mentions.each do |mentioned_account|
next if mentioned_account.local?
send_interaction_service.(status.stream_entry, mentioned_account)
status.mentioned_accounts.each do |mention|
mentioned_account = mention.account
if mentioned_account.local?
NotificationMailer.mention(mentioned_account, status).deliver_later
else
send_interaction_service.(status.stream_entry, mentioned_account)
end
end
end

View File

@ -5,9 +5,15 @@ class ReblogService < BaseService
# @return [Status]
def call(account, reblogged_status)
reblog = account.statuses.create!(reblog: reblogged_status, text: '')
fan_out_on_write_service.(reblog)
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
return reblog if reblogged_status.local?
send_interaction_service.(reblog.stream_entry, reblogged_status.account)
if reblogged_status.local?
NotificationMailer.reblog(reblogged_status, account).deliver_later
else
send_interaction_service.(reblog.stream_entry, reblogged_status.account)
end
reblog
end
@ -16,4 +22,8 @@ class ReblogService < BaseService
def send_interaction_service
@send_interaction_service ||= SendInteractionService.new
end
def fan_out_on_write_service
@fan_out_on_write_service ||= FanOutOnWriteService.new
end
end

View File

@ -1,14 +0,0 @@
class SetupLocalAccountService < BaseService
# Setup an account for a new user instance by generating
# an RSA key pair and a profile
# @param [User] user Unsaved user instance
# @param [String] username
def call(user, username)
user.build_account
user.account.username = username
user.account.domain = nil
user.save!
end
end

View File

@ -0,0 +1,8 @@
.account-grid-card
.account-grid-card__header
.avatar= image_tag account.avatar.url(:medium)
.name
= link_to url_for_target(account) do
%span.display_name= display_name(account)
%span.username= "@#{account.acct}"
%p.note= truncate(account.note, length: 124)

View File

@ -0,0 +1,20 @@
.card{ style: "background-image: url(#{@account.header.url(:medium)})" }
.avatar= image_tag @account.avatar.url(:large)
%h1.name
= display_name(@account)
%small= "@#{@account.username}"
.details
.counter{ class: active_nav_class(account_url(@account)) }
= link_to account_url(@account) do
%span.counter-label Posts
%span.counter-number= @account.statuses.count
.counter{ class: active_nav_class(following_account_url(@account)) }
= link_to following_account_url(@account) do
%span.counter-label Following
%span.counter-number= @account.following.count
.counter{ class: active_nav_class(followers_account_url(@account)) }
= link_to followers_account_url(@account) do
%span.counter-label Followers
%span.counter-number= @account.followers.count
.bio
%p= @account.note

View File

@ -0,0 +1 @@
%p.nothing-here There is nothing here!

View File

@ -0,0 +1,14 @@
- content_for :page_title do
People who follow
= display_name(@account)
= render partial: 'header'
.accounts-grid
- @followers.each do |f|
= render partial: 'grid_card', locals: { account: f }
- if @followers.empty?
= render partial: 'nothing_here'
= will_paginate @followers, pagination_options

View File

@ -0,0 +1,15 @@
- content_for :page_title do
People whom
= display_name(@account)
follows
= render partial: 'header'
.accounts-grid
- @following.each do |f|
= render partial: 'grid_card', locals: { account: f }
- if @following.empty?
= render partial: 'nothing_here'
= will_paginate @following, pagination_options

View File

@ -1,24 +1,14 @@
- content_for :page_title do
= display_name(@account)
- content_for :header_tags do
%link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
.card{ style: "background-image: url(#{@account.header.url(:medium)})" }
.avatar= image_tag @account.avatar.url(:large)
%h1.name
= @account.display_name.blank? ? @account.username : @account.display_name
%small= "@#{@account.username}"
.details
.counter
%span.counter-label Posts
%span.counter-number= @account.statuses.count
.counter
%span.counter-label Following
%span.counter-number= @account.following.count
.counter
%span.counter-label Followers
%span.counter-number= @account.followers.count
.bio
%p= @account.note
= render partial: 'header'
.activity-stream
- @statuses.each do |status|
= render partial: 'stream_entries/status', locals: { status: status, include_threads: false, is_successor: false, is_predecessor: false }
= will_paginate @statuses, pagination_options

View File

@ -2,7 +2,9 @@
%html
%head
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%title Mastodon
%title
= "#{yield(:page_title)} - " if content_for?(:page_title)
Mastodon
= stylesheet_link_tag 'application', media: 'all'
= javascript_include_tag 'application'
= csrf_meta_tags

View File

@ -6,7 +6,7 @@
.dashboard__current-user
= link_to account_path(current_user.account) do
= image_tag current_user.account.avatar.url(:medium), class: 'dashboard__current-user__avatar'
%strong.dashboard__current-user__display-name= current_user.account.display_name.blank? ? current_user.account.username : current_user.account.display_name
%strong.dashboard__current-user__display-name= display_name(current_user.account)
%span.dashboard__current-user__username= "@#{current_user.account.username}"
%ul
%li{ class: active_nav_class(root_path) }

View File

@ -0,0 +1,5 @@
<%= yield %>
---
Mastodon notifications from <%= Rails.configuration.x.local_domain %>

View File

@ -0,0 +1,5 @@
<%= display_name(@me) %>,
Your status was favourited by <%= @account.acct %>:
<%= account_stream_entry_url(@me, @status.stream_entry) %>

View File

@ -0,0 +1,5 @@
<%= display_name(@me) %>,
<%= @account.acct %> is now following you!
<%= url_for_target(@account) %>

View File

@ -0,0 +1,7 @@
<%= display_name(@me) %>,
You were mentioned by <%= @status.account.acct %> in:
<%= strip_tags(@status.content) %>
<%= url_for_target(@status) %>

View File

@ -0,0 +1,5 @@
<%= display_name(@me) %>,
Your status was reblogged by <%= @account.acct %>:
<%= account_stream_entry_url(@me, @status.stream_entry) %>

View File

@ -33,5 +33,7 @@ module Mastodon
Doorkeeper::AuthorizedApplicationsController.layout 'dashboard'
Doorkeeper::AuthorizationsController.layout 'auth'
end
config.middleware.use Rack::Attack
end
end

View File

@ -17,7 +17,8 @@ test:
production:
<<: *default
database: postgres
username: postgres
password:
host: db
database: <%= ENV['DB_NAME'] || 'mastodon_production' %>
username: <%= ENV['DB_USER'] || 'mastodon' %>
password: <%= ENV['DB_PASS'] || '' %>
host: <%= ENV['DB_HOST'] || 'localhost' %>
port: <%= ENV['DB_PORT'] || 5432 %>

View File

@ -38,4 +38,6 @@ Rails.application.configure do
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
config.action_mailer.delivery_method = :letter_opener
end

View File

@ -22,7 +22,7 @@ Rails.application.configure do
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.serve_static_files = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
@ -42,7 +42,7 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
config.force_ssl = ENV['LOCAL_HTTPS'] == 'true'
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
@ -76,4 +76,16 @@ Rails.application.configure do
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
# E-mails
config.action_mailer.smtp_settings = {
:port => ENV['SMTP_PORT'],
:address => ENV['SMTP_SERVER'],
:user_name => ENV['SMTP_LOGIN'],
:password => ENV['SMTP_PASSWORD'],
:domain => config.x.local_domain,
:authentication => :plain,
}
config.action_mailer.delivery_method = :smtp
end

View File

@ -15,6 +15,7 @@ Rails.application.configure do
# Configure static file server for tests with Cache-Control for performance.
config.serve_static_files = true
config.static_cache_control = 'public, max-age=3600'
config.assets.digest = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true

View File

@ -12,7 +12,7 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
config.mailer_sender = ENV['SMTP_FROM_ADDRESS'] || 'notifications@localhost'
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'

View File

@ -23,7 +23,7 @@ Doorkeeper.configure do
# Access token expiration time (default 2 hours).
# If you want to disable expiration, set this to nil.
# access_token_expires_in nil
access_token_expires_in nil
# Assign a custom TTL for implicit grants.
# custom_access_token_expires_in do |oauth_client|

View File

@ -1,4 +1,4 @@
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
Rails.application.config.filter_parameters += [:password, :private_key, :public_key]

View File

@ -0,0 +1,3 @@
class Rack::Attack
# TODO
end

View File

@ -14,6 +14,11 @@ Rails.application.routes.draw do
resources :accounts, path: 'users', only: [:show], param: :username do
resources :stream_entries, path: 'updates', only: [:show]
member do
get :followers
get :following
end
end
resource :settings, only: [:show, :update]

View File

@ -0,0 +1,10 @@
class AddMissingIndices < ActiveRecord::Migration
def change
add_index :users, :account_id
add_index :statuses, :account_id
add_index :statuses, :in_reply_to_id
add_index :statuses, :reblog_of_id
add_index :stream_entries, :account_id
add_index :stream_entries, [:activity_id, :activity_type]
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160314164231) do
ActiveRecord::Schema.define(version: 20160316103650) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -125,6 +125,9 @@ ActiveRecord::Schema.define(version: 20160314164231) do
t.string "url"
end
add_index "statuses", ["account_id"], name: "index_statuses_on_account_id", using: :btree
add_index "statuses", ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id", using: :btree
add_index "statuses", ["reblog_of_id"], name: "index_statuses_on_reblog_of_id", using: :btree
add_index "statuses", ["uri"], name: "index_statuses_on_uri", unique: true, using: :btree
create_table "stream_entries", force: :cascade do |t|
@ -135,6 +138,9 @@ ActiveRecord::Schema.define(version: 20160314164231) do
t.datetime "updated_at", null: false
end
add_index "stream_entries", ["account_id"], name: "index_stream_entries_on_account_id", using: :btree
add_index "stream_entries", ["activity_id", "activity_type"], name: "index_stream_entries_on_activity_id_and_activity_type", using: :btree
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.integer "account_id", null: false
@ -151,6 +157,7 @@ ActiveRecord::Schema.define(version: 20160314164231) do
t.inet "last_sign_in_ip"
end
add_index "users", ["account_id"], name: "index_users_on_account_id", using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

View File

@ -12,4 +12,7 @@ services:
depends_on:
- db
- redis
volumes:
- ./public/assets:/mastodon/public/assets
- ./public/system:/mastodon/public/system
env_file: .env.production

View File

@ -0,0 +1,13 @@
namespace :subscriptions do
desc "For all remote accounts that have no local followers, unsubscribe from PuSH"
task clear: :environment do
accounts = Account.where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) = 0').where.not(domain: nil)
accounts.each do |a|
a.subscription(api_subscription_url(a.id)).unsubscribe
a.update!(verify_token: '', secret: '')
end
end
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -4,14 +4,28 @@ RSpec.describe AccountsController, type: :controller do
let(:alice) { Fabricate(:account, username: 'alice') }
describe 'GET #show' do
it 'returns 200' do
it 'returns http success' do
get :show, username: alice.username
expect(response).to have_http_status(:success)
end
it 'returns 200 with Atom' do
it 'returns http success with Atom' do
get :show, username: alice.username, format: 'atom'
expect(response).to have_http_status(:success)
end
end
describe 'GET #followers' do
it 'returns http success' do
get :followers, username: alice.username
expect(response).to have_http_status(:success)
end
end
describe 'GET #following' do
it 'returns http success' do
get :following, username: alice.username
expect(response).to have_http_status(:success)
end
end
end

View File

@ -1,5 +1,71 @@
require 'rails_helper'
RSpec.describe Api::AccountsController, type: :controller do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { double acceptable?: true, resource_owner_id: user.id }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
it 'returns http success' do
get :show, id: user.account.id
expect(response).to have_http_status(:success)
end
end
describe 'GET #statuses' do
it 'returns http success' do
get :statuses, id: user.account.id
expect(response).to have_http_status(:success)
end
end
describe 'GET #followers' do
it 'returns http success' do
get :followers, id: user.account.id
expect(response).to have_http_status(:success)
end
end
describe 'GET #following' do
it 'returns http success' do
get :following, id: user.account.id
expect(response).to have_http_status(:success)
end
end
describe 'POST #follow' do
let(:other_account) { Fabricate(:account, username: 'bob') }
before do
post :follow, id: other_account.id
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
end
describe 'POST #unfollow' do
let(:other_account) { Fabricate(:account, username: 'bob') }
before do
user.account.follow!(other_account)
post :unfollow, id: other_account.id
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'removes the following relation between user and target user' do
expect(user.account.following?(other_account)).to be false
end
end
end

View File

@ -1,5 +1,48 @@
require 'rails_helper'
RSpec.describe Api::FollowsController, type: :controller do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { double acceptable?: true, resource_owner_id: user.id }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
stub_request(:post, "https://quitter.no/main/salmon/user/7477").to_return(:status => 200, :body => "", :headers => {})
stub_request(:post, "https://pubsubhubbub.superfeedr.com/").to_return(:status => 200, :body => "", :headers => {})
post :create, uri: 'gargron@quitter.no'
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'creates account for remote user' do
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
end
it 'creates a follow relation between user and remote user' do
expect(user.account.following?(Account.find_by(username: 'gargron', domain: 'quitter.no'))).to be true
end
it 'sends a salmon slap to the remote user' do
expect(a_request(:post, "https://quitter.no/main/salmon/user/7477")).to have_been_made
end
it 'notifies own hub' do
expect(a_request(:post, "https://pubsubhubbub.superfeedr.com/")).to have_been_made
end
it 'subscribes to remote hub' do
expect(a_request(:post, "https://quitter.no/main/push/hub")).to have_been_made
end
end
end

View File

@ -1,7 +1,35 @@
require 'rails_helper'
RSpec.describe Api::SalmonController, type: :controller do
let(:account) { Fabricate(:account, username: 'catsrgr8', user: Fabricate(:user)) }
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
end
describe 'POST #update' do
pending
before do
request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml'))
post :update, id: account.id
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'creates remote account' do
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
end
it 'creates status' do
expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil
end
it 'creates mention for target account' do
expect(account.mentions.count).to eq 1
end
end
end

View File

@ -1,5 +1,39 @@
require 'rails_helper'
RSpec.describe Api::StatusesController, type: :controller do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { double acceptable?: true, resource_owner_id: user.id }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
let(:status) { Fabricate(:status, account: user.account) }
it 'returns http success' do
get :show, id: status.id
expect(response).to have_http_status(:success)
end
end
describe 'GET #home' do
it 'returns http success'
end
describe 'GET #mentions' do
it 'returns http success'
end
describe 'POST #create' do
it 'returns http success'
end
describe 'POST #reblog' do
it 'returns http success'
end
describe 'POST #favourite' do
it 'returns http success'
end
end

View File

@ -1,11 +1,40 @@
require 'rails_helper'
RSpec.describe Api::SubscriptionsController, type: :controller do
let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', verify_token: '123', remote_url: 'topic_url', secret: 'abc') }
describe 'GET #show' do
pending
before do
get :show, id: account.id, 'hub.topic': 'topic_url', 'hub.verify_token': 123, 'hub.challenge': '456'
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'echoes back the challenge' do
expect(response.body).to match '456'
end
end
describe 'POST #update' do
pending
let(:feed) { File.read(File.join(Rails.root, 'spec', 'fixtures', 'push', 'feed.atom')) }
before do
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
request.env['RAW_POST_DATA'] = feed
post :update, id: account.id
end
it 'returns http created' do
expect(response).to have_http_status(:created)
end
it 'creates statuses for feed' do
expect(account.statuses.count).to_not eq 0
end
end
end

View File

@ -2,7 +2,7 @@ require 'rails_helper'
RSpec.describe HomeController, type: :controller do
describe 'GET #index' do
it 'returns 200' do
it 'redirects to login page' do
get :index
expect(response).to redirect_to(new_user_session_path)
end

View File

@ -1,5 +1,11 @@
require 'rails_helper'
RSpec.describe Oauth::ApplicationsController, type: :controller do
describe 'GET #index' do
it 'returns http success'
end
describe 'POST #create' do
it 'redirects to the application page'
end
end

View File

@ -5,12 +5,12 @@ RSpec.describe StreamEntriesController, type: :controller do
let(:status) { Fabricate(:status, account: alice) }
describe 'GET #show' do
it 'returns 200 with HTML' do
it 'returns http success with HTML' do
get :show, account_username: alice.username, id: status.stream_entry.id
expect(response).to have_http_status(:success)
end
it 'returns 200 with Atom' do
it 'returns http success with Atom' do
get :show, account_username: alice.username, id: status.stream_entry.id, format: 'atom'
expect(response).to have_http_status(:success)
end

View File

@ -2,7 +2,7 @@ require 'rails_helper'
RSpec.describe XrdController, type: :controller do
describe 'GET #host_meta' do
it 'returns 200' do
it 'returns http success' do
get :host_meta
expect(response).to have_http_status(:success)
end
@ -11,12 +11,12 @@ RSpec.describe XrdController, type: :controller do
describe 'GET #webfinger' do
let(:alice) { Fabricate(:account, username: 'alice') }
it 'returns 200 when account can be found' do
it 'returns http success when account can be found' do
get :webfinger, resource: "acct:#{alice.username}@anything.com"
expect(response).to have_http_status(:success)
end
it 'returns 404 when account cannot be found' do
it 'returns http not found when account cannot be found' do
get :webfinger, resource: 'acct:not@existing.com'
expect(response).to have_http_status(:not_found)
end

424
spec/fixtures/push/feed.atom vendored Normal file
View File

@ -0,0 +1,424 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.2.0-beta4">GNU social</generator>
<id>https://quitter.no/api/statuses/user_timeline/7477.atom</id>
<title>gargron timeline</title>
<subtitle>Updates from gargron on Quitter.no!</subtitle>
<logo>https://quitter.no/avatar/7477-96-20160211190340.png</logo>
<updated>2016-03-20T12:42:58+01:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://quitter.no/user/7477</uri>
<name>gargron</name>
<summary>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</summary>
<link rel="alternate" type="text/html" href="https://quitter.no/gargron"/>
<link rel="avatar" type="image/png" media:width="300" media:height="300" href="https://quitter.no/avatar/7477-300-20160211190340.png"/>
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://quitter.no/avatar/7477-96-20160211190340.png"/>
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://quitter.no/avatar/7477-48-20160211190449.png"/>
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://quitter.no/avatar/7477-24-20160211190517.png"/>
<poco:preferredUsername>gargron</poco:preferredUsername>
<poco:displayName> </poco:displayName>
<poco:note>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</poco:note>
<poco:address>
<poco:formatted>Germany</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://zeonfederated.com</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://quitter.no/gargron/subscribers"></followers>
<statusnet:profile_info local_id="7477"></statusnet:profile_info>
</author>
<link href="https://quitter.no/gargron" rel="alternate" type="text/html"/>
<link href="https://quitter.no/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://quitter.no/api/statuses/user_timeline/7477.atom?max_id=1243309" rel="next" type="application/atom+xml"/>
<link href="https://quitter.no/main/push/hub" rel="hub"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="salmon"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://quitter.no/api/statuses/user_timeline/7477.atom" rel="self" type="application/atom+xml"/>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note</id>
<title>New note by gargron</title>
<content type="html">@&lt;a href=&quot;https://cb6e6126.ngrok.io/users/catsrgr8&quot; class=&quot;h-card mention&quot;&gt;catsrgr8&lt;/a&gt; this is a mention</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1276923"/>
<status_net notice_id="1276923"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-20T11:05:31+00:00</published>
<updated>2016-03-20T11:05:31+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685"/>
<ostatus:conversation>tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cb6e6126.ngrok.io/users/catsrgr8"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1276923.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1276923.atom"/>
<statusnet:notice_info local_id="1276923" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1273635:objectType=note</id>
<title>New note by gargron</title>
<content type="html">Just testing a thing.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1273635"/>
<status_net notice_id="1273635"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-19T20:35:53+00:00</published>
<updated>2016-03-19T20:35:53+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2"/>
<ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273635.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273635.atom"/>
<statusnet:notice_info local_id="1273635" source="web"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
<title>Delete</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; deleted notice &lt;a href=&quot;https://quitter.no/notice/1272988&quot;&gt;{{tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note}}&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1273012"/>
<activity:verb>delete</activity:verb>
<published>2016-03-19T18:16:58+00:00</published>
<updated>2016-03-19T18:16:58+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b"/>
<ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<activity:target>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
</activity:target>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273012.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273012.atom"/>
<statusnet:notice_info local_id="1273012" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1269381:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://mastodon.social/users/Gargron&quot; class=&quot;h-card mention&quot; title=&quot;Eugen&quot;&gt;gargron&lt;/a&gt; I have to wonder if this will appear as a reply to the right status, and not just a mention.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1269381"/>
<status_net notice_id="1269381"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-19T00:10:14+00:00</published>
<updated>2016-03-19T00:10:14+00:00</updated>
<thr:in-reply-to ref="tag:mastodon.social,2016-03-18:objectId=60:objectType=Status" href="https://quitter.no/notice/1269244"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1269244"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9"/>
<ostatus:conversation>tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1269381.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1269381.atom"/>
<statusnet:notice_info local_id="1269381" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-18:noticeId=1265337:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Plus, Android can hardly be considered free software given how many proprietary blobs are used. I'm speaking as a disappointed Android user.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1265337"/>
<status_net notice_id="1265337"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-18T10:01:50+00:00</published>
<updated>2016-03-18T10:01:50+00:00</updated>
<thr:in-reply-to ref="tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment" href="https://quitter.no/notice/1265331"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1265331"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.no/user/7477"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265337.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265337.atom"/>
<statusnet:notice_info local_id="1265337" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Well as it turns out, Apple software is better than Android in terms of security, and Apple is fighting FBI while Google promised to build a messaging app that facilitates wire tapping. The whole free software thing should imo be considered a bonus and not overshadow other factors.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1265331"/>
<status_net notice_id="1265331"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-18T10:01:01+00:00</published>
<updated>2016-03-18T10:01:01+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-18:noticeId=54411:objectType=note" href="https://community.highlandarrow.com/notice/54411"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/54411"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265331.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265331.atom"/>
<statusnet:notice_info local_id="1265331" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-17:noticeId=1261358:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; @&lt;a href=&quot;https://gs.kawa-kun.com/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x7AF9;&amp;#x4E0B;&amp;#x61B2;&amp;#x4E8C;&quot;&gt;takeshitakenji&lt;/a&gt; There is a reason that was deprecated and we don't use tables to design websites anymore. HTML needs to be semantic, i.e. tags need to describe the *kind* of content, not how it should *look*, which is a responsibility delegated to CSS. There are so many upsides to this separation of concerns, should I start listing?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1261358"/>
<status_net notice_id="1261358"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-17T17:00:26+00:00</published>
<updated>2016-03-17T17:00:26+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-17:noticeId=53857:objectType=comment" href="https://community.highlandarrow.com/notice/53857"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/53857"/>
<link rel="ostatus:conversation" href="tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1"/>
<ostatus:conversation>tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1261358.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1261358.atom"/>
<statusnet:notice_info local_id="1261358" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:24:13+01:00</id>
<title> (gargron)'s status on Wednesday, 16-Mar-2016 21:24:13 CET</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256972"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:24:13+00:00</published>
<updated>2016-03-16T20:24:13+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>https://mastodon.social/users/Gargron</id>
<title>Eugen</title>
<summary>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</summary>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/Gargron"/>
<link rel="avatar" type="image/gif" media:width="96" media:height="96" href="https://quitter.no/avatar/15743-original-20160316180410.gif"/>
<link rel="avatar" type="image/gif" media:width="96" media:height="96" href="https://quitter.no/avatar/15743-original-20160316180410.gif"/>
<link rel="avatar" type="image/gif" media:width="48" media:height="48" href="https://quitter.no/avatar/15743-48-20160316180416.gif"/>
<link rel="avatar" type="image/gif" media:width="24" media:height="24" href="https://quitter.no/avatar/15743-24-20160316180416.gif"/>
<poco:preferredUsername>gargron</poco:preferredUsername>
<poco:displayName>Eugen</poco:displayName>
<poco:note>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</poco:note>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256972.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256972.atom"/>
<statusnet:notice_info local_id="1256972" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256966"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:22:38+00:00</published>
<updated>2016-03-16T20:22:38+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256966"/>
<status_net notice_id="1256966"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256966.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256966.atom"/>
<statusnet:notice_info local_id="1256966" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256939"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:16:15+00:00</published>
<updated>2016-03-16T20:16:15+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256939"/>
<status_net notice_id="1256939"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256939.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256939.atom"/>
<statusnet:notice_info local_id="1256939" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256929"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:13:06+00:00</published>
<updated>2016-03-16T20:13:06+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256929"/>
<status_net notice_id="1256929"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256929.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256929.atom"/>
<statusnet:notice_info local_id="1256929" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256888"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:05:03+00:00</published>
<updated>2016-03-16T20:05:03+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256888"/>
<status_net notice_id="1256888"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256888.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256888.atom"/>
<statusnet:notice_info local_id="1256888" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256253"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T18:04:16+00:00</published>
<updated>2016-03-16T18:04:16+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256253"/>
<status_net notice_id="1256253"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256253.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256253.atom"/>
<statusnet:notice_info local_id="1256253" source="activity"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1251422:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; LGB, not LGBT?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1251422"/>
<status_net notice_id="1251422"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T20:28:13+00:00</published>
<updated>2016-03-15T20:28:13+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-15:noticeId=51852:objectType=note" href="https://community.highlandarrow.com/notice/51852"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/51852"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1251422.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1251422.atom"/>
<statusnet:notice_info local_id="1251422" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1250742:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; I'm like reeeeally close to actually deploying the first production instance of Mastodon, but it bugs me that there's gonna be that issue with avatars and profiles not updating :(</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1250742"/>
<status_net notice_id="1250742"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T18:44:54+00:00</published>
<updated>2016-03-15T18:44:54+00:00</updated>
<thr:in-reply-to ref="tag:social.umeahackerspace.se,2016-03-15:noticeId=424348:objectType=comment" href="https://social.umeahackerspace.se/notice/424348"></thr:in-reply-to>
<link rel="related" href="https://social.umeahackerspace.se/notice/424348"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80"/>
<ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.umeahackerspace.se/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250742.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250742.atom"/>
<statusnet:notice_info local_id="1250742" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1250653:objectType=note</id>
<title>New note by gargron</title>
<content type="html">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; Any progress on the issues I created?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1250653"/>
<status_net notice_id="1250653"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T18:27:00+00:00</published>
<updated>2016-03-15T18:27:00+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80"/>
<ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.umeahackerspace.se/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250653.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250653.atom"/>
<statusnet:notice_info local_id="1250653" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-14:noticeId=1243566:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; I heard Piwik is also good.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1243566"/>
<status_net notice_id="1243566"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-14T15:35:23+00:00</published>
<updated>2016-03-14T15:35:23+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-14:noticeId=50467:objectType=note" href="https://community.highlandarrow.com/notice/50467"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/50467"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243566.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243566.atom"/>
<statusnet:notice_info local_id="1243566" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-14:noticeId=1243331:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">I do wish I had somebody else partake in the development process if only to give me feedback on my decisions</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1243331"/>
<status_net notice_id="1243331"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-14T14:52:03+00:00</published>
<updated>2016-03-14T14:52:03+00:00</updated>
<thr:in-reply-to ref="tag:quitter.no,2016-03-14:noticeId=1243309:objectType=comment" href="https://quitter.no/notice/1243309"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1243309"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01"/>
<ostatus:conversation>tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.no/user/7477"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243331.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243331.atom"/>
<statusnet:notice_info local_id="1243331" source="Qvitter"></statusnet:notice_info>
</entry>
</feed>

19
spec/fixtures/requests/.host-meta.txt vendored Normal file
View File

@ -0,0 +1,19 @@
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 20 Mar 2016 11:11:00 GMT
Content-Type: application/xrd+xml
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Vary: Accept-Encoding,Cookie
Strict-Transport-Security: max-age=31536000; includeSubdomains;
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/jrd+json" template="https://quitter.no/.well-known/webfinger?resource={uri}"/>
<Link rel="lrdd" type="application/json" template="https://quitter.no/.well-known/webfinger?resource={uri}"/>
<Link rel="lrdd" type="application/xrd+xml" template="https://quitter.no/.well-known/webfinger?resource={uri}"/>
<Link rel="http://apinamespace.org/oauth/access_token" href="https://quitter.no/api/oauth/access_token"/>
<Link rel="http://apinamespace.org/oauth/request_token" href="https://quitter.no/api/oauth/request_token"/>
<Link rel="http://apinamespace.org/oauth/authorize" href="https://quitter.no/api/oauth/authorize"/>
</XRD>

BIN
spec/fixtures/requests/avatar.txt vendored Normal file

Binary file not shown.

440
spec/fixtures/requests/feed.txt vendored Normal file
View File

@ -0,0 +1,440 @@
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 20 Mar 2016 11:15:03 GMT
Content-Type: application/atom+xml; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Vary: Accept-Encoding,Cookie
ETag: "ApiTimelineUser:0:en:7477:1458471931:1457967123"
Last-Modified: Sun, 20 Mar 2016 11:05:31 +0000
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private, must-revalidate, max-age=0
Pragma:
X-SUP-ID: https://quitter.no/main/sup
Strict-Transport-Security: max-age=31536000; includeSubdomains;
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.2.0-beta4">GNU social</generator>
<id>https://quitter.no/api/statuses/user_timeline/7477.atom</id>
<title>gargron timeline</title>
<subtitle>Updates from gargron on Quitter.no!</subtitle>
<logo>https://quitter.no/avatar/7477-96-20160211190340.png</logo>
<updated>2016-03-20T12:15:03+01:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://quitter.no/user/7477</uri>
<name>gargron</name>
<summary>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</summary>
<link rel="alternate" type="text/html" href="https://quitter.no/gargron"/>
<link rel="avatar" type="image/png" media:width="300" media:height="300" href="https://quitter.no/avatar/7477-300-20160211190340.png"/>
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://quitter.no/avatar/7477-96-20160211190340.png"/>
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://quitter.no/avatar/7477-48-20160211190449.png"/>
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://quitter.no/avatar/7477-24-20160211190517.png"/>
<poco:preferredUsername>gargron</poco:preferredUsername>
<poco:displayName> </poco:displayName>
<poco:note>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</poco:note>
<poco:address>
<poco:formatted>Germany</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://zeonfederated.com</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://quitter.no/gargron/subscribers"></followers>
<statusnet:profile_info local_id="7477"></statusnet:profile_info>
</author>
<link href="https://quitter.no/gargron" rel="alternate" type="text/html"/>
<link href="https://quitter.no/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://quitter.no/api/statuses/user_timeline/7477.atom?max_id=1243309" rel="next" type="application/atom+xml"/>
<link href="https://quitter.no/main/push/hub" rel="hub"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="salmon"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://quitter.no/main/salmon/user/7477" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://quitter.no/api/statuses/user_timeline/7477.atom" rel="self" type="application/atom+xml"/>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note</id>
<title>New note by gargron</title>
<content type="html">@&lt;a href=&quot;https://cb6e6126.ngrok.io/users/catsrgr8&quot; class=&quot;h-card mention&quot;&gt;catsrgr8&lt;/a&gt; this is a mention</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1276923"/>
<status_net notice_id="1276923"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-20T11:05:31+00:00</published>
<updated>2016-03-20T11:05:31+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685"/>
<ostatus:conversation>tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cb6e6126.ngrok.io/users/catsrgr8"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1276923.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1276923.atom"/>
<statusnet:notice_info local_id="1276923" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1273635:objectType=note</id>
<title>New note by gargron</title>
<content type="html">Just testing a thing.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1273635"/>
<status_net notice_id="1273635"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-19T20:35:53+00:00</published>
<updated>2016-03-19T20:35:53+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2"/>
<ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273635.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273635.atom"/>
<statusnet:notice_info local_id="1273635" source="web"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
<title>Delete</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; deleted notice &lt;a href=&quot;https://quitter.no/notice/1272988&quot;&gt;{{tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note}}&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1273012"/>
<activity:verb>delete</activity:verb>
<published>2016-03-19T18:16:58+00:00</published>
<updated>2016-03-19T18:16:58+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b"/>
<ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<activity:target>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>
</activity:target>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273012.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1273012.atom"/>
<statusnet:notice_info local_id="1273012" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-19:noticeId=1269381:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://mastodon.social/users/Gargron&quot; class=&quot;h-card mention&quot; title=&quot;Eugen&quot;&gt;gargron&lt;/a&gt; I have to wonder if this will appear as a reply to the right status, and not just a mention.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1269381"/>
<status_net notice_id="1269381"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-19T00:10:14+00:00</published>
<updated>2016-03-19T00:10:14+00:00</updated>
<thr:in-reply-to ref="tag:mastodon.social,2016-03-18:objectId=60:objectType=Status" href="https://quitter.no/notice/1269244"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1269244"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9"/>
<ostatus:conversation>tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1269381.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1269381.atom"/>
<statusnet:notice_info local_id="1269381" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-18:noticeId=1265337:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Plus, Android can hardly be considered free software given how many proprietary blobs are used. I'm speaking as a disappointed Android user.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1265337"/>
<status_net notice_id="1265337"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-18T10:01:50+00:00</published>
<updated>2016-03-18T10:01:50+00:00</updated>
<thr:in-reply-to ref="tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment" href="https://quitter.no/notice/1265331"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1265331"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.no/user/7477"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265337.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265337.atom"/>
<statusnet:notice_info local_id="1265337" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Well as it turns out, Apple software is better than Android in terms of security, and Apple is fighting FBI while Google promised to build a messaging app that facilitates wire tapping. The whole free software thing should imo be considered a bonus and not overshadow other factors.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1265331"/>
<status_net notice_id="1265331"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-18T10:01:01+00:00</published>
<updated>2016-03-18T10:01:01+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-18:noticeId=54411:objectType=note" href="https://community.highlandarrow.com/notice/54411"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/54411"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265331.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1265331.atom"/>
<statusnet:notice_info local_id="1265331" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-17:noticeId=1261358:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; @&lt;a href=&quot;https://gs.kawa-kun.com/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x7AF9;&amp;#x4E0B;&amp;#x61B2;&amp;#x4E8C;&quot;&gt;takeshitakenji&lt;/a&gt; There is a reason that was deprecated and we don't use tables to design websites anymore. HTML needs to be semantic, i.e. tags need to describe the *kind* of content, not how it should *look*, which is a responsibility delegated to CSS. There are so many upsides to this separation of concerns, should I start listing?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1261358"/>
<status_net notice_id="1261358"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-17T17:00:26+00:00</published>
<updated>2016-03-17T17:00:26+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-17:noticeId=53857:objectType=comment" href="https://community.highlandarrow.com/notice/53857"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/53857"/>
<link rel="ostatus:conversation" href="tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1"/>
<ostatus:conversation>tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1261358.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1261358.atom"/>
<statusnet:notice_info local_id="1261358" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:24:13+01:00</id>
<title> (gargron)'s status on Wednesday, 16-Mar-2016 21:24:13 CET</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256972"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:24:13+00:00</published>
<updated>2016-03-16T20:24:13+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>https://mastodon.social/users/Gargron</id>
<title>Eugen</title>
<summary>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</summary>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/Gargron"/>
<link rel="avatar" type="image/gif" media:width="96" media:height="96" href="https://quitter.no/avatar/15743-original-20160316180410.gif"/>
<link rel="avatar" type="image/gif" media:width="96" media:height="96" href="https://quitter.no/avatar/15743-original-20160316180410.gif"/>
<link rel="avatar" type="image/gif" media:width="48" media:height="48" href="https://quitter.no/avatar/15743-48-20160316180416.gif"/>
<link rel="avatar" type="image/gif" media:width="24" media:height="24" href="https://quitter.no/avatar/15743-24-20160316180416.gif"/>
<poco:preferredUsername>gargron</poco:preferredUsername>
<poco:displayName>Eugen</poco:displayName>
<poco:note>Software engineer, free time musician and enthusiast. Likes cats. Warning: May contain memes</poco:note>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256972.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256972.atom"/>
<statusnet:notice_info local_id="1256972" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256966"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:22:38+00:00</published>
<updated>2016-03-16T20:22:38+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256966"/>
<status_net notice_id="1256966"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256966.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256966.atom"/>
<statusnet:notice_info local_id="1256966" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256939"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:16:15+00:00</published>
<updated>2016-03-16T20:16:15+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256939"/>
<status_net notice_id="1256939"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256939.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256939.atom"/>
<statusnet:notice_info local_id="1256939" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256929"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:13:06+00:00</published>
<updated>2016-03-16T20:13:06+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256929"/>
<status_net notice_id="1256929"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256929.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256929.atom"/>
<statusnet:notice_info local_id="1256929" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256888"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T20:05:03+00:00</published>
<updated>2016-03-16T20:05:03+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256888"/>
<status_net notice_id="1256888"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256888.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256888.atom"/>
<statusnet:notice_info local_id="1256888" source="activity"></statusnet:notice_info>
</entry>
<entry>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>
<title></title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256253"/>
<activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
<published>2016-03-16T18:04:16+00:00</published>
<updated>2016-03-16T18:04:16+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>
<title>New person by gargron</title>
<content type="html">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt; &lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1256253"/>
<status_net notice_id="1256253"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908"/>
<ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256253.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1256253.atom"/>
<statusnet:notice_info local_id="1256253" source="activity"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1251422:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; LGB, not LGBT?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1251422"/>
<status_net notice_id="1251422"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T20:28:13+00:00</published>
<updated>2016-03-15T20:28:13+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-15:noticeId=51852:objectType=note" href="https://community.highlandarrow.com/notice/51852"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/51852"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1251422.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1251422.atom"/>
<statusnet:notice_info local_id="1251422" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1250742:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; I'm like reeeeally close to actually deploying the first production instance of Mastodon, but it bugs me that there's gonna be that issue with avatars and profiles not updating :(</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1250742"/>
<status_net notice_id="1250742"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T18:44:54+00:00</published>
<updated>2016-03-15T18:44:54+00:00</updated>
<thr:in-reply-to ref="tag:social.umeahackerspace.se,2016-03-15:noticeId=424348:objectType=comment" href="https://social.umeahackerspace.se/notice/424348"></thr:in-reply-to>
<link rel="related" href="https://social.umeahackerspace.se/notice/424348"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80"/>
<ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.umeahackerspace.se/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250742.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250742.atom"/>
<statusnet:notice_info local_id="1250742" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:quitter.no,2016-03-15:noticeId=1250653:objectType=note</id>
<title>New note by gargron</title>
<content type="html">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; Any progress on the issues I created?</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1250653"/>
<status_net notice_id="1250653"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-15T18:27:00+00:00</published>
<updated>2016-03-15T18:27:00+00:00</updated>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80"/>
<ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.umeahackerspace.se/user/2"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250653.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1250653.atom"/>
<statusnet:notice_info local_id="1250653" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-14:noticeId=1243566:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; I heard Piwik is also good.</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1243566"/>
<status_net notice_id="1243566"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-14T15:35:23+00:00</published>
<updated>2016-03-14T15:35:23+00:00</updated>
<thr:in-reply-to ref="tag:community.highlandarrow.com,2016-03-14:noticeId=50467:objectType=note" href="https://community.highlandarrow.com/notice/50467"></thr:in-reply-to>
<link rel="related" href="https://community.highlandarrow.com/notice/50467"/>
<link rel="ostatus:conversation" href="tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3"/>
<ostatus:conversation>tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://community.highlandarrow.com/user/1"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243566.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243566.atom"/>
<statusnet:notice_info local_id="1243566" source="Qvitter"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:quitter.no,2016-03-14:noticeId=1243331:objectType=comment</id>
<title>New comment by gargron</title>
<content type="html">I do wish I had somebody else partake in the development process if only to give me feedback on my decisions</content>
<link rel="alternate" type="text/html" href="https://quitter.no/notice/1243331"/>
<status_net notice_id="1243331"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2016-03-14T14:52:03+00:00</published>
<updated>2016-03-14T14:52:03+00:00</updated>
<thr:in-reply-to ref="tag:quitter.no,2016-03-14:noticeId=1243309:objectType=comment" href="https://quitter.no/notice/1243309"></thr:in-reply-to>
<link rel="related" href="https://quitter.no/notice/1243309"/>
<link rel="ostatus:conversation" href="tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01"/>
<ostatus:conversation>tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.no/user/7477"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243331.atom"/>
<link rel="edit" type="application/atom+xml" href="https://quitter.no/api/statuses/show/1243331.atom"/>
<statusnet:notice_info local_id="1243331" source="Qvitter"></statusnet:notice_info>
</entry>
</feed>

11
spec/fixtures/requests/webfinger.txt vendored Normal file
View File

@ -0,0 +1,11 @@
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sun, 20 Mar 2016 11:13:16 GMT
Content-Type: application/jrd+json
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Vary: Accept-Encoding,Cookie
Strict-Transport-Security: max-age=31536000; includeSubdomains;
{"subject":"acct:gargron@quitter.no","aliases":["https:\/\/quitter.no\/user\/7477","https:\/\/quitter.no\/gargron","https:\/\/quitter.no\/index.php\/user\/7477","https:\/\/quitter.no\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/quitter.no\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/quitter.no\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/quitter.no\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/quitter.no\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/quitter.no\/main\/ostatussub?profile={uri}"}]}

2
spec/fixtures/salmon/mention.xml vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the AccountsHelper. For example:
#
# describe AccountsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe AccountsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Api::AccountsHelper. For example:
#
# describe Api::AccountsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Api::AccountsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Api::FollowsHelper. For example:
#
# describe Api::FollowsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Api::FollowsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Api::SalmonHelper. For example:
#
# describe Api::SalmonHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Api::SalmonHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Api::StatusesHelper. For example:
#
# describe Api::StatusesHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Api::StatusesHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Api::SubscriptionsHelper. For example:
#
# describe Api::SubscriptionsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Api::SubscriptionsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -28,4 +28,8 @@ RSpec.describe ApplicationHelper, type: :helper do
expect(helper.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false
end
end
describe '#linkify' do
pending
end
end

View File

@ -6,95 +6,148 @@ RSpec.describe AtomBuilderHelper, type: :helper do
end
describe '#entry' do
pending
it 'creates an entry' do
expect(used_in_builder { |xml| helper.entry(xml) }).to match '<entry/>'
end
end
describe '#feed' do
pending
it 'creates a feed' do
expect(used_in_builder { |xml| helper.feed(xml) }).to match '<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" xmlns:media="http://purl.org/syndication/atommedia"/>'
end
end
describe '#unique_id' do
pending
it 'creates an id' do
time = Time.now
expect(used_in_builder { |xml| helper.unique_id(xml, time, 1, 'Status') }).to match "<id>#{helper.unique_tag(time, 1, 'Status')}</id>"
end
end
describe '#simple_id' do
pending
it 'creates an id' do
expect(used_in_builder { |xml| helper.simple_id(xml, 1) }).to match '<id>1</id>'
end
end
describe '#published_at' do
pending
it 'creates a published tag' do
time = Time.now
expect(used_in_builder { |xml| helper.published_at(xml, time) }).to match "<published>#{time.iso8601}</published>"
end
end
describe '#updated_at' do
pending
it 'creates an updated tag' do
time = Time.now
expect(used_in_builder { |xml| helper.updated_at(xml, time) }).to match "<updated>#{time.iso8601}</updated>"
end
end
describe '#verb' do
pending
it 'creates an entry' do
expect(used_with_namespaces { |xml| helper.verb(xml, 'verb') }).to match '<activity:verb>http://activitystrea.ms/schema/1.0/verb</activity:verb>'
end
end
describe '#content' do
pending
it 'creates a content' do
expect(used_in_builder { |xml| helper.content(xml, 'foo') }).to match '<content type="html">foo</content>'
end
end
describe '#title' do
pending
it 'creates a title' do
expect(used_in_builder { |xml| helper.title(xml, 'foo') }).to match '<title>foo</title>'
end
end
describe '#author' do
pending
it 'creates an author' do
expect(used_in_builder { |xml| helper.author(xml) }).to match '<author/>'
end
end
describe '#target' do
pending
it 'creates a target' do
expect(used_with_namespaces { |xml| helper.target(xml) }).to match '<activity:object/>'
end
end
describe '#object_type' do
pending
it 'creates an object type' do
expect(used_with_namespaces { |xml| helper.object_type(xml, 'test') }).to match '<activity:object-type>http://activitystrea.ms/schema/1.0/test</activity:object-type>'
end
end
describe '#uri' do
pending
it 'creates a uri' do
expect(used_in_builder { |xml| helper.uri(xml, 1) }).to match '<uri>1</uri>'
end
end
describe '#name' do
pending
it 'creates a name' do
expect(used_in_builder { |xml| helper.name(xml, 1) }).to match '<name>1</name>'
end
end
describe '#summary' do
pending
it 'creates a summary' do
expect(used_in_builder { |xml| helper.summary(xml, 1) }).to match '<summary>1</summary>'
end
end
describe '#subtitle' do
pending
it 'creates a subtitle' do
expect(used_in_builder { |xml| helper.subtitle(xml, 1) }).to match '<subtitle>1</subtitle>'
end
end
describe '#link_alternate' do
pending
it 'creates a link' do
expect(used_in_builder { |xml| helper.link_alternate(xml, 1) }).to match '<link rel="alternate" type="text/html" href="1"/>'
end
end
describe '#link_self' do
pending
it 'creates a link' do
expect(used_in_builder { |xml| helper.link_self(xml, 1) }).to match '<link rel="self" type="application/atom+xml" href="1"/>'
end
end
describe '#link_hub' do
pending
it 'creates a link' do
expect(used_in_builder { |xml| helper.link_hub(xml, 1) }).to match '<link rel="hub" href="1"/>'
end
end
describe '#link_salmon' do
pending
it 'creates a link' do
expect(used_in_builder { |xml| helper.link_salmon(xml, 1) }).to match '<link rel="salmon" href="1"/>'
end
end
describe '#portable_contact' do
pending
let(:account) { Fabricate(:account, username: 'alice', display_name: 'Alice in Wonderland') }
it 'creates portable contacts entries' do
expect(used_with_namespaces { |xml| helper.portable_contact(xml, account) }).to match '<poco:displayName>Alice in Wonderland</poco:displayName>'
end
end
describe '#in_reply_to' do
pending
it 'creates a thread' do
expect(used_with_namespaces { |xml| helper.in_reply_to(xml, 'uri', 'url') }).to match '<thr:in-reply-to ref="uri" href="url" type="text/html"/>'
end
end
describe '#link_mention' do
pending
let(:account) { Fabricate(:account, username: 'alice') }
it 'creates a link' do
expect(used_in_builder { |xml| helper.link_mention(xml, account) }).to match '<link rel="mentioned" href="http://test.host/users/alice"/>'
end
end
describe '#disambiguate_uri' do
@ -114,10 +167,25 @@ RSpec.describe AtomBuilderHelper, type: :helper do
end
describe '#link_avatar' do
pending
let(:account) { Fabricate(:account, username: 'alice') }
it 'creates a link' do
expect(used_with_namespaces { |xml| helper.link_avatar(xml, account) }).to match '<link rel="avatar" type="" media:width="300" media:height="300" href="http://test.host/assets/avatars/missing.png"/>'
end
end
describe '#logo' do
pending
it 'creates a logo' do
expect(used_in_builder { |xml| helper.logo(xml, 1) }).to match '<logo>1</logo>'
end
end
def used_in_builder(&block)
builder = Nokogiri::XML::Builder.new(&block)
builder.doc.root.to_xml
end
def used_with_namespaces(&block)
used_in_builder { |xml| helper.entry(xml, true, &block) }
end
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Oauth::ApplicationsHelper. For example:
#
# describe Oauth::ApplicationsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Oauth::ApplicationsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,15 +1,5 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the SettingsHelper. For example:
#
# describe SettingsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe SettingsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -16,4 +16,12 @@ RSpec.describe StreamEntriesHelper, type: :helper do
describe '#relative_time' do
pending
end
describe '#reblogged_by_me_class' do
pending
end
describe '#favourited_by_me_class' do
pending
end
end

View File

@ -0,0 +1,61 @@
require "rails_helper"
RSpec.describe NotificationMailer, type: :mailer do
let(:receiver) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:sender) { Fabricate(:account, username: 'bob') }
let(:foreign_status) { Fabricate(:status, account: sender) }
let(:own_status) { Fabricate(:status, account: receiver.account) }
describe "mention" do
let(:mail) { NotificationMailer.mention(receiver.account, foreign_status) }
it "renders the headers" do
expect(mail.subject).to eq("You were mentioned by bob")
expect(mail.to).to eq([receiver.email])
end
it "renders the body" do
expect(mail.body.encoded).to match("You were mentioned by bob")
end
end
describe "follow" do
let(:mail) { NotificationMailer.follow(receiver.account, sender) }
it "renders the headers" do
expect(mail.subject).to eq("bob is now following you")
expect(mail.to).to eq([receiver.email])
end
it "renders the body" do
expect(mail.body.encoded).to match("bob is now following you")
end
end
describe "favourite" do
let(:mail) { NotificationMailer.favourite(own_status, sender) }
it "renders the headers" do
expect(mail.subject).to eq("bob favourited your status")
expect(mail.to).to eq([receiver.email])
end
it "renders the body" do
expect(mail.body.encoded).to match("Your status was favourited by bob")
end
end
describe "reblog" do
let(:mail) { NotificationMailer.reblog(own_status, sender) }
it "renders the headers" do
expect(mail.subject).to eq("bob reblogged your status")
expect(mail.to).to eq([receiver.email])
end
it "renders the body" do
expect(mail.body.encoded).to match("Your status was reblogged by bob")
end
end
end

View File

@ -0,0 +1,24 @@
# Preview all emails at http://localhost:3000/rails/mailers/notification_mailer
class NotificationMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/mention
def mention
# NotificationMailer.mention
end
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/follow
def follow
# NotificationMailer.follow
end
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/favourite
def favourite
# NotificationMailer.favourite
end
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/reblog
def reblog
# NotificationMailer.reblog
end
end

View File

@ -111,4 +111,16 @@ RSpec.describe Account, type: :model do
describe '#ping!' do
pending
end
describe '#favourited?' do
pending
end
describe '#reblogged?' do
pending
end
describe '.find_local' do
pending
end
end

7
spec/models/feed_spec.rb Normal file
View File

@ -0,0 +1,7 @@
require 'rails_helper'
RSpec.describe Feed, type: :model do
describe '#get' do
pending
end
end

View File

@ -114,4 +114,12 @@ RSpec.describe Status, type: :model do
expect(subject.target).to eq other
end
end
describe '#reblogs_count' do
pending
end
describe '#favourites_count' do
pending
end
end

View File

@ -19,3 +19,7 @@ RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :view
end
def request_fixture(name)
File.read(File.join(Rails.root, 'spec', 'fixtures', 'requests', name))
end

Some files were not shown because too many files have changed in this diff Show More