# client-server
post "/" do
protected!
date = Time.now.strftime("%Y-%m-%dT%H:%M:%S")
outbox_path = File.join("public/outbox", date + ".json")
notes_path = File.join("public/notes", date + ".json")
recipients = ["https://www.w3.org/ns/activitystreams#Public", params[:to]]
recipients += Dir[File.join("public/followers", "*.json")].collect { |f| JSON.parse(File.read(f))["actor"] }
recipients.delete ACTOR
recipients.uniq!
content = []
attachment = []
tag = []
extensions = {
:image => ["jpeg","png"],
:audio => ["flac","wav","mp3","ogg"],
:video => ["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(SOCIAL_URL,'tags',name.sub('#',''))
tag << {
'type' => 'Hashtag',
'href' => href,
'name' => name
}
line.gsub!(name, "#{name}")
end
content << line
end
end
create = {
"@context" => "https://www.w3.org/ns/activitystreams",
"id" => File.join(SOCIAL_URL, outbox_path),
"type" => "Create",
"actor" => ACTOR,
"object" => {
"id" => File.join(SOCIAL_URL, notes_path),
"type" => "Note",
"attributedTo" => ACTOR,
"inReplyTo" => params[:inReplyTo],
"published" => date,
"content" => "
\n"+content.join("\n
")+"\n
",
"attachment" => attachment,
"tag" => tag,
"to" => recipients
},
"published" => date,
"to" => recipients
}
File.open(outbox_path, "w+") { |f| f.puts create.to_json }
File.open(notes_path, "w+") { |f| f.puts create["object"].to_json }
tag.each do |t|
dir = File.join('public','tags',t['name'].sub('#',''))
FileUtils.mkdir_p dir
FileUtils.ln_s File.join('/srv/social/',notes_path), dir
end
#recipients.delete "https://www.w3.org/ns/activitystreams#Public"
#recipients.each { |r| send_signed create, r }
send_signed create #, r }
redirect params['redirect']
end
post "/archive" do
protected!
FileUtils.mv params['file'], "archive/"
redirect to(params['redirect'])
end
post "/delete" do # delete not supported by html forms
protected!
params['file'] ? FileUtils.rm_f(params['file']) : FileUtils.rm_f(Dir["inbox/*.json"])
params['redirect'] ? redirect(params['redirect']) : redirect('/')
end
post "/follow" do
protected!
actor, mention = parse_follow params['follow']
follow = { "@context" => "https://www.w3.org/ns/activitystreams",
"id" => File.join(SOCIAL_URL, "following", mention+ ".json"),
"type" => "Follow",
"actor" => ACTOR,
"object" => actor,
'to' => [ actor ] }
send_signed follow#, actor
redirect "/"
end
post "/unfollow" do
protected!
actor, mention = parse_follow params['follow']
following_path = File.join("public", "following", mention + ".json")
if File.exists?(following_path)
undo = { "@context" => "https://www.w3.org/ns/activitystreams",
"id" => File.join(SOCIAL_URL + "#undo", SecureRandom.uuid),
"type" => "Undo",
"actor" => ACTOR,
"object" => JSON.parse(File.read(following_path)),
'to' => [ actor ] }
send_signed undo#, actor
FileUtils.rm following_path
redirect "/"
end
end
post "/login" do
session["client"] = true if OpenSSL::Digest::SHA256.base64digest(params["secret"]) == File.read(".digest").chomp
redirect "/"
end
# private
["/", "/archive"].each do |path|
get path, :provides => 'html' do
protected!
if path == '/'
@dir = 'inbox'
@alt_dir = '/archive'
@alt_name = 'archive'
else
@dir = path.sub('/','')
@alt_dir = '/'
@alt_name = 'inbox'
end
threads
erb :index
end
end
helpers do
def protected!
halt 403 unless session['client']
end
def items
nr = 0
p @dir
p Dir[File.join(@dir, '*', '*.json')]# + Dir['public/notes/*.json']
files = Dir[File.join(@dir, '*', '*.json')] + Dir['public/notes/*.json']
@items = files.sort.collect do |file|
item = JSON.parse(File.read(file))
mention = mention(item['attributedTo'])
following_path = File.join('public', 'following', mention + '.json')
File.exists?(following_path) ? follow = 'unfollow' : follow = 'follow'
nr += 1
{ :id => item['id'],
:nr => nr,
:parent => item['inReplyTo'],
:file => file,
:actor_url => item['attributedTo'],
:mention => mention,
:follow => follow,
:content => item['content'],
:attachment => item['attachment'],
:indent => 0,
:replies => []
}
end.compact
@items.last[:nr] = @items.last[:nr] - 2 unless @items.empty?
end
def threads
items
@threads = []
@items.each do |i|
if i[:parent].nil? or @items.select{|it| it[:id] == i[:parent] }.empty?
@threads << i
else
@items.select{|it| it[:id] == i[:parent] }.each do |it|
i[:indent] = it[:indent] + 4
it[:replies] << i
end
end
end
end
def html item
@item = item
erb :item
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