woodwing_elvis 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|