WPPost
Check-in [870da6391b]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Implement --tokenurl parsing and track token expiration. Add json parser and provide a simple display of the user name attached to the token for the --verbose option. Clean up --verbose output by adding the --debug option to cover most of the noisy printing.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 870da6391ba6ea2332aff7d85802328e2decbd38
User & Date: Ross 2014-10-03 22:33:59
Context
2014-10-14
00:28
Implement actual post creation through the REST API as documented in part 6 of the series. Also change to Lua-cURL (a binary is in this checkin) and add a bunch of commandline options. check-in: a6505fd2e2 user: Ross tags: trunk
2014-10-03
22:33
Implement --tokenurl parsing and track token expiration. Add json parser and provide a simple display of the user name attached to the token for the --verbose option. Clean up --verbose output by adding the --debug option to cover most of the noisy printing. check-in: 870da6391b user: Ross tags: trunk
2014-09-11
20:55
Snapshot of OAuth REST demo of the /me endpoint for the Post with Lua Part 4 article. check-in: 3b301fad10 user: Ross tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added pub.bat.











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
setlocal

rem set USR=RemoteName@
set USR=
if not %2x==x set USR=%2@

set PUBLICREPO=http://%USR%chiselapp.com/user/rberteig/repository/WPCLI

if %1x==x    goto usage
if %1==sync  goto ok
if %1==push  goto ok
if %1==pull  goto ok
goto usage

:ok
fossil %1 %PUBLICREPO% --once
goto :EOF

:usage
echo Usage: pub ^{push^|pull^|sync^} ^[RemoteName^] 

Changes to wprest/wppost.lua.

1
2
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
--- 
-- Utility to post a file to WordPress as a Draft of a Post.
--
-- Written as sample code for the curioser.cheshireeng.com blog. See:
--   http://curiouser.cheshireeng.com/applications/wp-cli-tools/
--
-- Copyright (C) 2014 Cheshire Engineering Corp. Licensed for use under
-- the terms of the MIT license. See readme.markdown for details.

local utils = require "pl.utils"
local app = require "pl.app"
local lapp = require "pl.lapp"
local config = require "pl.config"

require "luacurl"


-- Put the pl.lapp based options handling near the top for easy visibility
local args = lapp [[
Post a file on a WordPres blog as a draft post. Part of the WP CLI Tools.
http://curiouser.cheshireeng.com/applications/wp-cli-tools/

  --blog (default "")            The blog at which to post.
  --token (default "")           The OAuth token from the redirect URL

  -v,--verbose                   Be more chatty about the process  
  --showconfig                   Just display the config file
  --writeconfig                  Write the config file with the options  

  <filename> (default "")        The file to post.  
]]

-- Also read a config file stored in a "home directory" folder
local configfile = app.appfile"rest.ini"


if args.showconfig then
	print("config:", configfile)
	local s = utils.readfile(configfile)
	io.write(s or "--config file empty--\n")
end


local conf = config.read(configfile) or {
	blog = "curiouser.cheshireeng.com",
	token= 'X'
}


























-- Add missing configuration fields to args
for k,v in pairs(conf) do
	if (not args[k]) or (#args[k] < 1) then args[k] = v end
end


-- Possibly write back the config file
if args.writeconfig then
	local f = io.open(configfile, "w")
	f:write"# configuration written by the --writeconfig option\n\n"
	for _,k in ipairs({"blog","token"}) do
		f:write(k,"=",args[k],"\n")
	end
	f:close()
end

args.token = curl.unescape(args.token)



if #args.token ~= 64 then
	lapp.error("WP Access Token must be exactly 64 bytes long.", false) 
end











args.baseurl = "https://public-api.wordpress.com/rest/v1/sites/"..args.blog
if args.verbose then
	for k,v in pairs(args) do print(tostring(k)..": "..tostring(v)) end
end

function wp_showme()
	--$access_key = "YOUR_API_TOKEN";
	c = curl.new()
	c:setopt(curl.OPT_URL, "https://public-api.wordpress.com/rest/v1/me/")
	c:setopt(curl.OPT_HTTPHEADER, 'Authorization: Bearer ' .. args.token)
	c:setopt(curl.OPT_SSL_VERIFYPEER, false)
	local t = {}
	c:setopt(curl.OPT_WRITEFUNCTION, function(_,s) t[#t+1]=s end)
	c:perform()
	c:close()
	return table.concat(t)
end

if args.verbose then




	io.write("/me = ", wp_showme())





end

-- exit before actually doing anything if requested.
if args.showconfig or args.writeconfig then os.exit(0) end 

-- verify if we got this far that we really do have a file to process
if not (args.filename and #args.filename > 0) then 
	lapp.error("Must name a file to post.", true) 
end



local function htmlentities(s)
	local e = s:gsub("[%&%<%>]",{
		  ["&"]="&amp;",
		  ["<"]="&lt;",
		  [">"]="&gt;",
		})
	return e













>

>






|
|
>
|
|
|
>
|

















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











|






>
>
>




>
>
>
>
>
>
>
>
>


|
<
<















>
>
>
>
|
>
>
>
>
>










>
>







1
2
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
--- 
-- Utility to post a file to WordPress as a Draft of a Post.
--
-- Written as sample code for the curioser.cheshireeng.com blog. See:
--   http://curiouser.cheshireeng.com/applications/wp-cli-tools/
--
-- Copyright (C) 2014 Cheshire Engineering Corp. Licensed for use under
-- the terms of the MIT license. See readme.markdown for details.

local utils = require "pl.utils"
local app = require "pl.app"
local lapp = require "pl.lapp"
local config = require "pl.config"
local pretty = require "pl.pretty"
require "luacurl"
local json = require "json"

-- Put the pl.lapp based options handling near the top for easy visibility
local args = lapp [[
Post a file on a WordPres blog as a draft post. Part of the WP CLI Tools.
http://curiouser.cheshireeng.com/applications/wp-cli-tools/

  --blog (default "")         The blog at which to post.
  --token (default "")        The OAuth token from the redirect URL
  --tokenurl (default "")     The full URL containing the token
  -v,--verbose                Be more chatty about the process
  --showconfig                Just display the config file
  --writeconfig               Write the config file with the options  
  --debug  
  <filename> (default "")     The file to post.  
]]

-- Also read a config file stored in a "home directory" folder
local configfile = app.appfile"rest.ini"


if args.showconfig then
	print("config:", configfile)
	local s = utils.readfile(configfile)
	io.write(s or "--config file empty--\n")
end


local conf = config.read(configfile) or {
	blog = "curiouser.cheshireeng.com",
	token= 'X'
}

-- Parse the useful data out of a token redirect URL
-- Keep the token, confirm the other details.
--
-- http://<URL>/#access_token=<URL-Encoded-Token>&expires_in=<seconds>&token_type=bearer&site_id=73256621
--
if args.tokenurl and #args.tokenurl >= 64 then
	local base,rest = args.tokenurl:match"^([^#]+)%#(.+)$"
	if args.debug then 
		print("URL base:",base)
		print("URL rest:",rest)
	end
	if not rest then
		lapp.error("Please provide the entire URL and be sure to quote it.")
	else
		local t={}
		for k,v in rest:gmatch"([^&=]+)=([^&=]+)" do
			t[k] = v
			if args.debug then print("URL",k,v) end
		end
		args.token = t.access_token
		args.expires = tostring(os.time() + (tonumber(t.expires_in) or 0))
	end
end


-- Add missing configuration fields to args
for k,v in pairs(conf) do
	if (not args[k]) or (#args[k] < 1) then args[k] = v end
end


-- Possibly write back the config file
if args.writeconfig then
	local f = io.open(configfile, "w")
	f:write"# configuration written by the --writeconfig option\n\n"
	for _,k in ipairs({"blog","token","expires"}) do
		f:write(k,"=",args[k],"\n")
	end
	f:close()
end

args.token = curl.unescape(args.token)
if args.debug then
	print("unescaped token ("..#args.token.." bytes):", ("%q"):format(args.token))
end
if #args.token ~= 64 then
	lapp.error("WP Access Token must be exactly 64 bytes long.", false) 
end

args.expires = tonumber(args.expires)
if args.expires then
	local ttl = (args.expires - os.time()) / (24. * 3600.)
	if ttl < 0 then
		print(("WP Access Token expired %.1f days ago"):format(-ttl))
	else
		print(("WP Access Token expires in %.1f days"):format(ttl))
	end
end

args.baseurl = "https://public-api.wordpress.com/rest/v1/sites/"..args.blog
if args.debug then print(pretty.write(args)) end



function wp_showme()
	--$access_key = "YOUR_API_TOKEN";
	c = curl.new()
	c:setopt(curl.OPT_URL, "https://public-api.wordpress.com/rest/v1/me/")
	c:setopt(curl.OPT_HTTPHEADER, 'Authorization: Bearer ' .. args.token)
	c:setopt(curl.OPT_SSL_VERIFYPEER, false)
	local t = {}
	c:setopt(curl.OPT_WRITEFUNCTION, function(_,s) t[#t+1]=s end)
	c:perform()
	c:close()
	return table.concat(t)
end

if args.verbose then
	local me = wp_showme()
	local t = json.decode(me)
	if args.debug then
		io.write("/me = ", pretty.write(t), '\n')
		--io.write("/me = ", wp_showme())
	end
	print("Token user:", t.display_name or t.username)
	if t.email_verified then
		print("      email:", t.email or "unknown")
	end
end

-- exit before actually doing anything if requested.
if args.showconfig or args.writeconfig then os.exit(0) end 

-- verify if we got this far that we really do have a file to process
if not (args.filename and #args.filename > 0) then 
	lapp.error("Must name a file to post.", true) 
end

-- Very minimally entity encode a string. This covers only those code 
-- points that are mandatory: ampersand, less than, and greater than.
local function htmlentities(s)
	local e = s:gsub("[%&%<%>]",{
		  ["&"]="&amp;",
		  ["<"]="&lt;",
		  [">"]="&gt;",
		})
	return e