Skip to content

Commit

Permalink
client: Use Date internally everywhere
Browse files Browse the repository at this point in the history
It should be (de)serialized from/into string as soon as possible,
e.g. in HTTP api functions or when getting data from template.
  • Loading branch information
jtojnar committed Jan 26, 2021
1 parent d36ea78 commit efae041
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 28 deletions.
58 changes: 53 additions & 5 deletions assets/js/requests/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import * as ajax from '../helpers/ajax';
*/
export function getEntries(params) {
const { controller, promise } = ajax.get('', {
body: ajax.makeSearchParams(params)
body: ajax.makeSearchParams({
...params,
fromDatetime: params.fromDatetime ? params.fromDatetime.toISOString() : params.fromDatetime
})
});

return { controller, promise };
Expand Down Expand Up @@ -37,31 +40,76 @@ export function mark(id, read) {
return ajax.post(`${read ? 'unmark' : 'mark'}/${id}`).promise;
}

/**
* Converts some values like dates in an entry into a objects.
*/
function enrichEntry(entry) {
return {
...entry,
datetime: new Date(entry.datetime),
updatetime: entry.updatetime ? new Date(entry.updatetime) : entry.updatetime
};
}

/**
* Converts some values like dates in response into a objects.
*/
function enrichItemsResponse(data) {
return {
...data,
lastUpdate: data.lastUpdate ? new Date(data.lastUpdate) : data.lastUpdate,
// in getItems
entries: data.entries?.map(enrichEntry),
// in sync
newItems: data.newItems?.map(enrichEntry)
};
}

/**
* Get all items matching given filter.
*/
export function getItems(filter) {
const { controller, promise } = ajax.get('', {
body: ajax.makeSearchParams(filter)
body: ajax.makeSearchParams({
...filter,
fromDatetime: filter.fromDatetime ? filter.fromDatetime.toISOString() : filter.fromDatetime
})
});

return {
controller,
promise: promise.then(response => response.json())
promise: promise.then(response => response.json()).then(enrichItemsResponse)
};
}

/**
* Synchronize changes between client and server.
*/
export function sync(updatedStatuses, syncParams) {
let params = {
...syncParams,
updatedStatuses: syncParams.updatedStatuses ? syncParams.updatedStatuses.map((status) => {
return {
...status,
datetime: status.datetime.toISOString()
};
}) : syncParams.updatedStatuses
};

if ('since' in params) {
params.since = params.since.toISOString();
}
if ('itemsNotBefore' in params) {
params.itemsNotBefore = params.itemsNotBefore.toISOString();
}

const { controller, promise } = ajax.fetch('items/sync', {
method: updatedStatuses ? 'POST' : 'GET',
body: ajax.makeSearchParams(syncParams)
body: ajax.makeSearchParams(params)
});

return {
controller,
promise: promise.then(response => response.json())
promise: promise.then(response => response.json()).then(enrichItemsResponse)
};
}
15 changes: 6 additions & 9 deletions assets/js/selfoss-db.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ selfoss.dbOnline = {
}

var syncParams = {
since: selfoss.db.lastUpdate.toISOString(),
since: selfoss.db.lastUpdate,
tags: true,
sources: selfoss.filter.sourcesNav ? true : undefined,
itemsStatuses: getStatuses
Expand All @@ -117,7 +117,7 @@ selfoss.dbOnline = {

if (selfoss.db.enableOffline) {
syncParams.itemsSinceId = selfoss.dbOffline.lastItemId;
syncParams.itemsNotBefore = selfoss.dbOffline.newestGCedEntry.toISOString();
syncParams.itemsNotBefore = selfoss.dbOffline.newestGCedEntry;
syncParams.itemsHowMany = selfoss.filter.itemsPerPage;
}

Expand All @@ -131,15 +131,14 @@ selfoss.dbOnline = {
selfoss.db.lastSync = Date.now();
selfoss.dbOnline.firstSync = false;

var dataDate = new Date(data.lastUpdate);
var dataDate = data.lastUpdate;

var storing = false;

if (selfoss.db.enableOffline) {
if ('newItems' in data) {
var maxId = 0;
data.newItems.forEach(function(item) {
item.datetime = new Date(item.datetime);
maxId = Math.max(item.id, maxId);
});

Expand Down Expand Up @@ -259,7 +258,7 @@ selfoss.dbOnline = {

if (!selfoss.db.enableOffline) {
selfoss.db.lastSync = Date.now();
selfoss.db.lastUpdate = new Date(data.lastUpdate);
selfoss.db.lastUpdate = data.lastUpdate;
}

selfoss.refreshStats(data.all, data.unread, data.starred);
Expand Down Expand Up @@ -307,8 +306,7 @@ selfoss.dbOnline = {
selfoss.dbOffline = {


// the datetime of the newest garbage collected entry, i.e. deleted
// because not of interest.
/** @var Date the datetime of the newest garbage collected entry, i.e. deleted because not of interest. */
newestGCedEntry: null,
offlineDays: 10,

Expand Down Expand Up @@ -558,7 +556,6 @@ selfoss.dbOffline = {
var fromId = selfoss.filter.fromId;
if (fromDatetime && fromId) {
seek = true;
fromDatetime = new Date(fromDatetime);
}
var isMore = false;
var alwaysInDb = selfoss.filter.type === 'starred'
Expand Down Expand Up @@ -688,7 +685,7 @@ selfoss.dbOffline = {
selfoss.dbOffline.needsSync = true;
}

var d = new Date().toISOString();
var d = new Date();
let newQueuedStatuses = statuses.map(newStatus => ({
entryId: parseInt(newStatus.entryId),
name: newStatus.name,
Expand Down
2 changes: 1 addition & 1 deletion assets/js/selfoss-events-entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ selfoss.events.entries = function() {
var lastEntry = $('.entry').filter(':last');
selfoss.events.setHash();
selfoss.filter.extraIds.length = 0;
selfoss.filter.fromDatetime = lastEntry.data('entry-datetime');
selfoss.filter.fromDatetime = new Date(lastEntry.data('entry-datetime'));
selfoss.filter.fromId = lastEntry.data('entry-id');

selfoss.db.reloadList(true);
Expand Down
2 changes: 1 addition & 1 deletion assets/js/templates/Item.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function Item({item}) {
return (
<div data-entry-id={item.id}
data-entry-source={item.source}
data-entry-datetime={item.datetime}
data-entry-datetime={item.datetime.toISOString()}
data-entry-url={item.link}
class={['entry', item.unread == 1 ? 'unread' : null]} role="article">

Expand Down
6 changes: 6 additions & 0 deletions src/daos/Items.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ public function get($options = []) {
$options
);

if (isset($options['fromDatetime']) && strlen($options['fromDatetime']) > 0) {
$options['fromDatetime'] = new \DateTime($options['fromDatetime']);
} else {
unset($options['fromDatetime']);
}

$items = $this->backend->get($options);

// remove private posts with private tags
Expand Down
6 changes: 3 additions & 3 deletions src/daos/StatementsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ public static function rowTouch($column);
public static function bool($bool);

/**
* Convert a date string into a representation suitable for comparison by
* Convert a date into a representation suitable for comparison by
* the database engine.
*
* @param string $datestr ISO8601 datetime
* @param \DateTime $date datetime
*
* @return string representation of datetime
*/
public static function datetime($datestr);
public static function datetime(\DateTime $datestr);

/**
* Ensure row values have the appropriate PHP type. This assumes we are
Expand Down
1 change: 0 additions & 1 deletion src/daos/mysql/Items.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ public function get($options = []) {

// seek pagination (alternative to offset)
if (isset($options['fromDatetime'])
&& strlen($options['fromDatetime']) > 0
&& isset($options['fromId'])
&& is_numeric($options['fromId'])) {
// discard offset as it makes no sense to mix offset pagination
Expand Down
9 changes: 5 additions & 4 deletions src/daos/mysql/Statements.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,16 @@ public static function bool($bool) {
}

/**
* Convert a date string into a representation suitable for comparison by
* Convert a date into a representation suitable for comparison by
* the database engine.
*
* @param string $datestr ISO8601 datetime
* @param \DateTime $date datetime
*
* @return string representation of datetime
*/
public static function datetime($datestr) {
return $datestr; // mysql supports ISO8601 datetime comparisons
public static function datetime(\DateTime $date) {
// mysql supports ISO8601 datetime comparisons
return $date->format(\DateTime::ATOM);
}

/**
Expand Down
13 changes: 9 additions & 4 deletions src/daos/sqlite/Statements.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,20 @@ public static function bool($bool) {
}

/**
* Convert a date string into a representation suitable for comparison by
* Convert a date into a representation suitable for comparison by
* the database engine.
*
* @param string $datestr ISO8601 datetime
* @param \DateTime $date datetime
*
* @return string representation of datetime
*/
public static function datetime($datestr) {
$date = new \DateTime($datestr);
public static function datetime(\DateTime $date) {
// SQLite does not support timezones.
// The client previously sent the local timezone
// but now it sends UTC time so we need to adjust it here
// to avoid fromDatetime mismatch.
// TODO: Switch to UTC everywhere.
$date->setTimeZone((new \DateTime())->getTimeZone());

return $date->format('Y-m-d H:i:s');
}
Expand Down

0 comments on commit efae041

Please sign in to comment.