Skip to content
Snippets Groups Projects
Commit fa337501 authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Adding reblogs, favourites, improving atom generation

parent 3b0bc18d
No related branches found
No related tags found
No related merge requests found
Showing
with 251 additions and 79 deletions
class ProfileController < ApplicationController
def show
end
def entry
end
end
......@@ -93,6 +93,87 @@ module AtomHelper
xml['poco'].note account.note
end
def in_reply_to(xml, uri, url)
xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' })
end
def disambiguate_uri(target)
if target.local?
if target.object_type == :person
profile_url(name: target.username)
else
unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type)
end
else
target.uri
end
end
def disambiguate_url(target)
if target.local?
if target.object_type == :person
profile_url(name: target.username)
else
status_url(name: target.stream_entry.account.username, id: target.stream_entry.id)
end
else
target.url
end
end
def link_mention(xml, account)
xml.link(rel: 'mentioned', href: disambiguate_uri(account))
end
def include_author(xml, account)
object_type xml, :person
uri xml, profile_url(name: account.username)
name xml, account.username
summary xml, account.note
link_alternate xml, profile_url(name: account.username)
portable_contact xml, account
end
def include_entry(xml, stream_entry)
unique_id xml, stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type
published_at xml, stream_entry.activity.created_at
updated_at xml, stream_entry.activity.updated_at
title xml, stream_entry.title
content xml, stream_entry.content
verb xml, stream_entry.verb
link_self xml, atom_entry_url(id: stream_entry.id)
object_type xml, stream_entry.object_type
# Comments need thread element
if stream_entry.threaded?
in_reply_to xml, disambiguate_uri(stream_entry.thread), disambiguate_url(stream_entry.thread)
end
if stream_entry.targeted?
target(xml) do
object_type xml, stream_entry.target.object_type
simple_id xml, disambiguate_uri(stream_entry.target)
title xml, stream_entry.target.title
link_alternate xml, disambiguate_url(stream_entry.target)
# People have summary and portable contacts information
if stream_entry.target.object_type == :person
summary xml, stream_entry.target.content
portable_contact xml, stream_entry.target
end
# Statuses have content
if [:note, :comment].include? stream_entry.target.object_type
content xml, stream_entry.target.content
end
end
end
stream_entry.mentions.each do |mentioned|
link_mention xml, mentioned
end
end
private
def root_tag(xml, tag, &block)
......
......@@ -5,6 +5,7 @@ class Account < ActiveRecord::Base
# Timelines
has_many :stream_entries, inverse_of: :account
has_many :statuses, inverse_of: :account
has_many :favourites, inverse_of: :account
# Follow relations
has_many :active_relationships, class_name: 'Follow', foreign_key: 'account_id', dependent: :destroy
......@@ -41,7 +42,7 @@ class Account < ActiveRecord::Base
self.username
end
def summary
def content
self.note
end
......
class Favourite < ActiveRecord::Base
belongs_to :account, inverse_of: :favourites
belongs_to :status, inverse_of: :favourites
has_one :stream_entry, as: :activity
def verb
:favorite
end
def title
"#{self.account.acct} favourited a status by #{self.status.account.acct}"
end
def content
title
end
def object_type
target.object_type
end
def target
self.status
end
def mentions
[]
end
def thread
target
end
after_create do
self.account.stream_entries.create!(activity: self)
end
end
......@@ -2,20 +2,23 @@ class Follow < ActiveRecord::Base
belongs_to :account
belongs_to :target_account, class_name: 'Account'
has_one :stream_entry, as: :activity
validates :account, :target_account, presence: true
validates :account_id, uniqueness: { scope: :target_account_id }
def verb
:follow
end
def object_type
:person
end
def target
self.target_account
end
def object_type
target.object_type
end
def content
"#{self.account.acct} started following #{self.target_account.acct}"
end
......@@ -24,6 +27,10 @@ class Follow < ActiveRecord::Base
content
end
def mentions
[]
end
after_create do
self.account.stream_entries.create!(activity: self)
end
......
class Status < ActiveRecord::Base
belongs_to :account, inverse_of: :statuses
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status'
belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status'
has_one :stream_entry, as: :activity
has_many :favourites, inverse_of: :status
validates :account, presence: true
validates :uri, uniqueness: true, unless: 'local?'
def local?
self.uri.nil?
end
def reblog?
!self.reblog_of_id.nil?
end
def reply?
!self.in_reply_to_id.nil?
end
def verb
:post
reblog? ? :share : :post
end
def object_type
:note
reply? ? :comment : :note
end
def content
self.text
reblog? ? self.reblog.text : self.text
end
def target
self.reblog
end
def title
content.truncate(80, omission: "...")
end
def mentions
m = []
m << thread.account if reply?
m << reblog.account if reblog?
m
end
after_create do
self.account.stream_entries.create!(activity: self)
end
......
......@@ -5,7 +5,7 @@ class StreamEntry < ActiveRecord::Base
validates :account, :activity, presence: true
def object_type
self.activity.object_type
targeted? ? :activity : self.activity.object_type
end
def verb
......@@ -13,7 +13,7 @@ class StreamEntry < ActiveRecord::Base
end
def targeted?
[:follow].include? self.verb
[:follow, :share, :favorite].include? verb
end
def target
......@@ -27,4 +27,16 @@ class StreamEntry < ActiveRecord::Base
def content
self.activity.content
end
def threaded?
[:favorite, :comment].include? verb
end
def thread
self.activity.thread
end
def mentions
self.activity.mentions
end
end
......@@ -15,6 +15,7 @@ class FollowRemoteAccountService
account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href
account.salmon_url = data.link('salmon').href
account.url = data.link('http://webfinger.net/rel/profile-page').href
account.public_key = magic_key_to_pem(data.link('magic-public-key').href)
account.private_key = nil
......
......@@ -3,10 +3,10 @@ class ProcessInteractionService
body = salmon.unpack(envelope)
xml = Nokogiri::XML(body)
return if !involves_target_account(xml, target_account) || xml.at_xpath('//author/name').nil? || xml.at_xpath('//author/uri').nil?
return if !involves_target_account(xml, target_account) || xml.at_xpath('//xmlns:author/xmlns:name').nil? || xml.at_xpath('//xmlns:author/xmlns:uri').nil?
username = xml.at_xpath('//author/name').content
url = xml.at_xpath('//author/uri').content
username = xml.at_xpath('//xmlns:author/xmlns:name').content
url = xml.at_xpath('//xmlns:author/xmlns:uri').content
domain = Addressable::URI.parse(url).host
account = Account.find_by(username: username, domain: domain)
......
Nokogiri::XML::Builder.new do |xml|
entry(xml, true) do
unique_id xml, @entry.created_at, @entry.activity_id, @entry.activity_type
published_at xml, @entry.activity.created_at
updated_at xml, @entry.activity.updated_at
title xml, @entry.title
content xml, @entry.content
verb xml, @entry.verb
author(xml) do
object_type xml, :person
uri xml, profile_url(name: @entry.account.username)
name xml, @entry.account.username
summary xml, @entry.account.note
link_alternate xml, profile_url(name: @entry.account.username)
portable_contact xml, @entry.account
end
if @entry.targeted?
target(xml) do
object_type xml, @entry.target.object_type
simple_id xml, @entry.target.uri
title xml, @entry.target.title
summary xml, @entry.target.summary
link_alternate xml, @entry.target.uri
if @entry.target.object_type == :person
portable_contact xml, @entry.target
end
end
else
object_type xml, @entry.object_type
include_author xml, @entry.account
end
link_self xml, atom_entry_url(id: @entry.id)
include_entry xml, @entry
end
end
end.to_xml
......@@ -6,12 +6,7 @@ Nokogiri::XML::Builder.new do |xml|
updated_at xml, stream_updated_at
author(xml) do
object_type xml, :person
uri xml, profile_url(name: @account.username)
name xml, @account.username
summary xml, @account.note
link_alternate xml, profile_url(name: @account.username)
portable_contact xml, @account
include_author xml, @account
end
link_alternate xml, profile_url(name: @account.username)
......@@ -21,29 +16,7 @@ Nokogiri::XML::Builder.new do |xml|
@account.stream_entries.order('id desc').each do |stream_entry|
entry(xml, false) do
unique_id xml, stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type
published_at xml, stream_entry.activity.created_at
updated_at xml, stream_entry.activity.updated_at
title xml, stream_entry.title
content xml, stream_entry.content
verb xml, stream_entry.verb
link_self xml, atom_entry_url(id: stream_entry.id)
if stream_entry.targeted?
target(xml) do
object_type xml, stream_entry.target.object_type
simple_id xml, stream_entry.target.uri
title xml, stream_entry.target.title
summary xml, stream_entry.target.summary
link_alternate xml, stream_entry.target.uri
if stream_entry.target.object_type == :person
portable_contact xml, stream_entry.target
end
end
else
object_type xml, stream_entry.object_type
end
include_entry xml, stream_entry
end
end
end
......
......@@ -5,6 +5,7 @@ Rails.application.routes.draw do
get 'atom/entries/:id', to: 'atom#entry', as: :atom_entry
get 'atom/users/:id', to: 'atom#user_stream', as: :atom_user_stream
get 'users/:name', to: 'profile#show', as: :profile
get 'users/:name/:id', to: 'profile#entry', as: :status
mount Mastodon::API => '/api/'
......
class AddMetadataToStatuses < ActiveRecord::Migration
def change
add_column :statuses, :in_reply_to_id, :integer, null: true
add_column :statuses, :reblog_of_id, :integer, null: true
end
end
class MakeUrisNullableInStatuses < ActiveRecord::Migration
def change
change_column :statuses, :uri, :string, null: true, default: nil
end
end
class AddUrlToStatuses < ActiveRecord::Migration
def change
add_column :statuses, :url, :string, null: true, default: nil
end
end
class AddUrlToAccounts < ActiveRecord::Migration
def change
add_column :accounts, :url, :string, null: true, default: nil
end
end
class CreateFavourites < ActiveRecord::Migration
def change
create_table :favourites do |t|
t.integer :account_id, null: false
t.integer :status_id, null: false
t.timestamps null: false
end
add_index :favourites, [:account_id, :status_id], unique: true
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160222143943) do
ActiveRecord::Schema.define(version: 20160223171800) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -31,10 +31,20 @@ ActiveRecord::Schema.define(version: 20160222143943) do
t.text "note", default: "", null: false
t.string "display_name", default: "", null: false
t.string "uri", default: "", null: false
t.string "url"
end
add_index "accounts", ["username", "domain"], name: "index_accounts_on_username_and_domain", unique: true, using: :btree
create_table "favourites", force: :cascade do |t|
t.integer "account_id", null: false
t.integer "status_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "favourites", ["account_id", "status_id"], name: "index_favourites_on_account_id_and_status_id", unique: true, using: :btree
create_table "follows", force: :cascade do |t|
t.integer "account_id", null: false
t.integer "target_account_id", null: false
......@@ -45,11 +55,14 @@ ActiveRecord::Schema.define(version: 20160222143943) do
add_index "follows", ["account_id", "target_account_id"], name: "index_follows_on_account_id_and_target_account_id", unique: true, using: :btree
create_table "statuses", force: :cascade do |t|
t.string "uri", default: "", null: false
t.integer "account_id", null: false
t.text "text", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "uri"
t.integer "account_id", null: false
t.text "text", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "in_reply_to_id"
t.integer "reblog_of_id"
t.string "url"
end
add_index "statuses", ["uri"], name: "index_statuses_on_uri", unique: true, using: :btree
......
require 'rails_helper'
RSpec.describe Favourite, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment