| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 
 | # -*- coding: utf-8 -*-
#
# yo_update.rb - Yo all when an entry or a comment is posted
#
# Copyright (C) 2014, zunda <zundan at gmail.com>
#
# Permission is granted for use, copying, modification,
# distribution, and distribution of modified versions of this
# work under the terms of GPL version 2 or later.
#
require 'uri'
require 'timeout'
require 'net/http'
require 'json'
YO_UPDATE_TIMEOUT = 10
class YoUpdateError < StandardError; end
def yo_update_url(date = nil, frag = nil)	# date: Time frag: e.g. 'p01'
	url = @conf.index.dup
	url[0, 0] = base_url unless %r|^https?://|i =~ url
	url.gsub!( %r|/\./|, '/' )
	if date
		ymd = date.strftime('%Y%m%d')
		anc = frag ? "#{ymd}##{frag}" : ymd
		url += anchor(anc)
	end
	url
end
def yo_update_api_key
	r = @conf['yo_update.api_key']
	if not r or r.empty?
		return nil
	end
	return r
end
def yo_update_access_api(req)
	if @conf['proxy']
		proxy_uri = URI("http://" + @conf['proxy'])
		proxy_addr = proxy_uri.host
		proxy_port = proxy_uri.port
	else
		proxy_addr = nil
		proxy_port = nil
	end
	begin
		Timeout.timeout(YO_UPDATE_TIMEOUT) do
			return Net::HTTP.start(req.uri.host, req.uri.port, proxy_addr, proxt_port){|http|
				http.request(req)
			}
		end
	rescue Timeout::Error
		raise YoUpdateError, "Timeout accessing Yo API"
	rescue SocketError => e
		raise YoUpdateError, e.message
	end
end
def yo_update_send_yo(username = nil, url = '')
	api_key = yo_update_api_key
	unless api_key
		raise YoUpdateError, "Yo API Key is not set"
	end
	data = {'api_token' => api_key}
	data['link'] = url unless url.empty?
	unless username
		req = Net::HTTP::Post.new(URI("http://api.justyo.co/yoall/"))
		req.set_form_data(data)
		expected = '{}'
	else
		req = Net::HTTP::Post.new(URI("http://api.justyo.co/yo/"))
		data['username'] = username
		req.set_form_data(data)
		expected = '{"result": "OK"}'
	end
	res = yo_update_access_api(req)
	data = res.body
	unless data == expected
		raise YoUpdateError, "error from Yo API: #{data}"
	end
	return data
end
def yo_update_send_yo_or_log(username = nil, url = '')
	return unless yo_update_api_key
	begin
		yo_update_send_yo(username, url)
	rescue YoUpdateError => e
		@logger.error "yo_update.rb: #{e.message}"
	end
end
def yo_update_subscribers_count
	api_key = yo_update_api_key
	unless api_key
		raise YoUpdateError, "Yo API Key is not set"
	end
	req = Net::HTTP::Get.new(
		URI("http://api.justyo.co/subscribers_count/?api_token=#{URI.escape(api_key)}")
	)
	res = yo_update_access_api(req)
	data = res.body
	begin
		r = JSON::parse(data)
		if r.has_key?('result')
			return r['result']
		else
			raise YoUpdateError, "Error from Yo API: #{data}"
		end
	rescue JSON::ParserError
		raise YoUpdateError, "Error from Yo API: #{data}"
	end
end
unless defined? yo_update_conf_label	# maybe defined in a language resource
	def yo_update_conf_label
		'Send Yo with updates'
	end
end
unless defined? yo_update_test_result_label	# maybe defined in a language resource
	def yo_update_test_result_label(username, result)
		"- Sent to <tt>#{h username}</tt> and got <tt>#{h result}</tt>"
	end
end
unless defined? yo_update_conf_html	# maybe defined in a language resource
	def yo_update_conf_html(conf, n_subscribers, test_result)
		action_label = {
			'send_on_update' => 'when an entry is added',
			'send_on_comment' => 'when a comment is posted',
		}
		<<-HTML
		<h3 class="subtitle">API key</h3>
		<p><input name="yo_update.api_key" value="#{h conf['yo_update.api_key']}" size="40"></p>
		<h3 class="subtitle">Username</h3>
		<p><input name="yo_update.username" value="#{h conf['yo_update.username']}" size="40"></p>
		<h3 class="subtitle">Send Yo</h3>
		<ul>
		#{%w(send_on_update send_on_comment).map{|action|
			checked = conf["yo_update.#{action}"] ? ' checked' : ''
			%Q|<li><label for="yo_update.#{action}"><input id="yo_update.#{action}" name="yo_update.#{action}" value="t" type="checkbox"#{checked}>#{action_label[action]}</label>|
		}.join("\n\t")}
		</ul>
		<p>Test sending Yo! to <input name="yo_update.test" value="" size="10"> with optional link <input name="yo_update.link" value="#{yo_update_url}" size="40">#{test_result}</p>
		<h3 class="subtitle">Current Subscribers</h3>
		<p>#{h n_subscribers}</p>
		<h3 class="subtitle">Yo button</h3>
		<p>Add the following to somewhere or your diary.</p>
		<pre><div id="yo-button"></div></pre>
		<h3 class="subtitle">Howto</h3>
		<ol>
		<li>Sign in with your personal Yo account at <a href="http://dev.justyo.co/">http://dev.justyo.co/</a>
		<li>Follow the instructions to obtain new API account.
			Please leave the Callback URL blank.
		<li>Copy the API key and API username above.
		</ol>
		HTML
	end
end
add_conf_proc('yo_update', yo_update_conf_label) do
	test_result = ''
	if @mode == 'saveconf' then
		@conf['yo_update.api_key'] = @cgi.params['yo_update.api_key'][0]
		@conf['yo_update.username'] = @cgi.params['yo_update.username'][0]
		@conf['yo_update.send_on_update'] = (@cgi.params['yo_update.send_on_update'][0] == 't')
		@conf['yo_update.send_on_comment'] = (@cgi.params['yo_update.send_on_comment'][0] == 't')
		test_username = @cgi.params['yo_update.test'][0]
		test_link = @cgi.params['yo_update.link'][0]
		if test_username and not test_username.empty?
			begin
				result = yo_update_send_yo(test_username, test_link)
			rescue YoUpdateError => e
				result = e.message
			end
			test_result = yo_update_test_result_label(test_username, result)
		end
	end
	unless @conf.has_key?('yo_update.send_on_update')
		@conf['yo_update.send_on_update'] = true
	end
	begin
		n_subscribers = yo_update_subscribers_count
	rescue YoUpdateError => e
		n_subscribers = e.message
	end
	yo_update_conf_html(@conf, n_subscribers, test_result)
end
add_update_proc do
	if @mode == 'append' and @conf['yo_update.send_on_update']
		url = yo_update_url(@date)	# link to the date
		yo_update_send_yo_or_log(nil, url)
	elsif @mode == 'comment' and @comment and @comment.visible? and @conf['yo_update.send_on_comment']
		frag = "c%02d" % @diaries[@date.strftime("%Y%m%d")].count_comments(true)
		url = yo_update_url(@date, frag)
		yo_update_send_yo_or_log(nil, url)
	end
end
add_header_proc do
	if @conf['yo_update.api_key']
		triggers = []
		triggers << 'Entry' if @conf['yo_update.send_on_update']
		triggers << 'Tsukkomi' if @conf['yo_update.send_on_comment']
		trigger_str = "#{triggers.join(' or ')} is added"
		<<-HTML
	<script type="text/javascript"><!--
		var _yoData = {
			"username": "#{@conf['yo_update.username']}",
			"trigger": "#{trigger_str}"
		};
		var s = document.createElement("script");
		s.type = "text/javascript";
		s.src = "//yoapp.s3.amazonaws.com/js/yo-button.js";
		(document.head || document.getElementsByTagName("head")[0]).appendChild(s);
	--></script>
		HTML
	end
end
# Local Variables:
# mode: ruby
# indent-tabs-mode: t
# tab-width: 3
# ruby-indent-level: 3
# End:
# vim: ts=3 sw=3
 |