From 9f83bc026328bfe067a6256250c6361f2cf61e82 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 10 May 2015 00:26:00 +0200 Subject: [PATCH] properly handle backdated posts with timzone support --- controllers/controllers.php | 73 ++++++++++++++++++++++++++++++------- lib/helpers.php | 36 ++++++++++++++++-- views/new-post.php | 12 ++++-- views/partials/entry.php | 2 +- 4 files changed, 102 insertions(+), 21 deletions(-) diff --git a/controllers/controllers.php b/controllers/controllers.php index b67d147..99a7a9f 100644 --- a/controllers/controllers.php +++ b/controllers/controllers.php @@ -43,8 +43,26 @@ function generate_login_token() { $app->get('/new', function() use($app) { if($user=require_login($app)) { - $entry = false; - $photo_url = false; + // Get the last post and set the timezone offset to match + $date_str = date('Y-m-d'); + $time_str = date('H:i:s'); + $tz_offset = '+0000'; + + $last = ORM::for_table('entries')->where('user_id', $user->id) + ->order_by_desc('published')->find_one(); + if(false && $last) { + $seconds = $last->tz_offset; + $tz_offset = tz_seconds_to_offset($seconds); + + // Create a date object in the local timezone given the offset + $date = new DateTime(); + if($seconds > 0) + $date->add(new DateInterval('PT'.$seconds.'S')); + elseif($seconds < 0) + $date->sub(new DateInterval('PT'.abs($seconds).'S')); + $date_str = $date->format('Y-m-d'); + $time_str = $date->format('H:i:s'); + } // Initially populate the page with the list of options without considering location. // This way if browser location is disabled or not available, or JS is disabled, there @@ -59,6 +77,9 @@ $app->get('/new', function() use($app) { 'response_date' => $user->last_micropub_response_date, 'location_enabled' => $user->location_enabled, 'default_options' => get_entry_options($user->id), + 'tz_offset' => $tz_offset, + 'date_str' => $date_str, + 'time_str' => $time_str, 'enable_appcache' => true )); $app->response()->body($html); @@ -145,20 +166,20 @@ $app->post('/post', function() use($app) { // Store the post in the database $entry = ORM::for_table('entries')->create(); $entry->user_id = $user->id; - $entry->published = date('Y-m-d H:i:s'); + $location = false; if(k($params, 'location') && $location=parse_geo_uri($params['location'])) { $entry->latitude = $location['latitude']; $entry->longitude = $location['longitude']; - if($timezone=get_timezone($location['latitude'], $location['longitude'])) { - $entry->timezone = $timezone->getName(); - $entry->tz_offset = $timezone->getOffset(new DateTime()); - } - } else { - $entry->timezone = 'UTC'; - $entry->tz_offset = 0; } + // The post request is always going to have a date now + $date_string = $params['note_date'] . 'T' . $params['note_time'] . $params['note_tzoffset']; + $entry->published = date('Y-m-d H:i:s', strtotime($date_string)); + $entry->tz_offset = tz_offset_to_seconds($params['note_tzoffset']); + + $published = $date_string; + if(k($params, 'drank')) { $entry->content = trim($params['drank']); $type = 'drink'; @@ -193,6 +214,7 @@ $app->post('/post', function() use($app) { $mp_request = array( 'h' => 'entry', + 'published' => $published, 'p3k-food' => $entry->content, 'p3k-type' => $type, 'location' => k($params, 'location'), @@ -228,14 +250,39 @@ $app->post('/post', function() use($app) { } }); -$app->get('/options', function() use($app) { +$app->get('/options.json', function() use($app) { if($user=require_login($app)) { $params = $app->request()->params(); $options = get_entry_options($user->id, k($params,'latitude'), k($params,'longitude')); $html = partial('partials/entry-buttons', ['options'=>$options]); - $app->response()->body($html); + $tz_offset = '+0000'; + $date_str = date('Y-m-d'); + $time_str = date('H:i:s'); + if(k($params,'latitude')) { + if($timezone=get_timezone($params['latitude'], $params['longitude'])) { + $seconds = $timezone->getOffset(new DateTime()); + $tz_offset = tz_seconds_to_offset($seconds); + + // Create a date object in the local timezone given the offset + $date = new DateTime(); + if($seconds > 0) + $date->add(new DateInterval('PT'.$seconds.'S')); + elseif($seconds < 0) + $date->sub(new DateInterval('PT'.abs($seconds).'S')); + $date_str = $date->format('Y-m-d'); + $time_str = $date->format('H:i:s'); + } + } + + $app->response()['Content-type'] = 'application/json'; + $app->response()->body(json_encode([ + 'buttons'=>$html, + 'tz_offset'=>$tz_offset, + 'date_str'=>$date_str, + 'time_str'=>$time_str + ])); } }); @@ -251,7 +298,7 @@ $app->get('/map.png', function() use($app) { $app->response()->body($img); }); -$app->get('/teacup.appcache', function() use($app) { +$app->get('/-teacup.appcache', function() use($app) { $content = partial('appcache'); $app->response()['Content-type'] = 'text/cache-manifest'; diff --git a/lib/helpers.php b/lib/helpers.php index f7353ee..f47f016 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -192,15 +192,45 @@ function relative_time($date) { return $rel->timeAgo($date); } +function date_iso8601($date_string, $tz_offset) { + $date = new DateTime($date_string); + if($tz_offset > 0) + $date->add(new DateInterval('PT'.$tz_offset.'S')); + elseif($tz_offset < 0) + $date->sub(new DateInterval('PT'.abs($tz_offset).'S')); + $tz = tz_seconds_to_offset($tz_offset); + return $date->format('Y-m-d\TH:i:s') . $tz; +} + +function tz_seconds_to_offset($seconds) { + return ($seconds < 0 ? '-' : '+') . sprintf('%02d:%02d', abs($seconds/60/60), ($seconds/60)%60); +} + +function tz_offset_to_seconds($offset) { + if(preg_match('/([+-])(\d{2}):?(\d{2})/', $offset, $match)) { + $sign = ($match[1] == '-' ? -1 : 1); + return ($match[2] * 60 * 60) + ($match[3] * 60) * $sign; + } else { + return 0; + } +} + function entry_url($entry, $user) { return $entry->canonical_url ?: Config::$base_url . $user->url . '/' . $entry->id; } function entry_date($entry, $user) { $date = new DateTime($entry->published); - $tz = new DateTimeZone($entry->timezone); - $date->setTimeZone($tz); - return $date; + if($entry->tz_offset > 0) + $date->add(new DateInterval('PT'.$entry->tz_offset.'S')); + elseif($entry->tz_offset < 0) + $date->sub(new DateInterval('PT'.abs($entry->tz_offset).'S')); + $tz = tz_seconds_to_offset($entry->tz_offset); + return new DateTime($date->format('Y-m-d\TH:i:s') . $tz); + // Can switch back to this later if I prompt the user for a named timezone instead of just an offset + // $tz = new DateTimeZone($entry->timezone); + // $date->setTimeZone($tz); + // return $date; } function default_drink_options() { diff --git a/views/new-post.php b/views/new-post.php index 17c8c9c..ad32080 100644 --- a/views/new-post.php +++ b/views/new-post.php @@ -23,8 +23,9 @@

Date

- - + + +
@@ -101,7 +102,7 @@ $(function(){ navigator.geolocation.getCurrentPosition(function(position){ - $.get('/options', { + $.getJSON('/options.json', { latitude: position.coords.latitude, longitude: position.coords.longitude }, function(response) { @@ -117,7 +118,10 @@ $(function(){ selected = '#custom_eat'; } - $("#entry-buttons").html(response); + $("#entry-buttons").html(response.buttons); + $("#note_tzoffset").val(response.tz_offset); + $("#note_date").val(response.date_str); + $("#note_time").val(response.time_str); // restore the custom values entered $('#custom_eat').val(custom_eat); diff --git a/views/partials/entry.php b/views/partials/entry.php index 78a3b97..a718148 100644 --- a/views/partials/entry.php +++ b/views/partials/entry.php @@ -23,7 +23,7 @@
- +