|
| 1 | +#!/usr/bin/env ruby |
| 2 | + |
| 3 | +#-- |
| 4 | +# Upload script for Finder! |
| 5 | +# Version 2.0.1 beta |
| 6 | +# Copyright (c) 2008 FortiusOne |
| 7 | +# Copyright (c) 2005 Bill Stilwell ([email protected]) |
| 8 | +#++ |
| 9 | + |
| 10 | +require 'net/http' |
| 11 | +require 'net/https' |
| 12 | +require 'rexml/document' |
| 13 | +require 'uri' |
| 14 | +require 'cgi' |
| 15 | +require 'optparse' |
| 16 | +require 'ostruct' |
| 17 | +require 'yaml' |
| 18 | +require 'multipart' |
| 19 | + |
| 20 | +BATCH_FILE_FORMAT = "shp" |
| 21 | + |
| 22 | +class Net::HTTP |
| 23 | + alias_method :old_initialize, :initialize |
| 24 | + def initialize(*args) |
| 25 | + old_initialize(*args) |
| 26 | + @ssl_context = OpenSSL::SSL::SSLContext.new |
| 27 | + @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE |
| 28 | + end |
| 29 | +end |
| 30 | + |
| 31 | +def login( username, password ) |
| 32 | + uri = URI.parse($finder_path) |
| 33 | + res = Net::HTTP.new(uri.host, uri.port) |
| 34 | + res.use_ssl = (uri.scheme= 'https') |
| 35 | + post = Net::HTTP::Post.new("/sessions") |
| 36 | + post.set_form_data( {'login' => username, 'password' => password} ) |
| 37 | +# post.verify_mode = OpenSSL::SSL::VERIFY_NONE |
| 38 | +# post.use_ssl = (uri.scheme == 'https') |
| 39 | + |
| 40 | + res.start do |https| |
| 41 | +# if File.exist? RootCA |
| 42 | +# http.ca_file = RootCA |
| 43 | +# http.verify_mode = OpenSSL::SSL::VERIFY_PEER |
| 44 | +# http.verify_depth = 5 |
| 45 | +# else |
| 46 | +# end |
| 47 | + |
| 48 | + #make the initial get to get the JSESSION cookie |
| 49 | + |
| 50 | + response = https.request(post) |
| 51 | + case response |
| 52 | + when Net::HTTPFound |
| 53 | + puts "Badger got a cookie (logged in)" |
| 54 | + else |
| 55 | + puts "No cookies for badger (login failed)" |
| 56 | + end |
| 57 | + # get original cookie contains _f1gc_session=blahblahblah |
| 58 | + cookie = response.response['set-cookie'] |
| 59 | + end |
| 60 | +end |
| 61 | + |
| 62 | +def upload( query,cookie = nil ) |
| 63 | + url = URI.parse($finder_path) |
| 64 | + res = Net::HTTP.new(url.host, url.port) |
| 65 | + res.use_ssl = (url.scheme == 'https') |
| 66 | + req = Net::HTTP::Post.new("/overlays.xml") |
| 67 | + req["Cookie"] = cookie |
| 68 | + req.set_multipart_form_data(query) |
| 69 | + res = res.start {|http| http.request(req) } |
| 70 | +end |
| 71 | + |
| 72 | +def metadata(resource, params, cookie=nil) |
| 73 | + url = URI.parse($finder_path+"/overlays/"+resource) |
| 74 | + res = Net::HTTP.new(url.host, url.port) |
| 75 | + res.use_ssl = (url.scheme == 'https') |
| 76 | + req = Net::HTTP::Put.new(url.path) |
| 77 | + req["Cookie"] = cookie |
| 78 | + req.set_form_data(params) |
| 79 | + res = res.start {|http| http.request(req) } |
| 80 | + if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection) |
| 81 | + return res |
| 82 | + else |
| 83 | + raise StandardError, "Metadata Fail: #{res.body} for #{resource}" |
| 84 | + end |
| 85 | +end |
| 86 | + |
| 87 | +if __FILE__ == $0 |
| 88 | + |
| 89 | + # Parse the command line options |
| 90 | + options = OpenStruct.new |
| 91 | + opts = OptionParser.new |
| 92 | + opts.banner = "Usage: badger.rb [options] filename" |
| 93 | + opts.on("-e [USERNAME]", "--user [USERNAME]", "GeoCommons account username") {|username| options.username = username } |
| 94 | + opts.on("-p [PASSWORD]", "--password [PASSWORD]", "GeoCommons password") {|password| options.password = password } |
| 95 | + opts.on("-f FILE", "--file FILE", "--overlay FILE", "File to upload") {|overlay| options.overlay = overlay } |
| 96 | + opts.on("-t=[TITLE]", "--title=[TITLE]", "Title of the overlay") {|title| options.title = title } |
| 97 | + opts.on("-d=[DESCRIPTION]", "--description=[DESCRIPTION]", "--desc=[DESCRIPTION]", "Description of the overlay") {|description| options.description = description } |
| 98 | + opts.on("--tags=[TAGS]", Array, "Tags to be applied (comma separated)") {|tags| options.tags = tags} |
| 99 | + opts.on("--is-private", "Set visibility to private") {|private| options.private = private} |
| 100 | + opts.on("-s", "Store the credentials to a configuration file") {|save| options.save = save} |
| 101 | + opts.on("--meta=[METAFILE]", "Metadata Filename") {|metadata| options.metadata = metadata} |
| 102 | + opts.on("--batch=[DIRECTORY]", "Batch upload a directory") {|batch| options.batch = batch} |
| 103 | + opts.on("--finder=[FINDER URL]", "Finder web address") {|finder| options.finder = finder; $finder_path = finder} |
| 104 | + opts.on("-c", "Provide a terminal interface to get username and password") {|terminal| options.terminal = terminal} |
| 105 | + |
| 106 | + opts.on_tail("-h", "--help", "Show this message") do |
| 107 | + puts opts |
| 108 | + exit |
| 109 | + end |
| 110 | + |
| 111 | + files = opts.parse(ARGV) |
| 112 | + if options.batch |
| 113 | + files = Dir.glob(options.batch.gsub(/\/$/,'') + "/*.xml") |
| 114 | + elsif files.length == 0 |
| 115 | + raise "You must specify at least one file or a batch upload directory!" |
| 116 | + end |
| 117 | + |
| 118 | + # Split the tags |
| 119 | + if options.tags |
| 120 | + options.tags.each do |tag| |
| 121 | + tag.gsub!(/^(.*) (.*)$/, '"\1 \2"') |
| 122 | + end |
| 123 | + end |
| 124 | + |
| 125 | + # if options.terminal |
| 126 | + # options.username = ask("Enter your Finder! username: ") {|q| q.echo = false} unless options.username |
| 127 | + # options.password = ask("Enter your Finder! password: ") {|q| q.echo = false} unless options.password |
| 128 | + # options.finder = ask("Enter the URL to Finder!: ") {|q| q.echo = false} unless options.finder |
| 129 | + # options.batch = ask("Batch upload directory?: ") {|q| q.echo = false} unless options.batch |
| 130 | + # end |
| 131 | + |
| 132 | + # Optionally load or save the login credentials to a stored file |
| 133 | + # TODO: store the password as a hash |
| 134 | + if test ?r, "#{ENV['HOME']}/.geocommonsrc" |
| 135 | + config = YAML.load(File.open("#{ENV['HOME']}/.geocommonsrc")) |
| 136 | + options.username = config['username'] if ! options.username |
| 137 | + options.password = config['password'] if ! options.password |
| 138 | + else |
| 139 | + # puts "No config file, consider running with -s to create one." |
| 140 | + end |
| 141 | + |
| 142 | + if options.save |
| 143 | + conf = { |
| 144 | + "username" => options.username, |
| 145 | + "password" => options.password, |
| 146 | + } |
| 147 | + File.open("#{ENV['HOME']}/.geocommonsrc", "w") { |f| YAML.dump(conf, f)} |
| 148 | + puts "Config file saved." |
| 149 | + end |
| 150 | + |
| 151 | + ids=[] |
| 152 | + cookie = options.username.nil? ? nil : login(options.username, options.password) |
| 153 | + for overlay in files |
| 154 | + if options.batch |
| 155 | + options.metadata = overlay |
| 156 | + overlay = options.metadata.gsub(/\.xml/,'') |
| 157 | + else |
| 158 | + overlay = overlay.gsub(/\.shp/, '') |
| 159 | + end |
| 160 | + |
| 161 | + shp = "#{overlay}.shp" |
| 162 | + shx = "#{overlay}.shx" |
| 163 | + dbf = "#{overlay}.dbf" |
| 164 | + xml = "#{overlay}.xml" |
| 165 | + |
| 166 | + puts "Overlay: #{overlay}" |
| 167 | + |
| 168 | + # Upload the overlay file |
| 169 | + raise "File #{overlay} doesn't exist or isn't readable." if ! test ?r, shp |
| 170 | + shpfile = File.open( shp ) |
| 171 | + shxfile = File.open( shx ) |
| 172 | + dbffile = File.open( dbf ) |
| 173 | + #xmlfile = File.open( xml ) |
| 174 | + params = {} |
| 175 | + params["overlay[shp]"] = shpfile |
| 176 | + params["overlay[shx]"] = shxfile |
| 177 | + params["overlay[dbf]"] = dbffile |
| 178 | + |
| 179 | + response = upload(params, cookie) |
| 180 | + |
| 181 | + shpfile.close |
| 182 | + shxfile.close |
| 183 | + dbffile.close |
| 184 | + |
| 185 | + case response |
| 186 | + when Net::HTTPCreated |
| 187 | + ids << response.header["location"] |
| 188 | + else |
| 189 | + puts "error uploading file: #{response.body}." |
| 190 | + next |
| 191 | + end |
| 192 | + puts response.message.inspect |
| 193 | + overlay_id = response.header["location"].match(/(\d+)\.xml/)[1] |
| 194 | + |
| 195 | + # Upload the overlay metadata |
| 196 | + params = {} |
| 197 | + mapping = {"overlay_meta"=>["lineage", "metadata_url", "contact_address", "contact_phone", |
| 198 | + "citation_url", "shared", "description", "contact_name", |
| 199 | + "english_reference_date"], "overlay"=>["name"]} |
| 200 | + |
| 201 | + if options.metadata |
| 202 | + f = File.open(xml) |
| 203 | + overlay = REXML::Document.new(f) |
| 204 | + f.close() |
| 205 | + |
| 206 | + mapping.each do |set, attributes| |
| 207 | + attributes.each do |attribute| |
| 208 | + value = overlay.elements["//#{set.gsub(/_/,'-')}/#{attribute.gsub(/_/,'-')}"] |
| 209 | + params["#{set}[#{attribute}]"] = value.text unless value.nil? |
| 210 | + end |
| 211 | + end |
| 212 | + |
| 213 | + tags = REXML::XPath.match(overlay, "//tag/name").collect { |t| t.text } |
| 214 | + params["overlay[tag_list]"] = tags.join(",") |
| 215 | + |
| 216 | + else |
| 217 | + params["overlay[name]"] = options.title if options.title |
| 218 | + params["overlay_meta[description]"] = options.description if options.description |
| 219 | + params["overlay[tag_list]"] = options.tags.join(",") if options.tags |
| 220 | + params["overlay_meta[shared]"] = options.private ? false : true |
| 221 | + end |
| 222 | + |
| 223 | + response = metadata(overlay_id, params, cookie) |
| 224 | + |
| 225 | +# case response |
| 226 | +# when Net::HTTPOK |
| 227 | +# puts "Uploaded! #{ids.last.gsub(/\.xml/,'')}" |
| 228 | +# |
| 229 | +# else |
| 230 | + |
| 231 | + puts "Uploaded! #{ids.last.gsub(/\.xml/,'')}" |
| 232 | +# puts response.body |
| 233 | +# end |
| 234 | + end |
| 235 | + |
| 236 | + |
| 237 | +end |
0 commit comments