mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-02 21:23:14 +08:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3479bbbb36 | ||
|
|
e1a1a0652f | ||
|
|
3e9b775114 | ||
|
|
57c91aca3c | ||
|
|
05a64b8d9e | ||
|
|
30780f9c5f | ||
|
|
3455df9214 | ||
|
|
27aa8f9875 | ||
|
|
05451e3d1a | ||
|
|
b9b3295b52 | ||
|
|
f62ed66e26 | ||
|
|
e2a9a989ab | ||
|
|
4af27650cd | ||
|
|
76a603104d | ||
|
|
115ca0da0f | ||
|
|
673b545a83 | ||
|
|
d030fd1aa6 | ||
|
|
7c1e40be88 | ||
|
|
b739619532 | ||
|
|
372b83d92f | ||
|
|
4e3b5419d5 | ||
|
|
c34d5a35e2 | ||
|
|
a959b5bf02 | ||
|
|
45ac2c3c51 | ||
|
|
f6bddc6f24 | ||
|
|
6b8fc3228e | ||
|
|
8cf1a95df5 | ||
|
|
b3ea2969c5 | ||
|
|
054bbb8d5a | ||
|
|
19c1b29f59 | ||
|
|
264b8c2a9e | ||
|
|
ec33b95f97 | ||
|
|
4437d5305f | ||
|
|
f20f01e22e | ||
|
|
1ee30fe5dc | ||
|
|
4dc026d7fc | ||
|
|
1e862a8ee8 | ||
|
|
5ece2d1939 | ||
|
|
146e9100be | ||
|
|
0c854edc6b | ||
|
|
07d031e7b9 | ||
|
|
705dc2ec39 | ||
|
|
3b9221c7d2 | ||
|
|
576d602ed0 | ||
|
|
9df8bd63d4 | ||
|
|
99c4802367 | ||
|
|
94dc6f2053 | ||
|
|
d4005da35c | ||
|
|
cbe2c362d5 | ||
|
|
8bf79db66a | ||
|
|
b87964f716 | ||
|
|
b0a574f578 | ||
|
|
92dc3019de | ||
|
|
d8f92cb2be | ||
|
|
bf24660ddb | ||
|
|
b66268867a | ||
|
|
9abaa243e0 | ||
|
|
7030138ff4 | ||
|
|
906dfe60f8 | ||
|
|
01f60614ef | ||
|
|
eeb5306883 | ||
|
|
24c3a3e84c | ||
|
|
8b9663aea0 | ||
|
|
b59f4e2805 | ||
|
|
6293d57fde | ||
|
|
39ac2efe26 | ||
|
|
1f449e8ce1 | ||
|
|
ad906000c7 | ||
|
|
5361f33cc1 | ||
|
|
1937f3ea22 | ||
|
|
f4e9d0c8fe | ||
|
|
9b767ee9f3 | ||
|
|
43cb91bf52 | ||
|
|
f784ee5b28 | ||
|
|
cd6f067fe5 | ||
|
|
6d366188c9 | ||
|
|
c4ca59dcb0 | ||
|
|
74675ad314 | ||
|
|
b5e4da847a | ||
|
|
232bf5a68b | ||
|
|
67958a78d3 | ||
|
|
b8cdc29d8f | ||
|
|
30e4ddb950 | ||
|
|
a61a7db275 | ||
|
|
0f5e4e7fa2 | ||
|
|
eb17eae781 | ||
|
|
740a65f880 | ||
|
|
5bd7b53e0a | ||
|
|
9538f474de | ||
|
|
8f2e78c946 | ||
|
|
2f09ff456c | ||
|
|
c8d950e04d | ||
|
|
0f6a0da7a4 | ||
|
|
4300fb225f | ||
|
|
159021e87c | ||
|
|
9dc6ea9eeb | ||
|
|
42e84e526e | ||
|
|
700ee40109 | ||
|
|
4909bd9550 | ||
|
|
e0d20bf8ff |
@@ -3,7 +3,6 @@ APP_ENV=
|
||||
SECRET_KEY=
|
||||
SHORTENED_URL_SCHEMA=
|
||||
SHORTENED_URL_HOSTNAME=
|
||||
SHORTCODE_CHARS=
|
||||
|
||||
# Database
|
||||
DB_USER=
|
||||
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +1,2 @@
|
||||
github: ['acelaya']
|
||||
custom: ['https://acel.me/donate']
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/Bug.md
vendored
2
.github/ISSUE_TEMPLATE/Bug.md
vendored
@@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information
|
||||
* Shlink Version: x.y.z
|
||||
* PHP Version: x.y.z
|
||||
* How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image
|
||||
* Database engine used: MySQL|PostgreSQL|SQLite (x.y.z)
|
||||
* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z)
|
||||
|
||||
#### Summary
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/Question_Support.md
vendored
2
.github/ISSUE_TEMPLATE/Question_Support.md
vendored
@@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information
|
||||
* Shlink Version: x.y.z
|
||||
* PHP Version: x.y.z
|
||||
* How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image
|
||||
* Database engine used: MySQL|PostgreSQL|SQLite (x.y.z)
|
||||
* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z)
|
||||
|
||||
#### Summary
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ services:
|
||||
- postgresql
|
||||
- docker
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
before_install:
|
||||
- echo 'extension = apcu.so' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- yes | pecl install swoole
|
||||
@@ -25,7 +29,7 @@ before_install:
|
||||
|
||||
install:
|
||||
- composer self-update
|
||||
- composer install --no-interaction
|
||||
- composer install --no-interaction --prefer-dist
|
||||
|
||||
before_script:
|
||||
- mysql -e 'CREATE DATABASE shlink_test;'
|
||||
|
||||
91
CHANGELOG.md
91
CHANGELOG.md
@@ -4,6 +4,97 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
## 1.20.2 - 2019-12-06
|
||||
|
||||
#### Added
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Changed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Deprecated
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Removed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Fixed
|
||||
|
||||
* [#561](https://github.com/shlinkio/shlink/issues/561) Fixed `db:migrate` command failing because yaml extension is not installed, which makes config file not to be readable.
|
||||
* [#562](https://github.com/shlinkio/shlink/issues/562) Fixed internal server error being returned when renaming a tag to another tag's name. Now a meaningful API error with status 409 is returned.
|
||||
* [#555](https://github.com/shlinkio/shlink/issues/555) Fixed internal server error being returned when invalid dates are provided for new short URLs. Now a 400 is returned, as intended.
|
||||
|
||||
|
||||
## 1.20.1 - 2019-11-17
|
||||
|
||||
#### Added
|
||||
|
||||
* [#519](https://github.com/shlinkio/shlink/issues/519) Documented how to customize web workers and task workers for the docker image.
|
||||
|
||||
#### Changed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Deprecated
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Removed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Fixed
|
||||
|
||||
* [#512](https://github.com/shlinkio/shlink/issues/512) Fixed query params not being properly forwarded from short URL to long one.
|
||||
* [#540](https://github.com/shlinkio/shlink/issues/540) Fixed errors thrown when creating short URLs if the original URL has an internationalized domain name and URL validation is enabled.
|
||||
* [#528](https://github.com/shlinkio/shlink/issues/528) Ensured `db:create` and `db:migrate` commands do not silently fail when run as part of `install` or `update`.
|
||||
* [#518](https://github.com/shlinkio/shlink/issues/518) Fixed service which updates Geolite db file to use a local lock instead of a shared one, since every shlink instance holds its own db instance.
|
||||
|
||||
|
||||
## 1.20.0 - 2019-11-02
|
||||
|
||||
#### Added
|
||||
|
||||
* [#491](https://github.com/shlinkio/shlink/issues/491) Added improved short code generation logic.
|
||||
|
||||
Now, short codes are truly random, which removes the guessability factor existing in previous versions.
|
||||
|
||||
Generated short codes have 5 characters, and shlink makes sure they keep unique, while making it backwards-compatible.
|
||||
|
||||
* [#418](https://github.com/shlinkio/shlink/issues/418) and [#419](https://github.com/shlinkio/shlink/issues/419) Added support to redirect any 404 error to a custom URL.
|
||||
|
||||
It was already possible to configure this but only for invalid short URLs. Shlink now also support configuring redirects for the base URL and any other kind of "not found" error.
|
||||
|
||||
The three URLs can be different, and it is already possible to pass them to the docker image via configuration or env vars.
|
||||
|
||||
The installer also asks for these two new configuration options.
|
||||
|
||||
* [#497](https://github.com/shlinkio/shlink/issues/497) Officially added support for MariaDB.
|
||||
|
||||
#### Changed
|
||||
|
||||
* [#458](https://github.com/shlinkio/shlink/issues/458) Updated coding styles to use [shlinkio/php-coding-standard](https://github.com/shlinkio/php-coding-standard) v2.0.0.
|
||||
|
||||
#### Deprecated
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Removed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Fixed
|
||||
|
||||
* [#507](https://github.com/shlinkio/shlink/issues/507) Fixed error with too long original URLs by increasing size to the maximum value (2048) based on [the standard](https://stackoverflow.com/a/417184).
|
||||
* [#502](https://github.com/shlinkio/shlink/issues/502) Fixed error when providing the port as part of the domain on short URLs.
|
||||
* [#509](https://github.com/shlinkio/shlink/issues/509) Fixed error when trying to generate a QR code for a short URL which uses a custom domain.
|
||||
* [#522](https://github.com/shlinkio/shlink/issues/522) Highly mitigated errors thrown when lots of short URLs are created concurrently including new and existing tags.
|
||||
|
||||
|
||||
## 1.19.0 - 2019-10-05
|
||||
|
||||
#### Added
|
||||
|
||||
10
Dockerfile
10
Dockerfile
@@ -1,10 +1,10 @@
|
||||
FROM php:7.3.8-cli-alpine3.10
|
||||
FROM php:7.3.11-alpine3.10
|
||||
LABEL maintainer="Alejandro Celaya <alejandro@alejandrocelaya.com>"
|
||||
|
||||
ARG SHLINK_VERSION=1.18.1
|
||||
ARG SHLINK_VERSION=1.20.0
|
||||
ENV SHLINK_VERSION ${SHLINK_VERSION}
|
||||
ENV SWOOLE_VERSION 4.3.3
|
||||
ENV COMPOSER_VERSION 1.9.0
|
||||
ENV SWOOLE_VERSION 4.4.12
|
||||
ENV COMPOSER_VERSION 1.9.1
|
||||
|
||||
WORKDIR /etc/shlink
|
||||
|
||||
@@ -17,7 +17,7 @@ RUN \
|
||||
# Install postgres
|
||||
apk add --no-cache postgresql-dev && \
|
||||
docker-php-ext-install -j"$(nproc)" pdo_pgsql && \
|
||||
# [Deprecated] Install intl
|
||||
# Install intl
|
||||
apk add --no-cache icu-dev && \
|
||||
docker-php-ext-install -j"$(nproc)" intl && \
|
||||
# Install zip and gd
|
||||
|
||||
@@ -22,7 +22,7 @@ A PHP-based self-hosted URL shortener that can be used to serve shortened URLs u
|
||||
First make sure the host where you are going to run shlink fulfills these requirements:
|
||||
|
||||
* PHP 7.2 or greater with JSON, APCu, intl, curl, PDO and gd extensions enabled.
|
||||
* MySQL, PostgreSQL or SQLite.
|
||||
* MySQL, MariaDB, PostgreSQL or SQLite.
|
||||
* The web server of your choice with PHP integration (Apache or Nginx recommended).
|
||||
|
||||
Then, you will need a built version of the project. There are a few ways to get it.
|
||||
@@ -49,7 +49,7 @@ Then, you will need a built version of the project. There are a few ways to get
|
||||
|
||||
Despite how you built the project, you are going to need to install it now, by following these steps:
|
||||
|
||||
* If you are going to use MySQL or PostgreSQL, create an empty database with the name of your choice.
|
||||
* If you are going to use MySQL, MariaDB or PostgreSQL, create an empty database with the name of your choice.
|
||||
* Recursively grant write permissions to the `data` directory. Shlink uses it to cache some information.
|
||||
* Setup the application by running the `bin/install` script. It is a command line tool that will guide you through the installation process. **Take into account that this tool has to be run directly on the server where you plan to host Shlink. Do not run it before uploading/moving it there.**
|
||||
* Expose shlink to the web, either by using a traditional web server + fast CGI approach, or by using a [swoole](https://www.swoole.co.uk/) non-blocking server.
|
||||
@@ -103,8 +103,6 @@ Despite how you built the project, you are going to need to install it now, by f
|
||||
|
||||
* **Using swoole:**
|
||||
|
||||
**Important!** Swoole support is still experimental. Use it with care, and report any found issue.
|
||||
|
||||
First you need to install the swoole PHP extension with [pecl](https://pecl.php.net/package/swoole), `pecl install swoole`.
|
||||
|
||||
Once installed, it's actually pretty easy to get shlink up and running with swoole. Just run `./vendor/bin/zend-expressive-swoole start -d` and you will get shlink running on port 8080.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
|
||||
export APP_ENV=test
|
||||
export DB_DRIVER=mysql
|
||||
|
||||
# Try to stop server just in case it hanged in last execution
|
||||
vendor/bin/zend-expressive-swoole stop
|
||||
@@ -11,4 +10,9 @@ vendor/bin/zend-expressive-swoole start -d
|
||||
sleep 2
|
||||
|
||||
vendor/bin/phpunit --order-by=random -c phpunit-api.xml --testdox --colors=always
|
||||
testsExitCode=$?
|
||||
|
||||
vendor/bin/zend-expressive-swoole stop
|
||||
|
||||
# Exit this script with the same code as the tests. If tests failed, this script has to fail
|
||||
exit $testsExitCode
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"doctrine/dbal": "^2.9",
|
||||
"doctrine/migrations": "^2.0",
|
||||
"doctrine/orm": "^2.5",
|
||||
"endroid/qr-code": "^1.7",
|
||||
"endroid/qr-code": "^3.6",
|
||||
"firebase/php-jwt": "^4.0",
|
||||
"geoip2/geoip2": "^2.9",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
@@ -33,10 +33,11 @@
|
||||
"ocramius/proxy-manager": "~2.2.2",
|
||||
"phly/phly-event-dispatcher": "^1.0",
|
||||
"predis/predis": "^1.1",
|
||||
"shlinkio/shlink-common": "^2.0",
|
||||
"pugx/shortid-php": "^0.5",
|
||||
"shlinkio/shlink-common": "^2.2.1",
|
||||
"shlinkio/shlink-event-dispatcher": "^1.0",
|
||||
"shlinkio/shlink-installer": "^2.0",
|
||||
"shlinkio/shlink-ip-geolocation": "^1.0",
|
||||
"shlinkio/shlink-installer": "^3.1",
|
||||
"shlinkio/shlink-ip-geolocation": "^1.1",
|
||||
"symfony/console": "^4.3",
|
||||
"symfony/filesystem": "^4.3",
|
||||
"symfony/lock": "^4.3",
|
||||
@@ -59,12 +60,12 @@
|
||||
"devster/ubench": "^2.0",
|
||||
"eaglewu/swoole-ide-helper": "dev-master",
|
||||
"filp/whoops": "^2.4",
|
||||
"infection/infection": "^0.13.4",
|
||||
"phpstan/phpstan": "^0.11.2",
|
||||
"infection/infection": "^0.14.2",
|
||||
"phpstan/phpstan": "^0.11.16",
|
||||
"phpunit/phpcov": "^6.0",
|
||||
"phpunit/phpunit": "^8.3",
|
||||
"roave/security-advisories": "dev-master",
|
||||
"shlinkio/php-coding-standard": "~1.2.2",
|
||||
"shlinkio/php-coding-standard": "~2.0.0",
|
||||
"shlinkio/shlink-test-utils": "^1.0",
|
||||
"symfony/dotenv": "^4.3",
|
||||
"symfony/var-dumper": "^4.3",
|
||||
@@ -77,7 +78,10 @@
|
||||
"Shlinkio\\Shlink\\Rest\\": "module/Rest/src",
|
||||
"Shlinkio\\Shlink\\Core\\": "module/Core/src",
|
||||
"Shlinkio\\Shlink\\PreviewGenerator\\": "module/PreviewGenerator/src/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"module/Core/functions/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@@ -98,11 +102,9 @@
|
||||
"@test:ci",
|
||||
"@infect:ci"
|
||||
],
|
||||
|
||||
"cs": "phpcs",
|
||||
"cs:fix": "phpcbf",
|
||||
"stan": "phpstan analyse module/*/src/ module/*/config config docker/config --level=5 -c phpstan.neon",
|
||||
|
||||
"test": [
|
||||
"@test:unit",
|
||||
"@test:db",
|
||||
@@ -110,37 +112,42 @@
|
||||
],
|
||||
"test:ci": [
|
||||
"@test:unit:ci",
|
||||
"@test:db",
|
||||
"@test:db:ci",
|
||||
"@test:api"
|
||||
],
|
||||
"test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-php build/coverage-unit.cov --testdox",
|
||||
"test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml --testdox",
|
||||
"test:db": [
|
||||
"@test:db:sqlite",
|
||||
"@test:db:mysql",
|
||||
"@test:db:maria",
|
||||
"@test:db:postgres"
|
||||
],
|
||||
"test:db:ci": [
|
||||
"@test:db:sqlite",
|
||||
"@test:db:mysql",
|
||||
"@test:db:postgres"
|
||||
],
|
||||
"test:db:sqlite": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always -c phpunit-db.xml --coverage-php build/coverage-db.cov --testdox",
|
||||
"test:db:mysql": "DB_DRIVER=mysql composer test:db:sqlite",
|
||||
"test:db:maria": "DB_DRIVER=maria composer test:db:sqlite",
|
||||
"test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite",
|
||||
"test:api": "bin/test/run-api-tests.sh",
|
||||
|
||||
"test:pretty": [
|
||||
"@test",
|
||||
"phpdbg -qrr vendor/bin/phpcov merge build --html build/html"
|
||||
],
|
||||
"test:unit:pretty": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-html build/coverage",
|
||||
|
||||
"infect": "infection --threads=4 --min-msi=75 --log-verbosity=default --only-covered",
|
||||
"infect:ci": "infection --threads=4 --min-msi=75 --log-verbosity=default --only-covered --coverage=build",
|
||||
"infect:show": "infection --threads=4 --min-msi=75 --log-verbosity=default --only-covered --show-mutations",
|
||||
"infect:test": [
|
||||
"@test:unit:ci",
|
||||
"@infect:ci"
|
||||
]
|
||||
],
|
||||
"clean:dev": "rm -f data/database.sqlite && rm -f config/params/generated_config.php"
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"check": "<fg=blue;options=bold>Alias for \"cs\", \"stan\", \"test\" and \"infect\"</>",
|
||||
"ci": "<fg=blue;options=bold>Alias for \"cs\", \"stan\", \"test:ci\" and \"infect:ci\"</>",
|
||||
"cs": "<fg=blue;options=bold>Checks coding styles</>",
|
||||
"cs:fix": "<fg=blue;options=bold>Fixes coding styles, when possible</>",
|
||||
@@ -149,9 +156,11 @@
|
||||
"test:ci": "<fg=blue;options=bold>Runs all test suites, generating all needed reports and logs for CI envs</>",
|
||||
"test:unit": "<fg=blue;options=bold>Runs unit test suites</>",
|
||||
"test:unit:ci": "<fg=blue;options=bold>Runs unit test suites, generating all needed reports and logs for CI envs</>",
|
||||
"test:db": "<fg=blue;options=bold>Runs database test suites on a SQLite, MySQL and PostgreSQL</>",
|
||||
"test:db": "<fg=blue;options=bold>Runs database test suites on a SQLite, MySQL, MariaDB and PostgreSQL</>",
|
||||
"test:db:ci": "<fg=blue;options=bold>Runs database test suites on a SQLite, MySQL and PostgreSQL</>",
|
||||
"test:db:sqlite": "<fg=blue;options=bold>Runs database test suites on a SQLite database</>",
|
||||
"test:db:mysql": "<fg=blue;options=bold>Runs database test suites on a MySQL database</>",
|
||||
"test:db:maria": "<fg=blue;options=bold>Runs database test suites on a MariaDB database</>",
|
||||
"test:db:postgres": "<fg=blue;options=bold>Runs database test suites on a PostgreSQL database</>",
|
||||
"test:api": "<fg=blue;options=bold>Runs API test suites</>",
|
||||
"test:pretty": "<fg=blue;options=bold>Runs all test suites and generates an HTML code coverage report</>",
|
||||
@@ -159,7 +168,8 @@
|
||||
"infect": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing</>",
|
||||
"infect:ci": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing with existing reports and logs</>",
|
||||
"infect:show": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing and shows applied mutators</>",
|
||||
"infect:test": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing</>"
|
||||
"infect:test": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing</>",
|
||||
"clean:dev": "<fg=blue;options=bold>Deletes artifacts which are gitignored and could affect dev env</>"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use function Shlinkio\Shlink\Common\env;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Zend\ConfigAggregator\ConfigAggregator;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Zend\Expressive;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Common;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Shlinkio\Shlink\Installer\Config\Plugin;
|
||||
@@ -9,10 +10,7 @@ return [
|
||||
Plugin\UrlShortenerConfigCustomizer::class => [
|
||||
Plugin\UrlShortenerConfigCustomizer::SCHEMA,
|
||||
Plugin\UrlShortenerConfigCustomizer::HOSTNAME,
|
||||
Plugin\UrlShortenerConfigCustomizer::CHARS,
|
||||
Plugin\UrlShortenerConfigCustomizer::VALIDATE_URL,
|
||||
Plugin\UrlShortenerConfigCustomizer::ENABLE_NOT_FOUND_REDIRECTION,
|
||||
Plugin\UrlShortenerConfigCustomizer::NOT_FOUND_REDIRECT_TO,
|
||||
],
|
||||
|
||||
Plugin\ApplicationConfigCustomizer::class => [
|
||||
@@ -21,6 +19,8 @@ return [
|
||||
Plugin\ApplicationConfigCustomizer::CHECK_VISITS_THRESHOLD,
|
||||
Plugin\ApplicationConfigCustomizer::VISITS_THRESHOLD,
|
||||
Plugin\ApplicationConfigCustomizer::BASE_PATH,
|
||||
Plugin\ApplicationConfigCustomizer::WEB_WORKER_NUM,
|
||||
Plugin\ApplicationConfigCustomizer::TASK_WORKER_NUM,
|
||||
],
|
||||
|
||||
Plugin\DatabaseConfigCustomizer::class => [
|
||||
@@ -31,6 +31,12 @@ return [
|
||||
Plugin\DatabaseConfigCustomizer::HOST,
|
||||
Plugin\DatabaseConfigCustomizer::PORT,
|
||||
],
|
||||
|
||||
Plugin\RedirectsConfigCustomizer::class => [
|
||||
Plugin\RedirectsConfigCustomizer::INVALID_SHORT_URL_REDIRECT_TO,
|
||||
Plugin\RedirectsConfigCustomizer::REGULAR_404_REDIRECT_TO,
|
||||
Plugin\RedirectsConfigCustomizer::BASE_URL_REDIRECT_TO,
|
||||
],
|
||||
],
|
||||
|
||||
'installation_commands' => [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Shlinkio\Shlink\Common\Cache\RedisFactory;
|
||||
@@ -7,6 +8,10 @@ use Shlinkio\Shlink\Common\Logger\LoggerAwareDelegatorFactory;
|
||||
use Symfony\Component\Lock;
|
||||
use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory;
|
||||
|
||||
// This class alias tricks the ConfigAbstractFactory to return Lock\Factory instances even with a different service name
|
||||
$localLockFactory = 'Shlinkio\Shlink\LocalLockFactory';
|
||||
class_alias(Lock\Factory::class, $localLockFactory);
|
||||
|
||||
return [
|
||||
|
||||
'locks' => [
|
||||
@@ -18,11 +23,14 @@ return [
|
||||
Lock\Store\FlockStore::class => ConfigAbstractFactory::class,
|
||||
Lock\Store\RedisStore::class => ConfigAbstractFactory::class,
|
||||
Lock\Factory::class => ConfigAbstractFactory::class,
|
||||
$localLockFactory => ConfigAbstractFactory::class,
|
||||
],
|
||||
'aliases' => [
|
||||
// With this config, a user could alias 'lock_store' => 'redis_lock_store' to override the default
|
||||
'lock_store' => Lock\Store\FlockStore::class,
|
||||
'lock_store' => 'local_lock_store',
|
||||
|
||||
'redis_lock_store' => Lock\Store\RedisStore::class,
|
||||
'local_lock_store' => Lock\Store\FlockStore::class,
|
||||
],
|
||||
'delegators' => [
|
||||
Lock\Store\RedisStore::class => [
|
||||
@@ -38,6 +46,7 @@ return [
|
||||
Lock\Store\FlockStore::class => ['config.locks.locks_dir'],
|
||||
Lock\Store\RedisStore::class => [RedisFactory::SERVICE_NAME],
|
||||
Lock\Factory::class => ['lock_store'],
|
||||
$localLockFactory => ['local_lock_store'],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @deprecated */
|
||||
/* @deprecated */
|
||||
return [
|
||||
|
||||
'preview_generation' => [
|
||||
|
||||
13
config/autoload/redirects.global.php
Normal file
13
config/autoload/redirects.global.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
'not_found_redirects' => [
|
||||
'invalid_short_url' => null, // Formerly url_shortener.not_found_short_url.redirect_to
|
||||
'regular_404' => null,
|
||||
'base_url' => null,
|
||||
],
|
||||
|
||||
];
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Zend\Expressive\Router\FastRouteRouter;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
declare(strict_types=1);
|
||||
|
||||
use function Shlinkio\Shlink\Common\env;
|
||||
|
||||
@@ -12,12 +11,7 @@ return [
|
||||
'schema' => env('SHORTENED_URL_SCHEMA', 'http'),
|
||||
'hostname' => env('SHORTENED_URL_HOSTNAME'),
|
||||
],
|
||||
'shortcode_chars' => env('SHORTCODE_CHARS', UrlShortenerOptions::DEFAULT_CHARS),
|
||||
'validate_url' => true,
|
||||
'not_found_short_url' => [
|
||||
'enable_redirection' => false,
|
||||
'redirect_to' => null,
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
@@ -6,8 +7,10 @@ use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Zend\ServiceManager\ServiceManager;
|
||||
|
||||
/** @var ContainerInterface|ServiceManager $container */
|
||||
$container = include __DIR__ . '/container.php';
|
||||
$em = $container->get(EntityManager::class);
|
||||
return (function () {
|
||||
/** @var ContainerInterface|ServiceManager $container */
|
||||
$container = include __DIR__ . '/container.php';
|
||||
$em = $container->get(EntityManager::class);
|
||||
|
||||
return ConsoleRunner::createHelperSet($em);
|
||||
return ConsoleRunner::createHelperSet($em);
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
@@ -30,4 +31,5 @@ return (new ConfigAggregator\ConfigAggregator([
|
||||
], 'data/cache/app_config.php', [
|
||||
Core\Config\SimplifiedConfigParser::class,
|
||||
Core\Config\BasePathPrefixer::class,
|
||||
Core\Config\DeprecatedConfigParser::class,
|
||||
]))->getMergedConfig();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\TestUtils;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\TestUtils;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
@@ -15,40 +16,41 @@ use function sys_get_temp_dir;
|
||||
$swooleTestingHost = '127.0.0.1';
|
||||
$swooleTestingPort = 9999;
|
||||
|
||||
$buildDbConnection = function () {
|
||||
$buildDbConnection = function (): array {
|
||||
$driver = env('DB_DRIVER', 'sqlite');
|
||||
$isCi = env('TRAVIS', false);
|
||||
$getMysqlHost = function (string $driver) {
|
||||
return sprintf('shlink_db%s', $driver === 'mysql' ? '' : '_maria');
|
||||
};
|
||||
|
||||
switch ($driver) {
|
||||
case 'sqlite':
|
||||
return [
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => sys_get_temp_dir() . '/shlink-tests.db',
|
||||
];
|
||||
case 'mysql':
|
||||
return [
|
||||
'driver' => 'pdo_mysql',
|
||||
'host' => $isCi ? '127.0.0.1' : 'shlink_db',
|
||||
'user' => 'root',
|
||||
'password' => $isCi ? '' : 'root',
|
||||
'dbname' => 'shlink_test',
|
||||
'charset' => 'utf8',
|
||||
'driverOptions' => [
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||
],
|
||||
];
|
||||
case 'postgres':
|
||||
return [
|
||||
'driver' => 'pdo_pgsql',
|
||||
'host' => $isCi ? '127.0.0.1' : 'shlink_db_postgres',
|
||||
'user' => 'postgres',
|
||||
'password' => $isCi ? '' : 'root',
|
||||
'dbname' => 'shlink_test',
|
||||
'charset' => 'utf8',
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
$driverConfigMap = [
|
||||
'sqlite' => [
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => sys_get_temp_dir() . '/shlink-tests.db',
|
||||
],
|
||||
'mysql' => [
|
||||
'driver' => 'pdo_mysql',
|
||||
'host' => $isCi ? '127.0.0.1' : $getMysqlHost($driver),
|
||||
'user' => 'root',
|
||||
'password' => $isCi ? '' : 'root',
|
||||
'dbname' => 'shlink_test',
|
||||
'charset' => 'utf8',
|
||||
'driverOptions' => [
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||
],
|
||||
],
|
||||
'postgres' => [
|
||||
'driver' => 'pdo_pgsql',
|
||||
'host' => $isCi ? '127.0.0.1' : 'shlink_db_postgres',
|
||||
'user' => 'postgres',
|
||||
'password' => $isCi ? '' : 'root',
|
||||
'dbname' => 'shlink_test',
|
||||
'charset' => 'utf8',
|
||||
],
|
||||
];
|
||||
$driverConfigMap['maria'] = $driverConfigMap['mysql'];
|
||||
|
||||
return $driverConfigMap[$driver] ?? [];
|
||||
};
|
||||
|
||||
return [
|
||||
@@ -64,6 +66,7 @@ return [
|
||||
],
|
||||
|
||||
'zend-expressive-swoole' => [
|
||||
'enable_coroutine' => false,
|
||||
'swoole-http-server' => [
|
||||
'host' => $swooleTestingHost,
|
||||
'port' => $swooleTestingPort,
|
||||
@@ -72,6 +75,7 @@ return [
|
||||
'pid_file' => sys_get_temp_dir() . '/shlink-test-swoole.pid',
|
||||
'worker_num' => 1,
|
||||
'task_worker_num' => 1,
|
||||
'enable_coroutine' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
2
data/infra/database_maria/.gitignore
vendored
Executable file
2
data/infra/database_maria/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -1,9 +1,9 @@
|
||||
FROM php:7.3.1-fpm-alpine3.8
|
||||
FROM php:7.3.11-fpm-alpine3.10
|
||||
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
|
||||
|
||||
ENV APCU_VERSION 5.1.16
|
||||
ENV APCU_BC_VERSION 1.0.4
|
||||
ENV XDEBUG_VERSION "2.7.0RC1"
|
||||
ENV APCU_VERSION 5.1.18
|
||||
ENV APCU_BC_VERSION 1.0.5
|
||||
ENV XDEBUG_VERSION 2.8.0
|
||||
|
||||
RUN apk update
|
||||
|
||||
@@ -13,17 +13,17 @@ RUN docker-php-ext-install iconv
|
||||
RUN docker-php-ext-install mbstring
|
||||
RUN docker-php-ext-install calendar
|
||||
|
||||
RUN apk add --no-cache --virtual sqlite-libs
|
||||
RUN apk add --no-cache --virtual sqlite-dev
|
||||
RUN apk add --no-cache sqlite-libs
|
||||
RUN apk add --no-cache sqlite-dev
|
||||
RUN docker-php-ext-install pdo_sqlite
|
||||
|
||||
RUN apk add --no-cache --virtual icu-dev
|
||||
RUN apk add --no-cache icu-dev
|
||||
RUN docker-php-ext-install intl
|
||||
|
||||
RUN apk add --no-cache --virtual libzip-dev zlib-dev
|
||||
RUN apk add --no-cache libzip-dev zlib-dev
|
||||
RUN docker-php-ext-install zip
|
||||
|
||||
RUN apk add --no-cache --virtual libpng-dev
|
||||
RUN apk add --no-cache libpng-dev
|
||||
RUN docker-php-ext-install gd
|
||||
|
||||
RUN apk add --no-cache postgresql-dev
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
FROM php:7.3.1-cli-alpine3.8
|
||||
FROM php:7.3.11-alpine3.10
|
||||
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
|
||||
|
||||
ENV APCU_VERSION 5.1.16
|
||||
ENV APCU_BC_VERSION 1.0.4
|
||||
ENV APCU_VERSION 5.1.18
|
||||
ENV APCU_BC_VERSION 1.0.5
|
||||
ENV INOTIFY_VERSION 2.0.0
|
||||
ENV SWOOLE_VERSION 4.4.12
|
||||
|
||||
RUN apk update
|
||||
|
||||
@@ -13,17 +14,17 @@ RUN docker-php-ext-install iconv
|
||||
RUN docker-php-ext-install mbstring
|
||||
RUN docker-php-ext-install calendar
|
||||
|
||||
RUN apk add --no-cache --virtual sqlite-libs
|
||||
RUN apk add --no-cache --virtual sqlite-dev
|
||||
RUN apk add --no-cache sqlite-libs
|
||||
RUN apk add --no-cache sqlite-dev
|
||||
RUN docker-php-ext-install pdo_sqlite
|
||||
|
||||
RUN apk add --no-cache --virtual icu-dev
|
||||
RUN apk add --no-cache icu-dev
|
||||
RUN docker-php-ext-install intl
|
||||
|
||||
RUN apk add --no-cache --virtual libzip-dev zlib-dev
|
||||
RUN apk add --no-cache libzip-dev zlib-dev
|
||||
RUN docker-php-ext-install zip
|
||||
|
||||
RUN apk add --no-cache --virtual libpng-dev
|
||||
RUN apk add --no-cache libpng-dev
|
||||
RUN docker-php-ext-install gd
|
||||
|
||||
RUN apk add --no-cache postgresql-dev
|
||||
@@ -66,7 +67,7 @@ RUN rm /tmp/inotify.tar.gz
|
||||
# Install swoole
|
||||
# First line fixes an error when installing pecl extensions. Found in https://github.com/docker-library/php/issues/233
|
||||
RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS && \
|
||||
pecl install swoole && \
|
||||
pecl install swoole-${SWOOLE_VERSION} && \
|
||||
docker-php-ext-enable swoole && \
|
||||
apk del .phpize-deps
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
37
data/migrations/Version20191020074522.php
Normal file
37
data/migrations/Version20191020074522.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20191020074522 extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* @throws SchemaException
|
||||
*/
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->getOriginalUrlColumn($schema)->setLength(2048);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SchemaException
|
||||
*/
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->getOriginalUrlColumn($schema)->setLength(1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SchemaException
|
||||
*/
|
||||
private function getOriginalUrlColumn(Schema $schema): Column
|
||||
{
|
||||
return $schema->getTable('short_urls')->getColumn('original_url');
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace <namespace>;
|
||||
|
||||
@@ -24,3 +24,9 @@ services:
|
||||
volumes:
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
|
||||
shlink_db_maria:
|
||||
user: 1000:1000
|
||||
volumes:
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
|
||||
@@ -24,6 +24,7 @@ services:
|
||||
links:
|
||||
- shlink_db
|
||||
- shlink_db_postgres
|
||||
- shlink_db_maria
|
||||
- shlink_redis
|
||||
|
||||
shlink_swoole:
|
||||
@@ -33,11 +34,13 @@ services:
|
||||
dockerfile: ./data/infra/swoole.Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- ./:/home/shlink
|
||||
links:
|
||||
- shlink_db
|
||||
- shlink_db_postgres
|
||||
- shlink_db_maria
|
||||
- shlink_redis
|
||||
|
||||
shlink_db:
|
||||
@@ -65,6 +68,19 @@ services:
|
||||
POSTGRES_DB: shlink
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
|
||||
shlink_db_maria:
|
||||
container_name: shlink_db_maria
|
||||
image: mariadb:10.2
|
||||
ports:
|
||||
- "3308:3306"
|
||||
volumes:
|
||||
- ./:/home/shlink/www
|
||||
- ./data/infra/database_maria:/var/lib/mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: shlink
|
||||
MYSQL_INITDB_SKIP_TZINFO: 1
|
||||
|
||||
shlink_redis:
|
||||
container_name: shlink_redis
|
||||
image: redis:5.0-alpine
|
||||
|
||||
@@ -56,16 +56,16 @@ docker exec -it shlink_container shlink
|
||||
|
||||
The image comes with a working sqlite database, but in production you will probably want to usa a distributed database.
|
||||
|
||||
It is possible to use a set of env vars to make this shlink instance interact with an external MySQL or PostgreSQL database.
|
||||
It is possible to use a set of env vars to make this shlink instance interact with an external MySQL, MariaDB or PostgreSQL database.
|
||||
|
||||
* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql** or **postgres** to prevent the sqlite database to be used.
|
||||
* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql**, **maria** or **postgres** to prevent the sqlite database to be used.
|
||||
* `DB_NAME`: [Optional]. The database name to be used. Defaults to **shlink**.
|
||||
* `DB_USER`: **[Mandatory]**. The username credential for the database server.
|
||||
* `DB_PASSWORD`: **[Mandatory]**. The password credential for the database server.
|
||||
* `DB_HOST`: **[Mandatory]**. The host name of the server running the database engine.
|
||||
* `DB_PORT`: [Optional]. The port in which the database service is running.
|
||||
* Default value is based on the driver:
|
||||
* **mysql** -> `3306`
|
||||
* Default value is based on the value provided for `DB_DRIVER`:
|
||||
* **mysql** or **maria** -> `3306`
|
||||
* **postgres** -> `5432`
|
||||
|
||||
> PostgreSQL is supported since v1.16.1 of this image. Do not try to use it with previous versions.
|
||||
@@ -92,18 +92,24 @@ This is the complete list of supported env vars:
|
||||
|
||||
* `SHORT_DOMAIN_HOST`: The custom short domain used for this shlink instance. For example **doma.in**.
|
||||
* `SHORT_DOMAIN_SCHEMA`: Either **http** or **https**.
|
||||
* `SHORTCODE_CHARS`: A charset to use when building short codes. Only needed when using more than one shlink instance ([Multi instance considerations](#multi-instance-considerations)).
|
||||
* `DB_DRIVER`: **sqlite** (which is the default value), **mysql** or **postgres**.
|
||||
* `DB_DRIVER`: **sqlite** (which is the default value), **mysql**, **maria** or **postgres**.
|
||||
* `DB_NAME`: The database name to be used when using an external database driver. Defaults to **shlink**.
|
||||
* `DB_USER`: The username credential to be used when using an external database driver.
|
||||
* `DB_PASSWORD`: The password credential to be used when using an external database driver.
|
||||
* `DB_HOST`: The host name of the database server when using an external database driver.
|
||||
* `DB_PORT`: The port in which the database service is running when using an external database driver. Defaults to **3306**.
|
||||
* `DB_PORT`: The port in which the database service is running when using an external database driver.
|
||||
* Default value is based on the value provided for `DB_DRIVER`:
|
||||
* **mysql** or **maria** -> `3306`
|
||||
* **postgres** -> `5432`
|
||||
* `DISABLE_TRACK_PARAM`: The name of a query param that can be used to visit short URLs avoiding the visit to be tracked. This feature won't be available if not value is provided.
|
||||
* `DELETE_SHORT_URL_THRESHOLD`: The amount of visits on short URLs which will not allow them to be deleted. Defaults to `15`.
|
||||
* `VALIDATE_URLS`: Boolean which tells if shlink should validate a status 20x (after following redirects) is returned when trying to shorten a URL. Defaults to `true`.
|
||||
* `NOT_FOUND_REDIRECT_TO`: If a URL is provided here, when a user tries to access an invalid short URL, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
|
||||
* `INVALID_SHORT_URL_REDIRECT_TO`: If a URL is provided here, when a user tries to access an invalid short URL, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
|
||||
* `REGULAR_404_REDIRECT_TO`: If a URL is provided here, when a user tries to access a URL not matching any one supported by the router, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
|
||||
* `BASE_URL_REDIRECT_TO`: If a URL is provided here, when a user tries to access Shlink's base URL, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
|
||||
* `BASE_PATH`: The base path from which you plan to serve shlink, in case you don't want to serve it from the root of the domain. Defaults to `''`.
|
||||
* `WEB_WORKER_NUM`: The amount of concurrent http requests this shlink instance will be able to server. Defaults to 16.
|
||||
* `TASK_WORKER_NUM`: The amount of concurrent background tasks this shlink instance will be able to execute. Defaults to 16.
|
||||
* `REDIS_SERVERS`: A comma-separated list of redis servers where Shlink locks are stored (locks are used to prevent some operations to be run more than once in parallel).
|
||||
|
||||
This is important when running more than one Shlink instance ([Multi instance considerations](#multi-instance-considerations)). If not provided, Shlink stores locks on every instance separately.
|
||||
@@ -112,6 +118,9 @@ This is the complete list of supported env vars:
|
||||
|
||||
In the future, these redis servers could be used for other caching operations performed by shlink.
|
||||
|
||||
* `NOT_FOUND_REDIRECT_TO`: **Deprecated since v1.20 in favor of `INVALID_SHORT_URL_REDIRECT_TO`** If a URL is provided here, when a user tries to access an invalid short URL, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
|
||||
* `SHORTCODE_CHARS`: **Ignored when using Shlink 1.20 or newer**. A charset to use when building short codes. Only needed when using more than one shlink instance ([Multi instance considerations](#multi-instance-considerations)).
|
||||
|
||||
An example using all env vars could look like this:
|
||||
|
||||
```bash
|
||||
@@ -129,9 +138,13 @@ docker run \
|
||||
-e DISABLE_TRACK_PARAM="no-track" \
|
||||
-e DELETE_SHORT_URL_THRESHOLD=30 \
|
||||
-e VALIDATE_URLS=false \
|
||||
-e "NOT_FOUND_REDIRECT_TO=https://www.google.com" \
|
||||
-e "INVALID_SHORT_URL_REDIRECT_TO=https://my-landing-page.com" \
|
||||
-e "REGULAR_404_REDIRECT_TO=https://my-landing-page.com" \
|
||||
-e "BASE_URL_REDIRECT_TO=https://my-landing-page.com" \
|
||||
-e "REDIS_SERVERS=tcp://172.20.0.1:6379,tcp://172.20.0.2:6379" \
|
||||
-e "BASE_PATH=/my-campaign" \
|
||||
-e WEB_WORKER_NUM=64 \
|
||||
-e TASK_WORKER_NUM=32 \
|
||||
shlinkio/shlink
|
||||
```
|
||||
|
||||
@@ -150,7 +163,12 @@ The whole configuration should have this format, but it can be split into multip
|
||||
"short_domain_schema": "https",
|
||||
"short_domain_host": "doma.in",
|
||||
"validate_url": false,
|
||||
"not_found_redirect_to": "https://my-landing-page.com",
|
||||
"invalid_short_url_redirect_to": "https://my-landing-page.com",
|
||||
"regular_404_redirect_to": "https://my-landing-page.com",
|
||||
"base_url_redirect_to": "https://my-landing-page.com",
|
||||
"base_path": "/my-campaign",
|
||||
"web_worker_num": 64,
|
||||
"task_worker_num": 32,
|
||||
"redis_servers": [
|
||||
"tcp://172.20.0.1:6379",
|
||||
"tcp://172.20.0.2:6379"
|
||||
@@ -162,12 +180,15 @@ The whole configuration should have this format, but it can be split into multip
|
||||
"password": "123abc",
|
||||
"host": "something.rds.amazonaws.com",
|
||||
"port": "3306"
|
||||
}
|
||||
},
|
||||
"not_found_redirect_to": "https://my-landing-page.com"
|
||||
}
|
||||
```
|
||||
|
||||
> This is internally parsed to how shlink expects the config. If you are using a version previous to 1.17.0, this parser is not present and you need to provide a config structure like the one [documented previously](https://github.com/shlinkio/shlink-docker-image/tree/v1.16.3#provide-config-via-volumes).
|
||||
|
||||
> The `not_found_redirect_to` option has been deprecated in v1.20. Use `invalid_short_url_redirect_to` instead (however, it will still work for backwards compatibility).
|
||||
|
||||
Once created just run shlink with the volume:
|
||||
|
||||
```bash
|
||||
@@ -178,7 +199,13 @@ docker run --name shlink -p 8080:8080 -v ${PWD}/my/config/dir:/etc/shlink/config
|
||||
|
||||
These are some considerations to take into account when running multiple instances of shlink.
|
||||
|
||||
* The first time shlink is run, it generates a charset used to generate short codes, which is a shuffled base62 charset.
|
||||
* Some operations performed by Shlink should never be run more than once at the same time (like creating the database for the first time, or downloading the GeoLite2 database). For this reason, Shlink uses a locking system.
|
||||
|
||||
However, these locks are locally scoped to each Shlink instance by default.
|
||||
|
||||
You can (and should) make the locks to be shared by all Shlink instances by using a redis server/cluster. Just define the `REDIS_SERVERS` env var with the list of servers.
|
||||
|
||||
* **Ignore this if using Shlink 1.20 or newer**. The first time shlink is run, it generates a charset used to generate short codes, which is a shuffled base62 charset.
|
||||
|
||||
If you are using several shlink instances, you will probably want all of them to use the same charset.
|
||||
|
||||
@@ -186,18 +213,12 @@ These are some considerations to take into account when running multiple instanc
|
||||
|
||||
If you don't do this, each shlink instance will use a different charset. However this shouldn't be a problem in practice, since the chances to get a collision will be very low.
|
||||
|
||||
* Some operations performed by Shlink should never be run more than once at the same time (like creating the database for the first time, or downloading the GeoLite2 database). For this reason, Shlink uses a locking system.
|
||||
|
||||
However, these locks are locally scoped to each Shlink instance by default.
|
||||
|
||||
You can (and should) make the locks to be shared by all Shlink instances by using a redis server/cluster. Just define the `REDIS_SERVERS` env var with the list of servers.
|
||||
|
||||
## Versions
|
||||
|
||||
Versions of this image match the shlink version it contains.
|
||||
Versioning on this docker image works as follows:
|
||||
|
||||
For example, installing `shlinkio/shlink:1.15.0`, you will get an image containing shlink v1.15.0.
|
||||
* `X.X.X`: when providing a specific version number, the image version will match the shlink version it contains. For example, installing `shlinkio/shlink:1.15.0`, you will get an image containing shlink v1.15.0.
|
||||
* `stable`: always holds the latest stable tag. For example, if latest shlink version is 1.20.0, installing `shlinkio/shlink:stable`, you will get an image containing shlink v1.20.0
|
||||
* `latest`: always holds the latest contents in master, and it's considered unstable and not suitable for production.
|
||||
|
||||
The `latest` docker tag always holds the latest contents in master, and it's considered unestable and not suitable for production.
|
||||
|
||||
> There are no official shlink images previous to v1.15.0.
|
||||
> **Important**: The docker image was introduced with shlink v1.15.0, so there are no official images previous to that versions.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink;
|
||||
@@ -10,6 +11,7 @@ use function explode;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function Functional\contains;
|
||||
use function implode;
|
||||
use function Shlinkio\Shlink\Common\env;
|
||||
use function sprintf;
|
||||
@@ -21,24 +23,24 @@ $helper = new class {
|
||||
private const BASE62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
private const DB_DRIVERS_MAP = [
|
||||
'mysql' => 'pdo_mysql',
|
||||
'maria' => 'pdo_mysql',
|
||||
'postgres' => 'pdo_pgsql',
|
||||
];
|
||||
private const DB_PORTS_MAP = [
|
||||
'mysql' => '3306',
|
||||
'maria' => '3306',
|
||||
'postgres' => '5432',
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
private $charset;
|
||||
/** @var string */
|
||||
private $secretKey;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
[$this->charset, $this->secretKey] = $this->initShlinkKeys();
|
||||
[, $this->secretKey] = $this->initShlinkSecretKey();
|
||||
}
|
||||
|
||||
private function initShlinkKeys(): array
|
||||
private function initShlinkSecretKey(): array
|
||||
{
|
||||
$keysFile = sprintf('%s/shlink.keys', sys_get_temp_dir());
|
||||
if (file_exists($keysFile)) {
|
||||
@@ -46,29 +48,19 @@ $helper = new class {
|
||||
}
|
||||
|
||||
$keys = [
|
||||
env('SHORTCODE_CHARS', $this->generateShortcodeChars()),
|
||||
env('SECRET_KEY', $this->generateSecretKey()),
|
||||
'', // This was the SHORTCODE_CHARS. Kept as empty string for BC
|
||||
env('SECRET_KEY', $this->generateSecretKey()), // Deprecated
|
||||
];
|
||||
|
||||
file_put_contents($keysFile, implode(',', $keys));
|
||||
return $keys;
|
||||
}
|
||||
|
||||
private function generateShortcodeChars(): string
|
||||
{
|
||||
return str_shuffle(self::BASE62);
|
||||
}
|
||||
|
||||
private function generateSecretKey(): string
|
||||
{
|
||||
return substr(str_shuffle(self::BASE62), 0, 32);
|
||||
}
|
||||
|
||||
public function getShortcodeChars(): string
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
public function getSecretKey(): string
|
||||
{
|
||||
return $this->secretKey;
|
||||
@@ -84,8 +76,8 @@ $helper = new class {
|
||||
];
|
||||
}
|
||||
|
||||
$driverOptions = $driver !== 'mysql' ? [] : [
|
||||
// PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||
$driverOptions = ! contains(['maria', 'mysql'], $driver) ? [] : [
|
||||
// 1002 -> PDO::MYSQL_ATTR_INIT_COMMAND
|
||||
1002 => 'SET NAMES utf8',
|
||||
];
|
||||
return [
|
||||
@@ -99,13 +91,12 @@ $helper = new class {
|
||||
];
|
||||
}
|
||||
|
||||
public function getNotFoundConfig(): array
|
||||
public function getNotFoundRedirectsConfig(): array
|
||||
{
|
||||
$notFoundRedirectTo = env('NOT_FOUND_REDIRECT_TO');
|
||||
|
||||
return [
|
||||
'enable_redirection' => $notFoundRedirectTo !== null,
|
||||
'redirect_to' => $notFoundRedirectTo,
|
||||
'invalid_short_url' => env('INVALID_SHORT_URL_REDIRECT_TO', env('NOT_FOUND_REDIRECT_TO')),
|
||||
'regular_404' => env('REGULAR_404_REDIRECT_TO'),
|
||||
'base_url' => env('BASE_URL_REDIRECT_TO'),
|
||||
];
|
||||
}
|
||||
};
|
||||
@@ -133,11 +124,11 @@ return [
|
||||
'schema' => env('SHORT_DOMAIN_SCHEMA', 'http'),
|
||||
'hostname' => env('SHORT_DOMAIN_HOST', ''),
|
||||
],
|
||||
'shortcode_chars' => $helper->getShortcodeChars(),
|
||||
'validate_url' => (bool) env('VALIDATE_URLS', true),
|
||||
'not_found_short_url' => $helper->getNotFoundConfig(),
|
||||
],
|
||||
|
||||
'not_found_redirects' => $helper->getNotFoundRedirectsConfig(),
|
||||
|
||||
'logger' => [
|
||||
'handlers' => [
|
||||
'shlink_rotating_handler' => [
|
||||
@@ -172,4 +163,13 @@ return [
|
||||
'base_path' => env('BASE_PATH', ''),
|
||||
],
|
||||
|
||||
'zend-expressive-swoole' => [
|
||||
'swoole-http-server' => [
|
||||
'options' => [
|
||||
'worker_num' => (int) env('WEB_WORKER_NUM', 16),
|
||||
'task_worker_num' => (int) env('TASK_WORKER_NUM', 16),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
11
migrations.php
Normal file
11
migrations.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'name' => 'ShlinkMigrations',
|
||||
'migrations_namespace' => 'ShlinkMigrations',
|
||||
'table_name' => 'migrations',
|
||||
'migrations_directory' => 'data/migrations',
|
||||
'custom_template' => 'data/migrations_template.txt',
|
||||
];
|
||||
@@ -1,5 +0,0 @@
|
||||
name: ShlinkMigrations
|
||||
migrations_namespace: ShlinkMigrations
|
||||
table_name: migrations
|
||||
migrations_directory: data/migrations
|
||||
custom_template: data/migrations_template.txt
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI;
|
||||
@@ -57,7 +58,7 @@ return [
|
||||
],
|
||||
|
||||
ConfigAbstractFactory::class => [
|
||||
GeolocationDbUpdater::class => [DbUpdater::class, Reader::class, Locker::class],
|
||||
GeolocationDbUpdater::class => [DbUpdater::class, Reader::class, 'Shlinkio\Shlink\LocalLockFactory'],
|
||||
|
||||
Command\ShortUrl\GenerateShortUrlCommand::class => [Service\UrlShortener::class, 'config.url_shortener.domain'],
|
||||
Command\ShortUrl\ResolveUrlCommand::class => [Service\UrlShortener::class],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Config;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -17,6 +17,7 @@ use function str_shuffle;
|
||||
class GenerateCharsetCommand extends Command
|
||||
{
|
||||
public const NAME = 'config:generate-charset';
|
||||
private const DEFAULT_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
@@ -25,14 +26,14 @@ class GenerateCharsetCommand extends Command
|
||||
->setDescription(sprintf(
|
||||
'[DEPRECATED] Generates a character set sample just by shuffling the default one, "%s". '
|
||||
. 'Then it can be set in the SHORTCODE_CHARS environment variable',
|
||||
UrlShortenerOptions::DEFAULT_CHARS
|
||||
self::DEFAULT_CHARS
|
||||
))
|
||||
->setHelp('<fg=red;options=bold>This command is deprecated. Better leave shlink generate the charset.</>');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): ?int
|
||||
{
|
||||
$charSet = str_shuffle(UrlShortenerOptions::DEFAULT_CHARS);
|
||||
$charSet = str_shuffle(self::DEFAULT_CHARS);
|
||||
(new SymfonyStyle($input, $output))->success(sprintf('Character set: "%s"', $charSet));
|
||||
return ExitCodes::EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Config;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Db;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Command\Util\AbstractLockedCommand;
|
||||
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
|
||||
use Symfony\Component\Console\Helper\ProcessHelper;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Lock\Factory as Locker;
|
||||
@@ -28,6 +30,11 @@ abstract class AbstractDatabaseCommand extends AbstractLockedCommand
|
||||
protected function runPhpCommand(OutputInterface $output, array $command): void
|
||||
{
|
||||
array_unshift($command, $this->phpBinary);
|
||||
$this->processHelper->run($output, $command, null, null, $output->getVerbosity());
|
||||
$this->processHelper->mustRun($output, $command);
|
||||
}
|
||||
|
||||
protected function getLockConfig(): LockedCommandConfig
|
||||
{
|
||||
return new LockedCommandConfig($this->getName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Db;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
||||
use Symfony\Component\Console\Helper\ProcessHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -18,8 +18,8 @@ use function Functional\contains;
|
||||
class CreateDatabaseCommand extends AbstractDatabaseCommand
|
||||
{
|
||||
public const NAME = 'db:create';
|
||||
public const DOCTRINE_HELPER_SCRIPT = 'vendor/doctrine/orm/bin/doctrine.php';
|
||||
public const DOCTRINE_HELPER_COMMAND = 'orm:schema-tool:create';
|
||||
public const DOCTRINE_SCRIPT = 'vendor/doctrine/orm/bin/doctrine.php';
|
||||
public const DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create';
|
||||
|
||||
/** @var Connection */
|
||||
private $regularConn;
|
||||
@@ -60,7 +60,7 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
|
||||
|
||||
// Create database
|
||||
$io->writeln('<fg=blue>Creating database tables...</>');
|
||||
$this->runPhpCommand($output, [self::DOCTRINE_HELPER_SCRIPT, self::DOCTRINE_HELPER_COMMAND]);
|
||||
$this->runPhpCommand($output, [self::DOCTRINE_SCRIPT, self::DOCTRINE_CREATE_SCHEMA_COMMAND]);
|
||||
$io->success('Database properly created!');
|
||||
|
||||
return ExitCodes::EXIT_SUCCESS;
|
||||
@@ -86,13 +86,8 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
|
||||
private function schemaExists(): bool
|
||||
{
|
||||
// If at least one of the shlink tables exist, we will consider the database exists somehow.
|
||||
// Any inconsistency will be taken care by the migrations
|
||||
// Any inconsistency should be taken care by the migrations
|
||||
$schemaManager = $this->regularConn->getSchemaManager();
|
||||
return ! empty($schemaManager->listTableNames());
|
||||
}
|
||||
|
||||
protected function getLockConfig(): LockedCommandConfig
|
||||
{
|
||||
return new LockedCommandConfig($this->getName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Db;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -12,8 +12,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
class MigrateDatabaseCommand extends AbstractDatabaseCommand
|
||||
{
|
||||
public const NAME = 'db:migrate';
|
||||
public const DOCTRINE_HELPER_SCRIPT = 'vendor/doctrine/migrations/bin/doctrine-migrations.php';
|
||||
public const DOCTRINE_HELPER_COMMAND = 'migrations:migrate';
|
||||
public const DOCTRINE_MIGRATIONS_SCRIPT = 'vendor/doctrine/migrations/bin/doctrine-migrations.php';
|
||||
public const DOCTRINE_MIGRATE_COMMAND = 'migrations:migrate';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
@@ -27,14 +27,9 @@ class MigrateDatabaseCommand extends AbstractDatabaseCommand
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->writeln('<fg=blue>Migrating database...</>');
|
||||
$this->runPhpCommand($output, [self::DOCTRINE_HELPER_SCRIPT, self::DOCTRINE_HELPER_COMMAND]);
|
||||
$this->runPhpCommand($output, [self::DOCTRINE_MIGRATIONS_SCRIPT, self::DOCTRINE_MIGRATE_COMMAND]);
|
||||
$io->success('Database properly migrated!');
|
||||
|
||||
return ExitCodes::EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
protected function getLockConfig(): LockedCommandConfig
|
||||
{
|
||||
return new LockedCommandConfig($this->getName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
||||
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||
@@ -101,7 +101,7 @@ class GenerateShortUrlCommand extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
$longUrl = $io->ask('A long URL was not provided. Which URL do you want to be shortened?');
|
||||
$longUrl = $io->ask('Which URL do you want to shorten?');
|
||||
if (! empty($longUrl)) {
|
||||
$input->setArgument('longUrl', $longUrl);
|
||||
}
|
||||
@@ -126,8 +126,8 @@ class GenerateShortUrlCommand extends Command
|
||||
new Uri($longUrl),
|
||||
$tags,
|
||||
ShortUrlMeta::createFromParams(
|
||||
$this->getOptionalDate($input, 'validSince'),
|
||||
$this->getOptionalDate($input, 'validUntil'),
|
||||
$input->getOption('validSince'),
|
||||
$input->getOption('validUntil'),
|
||||
$customSlug,
|
||||
$maxVisits !== null ? (int) $maxVisits : null,
|
||||
$input->getOption('findIfExists'),
|
||||
@@ -150,10 +150,4 @@ class GenerateShortUrlCommand extends Command
|
||||
return ExitCodes::EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
private function getOptionalDate(InputInterface $input, string $fieldName): ?Chronos
|
||||
{
|
||||
$since = $input->getOption($fieldName);
|
||||
return $since !== null ? Chronos::parse($since) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
@@ -61,26 +62,26 @@ class ListShortUrlsCommand extends Command
|
||||
->addOption(
|
||||
'page',
|
||||
'p',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
sprintf('The first page to list (%s items per page)', ShortUrlRepositoryAdapter::ITEMS_PER_PAGE),
|
||||
'1'
|
||||
)
|
||||
->addOption(
|
||||
'searchTerm',
|
||||
's',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'A query used to filter results by searching for it on the longUrl and shortCode fields'
|
||||
)
|
||||
->addOption(
|
||||
'tags',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'A comma-separated list of tags to filter results'
|
||||
)
|
||||
->addOption(
|
||||
'orderBy',
|
||||
'o',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The field from which we want to order by. Pass ASC or DESC separated by a comma'
|
||||
)
|
||||
->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
||||
use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
|
||||
use Shlinkio\Shlink\Core\Exception\TagConflictException;
|
||||
use Shlinkio\Shlink\Core\Service\Tag\TagServiceInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@@ -49,6 +51,11 @@ class RenameTagCommand extends Command
|
||||
} catch (EntityDoesNotExistException $e) {
|
||||
$io->error(sprintf('A tag with name "%s" was not found', $oldName));
|
||||
return ExitCodes::EXIT_FAILURE;
|
||||
} catch (TagConflictException $e) {
|
||||
$io->error(
|
||||
sprintf('A tag with name "%s" cannot be renamed to "%s" because it already exists', $oldName, $newName)
|
||||
);
|
||||
return ExitCodes::EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Visit;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Visit;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Exception;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Exception;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Factory;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Util;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Api;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Config;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Db;
|
||||
@@ -115,10 +116,10 @@ class CreateDatabaseCommandTest extends TestCase
|
||||
$createDatabase = $this->schemaManager->createDatabase($shlinkDatabase)->will(function () {
|
||||
});
|
||||
$listTables = $this->schemaManager->listTableNames()->willReturn([]);
|
||||
$runCommand = $this->processHelper->run(Argument::type(OutputInterface::class), [
|
||||
$runCommand = $this->processHelper->mustRun(Argument::type(OutputInterface::class), [
|
||||
'/usr/local/bin/php',
|
||||
CreateDatabaseCommand::DOCTRINE_HELPER_SCRIPT,
|
||||
CreateDatabaseCommand::DOCTRINE_HELPER_COMMAND,
|
||||
CreateDatabaseCommand::DOCTRINE_SCRIPT,
|
||||
CreateDatabaseCommand::DOCTRINE_CREATE_SCHEMA_COMMAND,
|
||||
], Argument::cetera());
|
||||
|
||||
$this->commandTester->execute([]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\Db;
|
||||
@@ -47,36 +48,20 @@ class MigrateDatabaseCommandTest extends TestCase
|
||||
$this->commandTester = new CommandTester($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider provideVerbosities
|
||||
*/
|
||||
public function migrationsCommandIsRunWithProperVerbosity(int $verbosity): void
|
||||
/** @test */
|
||||
public function migrationsCommandIsRunWithProperVerbosity(): void
|
||||
{
|
||||
$runCommand = $this->processHelper->run(Argument::type(OutputInterface::class), [
|
||||
$runCommand = $this->processHelper->mustRun(Argument::type(OutputInterface::class), [
|
||||
'/usr/local/bin/php',
|
||||
MigrateDatabaseCommand::DOCTRINE_HELPER_SCRIPT,
|
||||
MigrateDatabaseCommand::DOCTRINE_HELPER_COMMAND,
|
||||
], null, null, $verbosity);
|
||||
MigrateDatabaseCommand::DOCTRINE_MIGRATIONS_SCRIPT,
|
||||
MigrateDatabaseCommand::DOCTRINE_MIGRATE_COMMAND,
|
||||
], Argument::cetera());
|
||||
|
||||
$this->commandTester->execute([], [
|
||||
'verbosity' => $verbosity,
|
||||
]);
|
||||
$this->commandTester->execute([]);
|
||||
$output = $this->commandTester->getDisplay();
|
||||
|
||||
if ($verbosity >= OutputInterface::VERBOSITY_VERBOSE) {
|
||||
$this->assertStringContainsString('Migrating database...', $output);
|
||||
$this->assertStringContainsString('Database properly migrated!', $output);
|
||||
}
|
||||
$this->assertStringContainsString('Migrating database...', $output);
|
||||
$this->assertStringContainsString('Database properly migrated!', $output);
|
||||
$runCommand->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
|
||||
public function provideVerbosities(): iterable
|
||||
{
|
||||
yield 'debug' => [OutputInterface::VERBOSITY_DEBUG];
|
||||
yield 'normal' => [OutputInterface::VERBOSITY_NORMAL];
|
||||
yield 'quiet' => [OutputInterface::VERBOSITY_QUIET];
|
||||
yield 'verbose' => [OutputInterface::VERBOSITY_VERBOSE];
|
||||
yield 'very verbose' => [OutputInterface::VERBOSITY_VERY_VERBOSE];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
|
||||
@@ -19,6 +20,11 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class GenerateShortUrlCommandTest extends TestCase
|
||||
{
|
||||
private const DOMAIN_CONFIG = [
|
||||
'schema' => 'http',
|
||||
'hostname' => 'foo.com',
|
||||
];
|
||||
|
||||
/** @var CommandTester */
|
||||
private $commandTester;
|
||||
/** @var ObjectProphecy */
|
||||
@@ -27,10 +33,7 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->urlShortener = $this->prophesize(UrlShortener::class);
|
||||
$command = new GenerateShortUrlCommand($this->urlShortener->reveal(), [
|
||||
'schema' => 'http',
|
||||
'hostname' => 'foo.com',
|
||||
]);
|
||||
$command = new GenerateShortUrlCommand($this->urlShortener->reveal(), self::DOMAIN_CONFIG);
|
||||
$app = new Application();
|
||||
$app->add($command);
|
||||
$this->commandTester = new CommandTester($command);
|
||||
@@ -39,9 +42,8 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
/** @test */
|
||||
public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void
|
||||
{
|
||||
$urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willReturn(
|
||||
(new ShortUrl(''))->setShortCode('abc123')
|
||||
);
|
||||
$shortUrl = new ShortUrl('');
|
||||
$urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willReturn($shortUrl);
|
||||
|
||||
$this->commandTester->execute([
|
||||
'longUrl' => 'http://domain.com/foo/bar',
|
||||
@@ -50,7 +52,7 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
$output = $this->commandTester->getDisplay();
|
||||
|
||||
$this->assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||
$this->assertStringContainsString('http://foo.com/abc123', $output);
|
||||
$this->assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output);
|
||||
$urlToShortCode->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
|
||||
@@ -85,6 +87,7 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
/** @test */
|
||||
public function properlyProcessesProvidedTags(): void
|
||||
{
|
||||
$shortUrl = new ShortUrl('');
|
||||
$urlToShortCode = $this->urlShortener->urlToShortCode(
|
||||
Argument::type(UriInterface::class),
|
||||
Argument::that(function (array $tags) {
|
||||
@@ -92,7 +95,7 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
return $tags;
|
||||
}),
|
||||
Argument::cetera()
|
||||
)->willReturn((new ShortUrl(''))->setShortCode('abc123'));
|
||||
)->willReturn($shortUrl);
|
||||
|
||||
$this->commandTester->execute([
|
||||
'longUrl' => 'http://domain.com/foo/bar',
|
||||
@@ -101,7 +104,7 @@ class GenerateShortUrlCommandTest extends TestCase
|
||||
$output = $this->commandTester->getDisplay();
|
||||
|
||||
$this->assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||
$this->assertStringContainsString('http://foo.com/abc123', $output);
|
||||
$this->assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output);
|
||||
$urlToShortCode->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user