ayadn 0.6.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +14 -0
  6. data/Guardfile +26 -0
  7. data/LICENSE.txt +22 -0
  8. data/MANUAL.md +946 -0
  9. data/README.md +26 -411
  10. data/Rakefile +6 -0
  11. data/ayadn.gemspec +39 -0
  12. data/bin/ayadn +3 -3
  13. data/lib/ayadn.rb +12 -25
  14. data/lib/ayadn/action.rb +1121 -0
  15. data/lib/ayadn/alias.rb +106 -0
  16. data/lib/ayadn/api.rb +312 -301
  17. data/lib/ayadn/app.rb +429 -365
  18. data/lib/ayadn/authorize.rb +127 -28
  19. data/lib/ayadn/blacklist.rb +116 -0
  20. data/lib/ayadn/cnx.rb +105 -0
  21. data/lib/ayadn/databases.rb +110 -0
  22. data/lib/ayadn/descriptions.rb +1043 -0
  23. data/lib/ayadn/endpoints.rb +220 -153
  24. data/lib/ayadn/errors.rb +37 -0
  25. data/lib/ayadn/extend.rb +4 -10
  26. data/lib/ayadn/fileops.rb +48 -0
  27. data/lib/ayadn/logs.rb +32 -0
  28. data/lib/ayadn/pinboard.rb +46 -35
  29. data/lib/ayadn/post.rb +229 -212
  30. data/lib/ayadn/scroll.rb +251 -0
  31. data/lib/ayadn/set.rb +377 -0
  32. data/lib/ayadn/settings.rb +195 -0
  33. data/lib/ayadn/status.rb +226 -165
  34. data/lib/ayadn/switch.rb +72 -0
  35. data/lib/ayadn/version.rb +4 -0
  36. data/lib/ayadn/view.rb +506 -269
  37. data/lib/ayadn/workers.rb +362 -0
  38. data/spec/helpers.rb +19 -0
  39. data/spec/mock/@ericd.json +160 -0
  40. data/spec/mock/@m.json +45 -0
  41. data/spec/mock/checkins.json +1856 -0
  42. data/spec/mock/fwr_@ayadn.json +1077 -0
  43. data/spec/mock/posted.json +1 -0
  44. data/spec/mock/stream.json +1 -0
  45. data/spec/spec_helper.rb +14 -0
  46. data/spec/unit/api_spec.rb +61 -0
  47. data/spec/unit/databases_spec.rb +5 -0
  48. data/spec/unit/descriptions_spec.rb +9 -0
  49. data/spec/unit/endpoints_spec.rb +35 -0
  50. data/spec/unit/post_spec.rb +136 -0
  51. data/spec/unit/status_spec.rb +9 -0
  52. data/spec/unit/view_spec.rb +119 -0
  53. data/spec/unit/workers_spec.rb +147 -0
  54. metadata +216 -40
  55. data/CHANGELOG.md +0 -250
  56. data/CONTRIBUTORS.md +0 -5
  57. data/LICENSE.md +0 -14
  58. data/lib/ayadn/adn_files.rb +0 -84
  59. data/lib/ayadn/client-http.rb +0 -226
  60. data/lib/ayadn/colors.rb +0 -62
  61. data/lib/ayadn/config.yml +0 -35
  62. data/lib/ayadn/debug.rb +0 -36
  63. data/lib/ayadn/files.rb +0 -184
  64. data/lib/ayadn/get-api.rb +0 -43
  65. data/lib/ayadn/help.rb +0 -152
  66. data/lib/ayadn/list.rb +0 -89
  67. data/lib/ayadn/main.rb +0 -542
  68. data/lib/ayadn/requires.rb +0 -12
  69. data/lib/ayadn/skip.rb +0 -27
  70. data/lib/ayadn/tools.rb +0 -208
  71. data/lib/ayadn/user-stream.rb +0 -91
  72. data/lib/ayadn/view-channels.rb +0 -120
  73. data/lib/ayadn/view-interactions.rb +0 -57
  74. data/lib/ayadn/view-object.rb +0 -195
  75. data/lib/experiments.rb +0 -109
data/lib/ayadn/logs.rb ADDED
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module Ayadn
3
+ class Logs
4
+ class << self
5
+ attr_accessor :rec
6
+ end
7
+ def self.create_logger
8
+ @rec = Logger.new(Settings.config[:paths][:log] + "/ayadn.log", 'monthly')
9
+ @rec.formatter = proc do |severity, datetime, progname, msg|
10
+ "#{datetime} (#{Settings.config[:version]}) #{severity} -- #{msg}\n"
11
+ end
12
+ end
13
+
14
+ # unused (experiment)
15
+ def self.send_log(from, args, content)
16
+ begin
17
+ log = {
18
+ "platform" => "#{Settings.config[:platform]}",
19
+ "date" => Time.now,
20
+ "version" => "#{Settings.config[:version]}",
21
+ "source" => from,
22
+ "args" => args,
23
+ "content" => content
24
+ }
25
+ Post.new.send_log(log)
26
+ rescue
27
+ @rec.warn("Unable to send log.")
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -1,37 +1,48 @@
1
- #!/usr/bin/env ruby
2
- require 'base64'
3
- require 'open-uri'
4
-
5
1
  # encoding: utf-8
6
- class AyaDN
7
- def ayadnBookmark(*args)
8
- post_id = args[0][1]
9
- tags = args[0][2]
10
- hash = @api.getSinglePost(post_id)
11
- data = hash['data']
12
- post_text = data['text']
13
- user_name = data['user']['username']
14
- link = data['entities']['links'][0]['url']
15
- if $tools.config['pinboard']['username'] != nil
16
- puts "\nSaving post ".green + post_id.brown + " to Pinboard...\n".green
17
- $tools.saveToPinboard(post_id, $tools.config['pinboard']['username'], URI.unescape(Base64::decode64($tools.config['pinboard']['password'])), link, tags, post_text, user_name)
18
- puts "Done!\n\n".green
19
- else
20
- puts "\nConfiguration does not include your Pinbard credentials.\n".red
21
- begin
22
- puts "Please enter your Pinboard username (CTRL+C to cancel): ".green
23
- pin_username = STDIN.gets.chomp()
24
- puts "\nPlease enter your Pinboard password (invisible, CTRL+C to cancel): ".green
25
- pin_password = STDIN.noecho(&:gets).chomp()
26
- rescue Exception
27
- abort($status.stopped)
28
- end
29
- $tools.config['pinboard']['username'] = pin_username
30
- $tools.config['pinboard']['password'] = URI.escape(Base64::encode64(pin_password))
31
- $tools.saveConfig
32
- puts "Saving post ".green + post_id.brown + " to Pinboard...\n".green
33
- $tools.saveToPinboard(post_id, pin_username, pin_password, link, tags, post_text, user_name)
34
- puts "Done!\n\n".green
35
- end
36
- end
2
+ module Ayadn
3
+ class PinBoard
4
+
5
+ def has_credentials_file?
6
+ File.exist?(Ayadn::Settings.config[:paths][:db] + '/ayadn_pinboard.db')
7
+ end
8
+
9
+ def ask_credentials
10
+ begin
11
+ puts "Please enter your Pinboard username (CTRL+C to cancel): ".color(:green)
12
+ pin_username = STDIN.gets.chomp()
13
+ puts "\nPlease enter your Pinboard password (invisible, CTRL+C to cancel): ".color(:green)
14
+ pin_password = STDIN.noecho(&:gets).chomp()
15
+ rescue Interrupt
16
+ abort(Status.canceled)
17
+ rescue => e
18
+ puts Status.wtf
19
+ Errors.global_error("pinboard/ask_credentials", pin_username, e)
20
+ end
21
+ save_credentials(encode(pin_username, pin_password))
22
+ end
23
+
24
+ def load_credentials
25
+ decode(File.read(Ayadn::Settings.config[:paths][:db] + '/ayadn_pinboard.db'))
26
+ end
27
+
28
+ def pin(data)
29
+ pinboard = Pinboard::Client.new(:username => data.username, :password => data.password)
30
+ pinboard.add(:url => data.url, :tags => data.tags, :extended => data.text, :description => data.description)
31
+ end
32
+
33
+ private
34
+
35
+ def decode(encoded_pinboard_credentials)
36
+ Base64.strict_decode64(encoded_pinboard_credentials[/AyadnPinboard (.*)/, 1]).split(":")
37
+ end
38
+
39
+ def save_credentials(encoded_pinboard_credentials)
40
+ File.write(Ayadn::Settings.config[:paths][:db] + '/ayadn_pinboard.db', encoded_pinboard_credentials)
41
+ end
42
+
43
+ def encode(username, password)
44
+ "AyadnPinboard #{Base64.strict_encode64([username, password].join(":"))}"
45
+ end
46
+
47
+ end
37
48
  end
data/lib/ayadn/post.rb CHANGED
@@ -1,212 +1,229 @@
1
- #!/usr/bin/env ruby
2
- # encoding: utf-8
3
- class AyaDN
4
- def ayadn_compose_post
5
- puts $status.writePost + "\n"
6
- char_count = $tools.ayadn_configuration[:post_max_length]
7
- begin
8
- input_text = STDIN.gets.chomp
9
- rescue Exception
10
- abort($status.errorPostNotSent)
11
- end
12
- real_text_length = $tools.getMarkdownText(input_text.dup).length
13
- remaining_text_length = char_count - real_text_length
14
- if remaining_text_length >= 0
15
- ayadnSendPost(input_text, nil)
16
- else
17
- abort($status.errorPostTooLong(real_text_length, remaining_text_length.abs))
18
- end
19
- end
20
- def ayadnSendPost(text, reply_to = nil)
21
- abort($status.emptyPost) if (text == nil)
22
- puts $status.sendPost
23
- blob = JSON.parse(@api.httpSend(text, reply_to))
24
- @hash = blob['data']
25
- my_post_id = @hash['id']
26
- puts @view.new(nil).buildSimplePostInfo(@hash)
27
- puts $status.postSent
28
- if $tools.config['files']['auto_save_sent_posts']
29
- fileURL = $tools.ayadn_configuration[:posts_path] + "/#{my_post_id}.post"
30
- f = File.new(fileURL, "w")
31
- f.puts(@hash)
32
- f.close
33
- end
34
- if (reply_to == nil || reply_to.empty?)
35
- @hash = @api.getSimpleUnified
36
- stream, last_page_id = completeStream
37
- stream.sub!(/#{my_post_id}/, my_post_id.to_s.green.reverse_color)
38
- displayStream(stream)
39
- else
40
- @hash = @api.getPostReplies(reply_to)
41
- stream, last_page_id = completeStream
42
- stream.sub!(/#{reply_to}/, reply_to.to_s.red.reverse_color)
43
- stream.sub!(/#{my_post_id}/, my_post_id.to_s.green.reverse_color)
44
- displayStream(stream)
45
- end
46
- end
47
- def ayadn_quote(post_id)
48
- @progress_indicator = false
49
- post_to_quote = @api.getSinglePost(post_id)
50
- meta, data = post_to_quote['meta'], post_to_quote['data']
51
- puts "\n"
52
- if data['text'] != nil
53
- text_to_quote = $tools.withoutSquareBraces(data['text']).chomp(" ")
54
- else
55
- abort("\n\nError: no text to quote.\n\n".red)
56
- end
57
- @new_string = text_to_quote
58
- if data['entities']['links'] != nil
59
- data['entities']['links'].each do |obj|
60
- @new_string = text_to_quote.gsub("#{obj['text']}", "[#{obj['text']}](#{obj['url']})").chomp(" ")
61
- end
62
- end
63
- new_text = " >> @#{data['user']['username']}: " + (@new_string ||= text_to_quote)
64
- remaining = $tools.ayadn_configuration[:post_max_length] - $tools.getMarkdownText(new_text.dup).length - 1
65
- puts "AyaDN will automatically quote the original post like this after your comment. Markdown and embedded links will be preserved. (CTRL-C to cancel):\n".green
66
- puts '"' + $tools.getMarkdownText(new_text.dup) + '"' + "\n"
67
- abort("\nCANCELED: original text is too long, can't quote it.\n\n".red) if remaining <= 1
68
- puts "\n#{remaining}".magenta + " characters remaining. Write your comment: \n\n".brown
69
- begin
70
- input_text = STDIN.gets.chomp
71
- rescue Exception
72
- abort($status.errorPostNotSent)
73
- end
74
- new_text = input_text + new_text
75
- remaining = $tools.ayadn_configuration[:post_max_length] - $tools.getMarkdownText(new_text.dup).length
76
- abort("\n" + $status.errorPostTooLong(new_text.length, new_text.length - $tools.ayadn_configuration[:post_max_length])) if remaining <= 0
77
- ayadnSendPost(new_text)
78
- end
79
- def ayadn_reply(postID)
80
- @progress_indicator = false
81
- puts $status.replyingToPost(postID)
82
- post_mentions_array, replying_to_this_username, is_repost = @api.getPostMentions(postID)
83
- if is_repost != nil
84
- puts $status.errorIsRepost(postID)
85
- postID = is_repost['id']
86
- puts $status.redirectingToOriginal(postID)
87
- post_mentions_array, replying_to_this_username, is_repost = @api.getPostMentions(postID)
88
- end
89
- if $tools.config['identity']['prefix'] == "me"
90
- me_saved = $files.users_read("me")
91
- me_saved ? (my_username = me_saved) : (my_username = @api.getUserName("me"))
92
- else
93
- my_username = $tools.config['identity']['prefix']
94
- end
95
- #my_handle = "@" + my_username
96
- replying_to_handle = "@" + replying_to_this_username
97
- new_content = Array.new
98
- # if I'm not answering myself, add the @username of the "replyee"
99
- new_content.push(replying_to_handle) if replying_to_this_username != my_username
100
- post_mentions_array.each do |item|
101
- new_content.push("@" + item) if item != my_username
102
- end
103
- if new_content.length > 1
104
- all_mentions = new_content.dup
105
- leading_mention = all_mentions.first
106
- all_mentions.shift
107
- puts "\nThe leading mention (".green + leading_mention.red + ") has been put at the beginning of your post.\nThe rest of the mentions (".green + all_mentions.join(", ").red + ") will be added automatically at the end.".green
108
- end
109
- ayadn_compose_reply(postID, new_content)
110
- end
111
- def ayadn_compose_reply(reply_to, mentions_list = "")
112
- puts $status.writePost
113
- all_mentions = mentions_list.dup
114
- char_count = $tools.ayadn_configuration[:post_max_length]
115
- leading_mention = all_mentions.first
116
- mentions_list.shift
117
- mentions_list = mentions_list.join(" ")
118
- if leading_mention != nil
119
- text = leading_mention + " "
120
- char_count -= 1
121
- else
122
- text = ""
123
- end
124
- print "\n#{text}"
125
- begin
126
- input_text = STDIN.gets.chomp
127
- rescue Exception
128
- abort($status.errorPostNotSent)
129
- end
130
- if leading_mention != nil
131
- post_text = text + input_text + " " + mentions_list
132
- real_text_length = $tools.getMarkdownText(post_text.dup).length
133
- else
134
- post_text = input_text
135
- real_text_length = $tools.getMarkdownText(post_text.dup).length
136
- end
137
- remaining_text_length = char_count - real_text_length
138
- if remaining_text_length >= 0
139
- ayadnSendPost(post_text, reply_to)
140
- else
141
- abort($status.errorPostTooLong(real_text_length, real_text_length - $tools.ayadn_configuration[:post_max_length]))
142
- end
143
- end
144
-
145
-
146
- def ayadnComposeMessage(target)
147
- puts $status.writeMessage
148
- begin
149
- input_text = STDIN.gets.chomp
150
- rescue Exception
151
- abort($status.errorMessageNotSent)
152
- end
153
- real_length = $tools.getMarkdownText(input_text.dup).length
154
- if real_length < $tools.ayadn_configuration[:message_max_length]
155
- ayadnSendMessage(target, input_text)
156
- else
157
- abort($status.errorMessageTooLong(real_length, real_length - $tools.ayadn_configuration[:message_max_length]))
158
- end
159
- end
160
- def ayadnSendMessage(target, text)
161
- abort($status.emptyPost) if (text.empty? || text == nil)
162
- puts $status.sendMessage
163
- if target.is_integer?
164
- target = $files.load_channel_id(target)
165
- end
166
- blob = JSON.parse(@api.httpSendMessage(target, text))
167
- @hash = blob['data']
168
- private_message_channel_ID = @hash['channel_id']
169
- #private_message_thread_ID = @hash['thread_id']
170
- $files.makedir($tools.ayadn_configuration[:messages_path])
171
- puts "Channel ID: ".cyan + private_message_channel_ID.brown + " Message ID: ".cyan + @hash['id'].brown + "\n\n"
172
- puts $status.postSent
173
- $files.save_channel_id(private_message_channel_ID, target)
174
- # save message
175
- if $tools.config['files']['auto_save_sent_messages']
176
- fileURL = $tools.ayadn_configuration[:messages_path] + "/#{target}-#{@hash['id']}.post"
177
- f = File.new(fileURL, "w")
178
- f.puts(@hash)
179
- f.close
180
- end
181
- end
182
-
183
- def ayadnComposeMessageToChannel(target)
184
- puts $status.writeMessage
185
- begin
186
- input_text = STDIN.gets.chomp
187
- rescue Exception
188
- abort($status.errorMessageNotSent)
189
- end
190
- real_length = $tools.getMarkdownText(input_text.dup).length
191
- if real_length < $tools.ayadn_configuration[:message_max_length]
192
- ayadnSendMessageToChannel(target, input_text)
193
- else
194
- abort($status.errorMessageTooLong(real_length, real_length - $tools.ayadn_configuration[:message_max_length]))
195
- end
196
- end
197
- def ayadnSendMessageToChannel(target, text)
198
- abort($status.emptyPost) if (text.empty? || text == nil)
199
- puts $status.sendMessage
200
- if !target.is_integer?
201
- target = $files.load_channel_id(target)
202
- end
203
- blob = JSON.parse(@api.httpSendMessageToChannel(target, text))
204
- @hash = blob['data']
205
- private_channel_ID = @hash['channel_id']
206
- #private_thread_ID = @hash['thread_id']
207
- $files.makedir($tools.ayadn_configuration[:messages_path])
208
- puts "Channel ID: ".cyan + private_channel_ID.brown + " Message ID: ".cyan + @hash['id'].brown + "\n\n"
209
- puts $status.postSent
210
- $files.save_channel_id(private_channel_ID, target)
211
- end
212
- end
1
+ module Ayadn
2
+ class Post
3
+
4
+ def post(args)
5
+ unless text_is_empty?(args)
6
+ send_post(args.join(" "))
7
+ else
8
+ error_text_empty
9
+ end
10
+ end
11
+
12
+ def compose
13
+ case Settings.config[:platform]
14
+ when /mswin|mingw|cygwin/
15
+ post = classic
16
+ else
17
+ require "readline"
18
+ post = readline
19
+ end
20
+ post
21
+ end
22
+
23
+ def auto_classic
24
+ loop do
25
+ begin
26
+ print "#{Settings.config[:identity][:handle]} >> ".color(:red)
27
+ t = STDIN.gets.chomp
28
+ send_post(t)
29
+ puts Status.done
30
+ rescue Interrupt
31
+ abort(Status.canceled)
32
+ end
33
+ end
34
+ end
35
+
36
+ def auto_readline
37
+ loop do
38
+ begin
39
+ while buffer = Readline.readline("#{Settings.config[:identity][:handle]} >> ".color(:red))
40
+ send_post(buffer)
41
+ puts Status.done
42
+ end
43
+ rescue Interrupt
44
+ abort(Status.canceled)
45
+ end
46
+ end
47
+ end
48
+
49
+ def readline
50
+ puts Status.readline
51
+ post = []
52
+ begin
53
+ while buffer = Readline.readline("> ")
54
+ post << buffer
55
+ end
56
+ rescue Interrupt
57
+ #temp
58
+ Errors.info "Write post: canceled."
59
+ abort(Status.canceled)
60
+ end
61
+ post
62
+ end
63
+
64
+ def classic
65
+ puts Status.classic
66
+ input_text = STDIN.gets.chomp
67
+ [input_text]
68
+ end
69
+
70
+ def reply(new_post, replied_to)
71
+ replied_to = replied_to.values[0]
72
+ reply = replied_to[:handle].dup
73
+ reply << " #{new_post}"
74
+ replied_to[:mentions].uniq!
75
+ replied_to[:mentions].each do |m|
76
+ next if m == replied_to[:username]
77
+ next if m == Settings.config[:identity][:username]
78
+ reply << " @#{m}"
79
+ end
80
+ reply
81
+ end
82
+
83
+ def send_pm(username, text)
84
+ url = Endpoints.new.pm_url
85
+ url << "?include_annotations=1&access_token=#{Ayadn::Settings.user_token}"
86
+ send_content(url, payload_pm(username, text))
87
+ end
88
+
89
+ def send_message(channel_id, text)
90
+ url = Endpoints.new.messages(channel_id, {})
91
+ send_content(url, payload_basic(text))
92
+ end
93
+
94
+ def send_log(data)
95
+ url = Endpoints.new.ayadnlog
96
+ send_content(url, payload_log(data))
97
+ end
98
+
99
+ def send_post(text)
100
+ url = Endpoints.new.posts_url
101
+ send_content(url, payload_basic(text))
102
+ end
103
+
104
+ def send_reply(text, post_id)
105
+ url = Endpoints.new.posts_url
106
+ send_content(url, payload_reply(text, post_id))
107
+ end
108
+
109
+ def send_content(url, payload)
110
+ url << "?include_annotations=1&access_token=#{Ayadn::Settings.user_token}"
111
+ JSON.parse(CNX.post(url, payload))
112
+ end
113
+
114
+ def check_post_length(lines_array)
115
+ max_size = Settings.config[:post_max_length]
116
+ check_length(lines_array, max_size)
117
+ end
118
+
119
+ def check_message_length(lines_array)
120
+ max_size = Settings.config[:message_max_length]
121
+ check_length(lines_array, max_size)
122
+ end
123
+
124
+ def check_length(lines_array, max_size)
125
+ words_array = []
126
+ lines_array.each { |word| words_array << get_markdown_text(word) }
127
+ size = words_array.join.length
128
+ if size < 1
129
+ error_text_empty
130
+ exit
131
+ elsif size > max_size
132
+ Errors.warn "Canceled: too long (#{size - max_size}chars)"
133
+ abort("\n\nCanceled: too long. #{max_size} max, #{size - max_size} characters to remove.\n\n\n".color(:red))
134
+ end
135
+ end
136
+
137
+ def get_markdown_text(str)
138
+ str.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\1')
139
+ end
140
+
141
+ def markdown_extract(str)
142
+ result = str.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\1|||\2')
143
+ result.split('|||') #=> [text, link]
144
+ end
145
+
146
+ def text_is_empty?(args)
147
+ args.empty? || args[0] == ""
148
+ end
149
+
150
+ def error_text_empty
151
+ puts "\n\nYou should provide some text.\n\n".color(:red)
152
+ Errors.warn "-Post without text-"
153
+ end
154
+
155
+ def annotations
156
+ [
157
+ {
158
+ "type" => "com.ayadn.user",
159
+ "value" => {
160
+ "+net.app.core.user" => {
161
+ "user_id" => "#{Settings.config[:identity][:handle]}",
162
+ "format" => "basic"
163
+ }
164
+ }
165
+ },
166
+ {
167
+ "type" => "com.ayadn.client",
168
+ "value" => {
169
+ "url" => "http://ayadn-app.net",
170
+ "author" => {
171
+ "name" => "Eric Dejonckheere",
172
+ "username" => "ericd",
173
+ "id" => "69904",
174
+ "email" => "eric@aya.io"
175
+ },
176
+ "version" => "#{Settings.config[:version]}"
177
+ }
178
+ }
179
+ ]
180
+ end
181
+
182
+ def entities
183
+ {
184
+ "parse_markdown_links" => true,
185
+ "parse_links" => true
186
+ }
187
+ end
188
+
189
+ def payload_basic(text)
190
+ {
191
+ "text" => text,
192
+ "entities" => entities,
193
+ "annotations" => annotations
194
+ }
195
+ end
196
+
197
+ def payload_pm(username, text)
198
+ {
199
+ "text" => text,
200
+ "entities" => entities,
201
+ "destinations" => username,
202
+ "annotations" => annotations
203
+ }
204
+ end
205
+
206
+ def payload_reply(text, reply_to)
207
+ {
208
+ "text" => text,
209
+ "reply_to" => reply_to,
210
+ "entities" => entities,
211
+ "annotations" => annotations
212
+ }
213
+ end
214
+
215
+ def payload_log(data)
216
+ extended = annotations
217
+ extended << {
218
+ "type" => "com.ayadn.log",
219
+ "value" => data
220
+ }
221
+ return {
222
+ "text" => "#ayadnlog",
223
+ "entities" => entities,
224
+ "annotations" => extended
225
+ }
226
+ end
227
+
228
+ end
229
+ end