Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
// photos
['name' => 'photos#getPhotosFromDb', 'url' => '/photos', 'verb' => 'GET'],
['name' => 'photos#getNonLocalizedPhotosFromDb', 'url' => '/photos/nonlocalized', 'verb' => 'GET'],
['name' => 'photos#getNonLocalizedPhotoIds', 'url' => '/photos/nonlocalizedids', 'verb' => 'GET'],
['name' => 'photos#getNonLocalizedPhotosByIds', 'url' => '/photos/nonlocalizedbyids', 'verb' => 'GET'],
['name' => 'photos#placePhotos', 'url' => '/photos', 'verb' => 'POST'],

// contacts
Expand Down
48 changes: 38 additions & 10 deletions js/nonLocalizedPhotosController.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function NonLocalizedPhotosController (optionsController, timeFilterController,
this.nonLocalizedPhotoMarkersLastVisible = -1;
this.timeFilterBegin = 0;
this.timeFilterEnd = Date.now();
this.nonLocalizedPhotoIds = [];
}

NonLocalizedPhotosController.prototype = {
Expand All @@ -30,6 +31,7 @@ NonLocalizedPhotosController.prototype = {
iconSize: [this.PHOTO_MARKER_VIEW_SIZE, this.PHOTO_MARKER_VIEW_SIZE]
}
});
this.callForImageIds();
this.nonLocalizedPhotoLayer.on('click', this.getNonLocalizedPhotoMarkerOnClickFunction());
this.nonLocalizedPhotoLayer.on('clusterclick', function (a) {
if (a.layer.getChildCount() > 20) {
Expand All @@ -48,7 +50,7 @@ NonLocalizedPhotosController.prototype = {
that.optionsController.saveOptionValues({nonLocalizedPhotosLayer: that.map.hasLayer(that.nonLocalizedPhotoLayer)});
that.updateTimeFilterRange();
that.timeFilterController.setSliderToMaxInterval();
});
})
// click on menu button
$('body').on('click', '.nonLocalizedPhotosMenuButton', function(e) {
var wasOpen = $(this).parent().parent().parent().find('>.app-navigation-entry-menu').hasClass('open');
Expand Down Expand Up @@ -269,30 +271,56 @@ NonLocalizedPhotosController.prototype = {
}
},

callForImages: function() {
this.nonLocalizedPhotosRequestInProgress = true;
$('#navigation-nonLocalizedPhotos').addClass('icon-loading-small');
callForImageIds: function() {
$.ajax({
url: OC.generateUrl('apps/maps/photos/nonlocalized'),
url: OC.generateUrl('apps/maps/photos/nonlocalizedids'),
type: 'GET',
async: true,
context: this
}).done(function (response) {
if (response.length == 0) {
if (response.length === 0) {
//showNoPhotosMessage();
}
else {
this.addNonLocalizedPhotosToMap(response);
this.nonLocalizedPhotoIds=response;
}
this.nonLocalizedPhotosDataLoaded = true;
}).always(function (response) {
this.nonLocalizedPhotosRequestInProgress = false;
$('#navigation-nonLocalizedPhotos').removeClass('icon-loading-small');
//do something;
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to load non-geolocalized photos'));
});
},

callForImages: function() {
this.nonLocalizedPhotosRequestInProgress = true;
$('#navigation-nonLocalizedPhotos').addClass('icon-loading-small');
var that = this;
for (var i=0; i<this.nonLocalizedPhotoIds.length/250; i++){
$.ajax({
url: OC.generateUrl('apps/maps/photos/nonlocalizedbyids'),
type: 'GET',
async: true,
context: this,
data: {ids: this.nonLocalizedPhotoIds.slice(i*250,(i+1)*250)}
}).done(function (response) {
if (response.length === 0) {
//showNoPhotosMessage();
}
else {
that.addNonLocalizedPhotosToMap(response);
}

}).always(function (response) {
//do something;
}).fail(function() {
OC.Notification.showTemporary(t('maps', 'Failed to load non-geolocalized photos'));
});
}
this.nonLocalizedPhotosDataLoaded = true;
this.nonLocalizedPhotosRequestInProgress = false;
$('#navigation-nonLocalizedPhotos').removeClass('icon-loading-small');
},

saveCordinatesToImage : function (marker) {
var latlng = marker.getLatLng();
this.photosController.placePhotos([marker.data.path], [latlng.lat], [latlng.lng]);
Expand Down
11 changes: 11 additions & 0 deletions js/photosController.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ PhotosController.prototype = {
$(this).parent().parent().parent().find('>.app-navigation-entry-menu').addClass('open');
}
});
// expand navigation
$('body').on('click', '#navigation-photos', function(e) {
if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-photos') {
that.toggleNavigation();
that.optionsController.saveOptionValues({photosNavigationShow: $('#navigation-favorites').hasClass('open')});
}
});
},

updateMyFirstLastDates: function() {
Expand Down Expand Up @@ -86,6 +93,10 @@ PhotosController.prototype = {
}
},

toggleNavigation: function() {
$('#navigation-photos').toggleClass('open');
},

getPhotoMarkerOnClickFunction: function() {
var _app = this;
return function(evt) {
Expand Down
17 changes: 17 additions & 0 deletions lib/Controller/PhotosController.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ public function getNonLocalizedPhotosFromDb() {
return new DataResponse($result);
}

/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function getNonLocalizedPhotoIds() {
$result = $this->geophotoService->getNonLocalizedIdsFromDB($this->userId);
return new DataResponse($result);
}

/**
* @param $ids
* @NoAdminRequired
* @NoCSRFRequired
*/
public function getNonLocalizedPhotosByIds($ids) {
return new DataResponse($this->geophotoService->getNonLocalizedByIds($this->userId, $ids));
}

/**
* @NoAdminRequired
Expand Down
12 changes: 12 additions & 0 deletions lib/DB/GeophotoMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ public function find($id) {
return $this->findEntity($sql, [$id]);
}

public function findByUserAndId($userId, $id) {
try {
$sql = 'SELECT * FROM `*PREFIX*maps_photos` ' .
'WHERE `user_id` = ? ' .
'AND `id` = ? ';
return $this->findEntity($sql, [$userId, $id]);
}
catch (\Throwable $e) {
return null;
}
}

public function findByFileId($userId, $fileId) {
try {
$sql = 'SELECT * FROM `*PREFIX*maps_photos` ' .
Expand Down
121 changes: 113 additions & 8 deletions lib/Service/GeophotoService.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
use OCP\Files\Folder;
use OCP\IPreview;
use OCP\ILogger;
use OCP\ICache;


use OCA\Maps\Service\PhotofilesService;
use OCA\Maps\DB\Geophoto;
use OCA\Maps\DB\GeophotoMapper;
use OCA\Maps\Service\TracksService;
use OCA\Maps\Service\DevicesService;

class GeophotoService {

Expand All @@ -34,18 +36,21 @@ class GeophotoService {
private $logger;
private $preview;
private $tracksService;
private $timeordedPointSets;
private $timeorderedPointSets;
private $devicesService;
private $cache;

public function __construct (ILogger $logger, IRootFolder $root, IL10N $l10n, GeophotoMapper $photoMapper, IPreview $preview, TracksService $tracksService, $userId) {
public function __construct (ILogger $logger, IRootFolder $root, IL10N $l10n, GeophotoMapper $photoMapper, IPreview $preview, TracksService $tracksService, DevicesService $devicesService, ICache $cache, $userId) {
$this->root = $root;
$this->l10n = $l10n;
$this->photoMapper = $photoMapper;
$this->logger = $logger;
$this->preview = $preview;
$this->tracksService = $tracksService;
$this->timeordedPointSets = null;
$this->timeorderedPointSets = null;
$this->userId = $userId;

$this->devicesService = $devicesService;
$this->cache = $cache;
}

/**
Expand Down Expand Up @@ -91,7 +96,7 @@ public function getAllFromDB ($userId) {
* @return array with geodatas of all nonLocalizedPhotos
*/
public function getNonLocalizedFromDB ($userId) {
$foo = $this->loadTimeordedPointSets($userId);
$foo = $this->loadTimeOrderedPointSets($userId);
$photoEntities = $this->photoMapper->findAllNonLocalized($userId);
$userFolder = $this->getFolderForUser($userId);
$filesById = [];
Expand Down Expand Up @@ -128,14 +133,88 @@ public function getNonLocalizedFromDB ($userId) {
return $filesById;
}

/**
* @param string $userId
* @return array with all id's of nonLocalizedPhotos
*/
public function getNonLocalizedIdsFromDB ($userId) {
$foo = $this->loadTimeOrderedPointSets($userId);
$photoEntities = $this->photoMapper->findAllNonLocalized($userId);
$fileIds = [];
$photoEntitiesById = [];
foreach ($photoEntities as $photoEntity) {
$fileIds[] = $photoEntity->getId();
$photoEntitiesById[$photoEntity->getId()] = [
"dateTaken"=>$photoEntity->getDateTaken(),
"fileId"=>$photoEntity->getFileId(),
];
}
$this->cache->set('mapsPhotoInformationById', json_encode($photoEntitiesById), $ttl=300);
$this->cache->set('mapsPhotoInformationByIdTime', time(), $ttl=300);
return $fileIds;
}
/**
*
*/
public function getNonLocalizedByIds($userId, $ids) {
$foo = $this->loadTimeOrderedPointSets($userId);
$photoInformationById = json_decode($this->cache->get('mapsPhotoInformationById'),TRUE);
if (!is_array($photoInformationById) or time()-$this->cache->get('mapsPhotoInformationByIdTime')>300) {
$foo = $this->getNonLocalizedIdsFromDB($userId);
}
$filesById = [];
foreach ($ids as $id) {
if (array_key_exists($id, $photoInformationById)) {
$photoInformation = $photoInformationById[$id];
} else {
$photoEntity = $this->photoMapper->findByUserAndId($userId, $id);
$photoInformation = [
"dateTaken"=>$photoEntity->getDateTaken(),
"fileId"=>$photoEntity->getFileId(),
];
}
if (!is_null($photoInformation)) {
$userFolder = $this->getFolderForUser($userId);

$cache = $userFolder->getStorage()->getCache();
$previewEnableMimetypes = $this->getPreviewEnabledMimetypes();

$cacheEntry = $cache->get($photoInformation["fileId"]);
if ($cacheEntry) {
// this path is relative to owner's storage
//$path = $cacheEntry->getPath();
// but we want it relative to current user's storage
$file = $userFolder->getById($photoInformation["fileId"])[0];
if (!is_null($file)) {
$path = preg_replace('/^\/'.$userId.'\//', '', $file->getPath());

$date = $photoInformation["dateTaken"] ?? \time();
$locations = $this->getLocationGuesses($date);
foreach ($locations as $location) {
$file_object = new \stdClass();
$file_object->fileId = $photoInformation["fileId"];
$file_object->path = $this->normalizePath($path);
$file_object->hasPreview = in_array($cacheEntry->getMimeType(), $previewEnableMimetypes);
$file_object->lat = $location[0];
$file_object->lng = $location[1];
$file_object->dateTaken = $date;
$filesById[] = $file_object;
};
}
}
}
}

return $filesById;
}
/**
* returns a array of locations for a given date
* @param $dateTaken
* @return array
*/
private function getLocationGuesses($dateTaken) {
$locations = [];
foreach ($this->timeordedPointSets as $timeordedPointSet) {
foreach ($this->timeorderedPointSets as $timeordedPointSet) {
$location = $this->getLocationFromSequenceOfPoints($dateTaken,$timeordedPointSet);
if (!is_null($location)) {
$locations[] = $location;
Expand All @@ -152,19 +231,37 @@ private function getLocationGuesses($dateTaken) {
* Timeorderd Point sets is an Array of Arrays with time => location as key=>value pair, which are orderd by the key.
* This function loads this Arrays from all Track files of the user.
*/
private function loadTimeordedPointSets($userId) {
private function loadTimeOrderedPointSets($userId) {
$this->timeorderedPointSets = json_decode($this->cache->get('mapsTimeOrderedPointSets'),TRUE);
if (is_array($this->timeorderedPointSets) and time()-$this->cache->get('mapsTimeOrderedPointSetsTime')<300) {
$this->logger->debug("timeorderedPointSets loaded from cache");
return null;
}
$this->timeorderedPointSets = [];
$userFolder = $this->getFolderForUser($userId);
foreach ($this->tracksService->getTracksFromDB($userId) as $gpxfile) {
$res = $userFolder->getById($gpxfile['file_id']);
if (is_array($res) and count($res) > 0) {
$file = $res[0];
if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
foreach ($this->getTracksFromGPX($file->getContent()) as $track) {
$this->timeordedPointSets[] = $this->getTimeorderdPointsFromTrack($track);
$this->timeorderedPointSets[] = $this->getTimeorderdPointsFromTrack($track);
}
}
}
}
foreach ($this->devicesService->getDevicesFromDB($userId) as $device) {
$device_points = $this->devicesService->getDevicePointsFromDB($userId, $device);
$points = [];
foreach ($device_points as $pt) {
$points[$pt->timestamp] = [(string) $pt->lat, (string) $pt->lng];
}
$foo = ksort($points);
$this->timeorderedPointSets[] = $points;
}
$this->logger->debug("timeorderedPointSets created");
$this->cache->set('mapsTimeOrderedPointSets', json_encode($this->timeorderedPointSets), $ttl=300);
$this->cache->set('mapsTimeOrderedPointSetsTime', time(), $ttl=300);
return null;
}

Expand All @@ -179,6 +276,7 @@ private function getTracksFromGPX($content) {
foreach ($gpx->trk as $trk) {
$tracks[] = $trk;
}

return $tracks;
}

Expand Down Expand Up @@ -207,6 +305,13 @@ private function getTimeorderdPointsFromTrack($track) {
* @param $points array sorted by keys timestamp => [lat, lng]
*/
private function getLocationFromSequenceOfPoints($dateTaken, $points) {
$foo = end($points);
$end = key($points);
$foo = reset($points);
$start = key($points);
if ($start > $dateTaken OR $end < $dateTaken) {
return null;
}
$smaller = null;
$bigger = null;
foreach ($points as $time => $locations) {
Expand Down
4 changes: 2 additions & 2 deletions templates/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
</ul>
</div>
</li>
<li id="navigation-photos">
<li id="navigation-photos" class="collapsible">
<a class="icon-picture" href="#"><?php p($l->t('Photos')); ?></a>
<div class="app-navigation-entry-utils">
<ul>
Expand All @@ -92,7 +92,7 @@
</div>
<ul>
<li id="navigation-nonLocalizedPhotos">
<a class="icon-picture" href="#"><?php p($l->t('non localized')); ?></a>
<a class="icon-picture" href="#"><?php p($l->t('without geo tag')); ?></a>
<div class="app-navigation-entry-utils">
<ul>
<li class="app-navigation-entry-utils-counter">
Expand Down