| Current Path : /var/www/consult-e-syn/public_html/plugins/ats/geolocation/ |
| Current File : /var/www/consult-e-syn/public_html/plugins/ats/geolocation/geolocation.php |
<?php
/**
* @package ats
* @copyright Copyright (c)2011-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
defined('_JEXEC') or die();
use Akeeba\TicketSystem\Admin\Helper\Permissions;
use Akeeba\TicketSystem\Admin\Model\Tickets;
use FOF40\IP\IPHelper as Ip;
use Joomla\CMS\Factory;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Registry\Registry;
class plgAtsGeolocation extends CMSPlugin
{
private $fieldSlug = 'geolocation';
/**
* Overridden constructor. We set up basic fields when the plugin initializes.
*
* @param object &$subject The object to observe
* @param array $config An optional associative array of configuration settings.
* Recognized key values include 'name', 'group', 'params', 'language'
* (this list is not meant to be comprehensive).
*
* @since 3.0.0
*/
public function __construct(&$subject, array $config = [])
{
parent::__construct($subject, $config);
$this->fieldSlug = trim($this->params->get('slug', 'geolocation'));
$this->fieldSlug = empty($this->fieldSlug) ? 'geolocation' : $this->fieldSlug;
}
/**
* Renders per-category custom fields
*
* @param array $cache Information about the ticket being created
*
* @return array
*
* @throws Exception
* @since 3.0.0
*
*/
public function onTicketFormRenderPerCatFields($cache)
{
// Only set up this field when filing a new ticket
if (!array_key_exists('ats_ticket_id', $cache) || !empty($cache['ats_ticket_id']))
{
return [];
}
// Setup the field
$slug = $this->fieldSlug;
$field = [
'id' => $slug,
'label' => '',
'elementHTML' => "<input type=\"hidden\" name=\"params[$slug]\" id=\"$slug\" />",
'isValid' => true,
'public' => false,
];
$maxAccuracy = (int) $this->params->get('w3c_accuracy', 7000);
$maxAccuracy = ($maxAccuracy <= 0) ? 7000 : $maxAccuracy;
$useW3C = $this->params->get('use_w3c', 1);
$js = <<< JS
var akeebatickets_{$slug}_content = {
latitude: 0,
longitude: 0,
accuracy: 0
};
akeeba.Loader.add(['akeeba.System', 'navigator.geolocation'], function() {
akeeba.System.documentReady(function(){
navigator.geolocation.getCurrentPosition(function(position) {
if (position.coords.accuracy <= $maxAccuracy)
{
akeebatickets_{$slug}_content.latitude = position.coords.latitude;
akeebatickets_{$slug}_content.longitude = position.coords.longitude;
akeebatickets_{$slug}_content.accuracy = position.coords.accuracy;
document.getElementById('$slug').value = JSON.stringify(akeebatickets_{$slug}_content);
}
});
})
});
JS;
if ($useW3C)
{
Factory::getApplication()->getDocument()->addScriptDeclaration($js);
}
return [$field];
}
/**
* Validate the custom fields' values. We use this to fetch GeoIP information is there was no data returned from the
* browser.
*
* @param array $data The values for all custom fields
* @param int $category The numeric category ID the ticket belongs to
*
* @return array
*
* @since 3.0.0
*/
public function onAtsValidate(&$data, $category)
{
if (!isset($data[$this->fieldSlug]) || empty($data[$this->fieldSlug]))
{
$data[$this->fieldSlug] = '{}';
}
$geo = @json_decode($data[$this->fieldSlug], true);
$geo = array_merge([
'latitude' => 0,
'longitude' => 0,
'accuracy' => 0,
], $geo);
if (
((abs($geo['latitude']) < 0.0000000001) && (abs($geo['longitude']) < 0.0000000001)) ||
($geo['accuracy'] < 0.0000000001)
)
{
$geo = $this->getGeoIP();
}
$data[$this->fieldSlug] = json_encode($geo);
return [
'valid' => true,
'isValid' => true,
'custom_validation' => [],
];
}
/**
* Renders custom fields
*
* @param Tickets $ticket The ticket we're rendering against
*
* @return array|null [['label' => $label, 'value' => $value], ...] or null when we can't render this field
*
* @since 3.0.0
*/
public function onAtsDisplayCustomFields(Tickets $ticket)
{
// Should I display the map at all?
$displayFor = $this->params->get('display_map_for', 'staff');
$isAdmin = Permissions::isManager($ticket->catid, $ticket->created_by);
$isOwner = $ticket->created_by == Factory::getUser()->id;
switch ($displayFor)
{
case 'staff':
default:
if (!$isAdmin)
{
return [];
}
break;
case 'user':
if (!$isAdmin && !$isOwner)
{
return [];
}
break;
}
foreach ($ticket->params as $slug => $value)
{
if ($slug != $this->fieldSlug)
{
continue;
}
$geo = @json_decode($value, true);
if (
((abs($geo['latitude']) < 0.0000000001) && (abs($geo['longitude']) < 0.0000000001)) ||
($geo['accuracy'] < 0.0000000001)
)
{
// No location recorded
return [];
}
$this->loadLanguage('plg_ats_geolocation');
$title = Text::_('PLG_ATS_GEOLOCATION_FIELD_LABEL');
$html = $this->getMapHTML($geo['latitude'], $geo['longitude']);
return [
[
'label' => $title,
'value' => $html,
],
];
break;
}
return [];
}
/**
* Get the HTML to display an embedded map.
*
* @param float $lat Latitude of pinned point on the map
* @param float $lon Longitude of pinned point on the map
*
* @return string
*
* @since 3.0.0
*/
protected function getMapHTML($lat, $lon)
{
$mapMethod = $this->params->get('display_map_with', 'osm');
$googleKey = $this->params->get('google_key', '');
$html = '';
$viewMapLbl = Text::_('PLG_ATS_GEOLOCATION_VIEWLARGER_LABEL');
switch ($mapMethod)
{
case 'google':
$html = <<< HTML
<iframe
width="425"
height="350"
frameborder="0" style="border:0"
scrolling="no" marginheight="0" marginwidth="0"
src="https://www.google.com/maps/embed/v1/place?key=$googleKey&q=$lat,$lon" allowfullscreen>
</iframe>
HTML;
break;
case 'bing':
$viewMapLbl = Text::_('PLG_ATS_GEOLOCATION_VIEWLARGER_LABEL');
$html = <<< HTML
<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://www.bing.com/maps/embed/viewer.aspx?v=3&cp=$lat~$lon&lvl=15&w=425&h=350&sty=r&typ=s&pp=~~$lat~$lon&ps=55&dir=0" style="border: 1px solid black"></iframe><br/><small><a href="https://www.bing.com/maps?v=2&cp=$lat~$lon&lvl=15&dir=0&sty=c&sp=point.{$lat}_{$lon}_Location" target="_blank">$viewMapLbl</a></small>
HTML;
break;
case 'osm':
default:
// Get a bounding box for the map
$stepLat = 0.003;
$stepLon = 0.003;
$boxLat1 = $lat - $stepLat;
$boxLat2 = $lat + $stepLon;
$boxLon1 = $lon - $stepLon;
$boxLon2 = $lon + $stepLat;
$html = <<< HTML
<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://www.openstreetmap.org/export/embed.html?bbox=$boxLon1%2C$boxLat1%2C$boxLon2%2C$boxLat2&layer=mapnik&marker=$lat%2C$lon" style="border: 1px solid black"></iframe><br/><small><a href="https://www.openstreetmap.org/?mlat=$lat&mlon=$lon#map=16/$lat/$lon" target="_blank">$viewMapLbl</a></small>
HTML;
break;
}
return $html;
}
/**
* Get location information from a GeoIP database
*
* @return array longitude, latitude, accuracy
*
* @since 3.0.0
*/
protected function getGeoIP()
{
$ip = Ip::getIp();
return $this->getFreeGeoIP($ip);
}
/**
* Get GeoIP information using the FreeGeoIP service
*
* @param string $ip The IP address to get GeoIP information for
*
* @return array longitude, latitude, accuracy
*
* @since 3.0.0
*/
private function getFreeGeoIP($ip)
{
$ret = [
'latitude' => 0,
'longitude' => 0,
'accuracy' => 0,
];
try
{
$options = new Registry();
$http = HttpFactory::getHttp($options);
$url = "https://freegeoip.net/json/" . urlencode($ip);
$response = $http->get($url);
}
catch (Exception $e)
{
return $ret;
}
if ($response->code != 200)
{
return $ret;
}
$data = @json_decode($response->body, true);
if (empty($data))
{
return $ret;
}
$ret['latitude'] = $data['latitude'];
$ret['longitude'] = $data['longitude'];
return $ret;
}
}