Commit c4cd63ed authored by Wim Vanderbauwhede's avatar Wim Vanderbauwhede

nm

parent 728b8ff5
Pipeline #3353 failed with stages
in 1 minute and 59 seconds
......@@ -101,20 +101,19 @@ config :pleroma, :media_proxy,
# base_url: "https://cache.pleroma.social"
config :pleroma, :chat, enabled: true
#Added by WV
config :pleroma, bots: [ :pixelbot, :drone]
# Added by WV
config :pleroma, bots: [:pixelbot, :drone]
config :pleroma, :drone,
module: Pleroma.Bots.PollBot
config :pleroma, :drone, module: Pleroma.Bots.PollBot
config :pleroma, :pixelbot,
module: Pleroma.Bots.PixelBot,
canvas_size: {32,32}
canvas_size: {32, 32}
# config :pleroma, :bot,
# enabled: true,
# canvas_size: {32,32}
#config :pleroma, :bot,
#enabled: true,
#canvas_size: {32,32}
config :ecto, json_library: Jason
config :phoenix, :format_encoders, json: Jason
......
......@@ -18,15 +18,15 @@ config :pleroma, Pleroma.Web.Endpoint,
watchers: []
# Do not include metadata nor timestamps in development logs
#config :logger, :console, format: "[$level] $message\n"
# config :logger, :console, format: "[$level] $message\n"
config :logger, level: :warn
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
#config :phoenix, :stacktrace_depth, 20
# config :phoenix, :stacktrace_depth, 20
# Configure your database
#config :pleroma, Pleroma.Repo,
# config :pleroma, Pleroma.Repo,
# adapter: Ecto.Adapters.Postgres,
# username: "pleroma",
# password: "pleroma",
......
......@@ -14,9 +14,9 @@ use Mix.Config
# manifest is generated by the mix phoenix.digest task
# which you typically run after static files are built.
config :pleroma, Pleroma.Web.Endpoint,
# on_init: {Pleroma.Web.Endpoint, :load_from_system_env, []},
# url: [host: "rpi.limited.systems", port: 443],
# cache_static_manifest: "priv/static/cache_manifest.json"
# on_init: {Pleroma.Web.Endpoint, :load_from_system_env, []},
# url: [host: "rpi.limited.systems", port: 443],
# cache_static_manifest: "priv/static/cache_manifest.json"
http: [port: 4000],
protocol: "http"
......
......@@ -11,7 +11,7 @@ defmodule Mix.Tasks.ListAllUsers do
q =
from(
u in User,
#where: fragment("? @> ?", u.info, ^%{"ap_enabled" => true}),
# where: fragment("? @> ?", u.info, ^%{"ap_enabled" => true}),
where: u.local == true
)
......
......@@ -44,15 +44,14 @@ defmodule Pleroma.Application do
] ++
if Mix.env() == :test,
do: [],
## Bot framework
else:
[worker(Pleroma.Web.Streamer, [])] ++
if(
!chat_enabled(),
do: [],
else: [worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
)
## Bot framework
++ if !bots_enabled(), do: [], else: Pleroma.Bots.Common.add_bot_workers()
) ++ if(!bots_enabled(), do: [], else: Pleroma.Bots.Common.add_bot_workers())
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
......
# This module provides some functions to get fields from an activity
# Each returns a tuple {status, field-value} where status is true if the field was present, false otherwise.
defmodule Pleroma.Bots.Activity do
def get_nickname(params) do
if is_map(params) and Map.has_key?(params,"nickname") do
{true,params["nickname"]}
if is_map(params) and Map.has_key?(params, "nickname") do
{true, params["nickname"]}
else
{false,""}
{false, ""}
end
end
def get_object(params) do
if is_map(params) and Map.has_key?(params,"object") do
obj = params["object"]
if is_map(obj) do
{true,params["object"]}
else
# Should really have a separate status I guess
{false,params["object"]}
end
if is_map(params) and Map.has_key?(params, "object") do
obj = params["object"]
if is_map(obj) do
{true, params["object"]}
else
# Should really have a separate status I guess
{false, params["object"]}
end
else
{false,%{}}
end
{false, %{}}
end
end
def get_content(activity) do
{status, obj} = get_object(activity)
if status and Map.has_key?(obj,"content") do
if status and Map.has_key?(obj, "content") do
{true, obj["content"]}
else
else
{false, ""}
end
end
def get_object_id(activity) do
{status, obj} = get_object(activity)
if status and Map.has_key?(obj,"id") do
if status and Map.has_key?(obj, "id") do
{true, obj["id"]}
else
else
{false, ""}
end
end
def get_attachments(activity) do
{status, obj} = get_object(activity)
if status and Map.has_key?(obj,"attachment") do
if status and Map.has_key?(obj, "attachment") do
{true, obj["attachment"]}
else
{false,[]}
{false, []}
end
end
def get_attachment_urls(activity) do
{status,attachments}= get_attachments(activity)
{status, attachments} = get_attachments(activity)
if status do
{true,List.flatten(Enum.map(attachments, fn(att) -> Enum.map(att["url"],fn(url) -> url["href"] end) end))}
{true,
List.flatten(
Enum.map(attachments, fn att -> Enum.map(att["url"], fn url -> url["href"] end) end)
)}
else
{false,[]}
{false, []}
end
end
def get_actor(params) do
if is_map(params) and Map.has_key?(params,"actor") do
if is_map(params) and Map.has_key?(params, "actor") do
{true, params["actor"]}
else
{false,""}
end
{false, ""}
end
end
def get_conversation(activity) do
{status, obj} = get_object(activity)
if status and Map.has_key?(obj,"conversation") do
if status and Map.has_key?(obj, "conversation") do
{true, obj["conversation"]}
else
{false,""}
end
{false, ""}
end
end
def get_context(activity) do
{status, obj} = get_object(activity)
if status and Map.has_key?(obj,"context") do
if status and Map.has_key?(obj, "context") do
{true, obj["context"]}
else
{false,[]}
end
{false, []}
end
end
def get_visibility(activity) do
{status, obj} = get_object(activity)
if status do
{true, Pleroma.Web.MastodonAPI.StatusView.get_visibility(obj)}
else
{false,"public"}
{false, "public"}
end
end
def get_sender(activity) do
get_actor(activity)
end
end
This diff is collapsed.
defmodule Pleroma.Bots.Parser do
# This returns the chunks of text between the tags
defp fsm_parse_chunk_on_tags(text,state, chunks,chunk) do
if length(text) == 0 do chunks++[chunk]
defp fsm_parse_chunk_on_tags(text, state, chunks, chunk) do
if length(text) == 0 do
chunks ++ [chunk]
else
[c | cs ] = text
{nstate,nchunks,nchunk} = if c == "<" do
{ 0 , chunks++[chunk],[]}
else
if c == ">" do
{1,chunks,[]}
[c | cs] = text
{nstate, nchunks, nchunk} =
if c == "<" do
{0, chunks ++ [chunk], []}
else
{state,chunks,chunk}
if c == ">" do
{1, chunks, []}
else
{state, chunks, chunk}
end
end
end
if nstate == 0 do
# it"s a tag, skip it
fsm_parse_chunk_on_tags(cs,nstate,nchunks,nchunk)
fsm_parse_chunk_on_tags(cs, nstate, nchunks, nchunk)
else
# it"s not a tag, append to chunk
if c != ">" do
fsm_parse_chunk_on_tags(cs,nstate,nchunks,nchunk++[c])
fsm_parse_chunk_on_tags(cs, nstate, nchunks, nchunk ++ [c])
else
fsm_parse_chunk_on_tags(cs,nstate,nchunks,nchunk)
fsm_parse_chunk_on_tags(cs, nstate, nchunks, nchunk)
end
end
end
end
def strip_tags(msg) do
text = String.codepoints(msg) # WV: there must be a better way, like converting to char list ...
fsm_parse_chunk_on_tags(text,0,[],[])
|> Enum.map(fn(lst) -> to_string(lst) end)
# I join the chunks with a "" but <br> might get me into trouble
|> Enum.join("")
# WV: there must be a better way, like converting to char list ...
text = String.codepoints(msg)
fsm_parse_chunk_on_tags(text, 0, [], [])
|> Enum.map(fn lst -> to_string(lst) end)
# I join the chunks with a "" but <br> might get me into trouble
|> Enum.join("")
end
@entities %{
"quot" => "\"",
"amp" => "&",
......@@ -58,18 +63,17 @@ defmodule Pleroma.Bots.Parser do
"#169;" => "©",
"reg;" => "®",
"#174;" => "®"
}
}
def replace_entities(str) do
Regex.replace(~r/\&(\#\d+|\w+);/,str, fn _, x -> Map.get(@entities,x,"") end)
Regex.replace(~r/\&(\#\d+|\w+);/, str, fn _, x -> Map.get(@entities, x, "") end)
end
end
# str="<span><a href='https://mbp.limited.systems/users/drone'>@<span>drone</span></a></span> PollBot: wim {&quot;answers&quot;:{&quot;1&quot;:[&quot;red&quot;,0],&quot;2&quot;:[&quot;green&quot;,0],&quot;3&quot;:[&quot;blue&quot;,0]},&quot;closed&quot;:false,&quot;closes&quot;:0,&quot;hashtag&quot;:&quot;<a href='https://mbp.limited.systems/tag/favcolourpoll' rel='tag'>#favcolourpoll</a>&quot;,&quot;onlyfor&quot;:[],&quot;owner&quot;:&quot;<a href=\"https://mbp.limited.systems/users/wim&quot;\">https://mbp.limited.systems/users/wim&quot;</a>;,&quot;question&quot;:&quot;text, e.g. what is your fav colour&quot;}"
# str_ = Pleroma.Bots.Parser.strip_tags(str)
# IO.puts(str_)
#str="<span><a href='https://mbp.limited.systems/users/drone'>@<span>drone</span></a></span> PollBot: wim {&quot;answers&quot;:{&quot;1&quot;:[&quot;red&quot;,0],&quot;2&quot;:[&quot;green&quot;,0],&quot;3&quot;:[&quot;blue&quot;,0]},&quot;closed&quot;:false,&quot;closes&quot;:0,&quot;hashtag&quot;:&quot;<a href='https://mbp.limited.systems/tag/favcolourpoll' rel='tag'>#favcolourpoll</a>&quot;,&quot;onlyfor&quot;:[],&quot;owner&quot;:&quot;<a href=\"https://mbp.limited.systems/users/wim&quot;\">https://mbp.limited.systems/users/wim&quot;</a>;,&quot;question&quot;:&quot;text, e.g. what is your fav colour&quot;}"
#str_ = Pleroma.Bots.Parser.strip_tags(str)
#IO.puts(str_)
#str__ = Pleroma.Bots.Parser.replace_entities(str_)
#IO.puts(str__)
#"""
# str__ = Pleroma.Bots.Parser.replace_entities(str_)
# IO.puts(str__)
# """
......@@ -2,7 +2,7 @@
# hellobot has no state, let's give it an empty list
defmodule Pleroma.Bots.HelloBot do
use GenServer
alias Pleroma.Bots.Activity
alias Pleroma.Bots.Common
......@@ -18,44 +18,44 @@ defmodule Pleroma.Bots.HelloBot do
hellobot_init()
end
def handle_cast( msg, state) do
hellobot_main( msg, state )
def handle_cast(msg, state) do
hellobot_main(msg, state)
end
# Implement this if you want a synchronous bot
#def handle_call(msg, _from, state) do
# def handle_call(msg, _from, state) do
## See https://hexdocs.pm/elixir/GenServer.html#c:handle_call/3
#end
# end
## These are the actual functions implementing the bot
defp hellobot_init() do
{:ok, [] }
{:ok, []}
end
defp hellobot_main( msg, state ) do
{status,msg_content} = Activity.get_content(msg)
defp hellobot_main(msg, state) do
{status, msg_content} = Activity.get_content(msg)
if status do
hellobot_post_status(msg)
{:noreply, state}
else
{:noreply, state}
end
end
end
defp hellobot_post_status(received_activity) do
{_,sender} = Activity.get_actor(received_activity)
sender_nickname = List.last( String.split(sender,"/") )
content = "Hello, "<>sender_nickname<>"!"
{_, sender} = Activity.get_actor(received_activity)
sender_nickname = List.last(String.split(sender, "/"))
content = "Hello, " <> sender_nickname <> "!"
{_,visibility} = Activity.get_visibility(received_activity["object"])
{_, visibility} = Activity.get_visibility(received_activity["object"])
status_details=%{
status_details = %{
content: content,
visibility: visibility
}
Common.bot_post_status(received_activity,status_details)
end
Common.bot_post_status(received_activity, status_details)
end
end
# WV: server for the pixelbot.
defmodule Pleroma.Bots.PixelBot do
use GenServer
alias Pleroma.Bots.PixelBot.ParseMessage
alias Pleroma.Bots.PixelBot.ParseMessage
alias Pleroma.Bots.PixelBot.PostStatus
# Starts a GenServer server process.
......@@ -16,47 +16,50 @@ defmodule Pleroma.Bots.PixelBot do
pixelbot_init()
end
def handle_cast( msg, canvas) do
pixelbot_main( msg, canvas )
def handle_cast(msg, canvas) do
pixelbot_main(msg, canvas)
end
# Implement this if you want a synchronous bot
#def handle_call(msg, _from, canvas) do
# def handle_call(msg, _from, canvas) do
## See https://hexdocs.pm/elixir/GenServer.html#c:handle_call/3
#end
# end
## These are the actual functions implementing the bot
defp pixelbot_init() do
{canvas_w,canvas_h}=get_canvas_size()
canvas = init_canvas(canvas_w,canvas_h)
{canvas_w, canvas_h} = get_canvas_size()
canvas = init_canvas(canvas_w, canvas_h)
{:ok, canvas}
end
defp pixelbot_main( msg, canvas ) do
{status,msg_content} = Pleroma.Bots.Activity.get_content(msg)
defp pixelbot_main(msg, canvas) do
{status, msg_content} = Pleroma.Bots.Activity.get_content(msg)
if status do
pixels = ParseMessage.get_pixels_from_message(msg_content)
updated_canvas = update_canvas(pixels,canvas)
if length( pixels ) > 0 do
updated_canvas = update_canvas(pixels, canvas)
if length(pixels) > 0 do
PostStatus.pixelbot_post_status(msg)
end
{:noreply, updated_canvas}
else
{:noreply, canvas}
end
end
end
defp get_canvas_size do
Application.get_env(:pleroma, :pixelbot, []) |> Keyword.get(:canvas_size)
Application.get_env(:pleroma, :pixelbot, []) |> Keyword.get(:canvas_size)
end
defp update_canvas(pixels,canvas) do
defp update_canvas(pixels, canvas) do
# pixels is a list of tuples
# for every tuple we need to update the canvas so this is a fold
updated_canvas = List.foldl(pixels,canvas, fn(pixel, canvas) -> update_single_pixel(pixel, canvas) end )
updated_canvas =
List.foldl(pixels, canvas, fn pixel, canvas -> update_single_pixel(pixel, canvas) end)
# Now write this to a PNG
# Easiest way: to write to CSV and then do a system call
write_canvas_to_csv(updated_canvas)
......@@ -64,24 +67,25 @@ defmodule Pleroma.Bots.PixelBot do
updated_canvas
end
defp update_single_pixel(pixel,canvas) do
{xx,yy,colour}=pixel
canvas_h=length(canvas)
canvas_w=length(List.first(canvas))
x = Integer.mod(xx,canvas_w)
y = Integer.mod(yy,canvas_h)
{row_at_x, canvas_min_row} = List.pop_at(canvas,x)
updated_row_at_x = List.replace_at(row_at_x,y,colour)
defp update_single_pixel(pixel, canvas) do
{xx, yy, colour} = pixel
canvas_h = length(canvas)
canvas_w = length(List.first(canvas))
x = Integer.mod(xx, canvas_w)
y = Integer.mod(yy, canvas_h)
{row_at_x, canvas_min_row} = List.pop_at(canvas, x)
updated_row_at_x = List.replace_at(row_at_x, y, colour)
List.insert_at(canvas_min_row, x, updated_row_at_x)
end
defp init_canvas(w,h) do
defp init_canvas(w, h) do
# If a canvas.csv file exists we should load that one first
canvas_from_csv = read_canvas_from_csv()
if length(canvas_from_csv)==0 do
row = List.duplicate(0,w)
canvas = List.duplicate(row,h)
if length(canvas_from_csv) == 0 do
row = List.duplicate(0, w)
canvas = List.duplicate(row, h)
canvas
else
# TODO: deal with canvas of different size
......@@ -90,36 +94,40 @@ defmodule Pleroma.Bots.PixelBot do
end
defp read_canvas_from_csv() do
{:ok,wd }= File.cwd()
file_path = wd <>"/pixelbot/canvas.csv"
{status, file} = File.open(file_path,[:read,:utf8])
{:ok, wd} = File.cwd()
file_path = wd <> "/pixelbot/canvas.csv"
{status, file} = File.open(file_path, [:read, :utf8])
if status != :ok do
[]
else
csv_str = IO.read(file, :all)
row_strs = String.split(csv_str,"\n")
|> Enum.filter(fn(str) -> str != "" end)
Enum.map(row_strs, fn(row_str) -> String.split(row_str,",") |> Enum.map(fn(elt) -> String.to_integer(elt) end) end)
csv_str = IO.read(file, :all)
row_strs =
String.split(csv_str, "\n")
|> Enum.filter(fn str -> str != "" end)
Enum.map(row_strs, fn row_str ->
String.split(row_str, ",") |> Enum.map(fn elt -> String.to_integer(elt) end)
end)
end
end
end
defp write_canvas_to_csv(canvas) do
{:ok,wd }= File.cwd()
file_path = wd <>"/pixelbot/canvas.csv"
csv_str = create_csv_str_from_canvas(canvas)
File.write(file_path,csv_str)
{:ok, wd} = File.cwd()
file_path = wd <> "/pixelbot/canvas.csv"
csv_str = create_csv_str_from_canvas(canvas)
File.write(file_path, csv_str)
end
defp create_csv_str_from_canvas(canvas) do
Enum.map(canvas,fn(row) -> Enum.join(row,",") end)
Enum.map(canvas, fn row -> Enum.join(row, ",") end)
|> Enum.join("\n")
end
defp create_png_via_system_call() do
{:ok,wd }= File.cwd()
file_path = wd <>"/pixelbot/create_png_from_csv"
System.cmd(file_path,[])
{:ok, wd} = File.cwd()
file_path = wd <> "/pixelbot/create_png_from_csv"
System.cmd(file_path, [])
end
end
This diff is collapsed.
defmodule Pleroma.Bots.PixelBot.PostStatus do
# I can use CommonAPI.post to create the activity from the simple status
# For the user I can use Repo.get(User, 2599)
# post() returns an activity but the attachment is not there
......@@ -7,14 +6,24 @@ defmodule Pleroma.Bots.PixelBot.PostStatus do
def pixelbot_post_status(received_activity) do
now = DateTime.to_string(DateTime.utc_now())
content = "Canvas at "<>now<>"<br><a href=\"https://pynq.limited.systems/pixelbot/canvas_512x512.png\" class='attachment'>canvas.png</a>"
attachments= [
%{"name" => "canvas_512x512.png", "type" => "Image",
"url" => [%{"href" => "https://pynq.limited.systems/pixelbot/canvas_512x512.png",
"mediaType" => "image/png", "type" => "Link"}],
"uuid" => "pixelbot-dummy-uuid"
content =
"Canvas at " <>
now <>
"<br><a href=\"https://pynq.limited.systems/pixelbot/canvas_512x512.png\" class='attachment'>canvas.png</a>"
attachments = [
%{
"name" => "canvas_512x512.png",
"type" => "Image",
"url" => [
%{
"href" => "https://pynq.limited.systems/pixelbot/canvas_512x512.png",
"mediaType" => "image/png",
"type" => "Link"
}
],
"uuid" => "pixelbot-dummy-uuid"
}
]
......@@ -23,13 +32,15 @@ defmodule Pleroma.Bots.PixelBot.PostStatus do
# The user should specificy what goes in the to: and what in the cc:
# Alternativelywe could inherit the visibility
{to, cc} = case visibility do
"public" ->{[:public],[:followers]}
"unlisted" ->{[:followers],[:public]}
"private" ->{[:followers],[:reply]}
"direct" -> {[:reply],[]}
end
status_details=%{