noms-command 0.5.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rst +104 -37
- data/TODO.rst +3 -3
- data/fixture/dnc.rb +110 -1
- data/fixture/public/dnc.json +6 -5
- data/fixture/public/lib/dnc.js +171 -24
- data/fixture/public/lib/nomsargs.js +72 -0
- data/lib/noms/command.rb +37 -8
- data/lib/noms/command/application.rb +32 -26
- data/lib/noms/command/auth.rb +44 -62
- data/lib/noms/command/auth/identity.rb +205 -5
- data/lib/noms/command/base.rb +11 -1
- data/lib/noms/command/formatter.rb +5 -4
- data/lib/noms/command/home.rb +21 -0
- data/lib/noms/command/useragent.rb +117 -40
- data/lib/noms/command/useragent/cache.rb +124 -0
- data/lib/noms/command/useragent/requester.rb +48 -0
- data/lib/noms/command/useragent/requester/httpclient.rb +61 -0
- data/lib/noms/command/useragent/requester/typhoeus.rb +73 -0
- data/lib/noms/command/useragent/response.rb +202 -0
- data/lib/noms/command/useragent/response/httpclient.rb +59 -0
- data/lib/noms/command/useragent/response/typhoeus.rb +74 -0
- data/lib/noms/command/version.rb +1 -1
- data/lib/noms/command/window.rb +21 -3
- data/lib/noms/command/xmlhttprequest.rb +8 -8
- data/noms-command.gemspec +3 -1
- data/spec/07js_spec.rb +1 -1
- data/spec/10auth_spec.rb +132 -0
- data/spec/11useragent_cache_spec.rb +160 -0
- data/spec/12useragent_auth_cookie_spec.rb +53 -0
- data/spec/13useragent_auth_spec.rb +90 -0
- data/spec/spec_helper.rb +5 -0
- metadata +46 -4
- data/fixture/public/lib/noms-args.js +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2ac7a3782b3dc374c77d11d618d66ac99d37c45
|
4
|
+
data.tar.gz: 241d7122a0756c8f8f5229d6ebfabcbd66eedcba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 760eb723b068038cdf9a65b082c22610a44ebcda16fe745ec2d7b415498d399bf36d89a1b162e18d026f6c80a7a5061a926a99691fde8c68857707eb2b389489
|
7
|
+
data.tar.gz: dcbd6336014c56f90e70d9e64957650fe5aa61c287ffb0c1be0f8b1b2892d620fd72204dcba9ebf5f9771f1df320382e26a1a5f489bcca6164b1b7a8d9fce559
|
data/README.rst
CHANGED
@@ -54,18 +54,18 @@ Syntax
|
|
54
54
|
|
55
55
|
The basic way of invoking a **noms** command is as follows::
|
56
56
|
|
57
|
-
noms
|
57
|
+
noms <url> <options> <arguments>
|
58
58
|
|
59
59
|
**noms** invokes the app at *url* with the given options and
|
60
|
-
|
60
|
+
arguments, displaying the results.
|
61
61
|
|
62
62
|
**noms** has its own options, which can be given before the
|
63
|
-
*url*, and are available when invoking ``noms --help
|
63
|
+
*url*, and are available when invoking ``noms --help``.
|
64
64
|
|
65
65
|
Bookmarks
|
66
66
|
~~~~~~~~~
|
67
67
|
|
68
|
-
* ``noms
|
68
|
+
* ``noms <bookmark>[/extra] ...``
|
69
69
|
|
70
70
|
**noms** bookmarks are stored, by default, in ``~/.noms/bookmarks.json``,
|
71
71
|
``/usr/local/etc/noms/bookmarks.json``, and ``/etc/noms/bookmarks.json``
|
@@ -101,7 +101,8 @@ strictness policies may be configurable in a file, but the point of
|
|
101
101
|
**noms** is to remove the distribution of thick client libraries that
|
102
102
|
try to abstract away server-side interfaces and the configurations
|
103
103
|
they require, so it would defeat part of its purpose to allow rich
|
104
|
-
configuration of things like default values for objects
|
104
|
+
configuration of things like default values for objects, extra
|
105
|
+
(application-level) connection or protocol information and so forth.
|
105
106
|
|
106
107
|
Implementation
|
107
108
|
--------------
|
@@ -119,28 +120,71 @@ according to `Dynamic Doctype`_, below. Otherwise, it is assumed to be
|
|
119
120
|
structured list or object data, and **noms** will render the object or
|
120
121
|
array using its default format (usually YAML).
|
121
122
|
|
123
|
+
Otherwise, **noms** assumes the data may be binary and will send it
|
124
|
+
to stdout as long as stdout is not a terminal.
|
125
|
+
|
122
126
|
Authentication
|
123
127
|
--------------
|
124
128
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
129
|
+
**noms** supports Basic authentication. It prompts the user for a
|
130
|
+
username and password when authorization is required, and saves the
|
131
|
+
authentication identity information in a "vault" to be used for future
|
132
|
+
invocations (that is, you don't need to enter a password for every
|
133
|
+
**noms** command run).
|
134
|
+
|
135
|
+
If you are "idle" for an hour (have not used the saved authentication
|
136
|
+
vault for any web transactions), **noms** will time out the vault and
|
137
|
+
you will need to re-authenticate.
|
138
|
+
|
139
|
+
You can "close" the vault immediately by using the ``--logout``
|
140
|
+
option. I strongly suggest you call this in your ``~/.logout``
|
141
|
+
mechanism so that it runs immediately when you have completed a
|
142
|
+
login session.
|
143
|
+
|
144
|
+
You can bypass the "vault" by running **noms** with the
|
145
|
+
``--plaintext-identity`` option. This has the effect of caching these
|
146
|
+
credentials permanently (well, until they are no longer good). You
|
147
|
+
should only use this option to generate an identity file for service
|
148
|
+
(non-interactive) accounts that need perpetual access to a web
|
149
|
+
service. The file will appear in the ``~/.noms/identities`` directory
|
150
|
+
in a file named for the SHA-1 hash of the munged authentication realm
|
151
|
+
and domain.
|
152
|
+
|
153
|
+
Such a saved identity file can be provided with the ``--identity`` option
|
154
|
+
to **noms** for non-interactive use.
|
155
|
+
|
156
|
+
Security
|
157
|
+
~~~~~~~~
|
158
|
+
|
159
|
+
**noms** uses strong cryptography to implement the "vault" metaphor, but
|
160
|
+
this is only a metaphor and the security provided is limited. The vault
|
161
|
+
is opened and closed by means of an on-disk key. Because you can easily
|
162
|
+
remove it and because it times out when idle (when this happens, **noms**
|
163
|
+
overwrites it the next time it tries to use it), it's significantly better
|
164
|
+
than ``.netrc`` files or passwords in environment variables or on the
|
165
|
+
command-line; and more ergonomic as well. In the future, this cryptographic
|
166
|
+
service will be provided by an independent **noms-agent**, similar to
|
167
|
+
ssh-agent or gpg-agent. These still have the same problem in that they
|
168
|
+
reduce the security of the system to operating system mechanisms rather
|
169
|
+
than cryptographic mechanisms, but it is still an improvement.
|
132
170
|
|
133
171
|
Dynamic Doctype
|
134
|
-
|
172
|
+
---------------
|
135
173
|
|
136
174
|
The dynamic doctype is the ``noms-v2`` type, which is an object with
|
137
175
|
the following top-level attributes:
|
138
176
|
|
139
177
|
``$doctype``
|
140
|
-
Must be ``noms-v2``. In future, backwards-incompatible extensions
|
178
|
+
Must be ``noms-v2``. In future, backwards-incompatible extensions
|
179
|
+
may be implemented in ``noms-v3`` or higher doctypes.
|
141
180
|
|
142
181
|
``$script``
|
143
|
-
An ordered array of
|
182
|
+
An ordered array of script references to fetch and evaluate; or
|
183
|
+
Javascript strings to evaluate directly. A script reference
|
184
|
+
consists of object with a ``$source`` key, the value of which
|
185
|
+
is the URL of the script to load. Additional fields in the
|
186
|
+
object are ignored and can be used to document the origin
|
187
|
+
or license of the scripts.
|
144
188
|
|
145
189
|
``$argv``
|
146
190
|
The arguments passed to the application. It's called ``$argv``
|
@@ -148,16 +192,18 @@ the following top-level attributes:
|
|
148
192
|
invoked (that is, the bookmark or URL).
|
149
193
|
|
150
194
|
``$exitcode``
|
151
|
-
The unix process exit code with which **noms** will exit at the
|
195
|
+
The unix process exit code with which **noms** will exit at the
|
196
|
+
completion of the command.
|
152
197
|
|
153
198
|
``$body``
|
154
|
-
The body of the document is the data to display. See `Output
|
199
|
+
The body of the document is the data to display. See `Output
|
200
|
+
Formatting`_ below.
|
155
201
|
|
156
202
|
From the perspective of javascript executing within the application,
|
157
203
|
these are accessible as properties of the global **document** object
|
158
204
|
(e.g., ``document.argv`` is the array of arguments given on the **noms**
|
159
205
|
command line; Javascript can set ``document.exitcode`` to determine
|
160
|
-
**noms'** exit code.
|
206
|
+
**noms'** exit code).
|
161
207
|
|
162
208
|
Output Formatting
|
163
209
|
~~~~~~~~~~~~~~~~~
|
@@ -202,8 +248,6 @@ The following entities are allowed in the body of a **noms-v2** document:
|
|
202
248
|
|
203
249
|
* **labels**: Default ``true``; whether to display header row with field labels
|
204
250
|
|
205
|
-
* **columns**: Field names, headings and widths
|
206
|
-
|
207
251
|
* **data**: The objects to render
|
208
252
|
|
209
253
|
* ``$type``: **object** An object has the following attributes:
|
@@ -251,7 +295,7 @@ Scripts have access to the following global objects:
|
|
251
295
|
* **argv** - The arguments being invoked. The first element of this
|
252
296
|
array is the first argument passed to **noms** itself (not the
|
253
297
|
script it ultimately fetches, but how it's invoked, similar to
|
254
|
-
``$
|
298
|
+
``$0``.
|
255
299
|
|
256
300
|
* **exitcode** - The numeric exit code with which **noms** will
|
257
301
|
exit. Initially 0.
|
@@ -264,20 +308,6 @@ Scripts have access to the following global objects:
|
|
264
308
|
|
265
309
|
.. _`NOMS::Command::XMLHttpRequest`: http://www.rubydoc.info/gems/noms-command/NOMS/Command/XMLHttpRequest
|
266
310
|
|
267
|
-
|
268
|
-
Web 1.0 vs Web 2.0
|
269
|
-
------------------
|
270
|
-
|
271
|
-
Like the "real web", **noms** commands can choose to do some
|
272
|
-
calculation on the server and some on the client: **noms** doesn't
|
273
|
-
care. You can use no ``$script`` tag at all and just calculate the
|
274
|
-
entire document to be rendered in the client (though this currently
|
275
|
-
doesn't allow for argument interpretation, in the future the
|
276
|
-
arguments may be passed in request headers or **noms** may allow a way
|
277
|
-
for them to show up in a query string or POST request--but **noms** is
|
278
|
-
not really a command-line http client either). This is up to the
|
279
|
-
application designer.
|
280
|
-
|
281
311
|
Example Application
|
282
312
|
-------------------
|
283
313
|
|
@@ -366,11 +396,48 @@ The example application is a very simple sinatra REST API to a data
|
|
366
396
|
store consisting of a JSON file, and the static files comprising the
|
367
397
|
Javascript source code and the **noms** application document.
|
368
398
|
|
369
|
-
Running Examples
|
370
|
-
|
399
|
+
Hacking/Running Examples
|
400
|
+
------------------------
|
401
|
+
|
402
|
+
Use Ruby 1.9.3 or higher (e.g. if you need to set PATH
|
403
|
+
so that Ruby 1.9 executables are found, do that:
|
404
|
+
``export PATH=/usr/local/ruby1.9/bin:$PATH``.
|
371
405
|
|
372
406
|
Use ``rake start`` to start the test webserver and run the
|
373
407
|
example applications (see the comments inside the
|
374
408
|
``fixture/public/*.json`` files for syntax).
|
375
409
|
|
376
410
|
Start with ``noms2 http://localhost:8787/echo.json hello world``.
|
411
|
+
|
412
|
+
Workflow
|
413
|
+
~~~~~~~~
|
414
|
+
|
415
|
+
Set up your environment::
|
416
|
+
|
417
|
+
mkdir ~/.noms
|
418
|
+
echo '{ "dnc": "http://localhost:8787/dnc.json" }' >~/.noms/bookmarks.json
|
419
|
+
export PATH=`pwd`/bin:$PATH
|
420
|
+
expert RUBYLIB=lib
|
421
|
+
bundle install
|
422
|
+
noms2 # NOMS usage message
|
423
|
+
noms2 dnc # dnc usage message
|
424
|
+
|
425
|
+
Do ``rake start`` to start the webserver: web root is is ``test/``.
|
426
|
+
|
427
|
+
Hack files in:
|
428
|
+
|
429
|
+
* ``lib/`` - Ruby files for ``noms2`` command
|
430
|
+
|
431
|
+
* ``fixture/dnc.rb`` - Sinatra app which is webserver for dnc app (serves
|
432
|
+
static files and implements rest interface).
|
433
|
+
|
434
|
+
* ``fixture/public/dnc.json`` - App document for 'dnc' subcommand.
|
435
|
+
|
436
|
+
* ``fixture/public/lib`` - Javascript files, ``dnc.js`` implements dnc
|
437
|
+
operations
|
438
|
+
|
439
|
+
Do ``rake sync`` to sync over updated files from ``fixture`` and test
|
440
|
+
(the webserver document root is ``test/public``).
|
441
|
+
|
442
|
+
``noms2 -d`` produces debugging showing full stack traces for Javascript
|
443
|
+
errors, ``console.log()`` output and web traffic.
|
data/TODO.rst
CHANGED
data/fixture/dnc.rb
CHANGED
@@ -7,7 +7,7 @@ class DNC < Sinatra::Application
|
|
7
7
|
|
8
8
|
set :port, 8787
|
9
9
|
set :root, File.expand_path("#{File.dirname(__FILE__)}")
|
10
|
-
enable :static
|
10
|
+
enable :static, :sessions
|
11
11
|
|
12
12
|
File.open(File.join(settings.root, 'dnc.pid'), 'w') {|f| f.puts Process.pid }
|
13
13
|
|
@@ -30,6 +30,41 @@ class DNC < Sinatra::Application
|
|
30
30
|
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
31
31
|
@auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == ['testuser', 'testpass']
|
32
32
|
end
|
33
|
+
|
34
|
+
def generated_body(h={})
|
35
|
+
JSON.pretty_generate({ 'generated' => Time.now.httpdate }.merge(h)) + "\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
def require_cookie_auth
|
39
|
+
return if cookie_authorized?
|
40
|
+
redirect "/cookie/login?return_to=#{CGI.escape(request.path)}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def cookie_authorized?
|
44
|
+
session[:userid] == 'testuser'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
before do
|
49
|
+
content_type 'application/json'
|
50
|
+
end
|
51
|
+
|
52
|
+
get '/cookie/login' do
|
53
|
+
require_auth
|
54
|
+
session[:userid] = @auth.credentials.first
|
55
|
+
landing = params[:return_to] || '/cookie/home'
|
56
|
+
redirect landing
|
57
|
+
end
|
58
|
+
|
59
|
+
get '/cookie/home' do
|
60
|
+
require_cookie_auth
|
61
|
+
generated_body({'cookie_user' => session[:userid] })
|
62
|
+
end
|
63
|
+
|
64
|
+
get '/cookie/logout' do
|
65
|
+
old_userid = session[:userid]
|
66
|
+
session[:userid] = nil
|
67
|
+
generated_body({'message' => "#{old_userid} logged out"})
|
33
68
|
end
|
34
69
|
|
35
70
|
get '/readme' do
|
@@ -66,6 +101,8 @@ class DNC < Sinatra::Application
|
|
66
101
|
request.body.rewind
|
67
102
|
new_object = JSON.parse request.body.read
|
68
103
|
|
104
|
+
puts "POST for object: #{new_object.inspect}"
|
105
|
+
|
69
106
|
data = load_data
|
70
107
|
# How unsafe is this?
|
71
108
|
new_object['id'] = data.map { |e| e['id'] }.max + 1
|
@@ -115,6 +152,78 @@ class DNC < Sinatra::Application
|
|
115
152
|
redirect to('/dnc.json')
|
116
153
|
end
|
117
154
|
|
155
|
+
get '/auth/ok' do
|
156
|
+
require_auth
|
157
|
+
"SUCCESS"
|
158
|
+
end
|
159
|
+
|
160
|
+
# Caching client should let sit in cache
|
161
|
+
# for 4s then refetch
|
162
|
+
get '/static/max-age-4' do
|
163
|
+
cache_control :max_age => 4
|
164
|
+
generated_body
|
165
|
+
end
|
166
|
+
|
167
|
+
# Caching client must always revalidate
|
168
|
+
# even within 4s
|
169
|
+
get '/static/must-revalidate' do
|
170
|
+
cache_control :must_revalidate, :max_age => 4
|
171
|
+
expires 4
|
172
|
+
etag "10"
|
173
|
+
generated_body
|
174
|
+
end
|
175
|
+
|
176
|
+
# Caching client must never cache
|
177
|
+
get '/static/no-cache' do
|
178
|
+
cache_control :no_cache
|
179
|
+
generated_body
|
180
|
+
end
|
181
|
+
|
182
|
+
# Caching client should let sit in cache
|
183
|
+
# for 4s then refetch
|
184
|
+
get '/static/expires-4' do
|
185
|
+
expires 4
|
186
|
+
generated_body
|
187
|
+
end
|
188
|
+
|
189
|
+
# Caching client should let sit in cache
|
190
|
+
# for 4s then revalidate using If-Modified-Since
|
191
|
+
get '/static/last-modified' do
|
192
|
+
expires 4
|
193
|
+
$static_time ||= Time.now
|
194
|
+
last_modified $static_time
|
195
|
+
generated_body
|
196
|
+
end
|
197
|
+
|
198
|
+
# Caching client should let sit in cache
|
199
|
+
# for 4s then revalidate using If-None-Match
|
200
|
+
get '/static/expires-4-changing' do
|
201
|
+
expires 4
|
202
|
+
etag Time.now.httpdate
|
203
|
+
generated_body
|
204
|
+
end
|
205
|
+
|
206
|
+
# Caching client should let sit in cache
|
207
|
+
# for 2s then revalidate using If-None-Match
|
208
|
+
get '/static/expires-2-constant' do
|
209
|
+
etag "10"
|
210
|
+
expires 2
|
211
|
+
generated_body
|
212
|
+
end
|
213
|
+
|
214
|
+
get '/static/long-cache' do
|
215
|
+
etag "11"
|
216
|
+
expires 100
|
217
|
+
generated_body
|
218
|
+
end
|
219
|
+
|
220
|
+
get '/auth/cacheable' do
|
221
|
+
require_auth
|
222
|
+
expires 100
|
223
|
+
etag "11"
|
224
|
+
generated_body
|
225
|
+
end
|
226
|
+
|
118
227
|
run! if app_file = $0
|
119
228
|
|
120
229
|
end
|
data/fixture/public/dnc.json
CHANGED
@@ -8,15 +8,16 @@
|
|
8
8
|
"$comment": "Optparse.js 1.0.3 - https://github.com/jfd/optparse-js; via rawgit.com" },
|
9
9
|
{ "$source": "https://rawgit.com/douglascrockford/JSON-js/master/json2.js",
|
10
10
|
"$comment": "JSON in JavaScript - https://github.com/douglascrockford/JSON-js" },
|
11
|
-
{ "$source": "lib/
|
11
|
+
{ "$source": "lib/nomsargs.js" },
|
12
12
|
{ "$source": "lib/dnc.js" }
|
13
13
|
],
|
14
14
|
"$body": [
|
15
15
|
"Usage:",
|
16
|
-
" noms dnc query <field>=<value>",
|
16
|
+
" noms dnc query [<field>=<value> [...]] [<field> [...]]",
|
17
|
+
" noms dnc list [<field> [...]]",
|
18
|
+
" noms dnc show id [<field> [...]]",
|
17
19
|
" noms dnc add <field>=<value> [<field>=<value> [...]]",
|
18
|
-
" noms dnc
|
19
|
-
" noms dnc
|
20
|
-
" noms dnc list"
|
20
|
+
" noms dnc set id <field>=<value> [<field>=<value> [...]]",
|
21
|
+
" noms dnc remove <id>"
|
21
22
|
]
|
22
23
|
}
|
data/fixture/public/lib/dnc.js
CHANGED
@@ -1,32 +1,42 @@
|
|
1
1
|
if (document.argv.length > 1) {
|
2
2
|
var argv = document.argv;
|
3
3
|
var me = argv.shift();
|
4
|
-
var command;
|
5
4
|
var format;
|
6
5
|
var xmlhttp = new XMLHttpRequest();
|
7
6
|
|
8
|
-
// document attributes can be set
|
9
|
-
// but are immutable
|
10
|
-
document.body = [ ];
|
11
|
-
var output = [ ];
|
12
|
-
|
13
7
|
var optspec = [
|
14
8
|
["-J", "--json", "Display JSON"],
|
15
9
|
["-Y", "--yaml", "Display YAML"],
|
16
10
|
["-C", "--csv", "Display CSV"],
|
17
11
|
["-v", "--verbose", "Enable verbose output"],
|
18
|
-
["--
|
12
|
+
["-q", "--terse", "Use terse output"],
|
13
|
+
["--nofeedback", "Don't print feedback"],
|
14
|
+
["--nolabel", "Don't print field names"],
|
15
|
+
["--noheader", "Don't print column headings"]
|
19
16
|
];
|
20
17
|
|
18
|
+
// document attributes can be set
|
19
|
+
// but are immutable
|
20
|
+
document.body = [ ];
|
21
|
+
var output = [ ];
|
22
|
+
|
21
23
|
var parser = new optparse.OptionParser(optspec);
|
22
24
|
var options = {
|
23
|
-
"feedback": true,
|
24
25
|
"format": "default",
|
25
|
-
"verbose": false
|
26
|
+
"verbose": false,
|
27
|
+
"feedback": true,
|
28
|
+
"label": true,
|
26
29
|
};
|
27
|
-
var args = [ ];
|
28
30
|
|
29
|
-
|
31
|
+
var field_config = {
|
32
|
+
'id': { 'field': 'id', 'width': 3, 'align': 'right' },
|
33
|
+
'name': { 'field': 'name', 'width': 20 },
|
34
|
+
'phone': { 'field': 'phone', 'width': 20 },
|
35
|
+
'street': { 'field': 'street', 'width': 40 },
|
36
|
+
'city': { 'field': 'city', 'width': 31 }
|
37
|
+
}
|
38
|
+
|
39
|
+
parser.on("verbose", function() { options["verbose"] = true; });
|
30
40
|
parser.on("json", function() {
|
31
41
|
options["format"] = "json";
|
32
42
|
options["feedback"] = false;
|
@@ -40,36 +50,173 @@ if (document.argv.length > 1) {
|
|
40
50
|
options["feedback"] = false;
|
41
51
|
});
|
42
52
|
parser.on("nofeedback", function() { options["feedback"] = false; });
|
43
|
-
parser.on(
|
44
|
-
parser.on(function(
|
53
|
+
parser.on("nolabel", function() { options["label"] = false; });
|
54
|
+
parser.on("terse", function() {
|
55
|
+
options["feedback"] = false;
|
56
|
+
options["label"] = false;
|
57
|
+
});
|
58
|
+
// parser.on(0, function(arg) { command = arg; });
|
59
|
+
|
60
|
+
var args = parser.parse(argv);
|
61
|
+
var command = args.shift();
|
45
62
|
|
46
|
-
|
63
|
+
var format, records, field_list;
|
47
64
|
|
48
65
|
switch(command) {
|
49
|
-
|
50
|
-
|
51
|
-
|
66
|
+
|
67
|
+
case "add":
|
68
|
+
var keywords = new nomsargs.NomsArgs(args);
|
69
|
+
|
70
|
+
xmlhttp.open("POST", "/dnc", false);
|
71
|
+
xmlhttp.setRequestHeader("Content-type", "application/json");
|
72
|
+
xmlhttp.send(JSON.stringify(keywords.assignment));
|
73
|
+
|
74
|
+
if (xmlhttp.status == 201) {
|
75
|
+
record = JSON.parse(xmlhttp.responseText);
|
76
|
+
output.push("Entry created with id " + record['id']);
|
77
|
+
} else {
|
78
|
+
alert("Error " + xmlhttp.status + " creating entry");
|
79
|
+
document.exitcode = 2;
|
80
|
+
}
|
81
|
+
|
82
|
+
break;
|
83
|
+
|
84
|
+
case "remove":
|
85
|
+
var id = args.shift();
|
86
|
+
|
87
|
+
if (id == undefined) {
|
88
|
+
alert("No id to remove");
|
89
|
+
document.exitcode = 1;
|
90
|
+
} else {
|
91
|
+
xmlhttp.open("DELETE", "/dnc/" + id, false);
|
92
|
+
xmlhttp.send();
|
93
|
+
|
94
|
+
if (xmlhttp.status == 404) {
|
95
|
+
alert("Entry " + id + " does not exist");
|
96
|
+
} else if (xmlhttp.status != 204) {
|
97
|
+
alert("Error deleting id " + id);
|
98
|
+
document.exitcode = 2;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
break;
|
103
|
+
|
104
|
+
case "set":
|
105
|
+
// We are not doing upsert
|
106
|
+
var id = args.shift();
|
107
|
+
var keywords = new nomsargs.NomsArgs(args);
|
108
|
+
|
109
|
+
if (id == undefined) {
|
110
|
+
alert("No id to set");
|
111
|
+
document.exitcode = 1;
|
52
112
|
} else {
|
53
|
-
|
113
|
+
xmlhttp.open("GET", "/dnc/" + id, false);
|
114
|
+
xmlhttp.send();
|
115
|
+
|
116
|
+
if (xmlhttp.status == 404) {
|
117
|
+
alert("Entry " + id + " does not exist (use add)");
|
118
|
+
document.exitcode = 2;
|
119
|
+
} else if (xmlhttp.status == 200) {
|
120
|
+
the_object = JSON.parse(xmlhttp.responseText);
|
121
|
+
|
122
|
+
// Update assigned fields in retrieved object
|
123
|
+
keywords.assignmentKeys().map(function (key) {
|
124
|
+
the_object[key] = keywords.assignment[key];
|
125
|
+
});
|
126
|
+
|
127
|
+
xmlhttp.open("PUT", "/dnc/" + id, false);
|
128
|
+
xmlhttp.send(JSON.stringify(the_object));
|
129
|
+
|
130
|
+
if (xmlhttp.status == 200) {
|
131
|
+
output.push("Entry " + id + " updated");
|
132
|
+
} else {
|
133
|
+
alert("Error " + xmlhttp.status + " updating entry " + id);
|
134
|
+
document.exitcode = 2;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
break;
|
140
|
+
|
141
|
+
case "show":
|
142
|
+
var id = args.shift();
|
143
|
+
var field_list = args;
|
144
|
+
format = (options["format"] == "default" ? "record" : options["format"]);
|
145
|
+
|
146
|
+
if (id == undefined) {
|
147
|
+
alert("No id to show");
|
148
|
+
document.exitcode = 1;
|
149
|
+
} else {
|
150
|
+
xmlhttp.open("GET", "/dnc/" + id, false);
|
151
|
+
xmlhttp.send();
|
152
|
+
|
153
|
+
if (xmlhttp.status == 404) {
|
154
|
+
alert("Entry " + id + " not found");
|
155
|
+
document.exitcode = 2;
|
156
|
+
} else {
|
157
|
+
console.log("output for record");
|
158
|
+
record = JSON.parse(xmlhttp.responseText);
|
159
|
+
|
160
|
+
console.log(record);
|
161
|
+
|
162
|
+
output.push({
|
163
|
+
'$type': 'object',
|
164
|
+
'$format': format,
|
165
|
+
'$labels': options["label"],
|
166
|
+
'$fields': field_list,
|
167
|
+
'$data': record
|
168
|
+
});
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
break;
|
173
|
+
|
174
|
+
case "query":
|
175
|
+
var keywords = new nomsargs.NomsArgs(args);
|
176
|
+
format = (options["format"] == "default" ? "lines" : options["format"]);
|
177
|
+
var query = keywords.query();
|
178
|
+
var field_list = keywords.extra;
|
179
|
+
|
180
|
+
if (field_list.length == 0) {
|
181
|
+
field_list = ['id', 'name', 'phone'];
|
54
182
|
}
|
183
|
+
xmlhttp.open("GET", "/dnc?" + query, false);
|
184
|
+
xmlhttp.send();
|
185
|
+
records = JSON.parse(xmlhttp.responseText);
|
186
|
+
|
187
|
+
output.push(
|
188
|
+
{
|
189
|
+
'$type': 'object-list',
|
190
|
+
'$format': format,
|
191
|
+
'$labels': options["label"],
|
192
|
+
'$columns': field_list.map(function(item) { return field_config[item]; }),
|
193
|
+
'$data': records
|
194
|
+
});
|
195
|
+
if (options["feedback"]) {
|
196
|
+
output.push(records.length + " objects");
|
197
|
+
}
|
198
|
+
break;
|
199
|
+
|
200
|
+
case "list":
|
201
|
+
format = (options["format"] == "default" ? "lines" : options["format"]);
|
202
|
+
|
55
203
|
xmlhttp.open("GET", "/dnc", false);
|
56
204
|
xmlhttp.send();
|
57
|
-
|
205
|
+
records = JSON.parse(xmlhttp.responseText);
|
206
|
+
field_list = (args.length == 0 ? ['id', 'name', 'phone'] : args)
|
58
207
|
output.push(
|
59
208
|
{
|
60
209
|
'$type': 'object-list',
|
61
210
|
'$format': format,
|
62
|
-
'$
|
63
|
-
|
64
|
-
{ 'field': 'name', 'width': 20 },
|
65
|
-
{ 'field': 'phone', 'width': 20 }
|
66
|
-
],
|
211
|
+
'$labels': options["label"],
|
212
|
+
'$columns': field_list.map(function(item) { return field_config[item]; }),
|
67
213
|
'$data': records
|
68
214
|
});
|
69
215
|
if (options["feedback"]) {
|
70
216
|
output.push(records.length + " objects");
|
71
217
|
}
|
72
218
|
break;
|
219
|
+
|
73
220
|
default:
|
74
221
|
document.exitcode = 8;
|
75
222
|
window.alert(
|