Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Aug 2, 2018
2 parents 975260f + 0ae44d3 commit d54b823
Show file tree
Hide file tree
Showing 24 changed files with 252 additions and 106 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# CHANGELOG

## 1.10.1 - 2018-08-02

#### Added

* *Nothing*

#### Changed

* [#167](https://github.com/shlinkio/shlink/issues/167) Shlink version is now set at build time to avoid older version numbers to be kept in newer builds.

#### Deprecated

* *Nothing*

#### Removed

* *Nothing*

#### Fixed

* [#165](https://github.com/shlinkio/shlink/issues/165) Fixed custom slugs failing when they are longer than 10 characters.
* [#166](https://github.com/shlinkio/shlink/issues/166) Fixed unusual edge case in which visits were not properly counted when ordering by visit and filtering by search term in `[GET] /short-codes` API endpoint.
* [#174](https://github.com/shlinkio/shlink/issues/174) Fixed geolocation not working due to a deprecation on used service.
* [#172](https://github.com/shlinkio/shlink/issues/172) Documented missing filtering params for `[GET] /short-codes/{shortCode}/visits` API endpoint, which allow the list to be filtered by date range.

For example: `https://doma.in/rest/v1/short-urls/abc123/visits?startDate=2017-05-23&endDate=2017-10-05`

* [#169](https://github.com/shlinkio/shlink/issues/169) Fixed unhandled error when parsing `ShortUrlMeta` and date fields are already `DateTime` instances.


## 1.10.0 - 2018-07-09

#### Added
Expand Down
3 changes: 3 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ rm -rf data/{cache,log,proxies}/{*,.gitignore}
rm -rf config/params/{*,.gitignore}
rm -rf config/autoload/{{,*.}local.php{,.dist},.gitignore}

# Update shlink version in config
sed -i "s/%SHLINK_VERSION%/${version}/g" config/autoload/app_options.global.php

# Compressing file
rm -f "${projectdir}"/build/shlink_${version}_dist.zip
zip -ry "${projectdir}"/build/shlink_${version}_dist.zip "../shlink_${version}_dist"
Expand Down
2 changes: 1 addition & 1 deletion config/autoload/app_options.global.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

'app_options' => [
'name' => 'Shlink',
'version' => '1.7.0',
'version' => '%SHLINK_VERSION%',
'secret_key' => env('SECRET_KEY'),
],

Expand Down
45 changes: 45 additions & 0 deletions data/migrations/Version20180801183328.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);

namespace ShlinkMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20180801183328 extends AbstractMigration
{
private const NEW_SIZE = 255;
private const OLD_SIZE = 10;

/**
* @param Schema $schema
* @throws SchemaException
*/
public function up(Schema $schema): void
{
$this->setSize($schema, self::NEW_SIZE);
}

/**
* @param Schema $schema
* @throws SchemaException
*/
public function down(Schema $schema): void
{
$this->setSize($schema, self::OLD_SIZE);
}

/**
* @param Schema $schema
* @param int $size
* @throws SchemaException
*/
private function setSize(Schema $schema, int $size): void
{
$schema->getTable('short_urls')->getColumn('short_code')->setLength($size);
}
}
18 changes: 18 additions & 0 deletions docs/swagger/paths/v1_short-codes_{shortCode}_visits.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@
"schema": {
"type": "string"
}
},
{
"name": "startDate",
"in": "query",
"description": "The date (in ISO-8601 format) from which we want to get visits.",
"required": false,
"schema": {
"type": "string"
}
},
{
"name": "endDate",
"in": "query",
"description": "The date (in ISO-8601 format) until which we want to get visits.",
"required": false,
"schema": {
"type": "string"
}
}
],
"security": [
Expand Down
4 changes: 2 additions & 2 deletions module/CLI/config/dependencies.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use Shlinkio\Shlink\CLI\Command;
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\Core\Service;
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
Expand Down Expand Up @@ -51,7 +51,7 @@
],
Command\Visit\ProcessVisitsCommand::class => [
Service\VisitService::class,
IpLocationResolver::class,
IpApiLocationResolver::class,
'translator',
],
Command\Config\GenerateCharsetCommand::class => ['translator'],
Expand Down
17 changes: 11 additions & 6 deletions module/CLI/src/Command/Visit/ProcessVisitsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

class ProcessVisitsCommand extends Command
{
const LOCALHOST = '127.0.0.1';
const NAME = 'visit:process';
private const LOCALHOST = '127.0.0.1';
public const NAME = 'visit:process';

/**
* @var VisitServiceInterface
Expand Down Expand Up @@ -57,10 +57,10 @@ public function execute(InputInterface $input, OutputInterface $output)

foreach ($visits as $visit) {
$ipAddr = $visit->getRemoteAddr();
$io->write(sprintf('%s <info>%s</info>', $this->translator->translate('Processing IP'), $ipAddr));
$io->write(\sprintf('%s <info>%s</info>', $this->translator->translate('Processing IP'), $ipAddr));
if ($ipAddr === self::LOCALHOST) {
$io->writeln(
sprintf(' (<comment>%s</comment>)', $this->translator->translate('Ignored localhost address'))
\sprintf(' (<comment>%s</comment>)', $this->translator->translate('Ignored localhost address'))
);
continue;
}
Expand All @@ -73,12 +73,17 @@ public function execute(InputInterface $input, OutputInterface $output)
$visit->setVisitLocation($location);
$this->visitService->saveVisit($visit);

$io->writeln(sprintf(
$io->writeln(\sprintf(
' (' . $this->translator->translate('Address located at "%s"') . ')',
$location->getCityName()
));
} catch (WrongIpException $e) {
continue;
$io->writeln(
\sprintf(' <error>%s</error>', $this->translator->translate('An error occurred while locating IP'))
);
if ($io->isVerbose()) {
$this->getApplication()->renderException($e, $output);
}
}
}

Expand Down
9 changes: 6 additions & 3 deletions module/CLI/test/Command/Api/GenerateKeyCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\CLI\Command\Api\GenerateKeyCommand;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
Expand Down Expand Up @@ -37,7 +38,8 @@ public function setUp()
*/
public function noExpirationDateIsDefinedIfNotProvided()
{
$this->apiKeyService->create(null)->shouldBeCalledTimes(1);
$this->apiKeyService->create(null)->shouldBeCalledTimes(1)
->willReturn(new ApiKey());
$this->commandTester->execute([
'command' => 'api-key:generate',
]);
Expand All @@ -46,9 +48,10 @@ public function noExpirationDateIsDefinedIfNotProvided()
/**
* @test
*/
public function expirationDateIsDefinedIfWhenProvided()
public function expirationDateIsDefinedIfProvided()
{
$this->apiKeyService->create(Argument::type(\DateTime::class))->shouldBeCalledTimes(1);
$this->apiKeyService->create(Argument::type(\DateTime::class))->shouldBeCalledTimes(1)
->willReturn(new ApiKey());
$this->commandTester->execute([
'command' => 'api-key:generate',
'--expirationDate' => '2016-01-01',
Expand Down
3 changes: 2 additions & 1 deletion module/CLI/test/Command/Tag/CreateTagCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace ShlinkioTest\Shlink\CLI\Command\Tag;

use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function serviceIsInvokedOnSuccess()
{
$tagNames = ['foo', 'bar'];
/** @var MethodProphecy $createTags */
$createTags = $this->tagService->createTags($tagNames)->willReturn([]);
$createTags = $this->tagService->createTags($tagNames)->willReturn(new ArrayCollection());

$this->commandTester->execute([
'--name' => $tagNames,
Expand Down
4 changes: 2 additions & 2 deletions module/CLI/test/Command/Visit/ProcessVisitsCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
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\Service\VisitService;
use Symfony\Component\Console\Application;
Expand All @@ -32,7 +32,7 @@ class ProcessVisitsCommandTest extends TestCase
public function setUp()
{
$this->visitService = $this->prophesize(VisitService::class);
$this->ipResolver = $this->prophesize(IpLocationResolver::class);
$this->ipResolver = $this->prophesize(IpApiLocationResolver::class);
$command = new ProcessVisitsCommand(
$this->visitService->reveal(),
$this->ipResolver->reveal(),
Expand Down
4 changes: 2 additions & 2 deletions module/Common/config/dependencies.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

Image\ImageBuilder::class => Image\ImageBuilderFactory::class,

Service\IpLocationResolver::class => ConfigAbstractFactory::class,
Service\IpApiLocationResolver::class => ConfigAbstractFactory::class,
Service\PreviewGenerator::class => ConfigAbstractFactory::class,
],
'aliases' => [
Expand All @@ -51,7 +51,7 @@
ConfigAbstractFactory::class => [
TranslatorExtension::class => ['translator'],
LocaleMiddleware::class => ['translator'],
Service\IpLocationResolver::class => ['httpClient'],
Service\IpApiLocationResolver::class => ['httpClient'],
Service\PreviewGenerator::class => [
ImageBuilder::class,
Filesystem::class,
Expand Down
15 changes: 7 additions & 8 deletions module/Common/src/Factory/EntityManagerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,22 @@ class EntityManagerFactory implements FactoryInterface
* @param null|array $options
* @return object
* @throws ServiceNotFoundException if unable to resolve the service.
* @throws ServiceNotCreatedException if an exception is raised when
* creating a service.
* @throws ServiceNotCreatedException if an exception is raised when creating a service.
* @throws ContainerException if any other error occurs
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$globalConfig = $container->get('config');
$isDevMode = isset($globalConfig['debug']) ? ((bool) $globalConfig['debug']) : false;
$cache = $container->has(Cache::class) ? $container->get(Cache::class) : new ArrayCache();
$emConfig = isset($globalConfig['entity_manager']) ? $globalConfig['entity_manager'] : [];
$connecitonConfig = isset($emConfig['connection']) ? $emConfig['connection'] : [];
$ormConfig = isset($emConfig['orm']) ? $emConfig['orm'] : [];
$emConfig = $globalConfig['entity_manager'] ?? [];
$connectionConfig = $emConfig['connection'] ?? [];
$ormConfig = $emConfig['orm'] ?? [];

return EntityManager::create($connecitonConfig, Setup::createAnnotationMetadataConfiguration(
isset($ormConfig['entities_paths']) ? $ormConfig['entities_paths'] : [],
return EntityManager::create($connectionConfig, Setup::createAnnotationMetadataConfiguration(
$ormConfig['entities_paths'] ?? [],
$isDevMode,
isset($ormConfig['proxies_dir']) ? $ormConfig['proxies_dir'] : null,
$ormConfig['proxies_dir'] ?? null,
$cache,
false
));
Expand Down
51 changes: 51 additions & 0 deletions module/Common/src/Service/IpApiLocationResolver.php
Original file line number Diff line number Diff line change
@@ -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'] ?? '',
];
}
}
38 changes: 0 additions & 38 deletions module/Common/src/Service/IpLocationResolver.php

This file was deleted.

Loading

0 comments on commit d54b823

Please sign in to comment.