# frozen_string_literal: true
# client-server
post '/' do # TODO
protected!
Time.now.strftime('%Y-%m-%dT%H:%M:%S.%N')
recipients = public
recipients << params[:to]
content = []
attachment = []
tag = []
extensions = {
image: %w[jpeg png],
audio: %w[flac wav mp3 ogg],
video: %w[mp4 webm]
}
params[:content].lines.each do |line|
line.chomp!
if line.match(/^http/)
ext = File.extname(line).sub('.', '')
media_type = extensions.select { |_k, v| v.include? ext }.keys[0].to_s + '/' + ext
attachment << {
'type' => 'Document',
'mediaType' => media_type,
'url' => line
}
else
tags = line.split(/\s+/).grep(/^#\w+$/)
tags.each do |name|
# href = File.join(TAGS_URL, name.sub('#', ''))
tag_url = File.join(TAGS_URL, name.sub('#', ''))
tag << {
'type' => 'Hashtag',
'href' => tag_url,
'name' => name
}
end
mentions = line.split(/\s+/).grep(/^@\w+@\S+$/)
mentions.each do |mention|
actor = actor(mention)
tag << {
'type' => 'Mention',
'href' => actor,
'name' => mention
}
end
content << line
end
end
object = {
'type' => 'Note',
'attributedTo' => ACTOR,
'inReplyTo' => params[:inReplyTo],
'content' => "
\n#{content.join("\n
")}\n
",
'attachment' => attachment,
'tag' => tag,
'to' => recipients
}
activity = outbox 'Create', object, recipients, true
activity['object']['tag'].each do |tag|
next unless tag['type'] == 'Hashtag'
tag_path = File.join(TAGS_DIR, tag['name'].sub('#', '')) + '.json'
unless File.exist? tag_path
File.open(tag_path, 'w+') do |f|
tag_collection = {
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => tag['href'],
'type' => 'OrderedCollection',
'totalItems' => 0,
'orderedItems' => []
}
f.puts tag_collection.to_json
end
end
update_collection tag_path, activity['object']['id']
end
redirect(params['anchor'] || '/inbox')
end
post '/delete' do
protected!
collection = Kernel.const_get(params['dir'].upcase)
if params['id']
update_collection collection, params, true
else
update_collection collection, JSON.parse(File.read(collection))['orderedItems'], true
end
redirect(params['anchor'] || '/inbox')
end
post '/follow' do
protected!
actor, = parse_follow params['follow']
outbox 'Follow', actor, [actor]
redirect(params['anchor'] || '/inbox')
end
post '/unfollow' do
protected!
actor, mention = parse_follow params['follow']
Dir[File.join(OUTBOX_DIR, 'follow', '*.json')].each do |f|
activity = JSON.parse(File.read(f))
if activity['object'] == actor
outbox 'Undo', activity, [actor]
update_collection FOLLOWING, actor, true
end
end
redirect(params['anchor'] || '/inbox')
end
post '/share' do # TODO
protected!
inbox = JSON.parse File.read(INBOX)
object = inbox['orderedItems'].find { |i| i['id'] == params['id'] }
update_collection SHARED, object
update_collection INBOX, object, true
recipients = public
recipients << object['attributedTo']
outbox 'Announce', params['id'], recipients
redirect(params['anchor'] || '/inbox')
end
post '/login' do
session['client'] = (OpenSSL::Digest::SHA256.base64digest(params['secret']) == File.read('.digest').chomp)
redirect '/inbox'
end
get '/' do
protected!
redirect '/inbox'
end
['/inbox', '/shared', '/outbox'].each do |path|
get path, provides: 'html' do
protected!
@dir = path.sub('/', '')
collection = JSON.parse(File.read(Kernel.const_get(@dir.upcase)))['orderedItems'].uniq
@threads = []
collection.each do |object|
object['indent'] = 0
object['replies'] = []
@threads << object if object['inReplyTo'].nil? || collection.select { |o| o['id'] == object['inReplyTo'] }.empty?
end
collection.each do |object|
collection.select { |o| o['id'] == object['inReplyTo'] }.each do |o|
object['indent'] = o['indent'] + 2
o['replies'] << object
end
end
erb :collection
end
end
helpers do
def protected!
halt 403 unless session['client']
end
def selection(params)
selection = Dir[File.join(SOCIAL_DIR, params['dir'], '*', '*.json')]
params['id'] ? selection.select { |f| JSON.parse(File.read(f))['id'] == params['id'] } : selection
end
def public
recipients = ['https://www.w3.org/ns/activitystreams#Public']
recipients += Dir[File.join(FOLLOWERS, '*.json')].collect { |f| JSON.parse(File.read(f))['actor'] }
recipients.delete ACTOR
recipients.uniq
end
def parse_follow(follow)
case follow
when /^#/
actor = "https://relay.fedi.buzz/tag/#{follow.sub(/^#/, '')}"
mention = follow
when /^http/
actor = follow
mention = mention(actor)
when /^@*\w+@\w+/
mention = follow
actor = actor(follow)
return 502 unless actor
end
[actor, mention]
end
end