woodwing_elvis 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE +1 -0
- data/README.md +14 -0
- data/Rakefile +2 -0
- data/lib/woodwing.rb +16 -0
- data/lib/woodwing/elvis.rb +273 -0
- data/lib/woodwing/elvis/rest.rb +30 -0
- data/lib/woodwing/elvis/rest/authorization_keys.rb +31 -0
- data/lib/woodwing/elvis/rest/browse.rb +65 -0
- data/lib/woodwing/elvis/rest/checkout.rb +24 -0
- data/lib/woodwing/elvis/rest/create.rb +71 -0
- data/lib/woodwing/elvis/rest/create_elvislink.rb +148 -0
- data/lib/woodwing/elvis/rest/folders.rb +27 -0
- data/lib/woodwing/elvis/rest/login_logout.rb +257 -0
- data/lib/woodwing/elvis/rest/relations.rb +24 -0
- data/lib/woodwing/elvis/rest/search.rb +156 -0
- data/lib/woodwing/elvis/rest/stub.rb +11 -0
- data/lib/woodwing/elvis/soap.rb +18 -0
- data/lib/woodwing/elvis/soap/stub.rb +11 -0
- data/lib/woodwing/elvis/utilities.rb +80 -0
- data/lib/woodwing/elvis/utilities/pmask.rb +52 -0
- data/lib/woodwing/version.rb +5 -0
- data/test/elvis_search.rb +416 -0
- data/woodwing_elvis.gemspec +23 -0
- metadata +98 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module WoodWing
|
2
|
+
class Elvis
|
3
|
+
module Rest
|
4
|
+
|
5
|
+
|
6
|
+
# https://elvis.tenderapp.com/kb/api/rest-create_relation
|
7
|
+
def create_relation(options={})
|
8
|
+
url = base_url + "create_relation"
|
9
|
+
response = get_response(url, options)
|
10
|
+
end # create_relation
|
11
|
+
|
12
|
+
|
13
|
+
# https://elvis.tenderapp.com/kb/api/rest-remove_relation
|
14
|
+
def remove_relation(options={})
|
15
|
+
url = base_url + "remove_relation"
|
16
|
+
response = get_response(url, options)
|
17
|
+
end # remove_relation
|
18
|
+
|
19
|
+
alias :delete_relation :remove_relation
|
20
|
+
|
21
|
+
|
22
|
+
end # module Rest
|
23
|
+
end # class Elvis
|
24
|
+
end # module WoodWing
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module WoodWing
|
2
|
+
class Elvis
|
3
|
+
module Rest
|
4
|
+
|
5
|
+
|
6
|
+
# https://elvis.tenderapp.com/kb/api/rest-search
|
7
|
+
# Search assets in Elvis using all of the powerful search functions provided
|
8
|
+
# by the Elvis search engine. You can execute all possible queries and even
|
9
|
+
# use faceted search.
|
10
|
+
#
|
11
|
+
# Returned information can be formatted as JSON, XML or HTML to support any
|
12
|
+
# kind of environment for clients.
|
13
|
+
#
|
14
|
+
# Apart from all sorts of metadata about the assets, the results returned
|
15
|
+
# by a search call also contain ready-to-use URLs to the thumbnail, preview
|
16
|
+
# and original file. This makes it extremely easy to display rich visual results.
|
17
|
+
#
|
18
|
+
# http://yourserver.com/services/search
|
19
|
+
# ?q=<query>
|
20
|
+
# &start=<first result>
|
21
|
+
# &num=<max result hits to return>
|
22
|
+
# &sort=<comma-delimited sort fields>
|
23
|
+
# &metadataToReturn=<comma-delimited fields>
|
24
|
+
# &facets=<comma-delimited fields>
|
25
|
+
# &facet.<field>.selection=<comma-delimited values>
|
26
|
+
# &format=<json|xml|html>
|
27
|
+
# &appendRequestSecret=<true|false>
|
28
|
+
#
|
29
|
+
# Options
|
30
|
+
# q (Required) The query to search for, see the query syntax guide
|
31
|
+
# for details. https://elvis.tenderapp.com/kb/technical/query-syntax
|
32
|
+
# Recap: supports wildcards: *? logical: AND && OR ||
|
33
|
+
# prefix terms with + to require - to remove
|
34
|
+
# suffix terms with ~ to include similar (eg. spelling errors)
|
35
|
+
# terms seperated by spaces default to an AND condition
|
36
|
+
# use "double quotes" to search for phrases.
|
37
|
+
# All searches are case insensitive.
|
38
|
+
#
|
39
|
+
# start First hit to be returned. Starting at 0 for the first hit. Used
|
40
|
+
# to skip hits to return 'paged' results. Optional. Default is 0.
|
41
|
+
#
|
42
|
+
# num Number of hits to return. Specify 0 to return no hits, this can be
|
43
|
+
# useful if you only want to fetch facets data. Optional. Default is 50.
|
44
|
+
#
|
45
|
+
# sort The sort order of returned hits. Comma-delimited list of fields to
|
46
|
+
# sort on. By default, date/time fields and number fields are sorted
|
47
|
+
# descending. All other fields are sorted ascending. To explicitly
|
48
|
+
# specify sort order, append "-desc" or "-asc" to the field.
|
49
|
+
# Some examples:
|
50
|
+
# sort=name
|
51
|
+
# sort=rating
|
52
|
+
# sort=fileSize-asc
|
53
|
+
# sort=status,assetModified-asc
|
54
|
+
# A special sort case is "relevance". This lets the search engine
|
55
|
+
# determine sorting based on the relevance of the asset against
|
56
|
+
# the search query. Relevance results are always returned descending.
|
57
|
+
# Optional. Default is assetCreated-desc.
|
58
|
+
#
|
59
|
+
# metadataToReturn Comma-delimited list of metadata fields to return in hits.
|
60
|
+
# It is good practice to always specify just the metadata
|
61
|
+
# fields that you need. This will make the searches faster
|
62
|
+
# because less data needs to be transferred over the network.
|
63
|
+
# Example: metadataToReturn=name,rating,assetCreated
|
64
|
+
# Specify "all", or omit to return all available metadata.
|
65
|
+
# Example: metadataToReturn=all
|
66
|
+
# metadataToReturn=
|
67
|
+
# Optional. Default returns all fields.
|
68
|
+
#
|
69
|
+
# facets Comma-delimited list fields to return facet for.
|
70
|
+
# Example: facets=tags,assetDomain
|
71
|
+
# Selected values for a facet must be specified with a
|
72
|
+
# "facet.<field>.selection" parameter. Do not add selected items to
|
73
|
+
# the query since that will cause incorrect facet filtering.
|
74
|
+
# Note: Only fields that are un_tokenized or tokenized with
|
75
|
+
# pureLowerCase analyzer can be used for faceted search
|
76
|
+
# Optional. Default returns no facets.
|
77
|
+
#
|
78
|
+
# facet.<field>.selection Comma-delimited list of values that should
|
79
|
+
# be 'selected' for a given facet.
|
80
|
+
# Example: facet.tags.selection=beach
|
81
|
+
# facet.assetDomain.selection=image,video
|
82
|
+
# Optional.
|
83
|
+
#
|
84
|
+
# format Response format to return, either json, xml or html.
|
85
|
+
# json format is lightweight and very suitable for consumption
|
86
|
+
# using AJAX and JavaScript.
|
87
|
+
# html format is the easiest way to embed results in HTML pages,
|
88
|
+
# but is heavier and less flexible than using a HitRenderer
|
89
|
+
# from our open-source JavaScript library.
|
90
|
+
# xml format is the same as returned by the Elvis SOAP webservice
|
91
|
+
# search operation. This format is suitable for environments
|
92
|
+
# that do not support JSON parsing and work better with XML.
|
93
|
+
# When you use format=xml, error responses will also be returned
|
94
|
+
# in xml format.
|
95
|
+
# Optional. Default is json.
|
96
|
+
#
|
97
|
+
# appendRequestSecret When set to true will append an encrypted code to
|
98
|
+
# the thumbnail, preview and original URLs. This is
|
99
|
+
# useful when the search is transformed to HTML by an
|
100
|
+
# intermediary (like a PHP or XSLT) and is then served
|
101
|
+
# to a web browser that is not authenticated against
|
102
|
+
# the server.
|
103
|
+
# Optional. Default is false.
|
104
|
+
#
|
105
|
+
# RETURNED VALUE
|
106
|
+
# ==============
|
107
|
+
#
|
108
|
+
# An array of hits in JSON, XML or HTML format. Each item in the array has
|
109
|
+
# the following properties.
|
110
|
+
#
|
111
|
+
# firstResult Index of the first result that is returned.
|
112
|
+
# maxResultHits Maximum number of hits that are returned.
|
113
|
+
# totalHits Total hits found by the search.
|
114
|
+
#
|
115
|
+
# hits
|
116
|
+
#
|
117
|
+
# id Unique ID of the asset in Elvis.
|
118
|
+
# permissions String that indicates the permissions the current user has
|
119
|
+
# for the asset.
|
120
|
+
# thumbnailUrl A ready to use URL to display the thumbnail of an asset.
|
121
|
+
# Only available for assets that have a thumbnail.
|
122
|
+
# previewUrl A ready to use URL to display the default preview of an
|
123
|
+
# asset. The type of preview depends on the asset type.
|
124
|
+
# Only available for assets that have a preview.
|
125
|
+
# originalUrl A ready to use URL to download the original asset.
|
126
|
+
# This URL will only work if the user has the 'use original'
|
127
|
+
# permission for this asset. This can be checked with the
|
128
|
+
# 'permissions' property.
|
129
|
+
# metadata An object with metadata that was requested to be returned.
|
130
|
+
# Some metadata will always be returned.
|
131
|
+
#
|
132
|
+
# Fields that have date or datetime values and the field fileSize contain
|
133
|
+
# both the actual numerical value and a formatted value.
|
134
|
+
|
135
|
+
def search(options={})
|
136
|
+
|
137
|
+
Utilities.demand_required_options!( :search, options )
|
138
|
+
url = base_url + "search"
|
139
|
+
|
140
|
+
# NOTE: One element of metadata is 'textContent' for books and
|
141
|
+
# large articles that is a LOT of text. The following
|
142
|
+
# line changes the default from 'all' to 'status,name'.
|
143
|
+
# If you want all metadata then you have to request
|
144
|
+
# 'all' in your options.
|
145
|
+
|
146
|
+
options = { metadataToReturn: 'status,name' }.merge(options)
|
147
|
+
response = get_response(url, options)
|
148
|
+
|
149
|
+
end # search
|
150
|
+
|
151
|
+
alias :find :search
|
152
|
+
|
153
|
+
|
154
|
+
end # module Rest
|
155
|
+
end # class Elvis
|
156
|
+
end # module WoodWing
|
@@ -0,0 +1,18 @@
|
|
1
|
+
###################################################
|
2
|
+
###
|
3
|
+
## File: soap.rb
|
4
|
+
## Desc: SOAP API definitions for WoodWing's Elvis
|
5
|
+
#
|
6
|
+
|
7
|
+
module WoodWing
|
8
|
+
class Elvis
|
9
|
+
module Soap
|
10
|
+
|
11
|
+
require_relative 'soap/stub'
|
12
|
+
|
13
|
+
end # module Soap
|
14
|
+
|
15
|
+
include Soap
|
16
|
+
|
17
|
+
end # class Elvis
|
18
|
+
end # module WoodWing
|
@@ -0,0 +1,80 @@
|
|
1
|
+
###################################################
|
2
|
+
###
|
3
|
+
## File: utilities.rb
|
4
|
+
## Desc: Utilitie methods for working with the REST API
|
5
|
+
## for WoodWing's Elvis product
|
6
|
+
#
|
7
|
+
|
8
|
+
require_relative 'utilities/pmask'
|
9
|
+
|
10
|
+
module WoodWing
|
11
|
+
class Elvis
|
12
|
+
class Utilities
|
13
|
+
class << self
|
14
|
+
|
15
|
+
=begin
|
16
|
+
# SMELL: Is this really necessary with RestClient ?
|
17
|
+
def url_encode_options(options)
|
18
|
+
raise "Invalid parameter class: expected Hash" unless Hash == options.class
|
19
|
+
a_string = ''
|
20
|
+
first_one = true
|
21
|
+
options.each_pair do |k, v|
|
22
|
+
if first_one
|
23
|
+
a_string += '?'
|
24
|
+
first_one = false
|
25
|
+
else
|
26
|
+
a_string += '&'
|
27
|
+
end
|
28
|
+
# a_string += "#{k}=#{String == v.class ? v.gsub(' ','%20') : v}"
|
29
|
+
a_string += "#{k}=#{URI::encode(v)}"
|
30
|
+
end # options.each_pair
|
31
|
+
#debug_me{:a_string} if debug?
|
32
|
+
return a_string
|
33
|
+
end # url_encode_options
|
34
|
+
|
35
|
+
=end
|
36
|
+
|
37
|
+
# encode the username and password for use on the URL for login
|
38
|
+
|
39
|
+
# SMELL: This is not necessary with a session-based logon/off system
|
40
|
+
# HOWEVER, it might still be useful for some cases. Can this
|
41
|
+
# scheme and a session management scheme work together?
|
42
|
+
|
43
|
+
def encode_login(username='guest', password='guest')
|
44
|
+
|
45
|
+
{
|
46
|
+
authcred: UrlSafeBase64.encode64("#{username}:#{password}"),
|
47
|
+
authpersist: 'true',
|
48
|
+
authclient: 'api_ruby'
|
49
|
+
}
|
50
|
+
|
51
|
+
end # def encode_login(username='guest', password='guest')
|
52
|
+
|
53
|
+
|
54
|
+
# raise ArgumentError if required options are not present
|
55
|
+
|
56
|
+
def demand_required_options!(command, options)
|
57
|
+
|
58
|
+
raise ArgumentError unless Symbol == command.class
|
59
|
+
raise ArgumentError unless Hash == options.class
|
60
|
+
raise ArgumentError unless WW::Elvis::COMMANDS.include?(command)
|
61
|
+
|
62
|
+
required_options = WW::Elvis::COMMANDS[command][1]
|
63
|
+
|
64
|
+
answer = true
|
65
|
+
|
66
|
+
return(answer) if required_options.empty?
|
67
|
+
|
68
|
+
required_options.each do |ro|
|
69
|
+
answer &&= options.include?(ro)
|
70
|
+
end
|
71
|
+
|
72
|
+
raise "ArgumentError: #{caller.first.split().last} requires #{required_options.join(', ')}" unless answer
|
73
|
+
|
74
|
+
end # def demand_required_options!(command, options)
|
75
|
+
|
76
|
+
end # eigenclass
|
77
|
+
end # class Utilities
|
78
|
+
end # class Elvis
|
79
|
+
end # module WoodWing
|
80
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
###################################################
|
2
|
+
###
|
3
|
+
## File: pmask.rb
|
4
|
+
## Desc: Utility class to check permissions 'mask' for available permissions
|
5
|
+
#
|
6
|
+
|
7
|
+
module WoodWing
|
8
|
+
class Elvis
|
9
|
+
class Utilities
|
10
|
+
|
11
|
+
# Utility class to check permissions 'mask' for available permissions.
|
12
|
+
# The permissions mask consists of a string with one character for
|
13
|
+
# every permission available in Elvis: VPUMERXCD
|
14
|
+
|
15
|
+
class Pmask
|
16
|
+
|
17
|
+
PERMISSIONS = {
|
18
|
+
'V' => 'VIEW',
|
19
|
+
'P' => 'VIEW_PREVIEW',
|
20
|
+
'U' => 'USE_ORIGINAL',
|
21
|
+
'M' => 'EDIT_METADATA',
|
22
|
+
'E' => 'EDIT',
|
23
|
+
'R' => 'RENAME',
|
24
|
+
'X' => 'MOVE',
|
25
|
+
'C' => 'CREATE',
|
26
|
+
'D' => 'DELETE',
|
27
|
+
}
|
28
|
+
|
29
|
+
def initialize(pmask='')
|
30
|
+
@pmask = pmask
|
31
|
+
end
|
32
|
+
|
33
|
+
def verbose
|
34
|
+
v=[]
|
35
|
+
@pmask.each_char{|c| v<<PERMISSIONS[c]}
|
36
|
+
return v.join(', ')
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method('can_view?') { @pmask.include? 'V' }
|
40
|
+
define_method('can_view_preview?') { @pmask.include? 'P' }
|
41
|
+
define_method('can_use_original?') { @pmask.include? 'U' }
|
42
|
+
define_method('can_edit_metadata?') { @pmask.include? 'M' }
|
43
|
+
define_method('can_edit?') { @pmask.include? 'E' }
|
44
|
+
define_method('can_rename?') { @pmask.include? 'R' }
|
45
|
+
define_method('can_move?') { @pmask.include? 'X' }
|
46
|
+
define_method('can_create?') { @pmask.include? 'C' }
|
47
|
+
define_method('can_delete?') { @pmask.include? 'D' }
|
48
|
+
|
49
|
+
end # class Pmask
|
50
|
+
end # class Utilities
|
51
|
+
end # class Elvis
|
52
|
+
end # module WoodWing
|
@@ -0,0 +1,416 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
##########################################################
|
4
|
+
###
|
5
|
+
## File: elvis_search.rb
|
6
|
+
## Desc: Search Elvis for stuff
|
7
|
+
## can produce an XML file for use with Carrot2 clustering
|
8
|
+
## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'debug_me'
|
12
|
+
include DebugMe
|
13
|
+
|
14
|
+
require 'pathname'
|
15
|
+
require_relative '../lib/woodwing'
|
16
|
+
|
17
|
+
|
18
|
+
me = Pathname.new(__FILE__).realpath
|
19
|
+
my_dir = me.parent
|
20
|
+
my_name = me.basename.to_s
|
21
|
+
|
22
|
+
$options = {
|
23
|
+
verbose: false,
|
24
|
+
debug: false,
|
25
|
+
show_text: false,
|
26
|
+
show_dates: false,
|
27
|
+
cluster_results: false,
|
28
|
+
cluster_filename: nil,
|
29
|
+
cluster_file: nil,
|
30
|
+
elvis_api_url: ENV['ELVIS_API_URL'] || 'http://localhost:8080/services/',
|
31
|
+
elvis_user: ENV['ELVIS_USER'] || 'guest',
|
32
|
+
elvis_pass: ENV['ELVIS_PASS'] || 'guest',
|
33
|
+
meta_fields: '',
|
34
|
+
query: '' # syntax identical to Elvis UI search box
|
35
|
+
}
|
36
|
+
|
37
|
+
def verbose?
|
38
|
+
$options[:verbose]
|
39
|
+
end
|
40
|
+
|
41
|
+
def debug?
|
42
|
+
$options[:debug]
|
43
|
+
end
|
44
|
+
|
45
|
+
def show_text?
|
46
|
+
$options[:show_text]
|
47
|
+
end
|
48
|
+
|
49
|
+
def show_dates?
|
50
|
+
$options[:show_dates]
|
51
|
+
end
|
52
|
+
|
53
|
+
def cluster_results?
|
54
|
+
$options[:cluster_results]
|
55
|
+
end
|
56
|
+
|
57
|
+
$KNOWN_MFIELDS = %w[ assetCreator
|
58
|
+
assetDomain
|
59
|
+
assetFileModifier
|
60
|
+
assetModifier
|
61
|
+
assetPath
|
62
|
+
assetPropertyETag
|
63
|
+
assetType
|
64
|
+
basicDataETag
|
65
|
+
cf_PrayerFocus
|
66
|
+
cf_Theme
|
67
|
+
cf_TFTD
|
68
|
+
cf_LongReading
|
69
|
+
cf_Citation
|
70
|
+
contentETag
|
71
|
+
extension
|
72
|
+
filename
|
73
|
+
fileSize
|
74
|
+
fileType
|
75
|
+
folderPath
|
76
|
+
indexRevision
|
77
|
+
metadataComplete
|
78
|
+
mimeType
|
79
|
+
name
|
80
|
+
previewETag
|
81
|
+
previewState
|
82
|
+
sceArchived
|
83
|
+
sceUsed
|
84
|
+
status
|
85
|
+
textContent
|
86
|
+
versionETag
|
87
|
+
versionNumber ]
|
88
|
+
|
89
|
+
usage = <<EOS
|
90
|
+
|
91
|
+
Search Elvis for stuff
|
92
|
+
|
93
|
+
Usage: #{my_name} [options] 'query'
|
94
|
+
|
95
|
+
Where:
|
96
|
+
|
97
|
+
options Do This
|
98
|
+
-h or --help Display this message
|
99
|
+
-v or --verbose Display progress
|
100
|
+
-d or --debug Sets $DEBUG
|
101
|
+
-m or --meta Display these metadata fields
|
102
|
+
field_names+ one of more metadata field
|
103
|
+
names seperated by commas
|
104
|
+
--dates Shows creation and modification
|
105
|
+
dates and users
|
106
|
+
--text Shows text around the search term(s)
|
107
|
+
for the first "hit" in the document
|
108
|
+
|
109
|
+
--cluster User document clustering
|
110
|
+
out_filename filename into which the search
|
111
|
+
results are stored
|
112
|
+
|
113
|
+
'query' The search query constrained by
|
114
|
+
single quotes.
|
115
|
+
|
116
|
+
NOTE:
|
117
|
+
|
118
|
+
The single quotes around the search query are required to
|
119
|
+
defeat the command line file glob/wildcard facility.
|
120
|
+
|
121
|
+
The '-m or --meta' option can be used many times as needed.
|
122
|
+
The following list contains the known (case-SENSITIVE)
|
123
|
+
metadata fields:
|
124
|
+
|
125
|
+
#{$KNOWN_MFIELDS.join(', ')}
|
126
|
+
|
127
|
+
EOS
|
128
|
+
|
129
|
+
# Check command line for Problems with Parameters
|
130
|
+
$errors = []
|
131
|
+
$warnings = []
|
132
|
+
|
133
|
+
|
134
|
+
# Get the next ARGV parameter after param_index
|
135
|
+
def get_next_parameter(param_index)
|
136
|
+
unless Fixnum == param_index.class
|
137
|
+
param_index = ARGV.find_index(param_index)
|
138
|
+
end
|
139
|
+
next_parameter = nil
|
140
|
+
if param_index+1 >= ARGV.size
|
141
|
+
$errors << "#{ARGV[param_index]} specified without parameter"
|
142
|
+
else
|
143
|
+
next_parameter = ARGV[param_index+1]
|
144
|
+
ARGV[param_index+1] = nil
|
145
|
+
end
|
146
|
+
ARGV[param_index] = nil
|
147
|
+
return next_parameter
|
148
|
+
end # def get_next_parameter(param_index)
|
149
|
+
|
150
|
+
|
151
|
+
# Get $options[:out_filename]
|
152
|
+
def get_out_filename(param_index)
|
153
|
+
filename_str = get_next_parameter(param_index)
|
154
|
+
$options[:out_filename] = Pathname.new( filename_str ) unless filename_str.nil?
|
155
|
+
end # def get_out_filename(param_index)
|
156
|
+
|
157
|
+
|
158
|
+
# Display global warnings and errors arrays and exit if necessary
|
159
|
+
def abort_if_errors
|
160
|
+
unless $warnings.empty?
|
161
|
+
STDERR.puts
|
162
|
+
STDERR.puts "The following warnings were generated:"
|
163
|
+
STDERR.puts
|
164
|
+
$warnings.each do |w|
|
165
|
+
STDERR.puts "\tWarning: #{w}"
|
166
|
+
end
|
167
|
+
STDERR.print "\nAbort program? (y/N) "
|
168
|
+
answer = (gets).chomp.strip.downcase
|
169
|
+
$errors << "Aborted by user" if answer.size>0 && 'y' == answer[0]
|
170
|
+
end
|
171
|
+
unless $errors.empty?
|
172
|
+
STDERR.puts
|
173
|
+
STDERR.puts "Correct the following errors and try again:"
|
174
|
+
STDERR.puts
|
175
|
+
$errors.each do |e|
|
176
|
+
STDERR.puts "\t#{e}"
|
177
|
+
end
|
178
|
+
STDERR.puts
|
179
|
+
exit(-1)
|
180
|
+
end
|
181
|
+
end # def abort_if_errors
|
182
|
+
|
183
|
+
|
184
|
+
# Display the usage info
|
185
|
+
if ARGV.empty? ||
|
186
|
+
ARGV.include?('-h') ||
|
187
|
+
ARGV.include?('--help')
|
188
|
+
puts usage
|
189
|
+
exit
|
190
|
+
end
|
191
|
+
|
192
|
+
%w[ -v --verbose ].each do |param|
|
193
|
+
if ARGV.include? param
|
194
|
+
$options[:verbose] = true
|
195
|
+
ARGV[ ARGV.index(param) ] = nil
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
%w[ -d --debug ].each do |param|
|
200
|
+
if ARGV.include? param
|
201
|
+
$options[:debug] = true
|
202
|
+
$DEBUG = true
|
203
|
+
ARGV[ ARGV.index(param) ] = nil
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
%w[ -m --meta ].each do |param|
|
208
|
+
while ARGV.include?(param) do
|
209
|
+
$options[:meta_fields] += ',' unless $options[:meta_fields].empty?
|
210
|
+
$options[:meta_fields] += get_next_parameter(ARGV.index(param))
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
%w[ --dates ].each do |param|
|
215
|
+
if ARGV.include? param
|
216
|
+
$options[:show_dates] = true
|
217
|
+
$options[:meta_fields] += ',' unless $options[:meta_fields].empty?
|
218
|
+
$options[:meta_fields] += "assetCreated,assetCreator,assetModified,assetModifier,versionNumber"
|
219
|
+
ARGV[ ARGV.index(param) ] = nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
%w[ --text ].each do |param|
|
224
|
+
if ARGV.include? param
|
225
|
+
$options[:show_text] = true
|
226
|
+
ARGV[ ARGV.index(param) ] = nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
%w[ --cluster ].each do |param|
|
231
|
+
if ARGV.include? param
|
232
|
+
$options[:cluster_results] = true
|
233
|
+
next_param = get_next_parameter(param)
|
234
|
+
unless next_param.nil?
|
235
|
+
$options[:cluster_filename] = Pathname.new(next_param)
|
236
|
+
$warnings << "File already exists: #{$options[:cluster_filename].realpath}" if $options[:cluster_filename].exist?
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
ARGV.compact!
|
243
|
+
|
244
|
+
debug_me(){ :ARGV }
|
245
|
+
|
246
|
+
|
247
|
+
if ARGV.empty?
|
248
|
+
$errors << "No search query was specified."
|
249
|
+
end
|
250
|
+
|
251
|
+
$options[:query] = ARGV.shift
|
252
|
+
|
253
|
+
unless ARGV.empty?
|
254
|
+
$errors << "The search query is malformed - may not be enclosed in quotes."
|
255
|
+
end
|
256
|
+
|
257
|
+
abort_if_errors
|
258
|
+
|
259
|
+
max_mfield_size = 0
|
260
|
+
|
261
|
+
unless $options[:meta_fields].empty?
|
262
|
+
$options[:meta_fields] = $options[:meta_fields].split(',')
|
263
|
+
$options[:meta_fields].each do |mf|
|
264
|
+
max_mfield_size = mf.size if mf.size > max_mfield_size
|
265
|
+
end
|
266
|
+
max_mfield_size += 2
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
if cluster_results?
|
271
|
+
$options[:cluster_file] = File.new($options[:cluster_filename],'w')
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
######################################################
|
276
|
+
# Local methods
|
277
|
+
|
278
|
+
|
279
|
+
|
280
|
+
|
281
|
+
######################################################
|
282
|
+
# Main
|
283
|
+
|
284
|
+
at_exit do
|
285
|
+
begin
|
286
|
+
$elvis.logout
|
287
|
+
rescue
|
288
|
+
# eat it
|
289
|
+
end
|
290
|
+
puts
|
291
|
+
puts "Done."
|
292
|
+
puts
|
293
|
+
end
|
294
|
+
|
295
|
+
$elvis = WoodWing::Elvis.new
|
296
|
+
$elvis.login
|
297
|
+
|
298
|
+
if debug?
|
299
|
+
puts
|
300
|
+
pp $options
|
301
|
+
puts
|
302
|
+
pp $elvis
|
303
|
+
puts
|
304
|
+
end
|
305
|
+
|
306
|
+
options = {
|
307
|
+
q: $options[:query],
|
308
|
+
appendRequestSecret: 'true'
|
309
|
+
}
|
310
|
+
|
311
|
+
options[:metadataToReturn] = $options[:meta_fields].join(',') unless $options[:meta_fields].empty?
|
312
|
+
|
313
|
+
|
314
|
+
response = $elvis.search options
|
315
|
+
|
316
|
+
if debug?
|
317
|
+
puts "======= Full Response ======="
|
318
|
+
pp response
|
319
|
+
end
|
320
|
+
|
321
|
+
puts
|
322
|
+
|
323
|
+
unless response.include?(:totalHits)
|
324
|
+
puts "ERROR: response does not include :totalHits"
|
325
|
+
exit
|
326
|
+
end
|
327
|
+
|
328
|
+
puts
|
329
|
+
puts "Total Hits: #{response[:totalHits]}"
|
330
|
+
puts "First Result: #{response[:firstResult]}"
|
331
|
+
puts "Max. Results: #{response[:maxResultHits]}"
|
332
|
+
puts
|
333
|
+
|
334
|
+
if cluster_results?
|
335
|
+
$options[:cluster_file].puts <<ENDXML
|
336
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
337
|
+
<searchresult>
|
338
|
+
<query>#{$options[:query]}</query>
|
339
|
+
ENDXML
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
if response[:totalHits] > 0
|
344
|
+
result_number = 0
|
345
|
+
response[:hits].each do |hit|
|
346
|
+
|
347
|
+
$options[:cluster_file].puts '<document>' if cluster_results?
|
348
|
+
|
349
|
+
metadata = hit[:metadata]
|
350
|
+
puts
|
351
|
+
puts "="*45
|
352
|
+
puts "== Result # #{result_number+=1} ID: #{hit[:id]}"
|
353
|
+
puts
|
354
|
+
puts "originalUrl: #{hit[:originalUrl]}"
|
355
|
+
puts "Asset Path: #{metadata[:assetPath]}"
|
356
|
+
puts "Status: #{metadata[:status]}"
|
357
|
+
|
358
|
+
unless $options[:meta_fields].empty?
|
359
|
+
puts
|
360
|
+
$options[:meta_fields].each do |mf|
|
361
|
+
mf_label = "#{mf}:" + ' '*(max_mfield_size-mf.size)
|
362
|
+
puts "#{mf_label} #{metadata[mf.to_sym]}"
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
if show_dates?
|
367
|
+
puts
|
368
|
+
puts "Created on: #{metadata[:assetCreated][:formatted]} by: #{metadata[:assetCreator]}"
|
369
|
+
puts "Modified on: #{metadata[:assetModified][:formatted]} by: #{metadata[:assetModifier]} Version Number # #{metadata[:versionNumber]}"
|
370
|
+
end
|
371
|
+
|
372
|
+
if show_text?
|
373
|
+
puts
|
374
|
+
puts "highlightedText: #{hit[:highlightedText]}"
|
375
|
+
end
|
376
|
+
|
377
|
+
puts
|
378
|
+
|
379
|
+
if cluster_results?
|
380
|
+
$options[:cluster_file].puts <<ENDXML
|
381
|
+
<title>#{metadata[:assetPath]}</title>
|
382
|
+
<snippet>#{hit[:highlightedText].gsub('<B>','').gsub('</B>','').gsub('<','').gsub('>','')}</snippet>
|
383
|
+
<url>http://localhost#{metadata[:assetPath]}</url>
|
384
|
+
</document>
|
385
|
+
ENDXML
|
386
|
+
|
387
|
+
end # if cluster_results?
|
388
|
+
|
389
|
+
end # response[:hits].each do |hit|
|
390
|
+
end # if response[:totalHits] > 0
|
391
|
+
|
392
|
+
|
393
|
+
if cluster_results?
|
394
|
+
$options[:cluster_file].puts "</searchresult>"
|
395
|
+
$options[:cluster_file].close
|
396
|
+
# TODO: invokl carrot2 CLI
|
397
|
+
# TODO: retrieve carrot2 generated XML file
|
398
|
+
# TODO: display document clusters
|
399
|
+
end
|
400
|
+
|
401
|
+
__END__
|
402
|
+
|
403
|
+
# To interface with Carrot2 document clustering workbench this kind of xml
|
404
|
+
# file needs to be generated with 1 document entry for each 'hit' of
|
405
|
+
# the query.
|
406
|
+
|
407
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
408
|
+
<searchresult>
|
409
|
+
<query>seattle</query>
|
410
|
+
<document>
|
411
|
+
<title>City of Seattle</title>
|
412
|
+
<snippet>Official site featuring a guide to living in Seattle and information on doing business, city services, and visitor's resources.</snippet>
|
413
|
+
<url>http://www.seattle.gov/</url>
|
414
|
+
</document>
|
415
|
+
</searchresult>
|
416
|
+
|