mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-28 00:38:46 +03:00
Fixed geolocation by switching to different API
This commit is contained in:
parent
863803b614
commit
899771cc2e
6 changed files with 78 additions and 55 deletions
|
@ -3,7 +3,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Command;
|
use Shlinkio\Shlink\CLI\Command;
|
||||||
use Shlinkio\Shlink\CLI\Factory\ApplicationFactory;
|
use Shlinkio\Shlink\CLI\Factory\ApplicationFactory;
|
||||||
use Shlinkio\Shlink\Common\Service\IpLocationResolver;
|
use Shlinkio\Shlink\Common\Service\IpApiLocationResolver;
|
||||||
use Shlinkio\Shlink\Common\Service\PreviewGenerator;
|
use Shlinkio\Shlink\Common\Service\PreviewGenerator;
|
||||||
use Shlinkio\Shlink\Core\Service;
|
use Shlinkio\Shlink\Core\Service;
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||||
|
@ -51,7 +51,7 @@ return [
|
||||||
],
|
],
|
||||||
Command\Visit\ProcessVisitsCommand::class => [
|
Command\Visit\ProcessVisitsCommand::class => [
|
||||||
Service\VisitService::class,
|
Service\VisitService::class,
|
||||||
IpLocationResolver::class,
|
IpApiLocationResolver::class,
|
||||||
'translator',
|
'translator',
|
||||||
],
|
],
|
||||||
Command\Config\GenerateCharsetCommand::class => ['translator'],
|
Command\Config\GenerateCharsetCommand::class => ['translator'],
|
||||||
|
|
|
@ -7,7 +7,7 @@ use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\Prophecy\ObjectProphecy;
|
use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\CLI\Command\Visit\ProcessVisitsCommand;
|
use Shlinkio\Shlink\CLI\Command\Visit\ProcessVisitsCommand;
|
||||||
use Shlinkio\Shlink\Common\Service\IpLocationResolver;
|
use Shlinkio\Shlink\Common\Service\IpApiLocationResolver;
|
||||||
use Shlinkio\Shlink\Core\Entity\Visit;
|
use Shlinkio\Shlink\Core\Entity\Visit;
|
||||||
use Shlinkio\Shlink\Core\Service\VisitService;
|
use Shlinkio\Shlink\Core\Service\VisitService;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
|
@ -32,7 +32,7 @@ class ProcessVisitsCommandTest extends TestCase
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$this->visitService = $this->prophesize(VisitService::class);
|
$this->visitService = $this->prophesize(VisitService::class);
|
||||||
$this->ipResolver = $this->prophesize(IpLocationResolver::class);
|
$this->ipResolver = $this->prophesize(IpApiLocationResolver::class);
|
||||||
$command = new ProcessVisitsCommand(
|
$command = new ProcessVisitsCommand(
|
||||||
$this->visitService->reveal(),
|
$this->visitService->reveal(),
|
||||||
$this->ipResolver->reveal(),
|
$this->ipResolver->reveal(),
|
||||||
|
|
|
@ -32,7 +32,7 @@ return [
|
||||||
|
|
||||||
Image\ImageBuilder::class => Image\ImageBuilderFactory::class,
|
Image\ImageBuilder::class => Image\ImageBuilderFactory::class,
|
||||||
|
|
||||||
Service\IpLocationResolver::class => ConfigAbstractFactory::class,
|
Service\IpApiLocationResolver::class => ConfigAbstractFactory::class,
|
||||||
Service\PreviewGenerator::class => ConfigAbstractFactory::class,
|
Service\PreviewGenerator::class => ConfigAbstractFactory::class,
|
||||||
],
|
],
|
||||||
'aliases' => [
|
'aliases' => [
|
||||||
|
@ -51,7 +51,7 @@ return [
|
||||||
ConfigAbstractFactory::class => [
|
ConfigAbstractFactory::class => [
|
||||||
TranslatorExtension::class => ['translator'],
|
TranslatorExtension::class => ['translator'],
|
||||||
LocaleMiddleware::class => ['translator'],
|
LocaleMiddleware::class => ['translator'],
|
||||||
Service\IpLocationResolver::class => ['httpClient'],
|
Service\IpApiLocationResolver::class => ['httpClient'],
|
||||||
Service\PreviewGenerator::class => [
|
Service\PreviewGenerator::class => [
|
||||||
ImageBuilder::class,
|
ImageBuilder::class,
|
||||||
Filesystem::class,
|
Filesystem::class,
|
||||||
|
|
51
module/Common/src/Service/IpApiLocationResolver.php
Normal file
51
module/Common/src/Service/IpApiLocationResolver.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\Common\Service;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use Shlinkio\Shlink\Common\Exception\WrongIpException;
|
||||||
|
|
||||||
|
class IpApiLocationResolver implements IpLocationResolverInterface
|
||||||
|
{
|
||||||
|
private const SERVICE_PATTERN = 'http://ip-api.com/json/%s';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Client
|
||||||
|
*/
|
||||||
|
private $httpClient;
|
||||||
|
|
||||||
|
public function __construct(Client $httpClient)
|
||||||
|
{
|
||||||
|
$this->httpClient = $httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $ipAddress
|
||||||
|
* @return array
|
||||||
|
* @throws WrongIpException
|
||||||
|
*/
|
||||||
|
public function resolveIpLocation(string $ipAddress): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $this->httpClient->get(\sprintf(self::SERVICE_PATTERN, $ipAddress));
|
||||||
|
return $this->mapFields(\json_decode((string) $response->getBody(), true));
|
||||||
|
} catch (GuzzleException $e) {
|
||||||
|
throw WrongIpException::fromIpAddress($ipAddress, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapFields(array $entry): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'country_code' => $entry['countryCode'] ?? '',
|
||||||
|
'country_name' => $entry['country'] ?? '',
|
||||||
|
'region_name' => $entry['regionName'] ?? '',
|
||||||
|
'city' => $entry['city'] ?? '',
|
||||||
|
'latitude' => $entry['lat'] ?? '',
|
||||||
|
'longitude' => $entry['lon'] ?? '',
|
||||||
|
'time_zone' => $entry['timezone'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Common\Service;
|
|
||||||
|
|
||||||
use GuzzleHttp\Client;
|
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
|
||||||
use Shlinkio\Shlink\Common\Exception\WrongIpException;
|
|
||||||
|
|
||||||
class IpLocationResolver implements IpLocationResolverInterface
|
|
||||||
{
|
|
||||||
const SERVICE_PATTERN = 'http://freegeoip.net/json/%s';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Client
|
|
||||||
*/
|
|
||||||
private $httpClient;
|
|
||||||
|
|
||||||
public function __construct(Client $httpClient)
|
|
||||||
{
|
|
||||||
$this->httpClient = $httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $ipAddress
|
|
||||||
* @return array
|
|
||||||
* @throws WrongIpException
|
|
||||||
*/
|
|
||||||
public function resolveIpLocation(string $ipAddress): array
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$response = $this->httpClient->get(sprintf(self::SERVICE_PATTERN, $ipAddress));
|
|
||||||
return json_decode((string) $response->getBody(), true);
|
|
||||||
} catch (GuzzleException $e) {
|
|
||||||
throw WrongIpException::fromIpAddress($ipAddress, $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,12 +8,12 @@ use GuzzleHttp\Exception\TransferException;
|
||||||
use GuzzleHttp\Psr7\Response;
|
use GuzzleHttp\Psr7\Response;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\Prophecy\ObjectProphecy;
|
use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\Common\Service\IpLocationResolver;
|
use Shlinkio\Shlink\Common\Service\IpApiLocationResolver;
|
||||||
|
|
||||||
class IpLocationResolverTest extends TestCase
|
class IpApiLocationResolverTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var IpLocationResolver
|
* @var IpApiLocationResolver
|
||||||
*/
|
*/
|
||||||
protected $ipResolver;
|
protected $ipResolver;
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@ class IpLocationResolverTest extends TestCase
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$this->client = $this->prophesize(Client::class);
|
$this->client = $this->prophesize(Client::class);
|
||||||
$this->ipResolver = new IpLocationResolver($this->client->reveal());
|
$this->ipResolver = new IpApiLocationResolver($this->client->reveal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,16 +32,26 @@ class IpLocationResolverTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function correctIpReturnsDecodedInfo()
|
public function correctIpReturnsDecodedInfo()
|
||||||
{
|
{
|
||||||
|
$actual = [
|
||||||
|
'countryCode' => 'bar',
|
||||||
|
'lat' => 5,
|
||||||
|
'lon' => 10,
|
||||||
|
];
|
||||||
$expected = [
|
$expected = [
|
||||||
'foo' => 'bar',
|
'country_code' => 'bar',
|
||||||
'baz' => 'foo',
|
'country_name' => '',
|
||||||
|
'region_name' => '',
|
||||||
|
'city' => '',
|
||||||
|
'latitude' => 5,
|
||||||
|
'longitude' => 10,
|
||||||
|
'time_zone' => '',
|
||||||
];
|
];
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
$response->getBody()->write(json_encode($expected));
|
$response->getBody()->write(\json_encode($actual));
|
||||||
$response->getBody()->rewind();
|
$response->getBody()->rewind();
|
||||||
|
|
||||||
$this->client->get('http://freegeoip.net/json/1.2.3.4')->willReturn($response)
|
$this->client->get('http://ip-api.com/json/1.2.3.4')->willReturn($response)
|
||||||
->shouldBeCalledTimes(1);
|
->shouldBeCalledTimes(1);
|
||||||
$this->assertEquals($expected, $this->ipResolver->resolveIpLocation('1.2.3.4'));
|
$this->assertEquals($expected, $this->ipResolver->resolveIpLocation('1.2.3.4'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +61,8 @@ class IpLocationResolverTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function guzzleExceptionThrowsShlinkException()
|
public function guzzleExceptionThrowsShlinkException()
|
||||||
{
|
{
|
||||||
$this->client->get('http://freegeoip.net/json/1.2.3.4')->willThrow(new TransferException())
|
$this->client->get('http://ip-api.com/json/1.2.3.4')->willThrow(new TransferException())
|
||||||
->shouldBeCalledTimes(1);
|
->shouldBeCalledTimes(1);
|
||||||
$this->ipResolver->resolveIpLocation('1.2.3.4');
|
$this->ipResolver->resolveIpLocation('1.2.3.4');
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue