source: subversion/applications/utils/gps-tracks/gpx-batch-upload/gpx-batch-upload.pl @ 18390

Last change on this file since 18390 was 4830, checked in by deelkar, 13 years ago

commit gpx-batch-upload v2.2 for Niccolo Rigacci

File size: 9.5 KB
Line 
1#!/usr/bin/perl
2
3# This Perl script extracts a GPX file from a PostgreSQL database         #
4# and uploads it to the OpenStreetMap site via an HTTP POST.              #
5#                                                                         #
6# The HTTP POST performs a login with password using a cookie,            #
7# the cookie is stored in a permanent file and eventually reused.         #
8#                                                                         #
9# Author:       Niccolo Rigacci <niccolo@rigacci.org>                     #
10#                                                                         #
11# Version:      2.2     2007-10-05                                        #
12#                                                                         #
13#   This program is free software; you can redistribute it and/or modify  #
14#   it under the terms of the GNU General Public License as published by  #
15#   the Free Software Foundation; either version 2 of the License, or     #
16#   (at your option) any later version.                                   #
17#                                                                         #
18#   This program is distributed in the hope that it will be useful,       #
19#   but WITHOUT ANY WARRANTY; without even the implied warranty of        #
20#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
21#   GNU General Public License for more details.                          #
22#                                                                         #
23#   You should have received a copy of the GNU General Public License     #
24#   along with this program; if not, write to the                         #
25#   Free Software Foundation, Inc.,                                       #
26#   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
27
28use strict;
29# Requires Debian package libdbd-pg-perl. See man DBD::Pg
30use DBI;
31# Requires Debian package libwww-perl.
32use LWP::UserAgent;
33use HTTP::Request::Common;
34# Install the libtimedate-perl Debian package.
35use Date::Parse;
36use Date::Format;
37# Require Debian package perl-modules.
38use File::Temp qw/ tempfile tempdir /;
39use Getopt::Std;
40use vars qw($opt_i $opt_d $opt_e $opt_p $opt_t $opt_u);
41
42# Read database credential from file...
43my $DBINFO = '/usr/local/lib/strade/dbinfo';
44# ... or define them here.
45my $DBHOST;
46my $DBNAME;
47my $DBUSER;
48my $DBPASS;
49
50my $OSM_LOGIN_PAGE   = 'http://www.openstreetmap.org/login.html';
51my $OSM_UPLOAD_TRACK = 'http://www.openstreetmap.org/trace/create';
52
53my $TMP_DIR = '/tmp';
54my $NAME    = `basename "$0"`;
55chomp($NAME);
56
57my $debug = 0;
58my $resp;
59my $sql;
60my $dbh;
61my $record;
62my $timestamp;
63my $tmp_filename;
64my $fp;
65
66my $ua;
67my $response;
68my $hex_string;
69my $cookie;
70my @stat;
71my $original_filename;
72
73#-------------------------------------------------------------------------
74# Get the track ID from the command line.
75#-------------------------------------------------------------------------
76if (! getopts('i:d:e:p:t:u:')) {
77    print "Usage: $NAME -i idgpx -e email -p pass -d description -t tags -u public\n\n";
78    print "Upload a GPX file extracted from PostgreSQL, to the OpenStreetMap site.\n";
79    exit 0;
80}
81
82die('Invalid GPX ID')      if (!($opt_i =~ m/^\d+$/));
83die('Invalid OSM email')   if (!($opt_e =~ m/^[\@\.0-9A-Za-z_-]{1,50}$/));
84die('Invalid OSM pass')    if (!($opt_p =~ m/^.{1,50}$/));
85die('Invalid description') if (!($opt_d =~ m/^.{0,255}$/));
86die('Invalid tags')        if (!($opt_p =~ m/^.{0,255}$/));
87die('Invalid public')      if ($opt_u ne '' and $opt_u ne 'on');
88
89# Get login and password for DB access.
90read_db_info();
91
92# Temporary file for cookie.
93$hex_string = $opt_e;
94$hex_string =~ s/(.)/sprintf('%02X', ord($1))/seg;
95$cookie = $TMP_DIR . '/.osm_cookie_' . $hex_string . '.txt';
96
97#-------------------------------------------------------------------------
98# Open the database connection and get the track.
99#-------------------------------------------------------------------------
100print "Getting track ID $opt_i from database...\n";
101$dbh = DBI->connect("dbi:Pg:dbname=$DBNAME;host=$DBHOST", $DBUSER, $DBPASS)
102    or die $DBI::errstr;
103
104$sql  = 'SELECT id,descr,date_time,osm_upload,xml_text,filename FROM gpxfiles';
105$sql .= ' WHERE id = ' . $opt_i;
106$sql .= ' AND osm_upload IS NOT TRUE';
107$record = $dbh->selectrow_hashref($sql);
108die 'Record not found or file already uploaded. Stopped' if (! $record);
109# Close the database connection.
110$dbh->disconnect;
111
112# Save GPX to a temporary file.
113#
114# TODO: Avoid to store all the GPX into a variable (RAM).
115#
116$timestamp = time2str('%Y-%m-%d', str2time($record->{'date_time'}));
117($fp, $tmp_filename) = tempfile($timestamp . '.XXXXX', DIR => $TMP_DIR, SUFFIX => '.gpx');
118print $fp $record->{'xml_text'};
119close($fp);
120
121# Get the original GPX filename, or compose a suitable one.
122if (!(defined($record->{'filename'})) or $record->{'filename'} eq '') {
123    $original_filename = $timestamp . '.gpx';
124} else {
125    $original_filename = $record->{'filename'};
126}
127
128# Description for OSM is from command line or from database.
129$opt_d = $record->{'descr'} if (! defined($opt_d));
130
131print '-' x 50 . "\n";
132print 'DB description: '     . $record->{'descr'}            . "\n";
133print 'DB timestamp: '       . $record->{'date_time'}        . "\n";
134print 'DB XML text lenght: ' . length($record->{'xml_text'}) . "\n";
135print '-' x 50 . "\n";
136#print "Tempoaray file for cookie: $cookie\n";
137#print "Tempoaray file for GPX: $tmp_filename\n";
138#print '-' x 50 . "\n";
139print "OSM filename: $original_filename\n";
140print "OSM description: $opt_d\n";
141print "OSM tags: $opt_t\n";
142print "OSM public: $opt_u\n";
143print '-' x 50 . "\n";
144
145#-------------------------------------------------------------------------
146# Begin WEB transactions.
147#-------------------------------------------------------------------------
148$ua = LWP::UserAgent->new;
149
150#-------------------------------------------------------------------------
151# Login to OpenStreetMap Editor.
152#-------------------------------------------------------------------------
153print "Logging into $OSM_LOGIN_PAGE...\n";
154
155# Remove the saved cookie, if it is too old.
156if (-f $cookie) {
157    @stat = stat($cookie);
158    if ((time() - $stat[9]) > 600) {
159        print "Removing old file: $cookie\n";
160        unlink($cookie);
161    } else {
162        print "Using existing cookie from file: $cookie\n";
163    }
164}
165
166# Save the login cookie into a permanent file.
167$ua->cookie_jar({
168    file => $cookie,
169    autosave => 1,
170    ignore_discard => 1,
171});
172
173if (! -f $cookie) {
174    print "Saving cookie to $cookie\n";
175    $response = $ua->request(POST $OSM_LOGIN_PAGE, [
176        'user[email]'    => $opt_e,
177        'user[password]' => $opt_p,
178        commit           => 'Login',
179    ]);
180
181    if ($response->status_line ne '302 Found') {
182        print $response->content . "\n";
183        print "Response: " . $response->status_line . "\n";
184        my_die("Login request failed.");
185    }
186}
187
188#-------------------------------------------------------------------------
189# Upload the track.
190#-------------------------------------------------------------------------
191print "Uploading track to $OSM_UPLOAD_TRACK...\n";
192$response = $ua->request(POST $OSM_UPLOAD_TRACK,
193    Content_Type => 'form-data',
194    Content      => [
195        "trace[gpx_file]"    => [
196            $tmp_filename,
197            $original_filename,
198            Content_Type => 'application/octet-stream',
199        ],
200        "trace[description]" => $opt_d,
201        "trace[tagstring]"   => $opt_t,
202        "trace[public]"      => $opt_u,
203    ]
204);
205
206# A success or redirect response is OK.
207if (($response->is_redirect) and ($response->content =~ m|/traces/mine|)) {
208    print "Status line: " . $response->status_line . "\n";
209    print "Upload successful.\n";
210} elsif ($response->is_success) {
211    print "Upload successful.\n";
212} else {
213    print "Status line: " . $response->status_line . "\n";
214    print "Content:     " . $response->content     . "\n";
215    my_die("Upload request failed. Delete login cookie and try again.");
216}
217
218#-------------------------------------------------------------------------
219# Update the database: set "osm_upload" field to TRUE.
220#-------------------------------------------------------------------------
221print "Setting osm_upload = TRUE for track $opt_i...\n";
222$dbh = DBI->connect("dbi:Pg:dbname=$DBNAME;host=$DBHOST", $DBUSER, $DBPASS)
223    or die $DBI::errstr;
224
225$sql  = 'UPDATE gpxfiles';
226$sql .= ' SET osm_upload = TRUE';
227$sql .= ' WHERE id = ' . $opt_i;
228$dbh->do($sql);
229# Close the database connection.
230$dbh->disconnect;
231
232#-------------------------------------------------------------------------
233# Remove temporary file.
234#-------------------------------------------------------------------------
235unlink($tmp_filename) if (! $debug);
236
237exit(0);
238
239#-------------------------------------------------------------------------
240# Print an error message, remove temporary file and die.
241#-------------------------------------------------------------------------
242sub my_die {
243    my $msg = shift;
244    print "\n" . $msg . "\n";
245    unlink($tmp_filename) if (defined($tmp_filename) and -f $tmp_filename);
246    exit(1);
247}
248
249#-------------------------------------------------------------------------
250# Read database account from file.
251#-------------------------------------------------------------------------
252sub read_db_info {
253    my $fp;
254    my $line;
255    open ($fp, $DBINFO) or die;
256    while ($line = <$fp>) {
257        chomp($line);
258        if ($line =~ m/^\s*([^#][^=]*)=(.*)/) {
259            if    ($1 eq 'DBHOST') { $DBHOST = $2; }
260            elsif ($1 eq 'DBNAME') { $DBNAME = $2; }
261            elsif ($1 eq 'DBUSER') { $DBUSER = $2; }
262            elsif ($1 eq 'DBPASS') { $DBPASS = $2; }
263        }
264    }
265    close($fp);
266}
267
Note: See TracBrowser for help on using the repository browser.