Compare commits

...

1005 Commits

Author SHA1 Message Date
Alejandro Celaya
89419e278c
Merge pull request #2539 from acelaya-forks/symfony-8.0
Update to Symfony 8.0
2025-12-03 07:58:39 +01:00
Alejandro Celaya
1996745f64 Update to Symfony 8.0 2025-12-02 12:20:52 +01:00
Alejandro Celaya
cfab13bc47
Merge pull request #2533 from acelaya-forks/improve-coverage-2
Add more code coverage improvements
2025-11-18 09:33:20 +01:00
Alejandro Celaya
9432a5ba78 Add tests for events 2025-11-18 09:30:30 +01:00
Alejandro Celaya
7812a85b39 Remove unused AppOptions::__toString method 2025-11-18 09:20:52 +01:00
Alejandro Celaya
1e0b6be67d Improved NorFoundRedirectResolver test 2025-11-18 09:06:11 +01:00
Alejandro Celaya
88e5bb5618 Add test for AbstractRestAction::getRouteDef() 2025-11-18 08:56:09 +01:00
Alejandro Celaya
db1411d3f8 Remove unused method in ApiKeyNotFoundException 2025-11-18 08:45:31 +01:00
Alejandro Celaya
933c54e884 Improve some console commands coverage 2025-11-18 08:44:15 +01:00
Alejandro Celaya
f3ff059d48 Improve RoleResolver coverage 2025-11-17 12:33:08 +01:00
Alejandro Celaya
039a58bb44
Merge pull request #2532 from acelaya-forks/improve-coverage
Remove dead code that is affecting code coverage
2025-11-17 12:23:55 +01:00
Alejandro Celaya
0604237b94 Remove dead code that is affecting code coverage 2025-11-17 12:12:06 +01:00
Alejandro Celaya
c8537e4f71
Merge pull request #2529 from acelaya-forks/php-8.4-goodies
Simplify NotFoundRedirectConfigInterface with property hooks and asymetric visibility
2025-11-08 22:58:34 +01:00
Alejandro Celaya
c42fb67efc Simplify NotFoundRedirectConfigInterface with property hooks and asymetric visibility 2025-11-08 22:47:24 +01:00
Alejandro Celaya
ad15ae1922
Merge pull request #2526 from acelaya-forks/remove-trusted-proxies-workaround
Remove workaround to detect trusted proxies automatically
2025-11-08 10:44:09 +01:00
Alejandro Celaya
a731e01bd4 Remove test covering trusted proxies workaround 2025-11-08 10:41:03 +01:00
Alejandro Celaya
63bea36c05 Remove workaround to detect trusted proxies automatically 2025-11-08 10:33:06 +01:00
Alejandro Celaya
8a33c6968a
Merge pull request #2525 from acelaya-forks/remove-tags-option
Remove deprecated --tags option in console commands
2025-11-08 10:29:26 +01:00
Alejandro Celaya
359129f586 Remove deprecated --tags option in console commands 2025-11-08 10:22:02 +01:00
Alejandro Celaya
fdcc9933a3
Merge pull request #2524 from acelaya-forks/list-urls-deprecations
Remove deprecated options from short-url:list command
2025-11-08 10:13:15 +01:00
Alejandro Celaya
94adba95eb Fix codecov/codecov-action arguments for v5 2025-11-08 10:09:20 +01:00
Alejandro Celaya
8bafd82e1d Remove deprecated options from short-url:list command 2025-11-08 10:07:51 +01:00
Alejandro Celaya
d2bc9f7c2b
Merge pull request #2523 from acelaya-forks/no-disable-by-api-key
Do not allow API keys to be disabled by plain-text key
2025-11-08 09:34:34 +01:00
Alejandro Celaya
9f564b9785 Do not allow API keys to be disabled by plain-text key 2025-11-08 09:16:15 +01:00
Alejandro Celaya
1b6929acf6
Merge pull request #2518 from acelaya-forks/remove-extra-path
Remove REDIRECT_APPEND_EXTRA_PATH env var
2025-11-08 08:53:33 +01:00
Alejandro Celaya
91fd5809ff Remove REDIRECT_APPEND_EXTRA_PATH env var 2025-11-08 08:28:52 +01:00
Alejandro Celaya
c7fd6b3cba
Merge pull request #2516 from acelaya-forks/drop-php-8.3
Drop support for PHP 8.3
2025-11-08 08:17:18 +01:00
Alejandro Celaya
1eb1f5344c Drop support for PHP 8.3 2025-11-07 17:21:54 +01:00
Alejandro Celaya
f9ec4cea62
Merge pull request #2515 from acelaya-forks/remove-qr-codes
Drop support for QR code generation
2025-11-07 17:21:04 +01:00
Alejandro Celaya
c3961b139a Remove image extensions from dev docker containers 2025-11-07 17:10:51 +01:00
Alejandro Celaya
c2aae9640d Remove requirement on ext-gd 2025-11-07 17:07:34 +01:00
Alejandro Celaya
b4043be7fa Drop support for QR code generation 2025-11-07 16:58:19 +01:00
Alejandro Celaya
49c67abf0a Add missing entry in 4.6.0 changelog 2025-11-01 12:53:14 +01:00
Alejandro Celaya
c6f718eb11 Add proper version contraints for shlinkio packages 2025-11-01 12:43:22 +01:00
Alejandro Celaya
d3e8e9a735 Add v4.6.0 to changelog 2025-11-01 12:38:00 +01:00
Alejandro Celaya
8f1542c7aa
Merge pull request #2509 from acelaya-forks/invokable-commands
Invokable commands
2025-11-01 12:37:04 +01:00
Alejandro Celaya
058c0ebfaf Update changelog 2025-11-01 12:31:46 +01:00
Alejandro Celaya
b69db91378 Make DownloadGeoLiteDbCommand invokable 2025-11-01 12:30:15 +01:00
Alejandro Celaya
6113c28768 Make RenameTagCommand invokable 2025-11-01 12:28:04 +01:00
Alejandro Celaya
506ed47531 Make ListTagsCommand invokable 2025-11-01 12:25:52 +01:00
Alejandro Celaya
10173d2ab8 Make DeleteTagsCommand invokable 2025-11-01 12:24:18 +01:00
Alejandro Celaya
9ee709f0f3 Make DeleteExpiredShortUrlsCommand invokable 2025-11-01 12:18:29 +01:00
Alejandro Celaya
0fe28a5eb5 Make MatomoSendVisitsCommand invokable 2025-11-01 11:56:40 +01:00
Alejandro Celaya
2142afae89 Make ListDomainsCommand invokable 2025-11-01 11:50:43 +01:00
Alejandro Celaya
e7f4b84c65 Make DomainRedirectsCommand invokable 2025-11-01 11:45:27 +01:00
Alejandro Celaya
2d83b8d046 Make InitialApiKeyCommand invokable 2025-11-01 11:41:50 +01:00
Alejandro Celaya
dfef735c89 Make ReadEnvVarCommand invokable 2025-11-01 11:38:10 +01:00
Alejandro Celaya
c34c4e0eea
Merge pull request #2508 from acelaya-forks/php-8.5-support
Add support for PHP 8.5
2025-11-01 11:04:08 +01:00
Alejandro Celaya
f024fd414e Add support for PHP 8.5 2025-11-01 10:13:00 +01:00
Alejandro Celaya
12d81c3213 Update changelog 2025-11-01 10:03:03 +01:00
Alejandro Celaya
628fb9ebb5
Merge pull request #2503 from acelaya-forks/domain-visits-filter
Allow tags, orphan and non-orphan visits lists to be filtered by domain
2025-11-01 10:02:32 +01:00
Alejandro Celaya
e21cea1971 Add API tests for visits domain filtering 2025-11-01 09:56:15 +01:00
Alejandro Celaya
37088b1a4b Allow filtering orphan visits by domain via DEFAULT keyword 2025-10-31 08:53:31 +01:00
Alejandro Celaya
b5f8e8a4cd Document domain param for visits endpoints 2025-10-30 10:23:00 +01:00
Alejandro Celaya
a236f19dc4 Allow filtering by domain in VisitRepository::findNonOrphanVisits 2025-10-30 10:08:46 +01:00
Alejandro Celaya
94426c7bf4 Allow filtering by domain in VisitRepository::findOrphanVisits 2025-10-30 09:04:51 +01:00
Alejandro Celaya
9dcc51abde Allow filtering by domain in VisitRepository::findVisitsByTag 2025-10-29 12:04:36 +01:00
Alejandro Celaya
70e376d569 Allow domain to be passed to tag:visits, visit:orphan and visit:non-orphan commands 2025-10-29 08:43:01 +01:00
Alejandro Celaya
14a7e3bb05 Allow tags, orphan and non-orphan visits to be provided a domain filter param 2025-10-28 11:08:33 +01:00
Alejandro Celaya
10dab5be20
Merge pull request #2504 from acelaya-forks/remove-set-accessible
Remove all calls to ReflectionProperty::setAccessible
2025-10-28 11:08:03 +01:00
Alejandro Celaya
532700028a Remove all calls to ReflectionProperty::setAccessible 2025-10-28 11:03:41 +01:00
Alejandro Celaya
fc54a25c32
Merge pull request #2501 from acelaya-forks/redis-sentinels-acl
Add support for redis credentials when using sentinels
2025-10-27 10:47:36 +01:00
Alejandro Celaya
ba16ba45f2 Add support for redis credentials when using sentinels 2025-10-27 10:16:57 +01:00
Alejandro Celaya
51c732a013 Document support for frankenphp in changelog 2025-10-24 08:45:52 +02:00
Alejandro Celaya
0f17990821
Merge pull request #2499 from acelaya-forks/api-key-filter
Allow filtering short URLs by API key name
2025-10-22 08:40:33 +02:00
Alejandro Celaya
02500143c1 Update changelog 2025-10-22 08:31:04 +02:00
Alejandro Celaya
9c22c7fc9c Add more tests for apiKeyName short URLs filtering 2025-10-22 08:28:45 +02:00
Alejandro Celaya
7860225c25 Add api-key-name option to short-url:list command 2025-10-22 08:04:29 +02:00
Alejandro Celaya
506ed6207f Allow filtering short URLs by API key name 2025-10-21 12:25:06 +02:00
Alejandro Celaya
30ed1d7c6b
Merge pull request #2497 from acelaya-forks/delete-api-key
Add new command to delete API keys
2025-10-20 15:06:50 +02:00
Alejandro Celaya
b5a9353b85 Add new command to delete API keys 2025-10-20 10:34:53 +02:00
Alejandro Celaya
cae18ccfb3
Merge pull request #2495 from acelaya-forks/tags-option
Extract tags option to its own Option class
2025-10-20 09:02:15 +02:00
Alejandro Celaya
f876769b67 Extract tags option to its own Option class 2025-10-20 08:58:07 +02:00
Alejandro Celaya
2b06f56a9a
Merge pull request #2492 from acelaya-forks/feature/exclude-tags
Allow listing short URLs which DO NOT include certain tags
2025-10-17 09:33:51 +02:00
Alejandro Celaya
1c38ab1217 Add exclude-tags CLI tests 2025-10-17 09:26:18 +02:00
Alejandro Celaya
fb9e8cd79f Update changelog 2025-10-17 08:56:26 +02:00
Alejandro Celaya
eb199a61da Add exclude-tags API tests 2025-10-17 08:52:25 +02:00
Alejandro Celaya
25de0263c5 Deprecate --tags and add --tag for short-url:list command 2025-10-17 08:35:41 +02:00
Alejandro Celaya
41c03a66e4 Fix static analysis 2025-10-16 19:16:11 +02:00
Alejandro Celaya
13c1b12d84 Update logic in ShortUrlListRepository to take excluded tags into consideration 2025-10-16 19:16:11 +02:00
Alejandro Celaya
fe10aaf245 Make --tags option allow multiple values in list short URLs command 2025-10-16 19:16:11 +02:00
Alejandro Celaya
464e3d7f8e Support excludeTags and excludeTagsMode in list short URLs command 2025-10-16 19:16:11 +02:00
Alejandro Celaya
ac40a7021b Document excludeTags and excludeTagsMode params for short URLs list 2025-10-16 19:16:11 +02:00
Alejandro Celaya
c60a5e750b Reference Jetbrains in README 2025-10-16 15:08:29 +02:00
Alejandro Celaya
785f728afc
Merge pull request #2493 from acelaya-forks/fix-phpstan
Fix issue reported by phpstan in CrossDomainMiddleware
2025-10-16 10:16:33 +02:00
Alejandro Celaya
648696f778 Fix issue reported by phpstan in CrossDomainMiddleware 2025-10-16 10:08:24 +02:00
Alejandro Celaya
774a579a94 Add v4.5.3 to changelog 2025-10-10 10:29:06 +02:00
Alejandro Celaya
98bbb01165 Update coding standard 2025-10-06 08:46:34 +02:00
Alejandro Celaya
0bcb9e0438 Update changelog 2025-10-03 10:24:38 +02:00
Alejandro Celaya
edb8b57a48
Merge pull request #2489 from acelaya-forks/feature/cors-credentials-fix
Make sure Access-Control-Allow-Credentials is always set if configured
2025-10-03 10:23:02 +02:00
Alejandro Celaya
b01f271f72 Make sure Access-Control-Allow-Credentials is always set if configured 2025-10-03 10:15:27 +02:00
Alejandro Celaya
98b504a2de
Merge pull request #2484 from acelaya-forks/feature/memory-efficient-geolite
Make GeoLite db download memory efficient
2025-09-11 09:39:32 +02:00
Alejandro Celaya
075e6347b6 Make GeoLite db download memory efficient 2025-09-11 09:28:44 +02:00
Alejandro Celaya
92a70b8c11
Merge pull request #2477 from acelaya-forks/feature/frankenphp
Add a development FrankenPHP server
2025-08-28 09:01:41 +02:00
Alejandro Celaya
613c7b7368
Merge pull request #2480 from acelaya-forks/feature/garbage-collection
Garbage collect after every request
2025-08-27 09:41:38 +02:00
Alejandro Celaya
232f6e37c6 Ensure pipeline is not marked as failed if only v8.5 fails 2025-08-27 09:30:41 +02:00
Alejandro Celaya
c818d5603d Garbage collect after every request 2025-08-27 09:24:28 +02:00
Alejandro Celaya
766b227e47 Add a development FrankenPHP server 2025-08-26 08:52:22 +02:00
Alejandro Celaya
95be5a93fc
Merge pull request #2478 from acelaya-forks/feature/memory-leak-mitigation
Try to mitigate memory leaks when using RoadRunner
2025-08-24 11:23:57 +02:00
Alejandro Celaya
20c41690da Try to mitigate memory leaks when using RoadRunner 2025-08-24 11:18:40 +02:00
Alejandro Celaya
22b5fa5a83
Merge pull request #2474 from acelaya-forks/feature/symfony-lock
Update to symfony/lock ^7.3.2
2025-08-01 08:28:05 +02:00
Alejandro Celaya
0c4d1b6d2f Update to symfony/lock ^7.3.2 2025-08-01 08:21:37 +02:00
Alejandro Celaya
d2514b7555
Merge pull request #2470 from acelaya-forks/feature/release-4.5.0
Add v4.5.0 to changelog
2025-07-24 12:11:03 +02:00
Alejandro Celaya
2d5734fc8b Add v4.5.0 to changelog 2025-07-24 12:07:11 +02:00
Alejandro Celaya
478ac344ff
Merge pull request #2469 from acelaya-forks/feature/logs-encoding
Allow logs format to be configured as console or JSON
2025-07-24 10:01:36 +02:00
Alejandro Celaya
e40b82618a Allow logs format to be configured as console or JSON 2025-07-24 09:57:34 +02:00
Alejandro Celaya
51dd671174
Merge pull request #2467 from acelaya-forks/feature/nullable-match-value
Make RedirectCondition->matchValue nullable
2025-07-22 08:32:25 +02:00
Alejandro Celaya
5b5d0aae49 Make RedirectCondition->matchValue nullable 2025-07-22 08:28:09 +02:00
Alejandro Celaya
56df880a93
Merge pull request #2466 from acelaya-forks/feature/php-8.5
Run tests under PHP 8.5 in CI
2025-07-21 10:38:02 +02:00
Alejandro Celaya
afa509613a Run tests under PHP 8.5 in CI 2025-07-21 10:30:35 +02:00
Alejandro Celaya
3be49a25a0
Merge pull request #2465 from acelaya-forks/feature/redirect-cache-visibility
Allow redirect cache visibility to be configured
2025-07-21 10:21:36 +02:00
Alejandro Celaya
8b259b364d Allow redirect cache visibility to be configured 2025-07-21 10:13:17 +02:00
Alejandro Celaya
13d9b7b0a7
Merge pull request #2464 from acelaya-forks/feature/desktop-devices
Add support for more device types in device-specific redirects
2025-07-20 12:02:11 +02:00
Alejandro Celaya
2b33095392 Add support for more device types in device-specific redirects 2025-07-20 11:56:33 +02:00
Alejandro Celaya
3a1ce40a49
Merge pull request #2461 from acelaya-forks/feature/trusted-proxies
Allow trusted proxies to be provided via TRUSTED_PROXIES env var or config option
2025-07-18 08:32:48 +02:00
Alejandro Celaya
a68300f19a Fix phpstan report 2025-07-18 08:29:16 +02:00
Alejandro Celaya
3318987d63 Allow providing hop count via TRUSTED_PROXIES 2025-07-18 08:24:57 +02:00
Alejandro Celaya
1f825797f6 Allow trusted proxies to be provided via TRUSTED_PROXIES env var 2025-07-17 09:57:34 +02:00
Alejandro Celaya
650fafb7c4 Register ReverseForwardedAddressesMiddlewareDecorator via ServiceManager delegator 2025-07-17 09:47:02 +02:00
Alejandro Celaya
978e24d6fa
Merge pull request #2460 from acelaya-forks/feature/enhanced-query-param-rules
Add support for any-value and valueless query param redirect rules
2025-07-17 08:57:30 +02:00
Alejandro Celaya
c3d3cc6288 Test RedirectConditionType::isValid() in isolation 2025-07-17 08:51:59 +02:00
Alejandro Celaya
223901324f Enhance RedirectRuleHandlerTest with new query-param-related conditions 2025-07-17 08:44:19 +02:00
Alejandro Celaya
47293be85c Enhance RedirectConditionTest with new query-param-related conditions 2025-07-17 08:39:37 +02:00
Alejandro Celaya
18c4c39fee Add support for any-value and valueless query param redirect rules 2025-07-17 08:31:29 +02:00
Alejandro Celaya
e762d28b67
Merge pull request #2455 from acelaya-forks/feature/cors-customization
Add new CORS configuration options
2025-07-16 08:41:42 +02:00
Alejandro Celaya
f5c6bc8204 Update changelog 2025-07-16 08:39:12 +02:00
Alejandro Celaya
3369afe22c Add CorsOptions test 2025-07-16 08:29:57 +02:00
Alejandro Celaya
1d96cc0279 Update CrossDomainMiddleware test 2025-07-08 13:17:46 +02:00
Alejandro Celaya
cd4fcc9b0a Update shlink-installer 2025-07-08 13:07:04 +02:00
Alejandro Celaya
834bc4ae20 Allow credentials to be enabled in CORS 2025-07-08 10:36:12 +02:00
Alejandro Celaya
92d7a44cee Add new CORS configuration options 2025-07-05 10:34:50 +02:00
Alejandro Celaya
c8e3b3df0a Update changelog 2025-07-04 18:31:20 +02:00
Alejandro Celaya
77244b52c9
Merge pull request #2454 from acelaya-forks/feature/real-time-updates-options
Allow individual real-time updates topics to be enabled
2025-07-04 18:29:12 +02:00
Alejandro Celaya
9e93e34e12 Add test to cover when visit updates topics are disabled 2025-07-04 18:25:45 +02:00
Alejandro Celaya
733b2e5647 Add test to cover when short URL updates topic is disabled 2025-07-04 18:04:27 +02:00
Alejandro Celaya
26fef87f3b Add RealTimeUpdatesOptions test 2025-07-04 10:07:40 +02:00
Alejandro Celaya
f4aaf02d55 Reduce duplicated code between enumValues and enumNames 2025-07-04 09:52:35 +02:00
Alejandro Celaya
314a99862d Update to latest shlink-installer with real-time updates support 2025-07-03 18:35:14 +02:00
Alejandro Celaya
240d9df177 Validate topic names in RealTimeUpdateOptions 2025-07-03 14:34:27 +02:00
Alejandro Celaya
fb995f2bea Allow individual real-time updates topics to be enabled 2025-07-03 10:10:06 +02:00
Alejandro Celaya
436be1985c
Merge pull request #2452 from acelaya-forks/feature/invokable-command-poc
Use invokable commands approach on some API console commands
2025-06-26 08:46:20 +02:00
Alejandro Celaya
850e8574e9 Use invokable commands approach on some API console commands 2025-06-26 08:41:18 +02:00
Alejandro Celaya
c2743cb488
Merge pull request #2453 from acelaya-forks/feature/phpunit-warnings
Adjust tests to fix warnings
2025-06-26 08:40:10 +02:00
Alejandro Celaya
f1157aa177 Adjust tests to fix warnings 2025-06-24 19:47:18 +02:00
Alejandro Celaya
497429e685 Forward questions to the global discussions repo 2025-06-23 10:14:18 +02:00
Alejandro Celaya
2cad5dd435 Update to roadrunner 2025.1 2025-05-27 14:23:49 +02:00
Alejandro Celaya
f38f1ae5da
Merge pull request #2439 from acelaya-forks/feature/mercure-enabled
Add new MERCURE_ENABLED env var
2025-05-22 08:29:23 +01:00
Alejandro Celaya
9c1db35d81 Add new MERCURE_ENABLED env var 2025-05-22 09:20:50 +02:00
Alejandro Celaya
11b8943919
Merge pull request #2432 from acelaya-forks/feature/docker-env-syntax
Update syntax used for env vars in Dockerfiles
2025-05-06 12:25:14 +02:00
Alejandro Celaya
27d24a4f15 Update syntax used for env vars in Dockerfiles 2025-05-06 11:56:49 +02:00
Alejandro Celaya
b2dbc4cf52
Fix typo in Dockerfile 2025-05-04 15:57:29 +02:00
Alejandro Celaya
1a7a745f2e
Update Dockerfile marking image-related extensions as delegated 2025-05-04 15:56:44 +02:00
Alejandro Celaya
99bc1a21dd
Merge pull request #2425 from acelaya-forks/feature/command-exit-codes
Replace ExitCode with standard symfony Command constants
2025-04-22 19:49:16 +02:00
Alejandro Celaya
cea8a982e2 Replace ExitCode with standard symfony Command constants 2025-04-22 12:07:41 +02:00
Alejandro Celaya
8bd1c6a79a
Merge pull request #2423 from acelaya-forks/feature/remove-bootstrap
Remove references to bootstrap from error templates
2025-04-22 09:12:08 +02:00
Alejandro Celaya
71a3b993b1 Remove references to bootstrap from error templates 2025-04-22 09:09:52 +02:00
Alejandro Celaya
6e25e3c31d
Merge pull request #2422 from acelaya-forks/feature/deprecate-qr-codes
Deprecate QR code generation endpoint
2025-04-22 08:50:34 +02:00
Alejandro Celaya
b15e832cf4 Deprecate QR code generation endpoint 2025-04-22 08:47:37 +02:00
Alejandro Celaya
851929ebef
Merge pull request #2403 from acelaya-forks/feature/phpunit-phpstan-fixes
Fix compatibility with PHPUnit 12.0.9 and phpstan-phpunit
2025-03-24 19:36:44 +01:00
Alejandro Celaya
87d5f9bc75 Fix compatibility with PHPUnit 12.0.9 and phpstan-phpunit 2025-03-24 19:33:52 +01:00
Alejandro Celaya
b7d9ba8258
Merge pull request #2397 from acelaya-forks/feature/endroid-fix
Fix error intrduced by endroid/qr-code 6.0.4
2025-03-20 09:19:58 +01:00
Alejandro Celaya
6526cf8c44 Fix error intrduced by endroid/qr-code 6.0.4 2025-03-20 09:16:53 +01:00
Alejandro Celaya
a85afb2bee
Merge pull request #2394 from acelaya-forks/feature/fix-artifact-removal
Update geekyeggo/delete-artifact action to v5
2025-03-14 18:00:47 +01:00
Alejandro Celaya
8b4067efbe Update geekyeggo/delete-artifact action to v5 2025-03-14 17:57:55 +01:00
Alejandro Celaya
c7c2272fab Update changelog 2025-03-14 17:53:23 +01:00
Alejandro Celaya
bc77750713
Merge pull request #2392 from wuuei/patch-1
Fix Matomo country logging by sending country code instead of country
2025-03-14 17:51:37 +01:00
Alejandro Celaya
1ceb38f50b Test actual arguments set to matomo tracker when sending visits 2025-03-14 17:40:37 +01:00
wuuei
d273b56144 Lock "endroid/qr-code" to 6.0.3 so that unit tests complete 2025-03-14 15:21:55 +00:00
wuuei
5cd7305666 Fix code style to resolve failing check 2025-03-14 15:20:49 +00:00
wuuei
3040a22c02
Fix Matomo country logging by sending country code instead of country name
Matomo expects the country code in lowercase for accurate logging and proper flag display
2025-03-13 15:33:00 +01:00
Alejandro Celaya
5eb1808217
Update CHANGELOG.md with V4.4.5 2025-03-01 09:14:37 +01:00
Alejandro Celaya
5eb14c5315
Merge pull request #2375 from acelaya-forks/feature/deprecation-error-reporting
Disable deprecation warnings when running in production envs
2025-02-21 21:18:44 +01:00
Alejandro Celaya
a18360a4d6 Disable deprecation warnings when running in production envs 2025-02-21 21:13:29 +01:00
Alejandro Celaya
af2d67695b
Merge pull request #2370 from acelaya-forks/feature/missing-join-fix
Fix 500 error when listing non-orphan visits with short-url-depending API key
2025-02-19 19:37:36 +01:00
Alejandro Celaya
449a588796 Fix 500 error when listing non-orphan visits with short-url-depending API key 2025-02-19 19:33:44 +01:00
Alejandro Celaya
7bbc938743
Merge pull request #2369 from acelaya-forks/feature/redis-cluster-fix
Downgrade to symfony/lock 7.1.6
2025-02-19 17:55:53 +01:00
Alejandro Celaya
766758ff9b Downgrade to symfony/lock 7.1.6 2025-02-19 17:45:52 +01:00
Alejandro Celaya
63d943d59d
Merge pull request #2363 from acelaya-forks/feature/find-url-perf
Fix unique_short_code_plus_domain index in Microsoft SQL
2025-02-15 11:24:26 +01:00
Alejandro Celaya
053e1f3073 Update changelog 2025-02-15 11:19:30 +01:00
Alejandro Celaya
f3da345bf3 Fix unique_short_code_plus_domain index in Microsoft SQL 2025-02-15 11:17:14 +01:00
Alejandro Celaya
745255736a Simplify query to find short URL when domain is null 2025-02-14 10:20:50 +01:00
Alejandro Celaya
8fd53afe3f
Merge pull request #2361 from acelaya-forks/feature/lock-downgrade
Downgrade symfony/lock to v7.2.0 to work around redis issue
2025-02-14 08:52:33 +01:00
Alejandro Celaya
259635ea2a Downgrade symfony/lock to v7.2.0 to work around redis issue 2025-02-14 08:40:06 +01:00
Alejandro Celaya
a1f2e6dc5c
Merge pull request #2359 from acelaya-forks/feature/multi-proxy-fix
Workaround for IP resolution from x-Forwarded-For with multiple proxies
2025-02-13 22:03:36 +01:00
Alejandro Celaya
81e07bf08d
Merge pull request #2358 from acelaya-forks/feature/phpunit-12
Update to PHPUnit 12
2025-02-13 21:59:00 +01:00
Alejandro Celaya
c650a3e665 Workaround for IP resolution from x-Forwarded-For with multiple proxies 2025-02-13 21:52:38 +01:00
Alejandro Celaya
65c01034ff Update to PHPUnit 12 2025-02-13 10:35:58 +01:00
Alejandro Celaya
48f910aaaa
Merge pull request #2355 from acelaya-forks/feature/openapi-warnings
Remove suppressed warnings when running openapi tools
2025-02-05 08:43:28 +01:00
Alejandro Celaya
e511e15a87 Remove suppressed warnings when running openapi tools 2025-02-05 08:39:22 +01:00
Alejandro Celaya
ed09bf90eb Tag v4.4.2 in changelog 2025-01-29 12:05:53 +01:00
Alejandro Celaya
0ddfcb75dd
Merge pull request #2347 from acelaya-forks/feature/docker-arm
Get back docker image building for ARM architecture
2025-01-29 12:02:19 +01:00
Alejandro Celaya
193be55f0c Get back docker image building for ARM architecture 2025-01-29 11:59:42 +01:00
Alejandro Celaya
7ffb64eee1 Do not build docker image for ARM 2025-01-28 15:51:20 +01:00
Alejandro Celaya
0a2cc554c6 Build docker image with buildx 0.19.2 2025-01-28 15:38:47 +01:00
Alejandro Celaya
af783dea57 Add v4.4.1 to changelog 2025-01-28 10:12:15 +01:00
Alejandro Celaya
a68a17f6b4
Merge pull request #2343 from acelaya-forks/feature/defensive-title-encoding
Fix error when creating short URL for page with unsupported encoding
2025-01-28 10:11:04 +01:00
Alejandro Celaya
e9fe1ac5d4 Fix error when creating short URL for page with unsupported encoding 2025-01-28 10:04:30 +01:00
Alejandro Celaya
88e97f18ad
Merge pull request #2342 from acelaya-forks/feature/too-many-connections
Close connections after every async job that uses the db
2025-01-27 15:48:22 +01:00
Alejandro Celaya
3372a2a9c8 Close connections after every async job that uses the db 2025-01-27 15:45:37 +01:00
Alejandro Celaya
f02a8c876c
Merge pull request #2340 from acelaya-forks/feature/update-shlink-deps
Update shlink packages
2025-01-25 16:16:42 +01:00
Alejandro Celaya
1549509eb8 Update shlink packages 2025-01-25 16:13:40 +01:00
Alejandro Celaya
62fde5a8e2 Update changelog 2025-01-13 08:47:19 +01:00
Alejandro Celaya
221e061ea6
Merge pull request #2332 from MaZe3D/develop
Add ADDRESS environment vairable to define the listening interface.
2025-01-13 08:45:20 +01:00
Mark Orlando Zeller
9ad565f8c8 Add ADDRESS environment vairable to define the listening interface. 2025-01-10 22:10:51 +01:00
Alejandro Celaya
11fa28e489
Merge pull request #2316 from acelaya-forks/feature/v4.4
Add v4.4.0 to changelog and update dependencies
2024-12-27 16:27:06 +01:00
Alejandro Celaya
d7e51b388e Add v4.4.0 to changelog and update dependencies 2024-12-27 16:24:25 +01:00
Alejandro Celaya
5ef2df3d53
Merge pull request #2315 from acelaya-forks/feature/import-redirect-rules
Implement logic to import redirect rules from other Shlink instances
2024-12-22 18:50:10 +01:00
Alejandro Celaya
9c251b3646 Update changelog 2024-12-22 18:41:58 +01:00
Alejandro Celaya
2807b9ce2f Fix ImportedLinksProcessorTest 2024-12-22 18:41:03 +01:00
Alejandro Celaya
2f39aff2fe Implement logic to import redirect rules from other Shlink instances 2024-12-22 12:42:06 +01:00
Alejandro Celaya
b8d7917691
Merge pull request #2314 from acelaya-forks/feature/database-ssl
Support encrypted connections to MySQL/Maria and Postgres
2024-12-20 09:54:59 +01:00
Alejandro Celaya
d228c16f82 Fix test for ip middleware 2024-12-20 09:52:30 +01:00
Alejandro Celaya
c34bfac6b1 Update installer with support for DB_USE_ENCRYPTION option 2024-12-20 09:29:28 +01:00
Alejandro Celaya
4e7d09035a Support encrypted connections to MySQL/Maria and Postgres 2024-12-19 09:00:01 +01:00
Alejandro Celaya
83570f5c25
Merge pull request #2313 from acelaya-forks/feature/qr-disable-logo
Allow QR code logo to be individually disabled
2024-12-18 09:14:47 +01:00
Alejandro Celaya
6ad8b03850 Allow QR code logo to be individually disabled 2024-12-18 09:10:53 +01:00
Alejandro Celaya
736e09adfe
Merge pull request #2310 from acelaya-forks/feature/less-restrictive-custom-slugs
Be less restrictive on what characters are disallowed in custom slugs
2024-12-17 18:08:51 +01:00
Alejandro Celaya
e80af78e09 Be less restrictive on what characters are disallowed in custom slugs 2024-12-17 18:04:38 +01:00
Alejandro Celaya
d533adf7ce
Merge pull request #2308 from acelaya-forks/feature/geolocation-updates
Improve how geolocation DB files are downloaded/updated
2024-12-16 20:21:35 +01:00
Alejandro Celaya
509ef668e6 Fix GeolocationDbUpdater test 2024-12-16 19:50:06 +01:00
Alejandro Celaya
e715a0fb6f Track reason for which a geolocation db download was attempted 2024-12-16 09:23:30 +01:00
Alejandro Celaya
72a962ec6d Handle differently when trying to update geolocation and already in progress 2024-12-15 12:03:01 +01:00
Alejandro Celaya
853c50a819 Fix some cases of database download in GeolocationDbUpdater 2024-12-15 11:34:38 +01:00
Alejandro Celaya
f10a9d3972 Simplify geolocation_db_updates indexes 2024-12-15 10:08:22 +01:00
Alejandro Celaya
a77e07f906 Refactor geolocation download logic based on database table 2024-12-15 10:05:32 +01:00
Alejandro Celaya
d4d97c3182 Create new table to track geolocation updates 2024-12-13 10:33:53 +01:00
Alejandro Celaya
55724dbff6
Merge pull request #2306 from acelaya-forks/feature/update-docker-images
Update docker images to Alpine 3.21
2024-12-12 09:06:49 +01:00
Alejandro Celaya
9e34183901 Update docker images to Alpine 3.21 2024-12-12 08:52:01 +01:00
Alejandro Celaya
88c283952c
Merge pull request #2304 from acelaya-forks/feature/geolocation-services-refactor
Move GeolocationDbUpdater to Core module
2024-12-11 08:58:23 +01:00
Alejandro Celaya
2ede615da8 Fix DownloadGeoLiteDbCommandTest 2024-12-11 08:50:56 +01:00
Alejandro Celaya
84d12f6811 Move GeolocationDbUpdaterTest to Core module 2024-12-11 08:47:13 +01:00
Alejandro Celaya
4f3c2c7d2d Fix UpdateGeoLiteDbTest 2024-12-11 08:35:24 +01:00
Alejandro Celaya
b8ac9f3673 Add more strict parameter for GeolocationDbUpdater 2024-12-11 08:27:56 +01:00
Alejandro Celaya
06c0a94b31 Move GeolocationDbUpdater from CLI to Core module 2024-12-10 10:58:08 +01:00
Alejandro Celaya
5d12b1d952
Merge pull request #2302 from acelaya-forks/feature/openapi-names
Use the openapi terminology over swagger
2024-12-06 11:40:15 +01:00
Alejandro Celaya
85c4c09afa Use the openapi terminology over swagger 2024-12-06 11:36:47 +01:00
Alejandro Celaya
e7c83d0b38
Merge pull request #2300 from acelaya-forks/feature/drop-8.2-support
Drop support for PHP 8.2
2024-12-02 09:21:50 +01:00
Alejandro Celaya
58de998596 Drop support for PHP 8.2 2024-12-02 09:16:15 +01:00
Alejandro Celaya
bfaab6c494
Merge pull request #2298 from acelaya-forks/feature/ignore-extra-path
Allow the extra path to be ignored when redirecting
2024-12-01 12:37:56 +01:00
Alejandro Celaya
d83081f4e9 Update shlink-installer 2024-12-01 12:28:29 +01:00
Alejandro Celaya
c65349d265 Allow the extra path to be ignored when redirecting 2024-12-01 09:56:09 +01:00
Alejandro Celaya
e74ee793a0
Merge pull request #2297 from acelaya-forks/feature/docker-php-8.4
Update docker images to PHP 8.4
2024-11-30 18:35:03 +01:00
Alejandro Celaya
ede58efe96 Update docker images to PHP 8.4 2024-11-30 13:53:19 +01:00
Alejandro Celaya
3f30af4794
Merge pull request #2294 from acelaya-forks/feature/user-agent
Migrate from mobiledetectlib to phpuseragentparser
2024-11-28 12:11:29 +01:00
Alejandro Celaya
6331fa3ed3 Migrate from mobiledetectlib to phpuseragentparser 2024-11-28 12:05:10 +01:00
Alejandro Celaya
d121d4d496
Merge pull request #2289 from acelaya-forks/feature/delete-old-migrations
Delete some old migrations
2024-11-28 09:00:40 +01:00
Alejandro Celaya
8499087a3b Move DEFAULT_DOMAIN constant to domains module 2024-11-28 08:54:29 +01:00
Alejandro Celaya
bb72c96ebb Delete some old migrations 2024-11-26 10:17:28 +01:00
Alejandro Celaya
557c74286b Add v4.3.1 to changelog 2024-11-25 23:45:02 +01:00
Alejandro Celaya
67abe21716
Merge pull request #2287 from acelaya-forks/feature/ms-index-fix
Fix columns order in unique_short_code_plus_domain index in MSSQL
2024-11-25 23:43:55 +01:00
Alejandro Celaya
33cea36b15 Fix columns order in unique_short_code_plus_domain index in MSSQL 2024-11-25 22:48:04 +01:00
Alejandro Celaya
4e8f3f737a
Merge pull request #2286 from acelaya-forks/feature/crawler-detect
Use jaybizzle/crawler-detect instead of acelaya/crawler-detect
2024-11-25 22:21:14 +01:00
Alejandro Celaya
35b835ec7b Use jaybizzle/crawler-detect instead of acelaya/crawler-detect 2024-11-25 22:17:15 +01:00
Alejandro Celaya
eff4f1fca3
Merge pull request #2284 from acelaya-forks/feature/rka-ip-address
Go back to using akrabat/ip-address-middleware instead of acelaya/ip-address-middleware
2024-11-25 09:31:43 +01:00
Alejandro Celaya
6f6388b2fc Go back to using akrabat/ip-address-middleware instead of acelaya/ip-address-middleware 2024-11-25 09:23:43 +01:00
Alejandro Celaya
19f56e7ab0 Add v4.3.0 to changelog 2024-11-24 14:26:09 +01:00
Alejandro Celaya
6a96b72b94 Add real version constraints for Shlink packages 2024-11-24 14:23:12 +01:00
Alejandro Celaya
7634f55587
Merge pull request #2282 from acelaya-forks/feature/track-redirect-url
Add redirect_url field to track where a visitor is redirected for a visit
2024-11-24 14:20:12 +01:00
Alejandro Celaya
571a4643ab Update changelog 2024-11-24 14:13:59 +01:00
Alejandro Celaya
d5544554ef Improve API docs description for redirectUrl fields 2024-11-24 14:08:23 +01:00
Alejandro Celaya
85065c9330 Test behavior to track redirect URL 2024-11-24 14:05:33 +01:00
Alejandro Celaya
86cc2b717c Save where a visitor is redirected for any kind of tracked visit 2024-11-24 13:21:48 +01:00
Alejandro Celaya
89f70114e4 Fix typo in migration 2024-11-24 13:18:32 +01:00
Alejandro Celaya
8274525f75 Add redirect_url field to track where a visitor is redirected for a visit 2024-11-24 12:53:49 +01:00
Alejandro Celaya
fef512a7a3
Merge pull request #2280 from acelaya-forks/feature/php-8.4-support
Feature/php 8.4 support
2024-11-24 11:41:59 +01:00
Alejandro Celaya
deb9d4bdc7 Update docker images to Alpine 3.20 2024-11-24 11:37:08 +01:00
Alejandro Celaya
259aadfdb2 Update changelog 2024-11-24 11:05:36 +01:00
Alejandro Celaya
fe660654ed Add PHP 8.4 to the release pipeline 2024-11-24 11:04:41 +01:00
Alejandro Celaya
b2fc19af44 Replace akrabat/ip-address-middleware with acelaya/ip-address-middleware 2024-11-24 11:04:14 +01:00
Alejandro Celaya
7434616a8d Update mobiledetect/mobiledetectlib to a commit including PHP 8.4 fixes 2024-11-24 10:55:55 +01:00
Alejandro Celaya
fbf1aabcf5 Replace jaybizzle/crawler-detect with acelaya/crawler-detect 2024-11-24 10:49:44 +01:00
Alejandro Celaya
8ee905882f
Merge pull request #2277 from acelaya-forks/feature/ip-address-factory
Use `IpAddressFactory` from akrabat/ip-address-middleware
2024-11-22 09:13:01 +01:00
Alejandro Celaya
2946b630c5 Use IpAddressFactory from akrabat/ip-address-middleware 2024-11-22 09:01:27 +01:00
Alejandro Celaya
b2bfe9799a
Merge pull request #2276 from acelaya-forks/feature/visits-list-duplication
Reduce duplication in actions listing visits
2024-11-20 09:51:54 +01:00
Alejandro Celaya
d7e300e2d5 Reduce duplication in actions listing visits 2024-11-20 09:48:12 +01:00
Alejandro Celaya
0c75202936
Merge pull request #2273 from acelaya-forks/feature/remove-laminas-config
Remove dependency on laminas config
2024-11-19 20:15:28 +01:00
Alejandro Celaya
81bed53f90 Update Shlink libraries to remove dependency on laminas-config 2024-11-19 20:12:38 +01:00
Alejandro Celaya
a56ff1293e Remove direct dependency on laminas/laminas-config 2024-11-19 09:18:06 +01:00
Alejandro Celaya
c323bfcd63
Merge pull request #2272 from acelaya-forks/feature/geolocate-localhost-fix
Make sure IpGeolocationMiddleware skips localhost
2024-11-19 09:14:45 +01:00
Alejandro Celaya
f57f159002 Remove no longer used Visit::isLocatable method 2024-11-19 09:10:47 +01:00
Alejandro Celaya
fa08014226 Make sure IpGeolocationMiddleware skips localhost 2024-11-19 09:08:04 +01:00
Alejandro Celaya
052c9e76a1
Merge pull request #2271 from acelaya-forks/feature/api-key-domain-exceptions
Use more meaningful domain exceptions to represent ApiKeyService thrown errors
2024-11-18 09:59:25 +01:00
Alejandro Celaya
8298ef36f8 Use more meaningful domain exceptions to represent ApiKeyService thrown errors 2024-11-18 09:51:27 +01:00
Alejandro Celaya
b11d5c6864 Do not ignore platform reqs when using PHP 8.4 2024-11-18 08:50:20 +01:00
Alejandro Celaya
08394431f8
Merge pull request #2269 from acelaya-forks/feature/no-php-8.4-error
Do not allow pipelines to continue on error
2024-11-17 10:25:33 +01:00
Alejandro Celaya
a9ae4a24d0 Do not allow pipelines to continue on error 2024-11-17 10:15:25 +01:00
Alejandro Celaya
9b7b91402c
Merge pull request #2268 from acelaya-forks/feature/delete-visits-fix
Fix visits counts not being deleted when deleting short URL or orphan visits
2024-11-15 19:26:57 +01:00
Alejandro Celaya
178a99b993 Fix visits counts not being deleted when deleting short URL or orphan visits 2024-11-15 19:22:29 +01:00
Alejandro Celaya
a8f046dfff
Merge pull request #2266 from acelaya-forks/feature/geolocation-middleware
Feature/geolocation middleware
2024-11-15 10:47:18 +01:00
Alejandro Celaya
42ff0d5b69 Create IpGeolocationMiddlewareTest 2024-11-15 10:17:56 +01:00
Alejandro Celaya
6aaea2ac26 Simplify logic in RedirectRule when checking geolocation conditions 2024-11-15 09:00:59 +01:00
Alejandro Celaya
b5ff568651 Use IpGeolocationMiddleware to geolocate visitors instead of LocateVisit event 2024-11-15 08:55:43 +01:00
Alejandro Celaya
4a0b7e3fc9 Refactor Visitor model and allow a Location object to be passed to it 2024-11-14 14:48:18 +01:00
Alejandro Celaya
1fee745786
Merge pull request #2263 from acelaya-forks/feature/geolocation-city-name-redirects
Add support for city name dynamic redirects
2024-11-14 10:07:01 +01:00
Alejandro Celaya
a6e0916272 Add support for city name dynamic redirects 2024-11-14 09:58:53 +01:00
Alejandro Celaya
dbef32ffcb
Merge pull request #2257 from acelaya-forks/feature/geolocation-country-code-redirects
Add new geolocatio-country-code redirect condition type
2024-11-14 09:43:10 +01:00
Alejandro Celaya
7ddb3e7a70 Add tests covering country code validation 2024-11-14 09:40:10 +01:00
Alejandro Celaya
fd34332e69 Improve ExtraPathRedirectMiddlewareTest 2024-11-14 09:28:10 +01:00
Alejandro Celaya
51d838870d Add reference to ISO 3166-1 alpha-2 country codes wikipedia page 2024-11-14 09:14:17 +01:00
Alejandro Celaya
4619ebd014 After tracking a visit, set its location in the request as attribute 2024-11-14 08:21:16 +01:00
Alejandro Celaya
f2371b6124 Update RedirectRuleHandlerTest 2024-11-13 10:01:52 +01:00
Alejandro Celaya
b5b5f92eda Add validation for country-code redirect conditions 2024-11-12 10:25:39 +01:00
Alejandro Celaya
781c083c9f Add new geolocatio-country-code redirect condition type 2024-11-12 10:25:39 +01:00
Alejandro Celaya
a444ed0246
Merge pull request #2258 from acelaya-forks/feature/phpstan-2
Update to PHPStan 2.0
2024-11-12 10:25:02 +01:00
Alejandro Celaya
9a69d06531 Update to PHPStan 2.0 2024-11-12 10:22:23 +01:00
Alejandro Celaya
15cb3bb73c
Merge pull request #2256 from acelaya-forks/feature/unecessary-flush
Remove unnecessary flush calls when used in wrapInTransaction
2024-11-11 09:35:30 +01:00
Alejandro Celaya
7ca605e216 Remove unnecessary flush calls when used in wrapInTransaction 2024-11-11 09:31:23 +01:00
Alejandro Celaya
59a4704658
Merge pull request #2255 from acelaya-forks/feature/expose-tracked-visits
Return `Visit` object created when tracking a visit successfully
2024-11-11 09:19:20 +01:00
Alejandro Celaya
48ecef3436 Update RequestTracker so that its methods return the new Visit instance, if any 2024-11-11 08:58:16 +01:00
Alejandro Celaya
a5a98bd578 Update VisitsTracker so that its methods return the new Visit instance, if any 2024-11-11 08:51:55 +01:00
Alejandro Celaya
12a08cb373
Merge pull request #2253 from acelaya-forks/feature/api-key-improvements
Feature/api key improvements
2024-11-09 12:23:10 +01:00
Alejandro Celaya
3c6f12aec6 Ensure auto-generated name API keys do not throw duplicated name 2024-11-09 12:07:07 +01:00
Alejandro Celaya
d228b88e51 Lock transaction to avoid race conditions when renaming an API key 2024-11-09 11:16:36 +01:00
Alejandro Celaya
95685d958d Update to latest test utils 2024-11-09 11:02:10 +01:00
Alejandro Celaya
1a278eaf07
Merge pull request #2252 from acelaya-forks/feature/readonly-classes
Make classes readonly when possible
2024-11-09 09:58:56 +01:00
Alejandro Celaya
72f1e243b5 Make classes readonly when possible 2024-11-09 09:55:51 +01:00
Alejandro Celaya
d6b103de83
Merge pull request #2251 from acelaya-forks/feature/inject-repos
Feature/inject repos
2024-11-09 09:54:06 +01:00
Alejandro Celaya
fca3891819 Inject ShortUrlRepository in ShortCodeUniquenessHelper 2024-11-09 09:47:47 +01:00
Alejandro Celaya
3ec24e3c67 Inject ShortUrlRepository in UrlShortener 2024-11-09 09:43:55 +01:00
Alejandro Celaya
532102e662 Inject ShortUrlRepository in ShortUrlResolver 2024-11-09 09:39:56 +01:00
Alejandro Celaya
fcd82522ab
Merge pull request #2250 from acelaya-forks/feature/inject-tag-repo
Inject TagRepository in TagService, instead of getting it from EntityManager
2024-11-09 09:39:03 +01:00
Alejandro Celaya
102169b6c7 Inject DomainRepository in DomainService 2024-11-09 09:34:24 +01:00
Alejandro Celaya
dba9302f78 Inject TagRepository in TagService, instead of getting it from EntityManager 2024-11-09 09:25:01 +01:00
Alejandro Celaya
92ad6d2732
Merge pull request #2249 from acelaya-forks/feature/hash-api-keys
Feature/hash api keys
2024-11-09 09:14:38 +01:00
Alejandro Celaya
7e573bdb9b Add tests for RenameApiKeyCOmmand and ApiKeyMeta 2024-11-08 09:58:02 +01:00
Alejandro Celaya
6f837b3b91 Move logic to determine if a new key has a duplicated name to the APiKeyService 2024-11-08 09:03:50 +01:00
Alejandro Celaya
b08c498b13 Create command to rename API keys 2024-11-08 08:47:49 +01:00
Alejandro Celaya
a661d05100 Allow API keys to be renamed 2024-11-08 08:25:07 +01:00
Alejandro Celaya
9e6f129de6 Make sure a unique name is required by api-key:generate command 2024-11-07 14:52:06 +01:00
Alejandro Celaya
4c1ff72438 Add method to check if an API exists for a given name 2024-11-07 09:55:10 +01:00
Alejandro Celaya
6f95acc202 Inject ApiKeyRepository in ApiKeyService 2024-11-07 09:34:42 +01:00
Alejandro Celaya
bd73362c94 Update api-key:disable command to allow passing a name 2024-11-06 20:10:06 +01:00
Alejandro Celaya
f6d70c599e Make name required in ApiKey entity 2024-11-06 08:57:10 +01:00
Alejandro Celaya
1b9c8377ae Hash existing API keys, and do checks against the hash 2024-11-05 23:27:39 +01:00
Alejandro Celaya
9f6975119e Show only API key name in short URLs list 2024-11-05 22:52:01 +01:00
Alejandro Celaya
a094be2b9e Fall back API key names to auto-generated keys 2024-11-05 11:26:39 +01:00
Alejandro Celaya
819a535bfe Create migration to set API keys in name column 2024-11-05 11:08:11 +01:00
Alejandro Celaya
e4fe7adf00
Merge pull request #2248 from acelaya-forks/feature/api-key-simplification
Simplify ApiKey entity by exposing key as a readonly prop
2024-11-04 23:17:17 +01:00
Alejandro Celaya
79c5418ac2 Simplify ApiKey entity by exposing key as a readonly prop 2024-11-04 14:22:39 +01:00
Alejandro Celaya
b5010e4d8c
Merge pull request #2246 from acelaya-forks/feature/nanoid-2
Update to hidehalo/nanoid-php 2.0
2024-11-04 08:55:17 +01:00
Alejandro Celaya
3085fa76cf Update to hidehalo/nanoid-php 2.0 2024-11-04 08:50:58 +01:00
Alejandro Celaya
1fd7d58084 Update Bluesky handle 2024-11-03 11:38:31 +01:00
Alejandro Celaya
eae001a34a Rename ShortUrlWithVisitsSummary to ShortUrlWithDeps 2024-11-03 11:38:31 +01:00
Alejandro Celaya
d7ecef94f2 Avoid selecting domains for every short URL in list 2024-11-03 11:38:31 +01:00
Alejandro Celaya
98364a1aae Update to mlocati/ip-lib 1.18.1 2024-11-03 11:38:31 +01:00
Alejandro Celaya
9ccb866e5e Display warnings and deprecations in all test suites 2024-11-03 11:38:31 +01:00
Alejandro Celaya
3f1d61e01e Update to PHP coding standard 2.4.0 2024-11-03 11:38:31 +01:00
Alejandro Celaya
93a277a94d Allow short URLs to be filtered by domain from the command line 2024-11-03 11:38:30 +01:00
Alejandro Celaya
a10ca655a2 Cover domain filtering in ListShortUrls API test 2024-11-03 11:37:59 +01:00
Alejandro Celaya
bb270396b6 Allow short URLs list to be filtered by domain authority 2024-11-03 11:37:59 +01:00
Alejandro Celaya
525a306ec6 Create constant representing default domain identifier 2024-11-03 11:37:59 +01:00
Alejandro Celaya
1dd71d2ee7 Update changelog 2024-11-03 11:37:59 +01:00
Alejandro Celaya
ac2e249746 Update swagger Short URL examples to include forwardQuery and hasRedirectRules 2024-11-03 11:37:16 +01:00
Alejandro Celaya
af569ad7a5 Fix PHPStan rules 2024-11-03 11:37:16 +01:00
Alejandro Celaya
bf121c58ba Fix API tests 2024-11-03 11:37:16 +01:00
Alejandro Celaya
d2403367b5 Fix PublishingUpdatesGeneratorTest 2024-11-03 11:37:16 +01:00
Alejandro Celaya
84a187a26f Include left join with domains when listing short URLs to avoid N+1 SELECT problem 2024-11-03 11:37:15 +01:00
Alejandro Celaya
3149adebdb Expose the fact that a short URL has redirect rules attached to it 2024-11-03 11:36:50 +01:00
Alejandro Celaya
228bf093d3
Merge pull request #2245 from acelaya-forks/feature/fix-redis-7.4-scan
Update to shlink-common 6.5 to fix integration with redis 7.4
2024-11-03 11:35:50 +01:00
Alejandro Celaya
26589e6126 Update to shlink-common 6.5 to fix integration with redis 7.4 2024-11-03 11:32:44 +01:00
Alejandro Celaya
02e48ae665
Merge pull request #2237 from shlinkio/develop
Release 4.2.4
2024-10-27 08:48:05 +01:00
Alejandro Celaya
0d627ce808 Set user to 0 in database containers when running in CI 2024-10-27 08:45:11 +01:00
Alejandro Celaya
99639b9844 Depend on actual versions for shlink packages 2024-10-27 08:36:57 +01:00
Alejandro Celaya
0c3c7ff3b2 Add v4.2.4 to changelog 2024-10-27 08:23:38 +01:00
Alejandro Celaya
d7423585ff Build docker image in CI using reusable workflow 2024-10-26 10:25:11 +02:00
Alejandro Celaya
7de07a9cd4
Merge pull request #2236 from acelaya-forks/feature/normalize-composer-json
Feature/normalize composer json
2024-10-24 14:25:01 +02:00
Alejandro Celaya
2a734b5d89 Ensure proper env vars are promoted for dev and test envs 2024-10-24 14:20:49 +02:00
Alejandro Celaya
4520afb271 Normalize composer.json scripts with composer capabilities 2024-10-24 14:08:48 +02:00
Alejandro Celaya
e7a9ad1db0
Merge pull request #2224 from acelaya-forks/feature/dev-config-as-env
Migrate dev-specific configuration to env vars via .env file
2024-10-24 12:01:13 +02:00
Alejandro Celaya
84860539ce Ensure dev env files are not accidentally leaked to locally built docker images 2024-10-24 11:58:04 +02:00
Alejandro Celaya
2901fe8b7b Reduce duplication in CLI tests 2024-10-24 11:50:06 +02:00
Alejandro Celaya
f9694333c5 Add ADR for transition to env vars for dev configs 2024-10-24 11:44:05 +02:00
Alejandro Celaya
fc1f35ad59 Update CONTRIBUTING file removing references to old local config files 2024-10-24 10:12:34 +02:00
Alejandro Celaya
9a58748581 Get LC_ALL env var back to docker compose 2024-10-24 10:00:57 +02:00
Alejandro Celaya
45e108d21e Load dev env as a PHP array instead of an env file 2024-10-24 09:59:13 +02:00
Alejandro Celaya
f4da9c1fcc Update dependencies to stop using cuyz/valinor 2024-10-24 09:22:44 +02:00
Alejandro Celaya
a3ea8f56dd Remove app_options config 2024-10-24 08:49:58 +02:00
Alejandro Celaya
f3244b35e3 Remove remaining local config files 2024-10-23 10:53:09 +02:00
Alejandro Celaya
442eea0ea7 Add script to run CLI tests that loads and exports test env vars 2024-10-23 10:16:38 +02:00
Alejandro Celaya
46601443f5 Load specific env file when running API tests 2024-10-23 09:17:00 +02:00
Alejandro Celaya
c0200317dd Load dev env vars via roadrunner instead of docker compose 2024-10-22 15:31:53 +02:00
Alejandro Celaya
c8e5196aab Remove dependencies on url_shortener raw config 2024-10-22 15:15:41 +02:00
Alejandro Celaya
b991b1699e Define unique dev .env file 2024-10-22 15:15:41 +02:00
Alejandro Celaya
582033ceb3 Migrate dev-specific configuration to env vars via .env file 2024-10-22 15:15:41 +02:00
Alejandro Celaya
549a8d8837
Merge pull request #2233 from acelaya-forks/feature/endroid-qr-code-6
Update to endroid/qr-code 6.0
2024-10-22 09:06:30 +02:00
Alejandro Celaya
5fb6c8708c Update to endroid/qr-code 6.0 2024-10-22 09:02:32 +02:00
Alejandro Celaya
7ee757243a
Merge pull request #2230 from acelaya-forks/feature/xdebug-coverage
Switch to xdebug for code coverage reports
2024-10-21 12:01:29 +02:00
Alejandro Celaya
044efe6ee4 Switch to xdebug for code coverage reports 2024-10-21 11:54:45 +02:00
Alejandro Celaya
9b16749737 Remove twitter badge from readme 2024-10-17 16:27:38 +02:00
Alejandro Celaya
6d51ff831f
Merge pull request #2228 from acelaya-forks/feature/docker-signals
Feature/docker signals
2024-10-17 15:09:08 +02:00
Alejandro Celaya
0635615149 Run RoadRunner in docker with exec to ensure signals are properly handled 2024-10-17 15:03:55 +02:00
Alejandro Celaya
51de4b17c0
Merge pull request #2227 from shlinkio/develop
Release 4.2.3
2024-10-17 09:41:21 +02:00
Alejandro Celaya
615b443652
Merge pull request #2226 from acelaya-forks/feature/fix-qr-codes
Update to shlink-config 3.2.1, which fixes skipping config options with null value
2024-10-17 09:37:21 +02:00
Alejandro Celaya
4b7b530f49 Update to shlink-config 3.2.1, which fixes skipping config options with null value 2024-10-17 09:33:53 +02:00
Alejandro Celaya
fa7969c746
Merge pull request #2222 from shlinkio/develop
Release 4.2.2
2024-10-14 09:50:13 +02:00
Alejandro Celaya
aef04af4f0
Merge pull request #2220 from acelaya-forks/feature/env-var-command
Feature/env var command
2024-10-14 09:45:48 +02:00
Alejandro Celaya
f118ea252c Depend on shlink-config 3.2 2024-10-14 09:41:47 +02:00
Alejandro Celaya
d514f39a82 Update changelog 2024-10-14 09:41:46 +02:00
Alejandro Celaya
e17556a7ae Add ReadEnvVarCommand test 2024-10-14 09:41:22 +02:00
Alejandro Celaya
d79f11eeb8 Add missing default value for DEFAULT_QR_CODE_BG_COLOR env var 2024-10-14 09:41:22 +02:00
Alejandro Celaya
1ec950ee1e Fix tests not properly unsetting env vars 2024-10-14 09:41:22 +02:00
Alejandro Celaya
14ba9fd6a4 Create command to return the value of an env var for current env 2024-10-14 09:41:22 +02:00
Alejandro Celaya
83e8801827 Move env var default values to EnvVars enum 2024-10-14 09:41:22 +02:00
Alejandro Celaya
be822646e4 Update changelog 2024-10-13 09:49:34 +02:00
Alejandro Celaya
3a4a27a60c
Merge pull request #2214 from acelaya-forks/feature/fix-query-params
Ensure query parameters are preserved verbatim when forwarded to long URL
2024-10-10 11:38:15 +02:00
Alejandro Celaya
1773e6ecae Ensure query parameters are preserved verbatim when forwarded to long URL 2024-10-10 11:35:29 +02:00
Alejandro Celaya
a8e4b2fceb
Merge pull request #2211 from acelaya-forks/feature/explicit-env-from-config
Promote installer config options as env vars explicitly
2024-10-08 09:07:11 +02:00
Alejandro Celaya
15b53ef43c Update changelog 2024-10-08 09:04:30 +02:00
Alejandro Celaya
11a4702b10 Promote installer config options as env vars explicitly 2024-10-08 08:57:51 +02:00
Alejandro Celaya
6b15cd6d51
Merge pull request #2204 from shlinkio/develop
Release 4.2.1
2024-10-04 12:53:11 +02:00
Alejandro Celaya
00169a5729 Require shlink-common 6.3 2024-10-04 12:48:19 +02:00
Alejandro Celaya
94702791d9
Merge pull request #2203 from acelaya-forks/feature/fix-memory-limit
Fix `MEMORY_LIMIT` being ignored when provided as installer config option
2024-10-04 12:43:38 +02:00
Alejandro Celaya
447cccacdf Update changelog 2024-10-04 12:41:02 +02:00
Alejandro Celaya
0413399102 Make sure MEMORY_LIMIT env var is read after config options have been promoted to env vars 2024-10-04 12:33:27 +02:00
Alejandro Celaya
9afc7876c4
Merge pull request #2184 from acelaya-forks/feature/redis-db-index
Allow specifying the redis database index to be used
2024-08-26 10:00:05 +02:00
Alejandro Celaya
187c17319a Take all Postgres platform classes into consideration 2024-08-26 09:57:17 +02:00
Alejandro Celaya
7310ecd886 Allow specifying the redis database index to be used 2024-08-25 12:51:34 +02:00
Alejandro Celaya
620cd92d11
Merge pull request #2172 from shlinkio/develop
Release v4.2.0
2024-08-11 18:33:09 +02:00
Alejandro Celaya
f9658c8da1 Add v4.2.0 to changelog 2024-08-11 18:30:06 +02:00
Alejandro Celaya
613b1d3045 Update changelog 2024-08-06 10:13:55 +02:00
Alejandro Celaya
d39711ec51
Merge pull request #2170 from acelaya-forks/feature/testdox-summary
Add --testdox-summary flag to phpunit executions
2024-08-04 13:16:32 +02:00
Alejandro Celaya
69dcab96f8 Add --testdox-summary flag to phpunit executions 2024-08-04 13:13:03 +02:00
Alejandro Celaya
d76c96ad41 Fix coding standard 2024-08-01 08:38:49 +02:00
Alejandro Celaya
133efff2cd Improve PHPStan config 2024-07-31 19:53:05 +02:00
Alejandro Celaya
c10f0db170
Merge pull request #2168 from acelaya-forks/feature/update-common
Update to latest shlink-common and remove deprecation references
2024-07-29 20:47:04 +02:00
Alejandro Celaya
037cd8a389 Add missing generic tyoes annotations 2024-07-29 20:43:52 +02:00
Alejandro Celaya
1d24750f43 Fix phpstan checks 2024-07-29 19:59:46 +02:00
Alejandro Celaya
b52ceaff9a Update to latest shlink-common and remove deprecation references 2024-07-29 19:41:40 +02:00
Alejandro Celaya
6b0b52853c
Improve repro steps description in bug issue template 2024-07-28 10:49:24 +02:00
Alejandro Celaya
64d7ac7093
Merge pull request #2166 from acelaya-forks/feature/options-enum
Reduce hardcoded options in ShortUrlDataInput
2024-07-27 09:15:16 +02:00
Alejandro Celaya
b9ba1246d4 Reduce hardcoded options in ShortUrlDataInput 2024-07-27 09:12:54 +02:00
Alejandro Celaya
7f9dc10f6a
Merge pull request #2164 from acelaya-forks/feature/update-url-cli
Add command to update short URLs
2024-07-26 20:14:02 +02:00
Alejandro Celaya
a1afc90150 Fix sqlcmd path 2024-07-26 20:09:59 +02:00
Alejandro Celaya
df94c68e2e Add unit test for EditShortUrlCommand 2024-07-26 19:54:39 +02:00
Alejandro Celaya
65ea1e00a6 Prevent resetting of non-providen params in EditShortUrlCommand 2024-07-26 19:26:48 +02:00
Alejandro Celaya
5bccdded8a Create command to edit existing short URLs 2024-07-26 09:21:00 +02:00
Alejandro Celaya
8917ed5c2e Create command to edit existing short URLs 2024-07-26 00:01:40 +02:00
Alejandro Celaya
fabc752398 Extract reading and parsing of arguments for short URLs data in commands 2024-07-25 23:44:46 +02:00
Alejandro Celaya
38d8086516
Merge pull request #2161 from acelaya-forks/feature/php-8.4-ci
Add PHP 8.4 to CI
2024-07-23 20:06:09 +02:00
Alejandro Celaya
ae0ff5f23c Add PHP 8.4 to CI 2024-07-23 20:02:49 +02:00
Alejandro Celaya
7c659699f3
Merge pull request #2151 from acelaya-forks/feature/ip-dynamic-redirects
Add logic for IP-based dynamic redirects
2024-07-18 21:32:24 +02:00
Alejandro Celaya
9e6cdcb838 Update changelog 2024-07-18 21:26:28 +02:00
Alejandro Celaya
7e2f755dfd Validate IP address patterns when creating ip-address redirect conditions 2024-07-18 21:23:48 +02:00
Alejandro Celaya
ce2ed237c7 Add ip-address condition type to redirect rules API spec docs 2024-07-17 20:23:58 +02:00
Alejandro Celaya
626caa4afa Add API test for dynamic IP-based redirects 2024-07-17 20:13:46 +02:00
Alejandro Celaya
f4a7712ded Add InvalidIpFormatExceptionTest 2024-07-17 19:59:13 +02:00
Alejandro Celaya
bab6a3951e Add missing unit test 2024-07-17 19:56:53 +02:00
Alejandro Celaya
f49d98f2ea Add logic for IP-based dynamic redirects 2024-07-17 19:51:13 +02:00
Alejandro Celaya
1312ea61f4 Add new IP address redirect condition 2024-07-06 10:35:33 +02:00
Alejandro Celaya
8d90661d0a Extract logic to match IP address against list of groups 2024-07-06 10:12:05 +02:00
Alejandro Celaya
b6b2530cb6
Merge pull request #2149 from acelaya-forks/feature/robots-user-agents
Add option to customize user agents in robots.txt
2024-07-06 10:08:03 +02:00
Alejandro Celaya
e4f66b7ce6 Update installer 2024-07-05 09:41:26 +02:00
Alejandro Celaya
4b52c92e97 Add option to customize user agents in robots.txt 2024-07-05 08:54:54 +02:00
Alejandro Celaya
76c42bc17c
Merge pull request #2148 from acelaya-forks/feature/roadrunner-2024
Update to RoadRunner 2024
2024-07-03 19:56:36 +02:00
Alejandro Celaya
c4f8da5f02 Fix phpstan error definition 2024-07-03 19:53:26 +02:00
Alejandro Celaya
80bdeb280a Update to RoadRunner 2024 2024-07-03 19:52:06 +02:00
Alejandro Celaya
99010b6eae Fix merge conflicts 2024-05-23 09:26:27 +02:00
Alejandro Celaya
b2dabf06bf
Merge pull request #2136 from acelaya-forks/release/4.1.1
Release/4.1.1
2024-05-23 09:21:56 +02:00
Alejandro Celaya
67ae05f473 Add v4.1.1 to changelog 2024-05-23 09:18:58 +02:00
Alejandro Celaya
fb4fecf411 Merge pull request #2135 from acelaya-forks/feature/non-utf8-titles
Convert encoding of resolved titles based on page encoding
2024-05-23 09:17:49 +02:00
Alejandro Celaya
c855f011d1 Merge pull request #2132 from acelaya-forks/feature/update-phpstan
Update to latest phpstan
2024-05-23 09:17:37 +02:00
Alejandro Celaya
02717eb2fb Merge pull request #2130 from marijnvandevoorde/nanoid
Replaces short-id by nano-id
2024-05-23 09:17:26 +02:00
Alejandro Celaya
de70ebe769 Merge pull request #2125 from acelaya-forks/feature/phpunit-11
Update to PHPUnit 11
2024-05-23 09:16:56 +02:00
Alejandro Celaya
c6109fd396 Merge pull request #2115 from acelaya-forks/feature/fix-oas-docs
Fix typo in OAS docs
2024-05-23 09:16:24 +02:00
Alejandro Celaya
83584a3175 Link crchived changelogs from main one 2024-05-23 09:15:40 +02:00
Alejandro Celaya
f5dcc52b3b Migrate to new docker-publish-image reusable workflow 2024-05-23 09:15:16 +02:00
Alejandro Celaya
1901964de1
Merge pull request #2135 from acelaya-forks/feature/non-utf8-titles
Convert encoding of resolved titles based on page encoding
2024-05-22 18:14:56 +02:00
Alejandro Celaya
80e9c2452b Convert encoding of resolved titles based on page encoding 2024-05-22 18:11:55 +02:00
Alejandro Celaya
5ad4b39160
Merge pull request #2132 from acelaya-forks/feature/update-phpstan
Update to latest phpstan
2024-05-21 19:05:39 +02:00
Alejandro Celaya
89b73a9cfa Update to latest phpstan 2024-05-21 18:09:45 +02:00
Alejandro Celaya
e2d8334d69
Merge pull request #2130 from marijnvandevoorde/nanoid
Replaces short-id by nano-id
2024-05-21 17:58:53 +02:00
Marijn Vandevoorde
9b16d7acc0 Replaces short-id by nano-id 2024-05-16 14:00:39 +02:00
Alejandro Celaya
6836840746
Merge pull request #2125 from acelaya-forks/feature/phpunit-11
Update to PHPUnit 11
2024-05-12 13:22:26 +02:00
Alejandro Celaya
4084d301ca Update to PHPUnit 11 2024-05-12 12:49:53 +02:00
Alejandro Celaya
added21b18
Merge pull request #2118 from shlinkio/revert-2117-feature/superfluous-distinct
Revert "Remove unneeded DISTINCT from list short URLs query"
2024-05-09 10:00:29 +02:00
Alejandro Celaya
8cd77391cc
Revert "Remove unneeded DISTINCT from list short URLs query" 2024-05-09 09:43:55 +02:00
Alejandro Celaya
05ebfccc63
Merge pull request #2117 from acelaya-forks/feature/superfluous-distinct
Remove unneeded DISTINCT from list short URLs query
2024-05-06 18:54:01 +02:00
Alejandro Celaya
cb3a690294 Remove unneeded DISTINCT from list short URLs query 2024-05-06 18:50:10 +02:00
Alejandro Celaya
194a7b0e57
Merge pull request #2115 from acelaya-forks/feature/fix-oas-docs
Fix typo in OAS docs
2024-04-29 15:22:32 +02:00
Alejandro Celaya
98e4d01feb Fix typo in OAS docs 2024-04-29 15:18:54 +02:00
Alejandro Celaya
c22e3895b5 Allow more dev hosts in dev mercure 2024-04-29 08:52:18 +02:00
Alejandro Celaya
9a76c19615 Migrate to new docker-publish-image reusable workflow 2024-04-26 09:27:21 +02:00
Alejandro Celaya
59fa088975
Merge pull request #2107 from acelaya-forks/feature/robots-allow-all
Add option to allow all URLs to be crawlable via robots.txt
2024-04-22 09:23:34 +02:00
Alejandro Celaya
163244f40f Add option to allow all URLs to be crawlable via robots.txt 2024-04-22 09:16:44 +02:00
Alejandro Celaya
a89b53af4f Link crchived changelogs from main one 2024-04-21 16:46:24 +02:00
Alejandro Celaya
35508e253d
Merge pull request #2099 from shlinkio/develop
Release 4.1.0
2024-04-14 09:12:56 +02:00
Alejandro Celaya
e586fec338 Rearrange changelog 2024-04-14 08:53:31 +02:00
Alejandro Celaya
93fa27bdba Add v4.1.0 to changelog 2024-04-14 08:40:52 +02:00
Alejandro Celaya
048856c333
Merge pull request #2098 from acelaya-forks/feature/matomo-command
Create console command to send visits to matomo
2024-04-13 20:59:57 +02:00
Alejandro Celaya
986f1162dd Set COLUMNS env var when running unit tests 2024-04-13 20:56:59 +02:00
Alejandro Celaya
dc8dfa9f0c Update changelog 2024-04-13 20:49:34 +02:00
Alejandro Celaya
82e7094f3a Fix VisitIterationRepositoryTest for MS SQL 2024-04-13 20:48:03 +02:00
Alejandro Celaya
f0e62004d5 Add unit test to MatomoSendVisitsCommand 2024-04-13 20:30:31 +02:00
Alejandro Celaya
bbdbafd8db Test MatomoVisitSender::sendVisitsInDateRange 2024-04-13 19:27:03 +02:00
Alejandro Celaya
6121efec59 Create command to send visits to matomo 2024-04-13 18:59:09 +02:00
Alejandro Celaya
4fdbcc25a0 Pass visit date to matomo when tracking 2024-04-13 18:59:09 +02:00
Alejandro Celaya
ca42425b33 Make Visit::date field readonly 2024-04-13 18:59:09 +02:00
Alejandro Celaya
ce0f61b66d Allow filtering by date in VisitIterationRepository 2024-04-13 18:59:09 +02:00
Alejandro Celaya
13ee71f351 Move allowed HTTP methods definition to RedirectStatus enum 2024-04-13 18:59:09 +02:00
Alejandro Celaya
c57494d7cd Extract logic to send visits to Matomo to its own service 2024-04-13 18:59:09 +02:00
Alejandro Celaya
d2e74ab330
Merge pull request #2097 from acelaya-forks/feature/bitly-custom-slugs
Fix custom slugs not being properly imported from bitly
2024-04-12 22:31:12 +02:00
Alejandro Celaya
850dde1a06 Fix custom slugs not being properly imported from bitly 2024-04-12 22:28:13 +02:00
Alejandro Celaya
5e83f301ff
Merge pull request #2092 from acelaya-forks/customizable-memory-limit
Allow memory_limit to be configurable
2024-04-09 09:45:08 +02:00
Alejandro Celaya
5e74dd7a6d Update to installer version with support for memory limit option 2024-04-09 09:40:08 +02:00
Alejandro Celaya
8a273e01e9 Allow memory_limit to be configurable 2024-04-09 08:47:01 +02:00
Alejandro Celaya
75f6f8dd18
Merge pull request #2090 from acelaya-forks/feature/propagate-job-request-id
Forward request ID from sync request process to async job processes
2024-04-07 11:30:47 +02:00
Alejandro Celaya
e1cf0c4ea7 Forward request ID from sync request process to async job processes 2024-04-07 11:26:17 +02:00
Alejandro Celaya
cc134abd12
Merge pull request #2086 from acelaya-forks/feature/delete-expired
Feature/delete expired
2024-04-03 19:27:17 +02:00
Alejandro Celaya
b7db676cba Test non-interactivity on DeleteExpiredShortUrlsCommand 2024-04-03 19:24:08 +02:00
Alejandro Celaya
3881996560 Migrate from docker-compose to docker compose in CI pipelines 2024-04-03 19:20:38 +02:00
Alejandro Celaya
527d28ad81 Add DeleteExpiredShortUrlsCommand test 2024-04-03 19:18:56 +02:00
Alejandro Celaya
f2371e8a80 Add command to delete expired short URLs 2024-04-03 18:57:09 +02:00
Alejandro Celaya
fd882834d3 Create repository to handle expired short URLs deletion 2024-04-03 09:52:38 +02:00
Alejandro Celaya
f92a720d63 Use short_url_visits_counts table when excluding short URLs which reached max visits 2024-04-03 09:06:43 +02:00
Alejandro Celaya
d6f58698b7
Merge pull request #2082 from acelaya-forks/feature/orphan-visits-counts
Track orphan visits counts
2024-04-01 10:28:05 +02:00
Alejandro Celaya
d090260b17 Track orphan visits counts 2024-04-01 10:22:51 +02:00
Alejandro Celaya
cd43c1c01f
Merge pull request #2083 from acelaya-forks/feature/matomo-title
Track short URL title as document title when sending visits to matomo
2024-03-31 13:53:58 +02:00
Alejandro Celaya
284b28e8d9 Track short URL title as document title when sending visits to matomo 2024-03-31 13:51:03 +02:00
Alejandro Celaya
b50547d868 Create new orphan_visits_counts table 2024-03-31 13:18:44 +02:00
Alejandro Celaya
401046fbe5
Merge pull request #2081 from acelaya-forks/feature/performant-count-visits
Load non-orphan visits overview via short url visits counts
2024-03-31 13:07:52 +02:00
Alejandro Celaya
6e82509964 Update changelog 2024-03-31 13:04:58 +02:00
Alejandro Celaya
ab6fa490e5 Test ShortUrlVisitsCountRepository via VisitRepositoryTest 2024-03-31 12:37:22 +02:00
Alejandro Celaya
55e2780f50 Load non-orphan visits overview via short url visits counts 2024-03-31 12:27:20 +02:00
Alejandro Celaya
f4803c675c
Merge pull request #2079 from acelaya-forks/feature/fix-order-by-title
Ensure ordering by title is consistent between database engines
2024-03-29 09:38:25 +01:00
Alejandro Celaya
90514c603f Ensure ordering by title is consistent between database engines 2024-03-29 09:35:54 +01:00
Alejandro Celaya
7f4137e7cc
Merge pull request #2078 from acelaya-forks/feature/tags-stats-improvements
Improve tags stats performance by using the new short_url_visits_counts table
2024-03-28 19:26:33 +01:00
Alejandro Celaya
071cb9af2b Improve tags stats performance by using the new short_url_visits_counts table 2024-03-28 19:17:37 +01:00
Alejandro Celaya
6ce1550457
Merge pull request #2074 from acelaya-forks/feature/slotted-counts
Feature/slotted counts
2024-03-28 17:44:31 +01:00
Alejandro Celaya
8cb5d44dc9 Update changelog 2024-03-28 17:27:49 +01:00
Alejandro Celaya
1331b3f87c Fix RabbitMQ dev port 2024-03-28 17:24:00 +01:00
Alejandro Celaya
ab96297e58 Make sure VisitsTracker wraps as little operations as possible in the transaction 2024-03-28 17:06:18 +01:00
Alejandro Celaya
c4fd3a74c5 Fix type hint in migration 2024-03-28 16:10:56 +01:00
Alejandro Celaya
da922fb2a7 Add ShortUrlVisitsCountTrackerTest 2024-03-28 09:43:58 +01:00
Alejandro Celaya
4a05c4be40 Wrap visits tracking in transaction 2024-03-27 19:14:41 +01:00
Alejandro Celaya
cef30c8e2d Fix type in Version20240318084804 2024-03-27 19:08:25 +01:00
Alejandro Celaya
8417498f08 Fixes on static check and unit tests 2024-03-27 19:08:25 +01:00
Alejandro Celaya
10e941cea6 Add missing COALESCE when summing visits counts 2024-03-27 19:08:25 +01:00
Alejandro Celaya
3d7b1ca799 Move from preFlush to onFlush + postFlush 2024-03-27 19:08:25 +01:00
Alejandro Celaya
b236354fc7 Fix order in which entities are flushed in ShortUrlListRepositoryTest 2024-03-27 19:08:25 +01:00
Alejandro Celaya
6fbb5a380d Add missing default value for short url visits count 2024-03-27 19:08:25 +01:00
Alejandro Celaya
054eb42613 Remove no-longer used methods in OrderableField enum 2024-03-27 19:08:25 +01:00
Alejandro Celaya
6074f4475d Add preFlush listener to track visits counts 2024-03-27 19:08:25 +01:00
Alejandro Celaya
7afd3fd6a2 Load visits and nonBotVisits via sub-queries in ShortUrlListRepository 2024-03-27 19:08:25 +01:00
Alejandro Celaya
7d415e40b2 Add unique index in short_url_visits_counts 2024-03-27 19:08:25 +01:00
Alejandro Celaya
3c89d252d2 Simplify logic to match order by for short URL lists 2024-03-27 19:08:25 +01:00
Alejandro Celaya
f678873e9f Use pre-calculated visits counts when listing short URLs 2024-03-27 19:08:25 +01:00
Alejandro Celaya
17d37a062a Add new table to track short URL visits counts 2024-03-27 19:08:25 +01:00
Alejandro Celaya
14702063f2
Merge pull request #2076 from acelaya-forks/feature/fix-array-inputs
Make sure tags fallback to empty array when null
2024-03-27 19:08:06 +01:00
Alejandro Celaya
c599d8a0ed Make sure tags fallback to empty array when null 2024-03-27 13:04:42 +01:00
Alejandro Celaya
207d5adceb
Merge pull request #2070 from acelaya-forks/feature/visited-url-always
Feature/visited url always
2024-03-24 17:27:57 +01:00
Alejandro Celaya
b4c46ce222 Update changelog 2024-03-24 17:24:46 +01:00
Alejandro Celaya
6fe269193a Expose visitedUrl when serializing any kind of visit, not only orphan visits 2024-03-24 17:20:41 +01:00
Alejandro Celaya
d948543d5c Wrap JSON serialization for any kind of visit in Visit entity itself 2024-03-24 17:06:11 +01:00
Alejandro Celaya
a327e6c0a7 Make Visit::jsonSerialize() return different props for orphan visits 2024-03-24 16:54:49 +01:00
Alejandro Celaya
fbd35b7974 Add more named constructors to Ordering class 2024-03-20 09:15:45 +01:00
Alejandro Celaya
b94a22e6a7 Rename Ordering::emptyInstance to Ordering::none to make it more clear 2024-03-20 09:06:35 +01:00
Alejandro Celaya
63ea9e4a21
Merge pull request #2069 from acelaya-forks/feature/short-url-simplification
Move logic to serialize ShortUrls to entity itself
2024-03-19 07:34:59 +01:00
Alejandro Celaya
e028d8ea31 Move logic to serialize ShortUrls to entity itself 2024-03-18 22:09:15 +01:00
Alejandro Celaya
457a7a14e5
Merge pull request #2068 from acelaya-forks/feature/modernize-entities
Feature/modernize entities
2024-03-18 20:26:47 +01:00
Alejandro Celaya
cd387328be Update changelog 2024-03-18 20:22:54 +01:00
Alejandro Celaya
5524476787 Modernize ShortUrl entity 2024-03-18 20:21:26 +01:00
Alejandro Celaya
78526fb405 Modernize Visit entity 2024-03-18 19:57:30 +01:00
Alejandro Celaya
b2dee43bb0 Modernize VisitLocation entity 2024-03-18 19:11:42 +01:00
Alejandro Celaya
60e9443b12 Modernize ApiKey entity 2024-03-18 18:33:56 +01:00
Alejandro Celaya
ab8fa52ca4 Modernize Domain entity 2024-03-18 18:15:05 +01:00
Alejandro Celaya
16f64f6247
Merge pull request #2064 from shlinkio/develop
Release 4.0.3
2024-03-15 23:07:25 +01:00
Alejandro Celaya
98992c656f
Merge pull request #2063 from acelaya-forks/feature/non-http-url
Fix error when redirecting to a non-http URL
2024-03-15 23:05:02 +01:00
Alejandro Celaya
053e026982 Fix error when redirecting to a non-http URL 2024-03-15 23:00:40 +01:00
Alejandro Celaya
74180a4381
Merge pull request #2062 from acelaya-forks/feature/string-db-credentials
Feature/string db credentials
2024-03-15 18:33:29 +01:00
Alejandro Celaya
293725f933 Update changelog 2024-03-15 18:22:27 +01:00
Alejandro Celaya
c33f8d0ea2 Cast database credentials to string when read from the env 2024-03-15 14:32:53 +01:00
Alejandro Celaya
0f2cd3cb7f Remove useless return annotation 2024-03-12 09:09:59 +01:00
Alejandro Celaya
2441ac5e77 Update Bug template 2024-03-12 09:00:49 +01:00
Alejandro Celaya
f248001460
Merge pull request #2053 from shlinkio/develop
Release 4.0.2
2024-03-09 09:49:51 +01:00
Alejandro Celaya
1fe2c93946
Merge pull request #2051 from acelaya-forks/feature/fix-geolite-update
Fix infinite GeoLite2 downloads
2024-03-09 09:39:31 +01:00
Alejandro Celaya
a3d50605c1 Update changelog 2024-03-09 09:32:05 +01:00
Alejandro Celaya
5427152f15 Make sure GeoLite2 db file is always read from the filesystem befor etrying to operate on it 2024-03-09 09:30:05 +01:00
Alejandro Celaya
a4e9c2fdde
Merge pull request #2046 from shlinkio/develop
Release 4.0.1
2024-03-08 08:57:40 +01:00
Alejandro Celaya
e244b2dc51 Add v4.0.1 to changelog 2024-03-08 08:56:55 +01:00
Alejandro Celaya
31dea8fa99
Merge pull request #2045 from acelaya-forks/feature/match-languages-fix
Ensure language redirect conditions do not match for too low quality accepted languages
2024-03-07 23:23:58 +01:00
Alejandro Celaya
be8cf56240 Ensure language redirect conditions do not match for too low quality accepted languages 2024-03-07 23:21:31 +01:00
Alejandro Celaya
0bc7412430 Fix incorrect redirect condition type definiition 2024-03-05 15:09:44 +01:00
Alejandro Celaya
6d56e92306
Merge pull request #2042 from acelaya-forks/feature/qr-code-color-args
Document color and bgColor QR code query params
2024-03-05 11:16:49 +01:00
Alejandro Celaya
97c94f8fcc Document color and bgColor QR code query params 2024-03-05 11:14:07 +01:00
Alejandro Celaya
92b5a5296d
Merge pull request #2039 from shlinkio/develop
Release 4.0.0
2024-03-03 19:23:35 +01:00
Alejandro Celaya
febca6d441 Small reword in UPGRADE guide 2024-03-03 19:16:46 +01:00
Alejandro Celaya
bf29abc468
Merge pull request #2040 from acelaya-forks/feature/redirect-checks
Feature/redirect checks
2024-03-03 18:54:15 +01:00
Alejandro Celaya
97cb30565c Add v4.0.0 2024-03-03 18:50:23 +01:00
Alejandro Celaya
9809f050ef Update changelog 2024-03-03 18:19:40 +01:00
Alejandro Celaya
7ecfb24584
Merge pull request #2038 from acelaya-forks/feature/redirect-rules-cli
Add command to manage the redirect rules for a short URLs
2024-03-03 13:19:42 +01:00
Alejandro Celaya
4aa65f750e Add CLI test for manage redirects command, to cover validation errors 2024-03-03 13:16:37 +01:00
Alejandro Celaya
63c533fa62 Fix incorrect rule selection when deleting rules with same long URL 2024-03-03 12:59:58 +01:00
Alejandro Celaya
8751d6c315 Add unit test for RedirectRuleHandler 2024-03-03 12:51:17 +01:00
Alejandro Celaya
eb40dc2d5d Add unit test for ShortUrlRedirectRuleService::saveRulesForShortUrl 2024-03-03 10:36:17 +01:00
Alejandro Celaya
c9d1a955b9 Add ManageRedirectRulesCommand unit test 2024-03-03 10:27:21 +01:00
Alejandro Celaya
c346fd0602 Reduce duplicated code when parsing short codes and domains from CLI 2024-03-03 10:11:12 +01:00
Alejandro Celaya
a45550b0c6 Extract logic to determine list of rules from ManageRedirectRulesCommand to a helper service 2024-03-03 09:51:56 +01:00
Alejandro Celaya
a843c59d77 Fix inconsistencies when editing rules and saving a mix of new and old ones 2024-03-03 09:09:43 +01:00
Alejandro Celaya
3bfb29a51c Test new methods for RedirectCondition and ShortUrlRedirectRule 2024-03-03 08:47:31 +01:00
Alejandro Celaya
d8ede3263f Implement command to manage redirect rules for a short URL 2024-03-02 23:01:49 +01:00
Alejandro Celaya
c36e43e249
Merge pull request #2037 from acelaya-forks/feature/improve-rules-swagger
Define different swagger models for get and set redirect rules
2024-03-01 08:58:11 +01:00
Alejandro Celaya
52150b3067 Define different swagger models for get and set redirect rules 2024-03-01 08:56:03 +01:00
Alejandro Celaya
e7796cc917
Merge pull request #2033 from acelaya-forks/feature/redirect-rule-creation
Create endpoint to set redirect rules for a short URL
2024-02-29 20:23:42 +01:00
Alejandro Celaya
7f560e6a65 Add SetRedirectRulesAction API test 2024-02-29 20:20:04 +01:00
Alejandro Celaya
8f233221e5 Add SetRedirectRulesAction unit test 2024-02-29 20:14:15 +01:00
Alejandro Celaya
f700abd65d Add tests for ShortUrlRedirectionRuleService::setRulesForShortUrl 2024-02-29 19:55:34 +01:00
Alejandro Celaya
f9e4d6d617 Create RedirectRulesDataTest 2024-02-29 19:17:10 +01:00
Alejandro Celaya
d9286765e1 Create endpoint to set redirect rules for a short URL 2024-02-29 10:16:41 +01:00
Alejandro Celaya
a7cde9364a
Merge pull request #2035 from acelaya-forks/feature/improve-rules-persistence
Remove name and uniqueness in redirect condition table
2024-02-29 09:26:51 +01:00
Alejandro Celaya
070d74830b Remove name and uniqueness in redirect condition table 2024-02-29 09:05:30 +01:00
Alejandro Celaya
23c07c4e82
Merge pull request #2031 from acelaya-forks/feature/redirect-rules-api
Create endpoint to list redirect rules for a specific short URL
2024-02-28 09:17:05 +01:00
Alejandro Celaya
ab7824aa85 Add unit test for ListRedirectRulesAction 2024-02-28 09:14:27 +01:00
Alejandro Celaya
67bafbe44e Add API test for redirect rules list 2024-02-28 08:55:44 +01:00
Alejandro Celaya
c4805b8152 Remove old error models and examples from swagger spec 2024-02-28 08:39:26 +01:00
Alejandro Celaya
33729289c7 Create endpoint to list redirect rules for a specific short URL 2024-02-27 21:00:53 +01:00
Alejandro Celaya
721e3d9ef9
Merge pull request #2030 from acelaya-forks/feature/device-redirect-rules
Feature/device redirect rules
2024-02-27 19:27:59 +01:00
Alejandro Celaya
a72e22e046 Unit-test RedirectCondition for devices 2024-02-27 19:24:26 +01:00
Alejandro Celaya
36749658da Remove device long URLs support 2024-02-27 18:46:49 +01:00
Alejandro Celaya
4ad3dc0bc7 Create new migration to drop old device_long_urls table 2024-02-27 09:09:03 +01:00
Alejandro Celaya
73864b923d Add migration to migrate device_long_urls to redirect_rules 2024-02-26 23:42:37 +01:00
Alejandro Celaya
71277e979a
Merge pull request #2026 from acelaya-forks/feature/language-redirects
Feature/language redirects
2024-02-26 20:10:26 +01:00
Alejandro Celaya
60fef3de74 Merge lines 2024-02-26 20:06:15 +01:00
Alejandro Celaya
0fe503fa0e Update changelog 2024-02-26 19:59:34 +01:00
Alejandro Celaya
db02d9f1ba Finalize logic to dynamically match accept language rules 2024-02-26 19:58:46 +01:00
Alejandro Celaya
89a987d03a
Merge pull request #2024 from acelaya-forks/feature/rule-based-redirects
Logic to resolve the long URL to redirect to for a short URL
2024-02-26 19:11:13 +01:00
Alejandro Celaya
3284cea6f2 Update changelog 2024-02-26 19:08:21 +01:00
Alejandro Celaya
df5ad554c1 Add E2E tests for dynamic rule-based redirects 2024-02-26 19:05:39 +01:00
Alejandro Celaya
07ae92943d Add test for ShortUrlRedirectResolver rule matching 2024-02-25 23:09:16 +01:00
Alejandro Celaya
175712d4a9 Add test for ShortUrlRedirectRule request matching 2024-02-25 19:38:54 +01:00
Alejandro Celaya
3f1b253c31 Add test for RedirectCondition request matching 2024-02-25 19:21:39 +01:00
Alejandro Celaya
202d0b86b3 Extract logic to match every type of redirect condition to its own private method 2024-02-25 17:13:54 +01:00
Alejandro Celaya
4e87affb0b Take redirect rules into consideration when resolving the long URL for a short URL 2024-02-25 12:34:27 +01:00
Alejandro Celaya
7f83d37b3c Add logic to match redirect conditions based on query params or language 2024-02-25 12:34:27 +01:00
Alejandro Celaya
09e81b00c5 Create component to resolve the long URL to redirect to for a short URL 2024-02-25 12:34:27 +01:00
Alejandro Celaya
68b77e22c5
Merge pull request #2025 from acelaya-forks/feature/old-migrations
Delete old migrations
2024-02-25 12:33:49 +01:00
Alejandro Celaya
c5ddd8302a Delete old migrations 2024-02-25 12:28:20 +01:00
Alejandro Celaya
1a0fe0429a
Merge pull request #2022 from acelaya-forks/feature/redirect-rules-persistence
Create migration for new rules and conditions tables
2024-02-24 20:27:47 +01:00
Alejandro Celaya
6646232311 Set eager loading for redirect rule conditions 2024-02-24 20:24:41 +01:00
Alejandro Celaya
c1e88c3e83 Use named args to avoid passing default values for args 2024-02-24 18:21:53 +01:00
Alejandro Celaya
c91a534d1a Create new entities for redirect rules 2024-02-24 18:17:09 +01:00
Alejandro Celaya
752100f1ce Create migration for new rules and conditions tables 2024-02-24 17:30:46 +01:00
Alejandro Celaya
dae083c540
Merge pull request #2023 from acelaya-forks/feature/unused-env-vars
Remove unused entries from EnvVars enum
2024-02-24 17:29:46 +01:00
Alejandro Celaya
857c3a4f8d Remove unused entries from EnvVars enum 2024-02-24 17:26:12 +01:00
Alejandro Celaya
acc4c4756e Simplify and normalize API tests script 2024-02-23 19:30:58 +01:00
Alejandro Celaya
0bacb215c5
Merge pull request #2019 from acelaya-forks/feature/long-url-as-text
Change long URL columns to TEXT type
2024-02-22 09:39:46 +01:00
Alejandro Celaya
d1a6e60b01 Add migration to update long URLs columns to text type 2024-02-22 09:35:14 +01:00
Alejandro Celaya
8f954151ca Change long URL columns to TEXT type 2024-02-21 19:43:02 +01:00
Alejandro Celaya
145d4eaaed
Merge pull request #2020 from acelaya-forks/feature/path-prefix
Feature/path prefix
2024-02-21 19:41:19 +01:00
Alejandro Celaya
7673232793 Add --path-prefix to short URL creation 2024-02-21 19:38:11 +01:00
Alejandro Celaya
f08951a9b9 Add unit test for short URL path prefix 2024-02-21 19:24:30 +01:00
Alejandro Celaya
ff963a9df4 Add API test for short URL path prefix 2024-02-21 19:14:30 +01:00
Alejandro Celaya
f30c74b987 Prepend path prefix to generated short code or custom slug 2024-02-21 18:06:06 +01:00
Alejandro Celaya
467dbdd183 Update to latest shlink-common 2024-02-21 17:57:45 +01:00
Alejandro Celaya
0e78deb8f2 Refactor ShortUrlInputFilter for creation and edition 2024-02-21 10:12:40 +01:00
Alejandro Celaya
50cc7ae632 Fix donate URL 2024-02-20 22:33:10 +01:00
Alejandro Celaya
512d765d60
Merge pull request #2018 from acelaya-forks/feature/remove-infection
Remove dependency on infection and mutation tests
2024-02-20 22:28:48 +01:00
Alejandro Celaya
7b9331bd14 Merge DB test jobs into one with a matrix 2024-02-20 22:26:04 +01:00
Alejandro Celaya
4f5ce9fb43 Remove dependency on infection and mutation tests 2024-02-20 22:20:16 +01:00
Alejandro Celaya
83f73eb631
Merge pull request #2017 from acelaya-forks/feature/improve-e2e-coverage
Simplify and improve how code coverage is generated in API and CLI tests
2024-02-20 22:03:17 +01:00
Alejandro Celaya
3f1b89d665 Install dependencies in upload-coverage CI job 2024-02-20 18:30:34 +01:00
Alejandro Celaya
8f6fc97fc8 Simplify and improve how code coverage is generated in API and CLI tests 2024-02-20 18:23:37 +01:00
Alejandro Celaya
a463e6f9d7
Merge pull request #2014 from acelaya-forks/feature/qr-code-improvements
Allow customizing color, background color and logo in QR codes
2024-02-19 23:22:57 +01:00
Alejandro Celaya
2a0364ca8f Update changelog 2024-02-19 23:13:09 +01:00
Alejandro Celaya
23e9ed93bb Add test for QrCodeAction with logo URL 2024-02-19 23:10:51 +01:00
Alejandro Celaya
689343d1c9 Test QR codes logic when providing a color 2024-02-18 21:02:35 +01:00
Alejandro Celaya
d01dc334d7 Update to endroid/qr-code 5 2024-02-18 19:58:19 +01:00
Alejandro Celaya
58a3791a5c Allow customizing color, background color and logo in QR codes 2024-02-18 14:22:25 +01:00
Alejandro Celaya
1a133af141
Merge pull request #2013 from acelaya-forks/feature/title-resolution-timeout
Add a 5-second timeout to title resolution
2024-02-18 14:21:46 +01:00
Alejandro Celaya
938fb6509e Add API test to verify titles for timing-out long URLs 2024-02-18 12:45:59 +01:00
Alejandro Celaya
d3bfd99210 Add a 3-second timeout to title resolution 2024-02-18 11:32:31 +01:00
Alejandro Celaya
3a1740fdca
Merge pull request #2012 from acelaya-forks/feature/remove-validate-url
Feature/remove validate url
2024-02-17 12:13:05 +01:00
Alejandro Celaya
e3de403c6c Remove support to validate long URLs during short URL creation/edition 2024-02-17 12:02:57 +01:00
Alejandro Celaya
5c1ab02753 Update shlink dependencies 2024-02-17 10:59:06 +01:00
Alejandro Celaya
e5713df008
Merge pull request #2011 from acelaya-forks/feature/update-symfony
Update to Symfony 7
2024-02-17 10:52:41 +01:00
Alejandro Celaya
95ea64980b Update to Symfony 7 2024-02-17 10:46:29 +01:00
Alejandro Celaya
c0a77b790d
Merge pull request #2009 from acelaya-forks/feature/doctrine-orm-3
Update to doctrine ORM 3.0
2024-02-17 10:36:29 +01:00
Alejandro Celaya
e073b4331a Update to doctrine ORM 3.0 2024-02-17 10:23:37 +01:00
Alejandro Celaya
e919901487
Merge pull request #2007 from acelaya-forks/feature/coverage-improvements
Feature/coverage improvements
2024-02-17 08:46:18 +01:00
Alejandro Celaya
13f9f106be Update to event-dispatcher without swoole 2024-02-17 08:41:53 +01:00
Alejandro Celaya
e9c7053ef5 Move code around generating code coverage to test-utils lib 2024-02-17 08:41:17 +01:00
Alejandro Celaya
62051c8809
Merge pull request #2006 from acelaya-forks/feature/fix-ci
Recover prev approach to generate API tests coverage
2024-02-16 23:46:06 +01:00
Alejandro Celaya
0a6a794e23 Recover prev approach to generate API tests coverage 2024-02-16 23:32:20 +01:00
Alejandro Celaya
01846657d1
Merge pull request #2003 from acelaya-forks/feature/improve-coverage-collection
Move E2E coverage collectors to shlink-test-utils
2024-02-16 23:27:44 +01:00
Alejandro Celaya
dd7545afdf Move E2E coverage collectors to shlink-test-utils 2024-02-16 23:25:42 +01:00
Alejandro Celaya
9296013596
Merge pull request #2005 from acelaya-forks/feature/remove-swoole
Drop support for openswoole
2024-02-16 23:18:39 +01:00
Alejandro Celaya
8015c6cc88 Skip extensions cache if there are no extensions to install 2024-02-16 23:11:38 +01:00
Alejandro Celaya
8c93444286 Do not set default value for php-extensions input in ci-setup action 2024-02-16 23:08:03 +01:00
Alejandro Celaya
96ed7cae0d Drop support for openswoole 2024-02-16 23:02:46 +01:00
Alejandro Celaya
72c4628b79
Merge pull request #2002 from acelaya-forks/feature/rr-e2e-tests
Feature/rr e2e tests
2024-02-16 07:57:04 +01:00
Alejandro Celaya
1117631717 Move rr tests config back to the config/roadrunner folder 2024-02-16 00:01:35 +01:00
Alejandro Celaya
60176060cb Update changelog 2024-02-15 23:42:03 +01:00
Alejandro Celaya
d949b54ef4 Switch to roadrunner as the default runtime for API tests 2024-02-15 23:39:50 +01:00
Alejandro Celaya
720db64a03 Switch to RoadRunner as default API test runtime 2024-02-14 09:31:26 +01:00
Alejandro Celaya
37e0978bfc
Merge pull request #1999 from acelaya-forks/feature/remove-deprecated-stuff
Removed deprecated features
2024-02-13 22:52:00 +01:00
Alejandro Celaya
cf355b0b69 Update shlink-common and shlink-installer 2024-02-13 22:46:25 +01:00
Alejandro Celaya
f2edb54b8b Document changes from v3 to v4 2024-02-13 09:30:37 +01:00
Alejandro Celaya
13ec27039d Ensure non-root user in Dockerfile 2024-02-13 08:55:22 +01:00
Alejandro Celaya
ad3805a560 Removed deprecated features 2024-02-12 23:18:30 +01:00
Alejandro Celaya
cc4afa7b62
Merge pull request #1998 from acelaya-forks/feature/default-php-8.3
Feature/default php 8.3
2024-02-11 11:56:20 +01:00
Alejandro Celaya
7a6bfed445 Update changelog 2024-02-11 11:23:34 +01:00
Alejandro Celaya
f2a7b687a9 Update docker images to PHP 8.3 2024-02-11 11:22:48 +01:00
Alejandro Celaya
522d021264
Merge pull request #1995 from acelaya-forks/feature/orphan-visits-filter
Support filtering orphan visits by type in VisitRepository
2024-02-10 18:37:17 +01:00
Alejandro Celaya
14a0db1f34 Update changelog 2024-02-10 18:28:54 +01:00
Alejandro Celaya
430883987a Add API test for type-filtering in orphan visits list 2024-02-10 18:26:19 +01:00
Alejandro Celaya
f17b641d46 Allow filtering orphan visits by type from the CLI 2024-02-10 18:19:28 +01:00
Alejandro Celaya
48a8290e92 Allow type filter property for orphan visits list 2024-02-10 17:51:42 +01:00
Alejandro Celaya
46acf4de1c Support filtering orphan visits by type in VisitRepository 2024-02-10 13:58:03 +01:00
Alejandro Celaya
17792a1603
Merge pull request #1994 from acelaya-forks/feature/docker-compose-secrets
Support loading env vars from secret files
2024-02-10 10:12:02 +01:00
Alejandro Celaya
a8611f5d80 Support loading env vars from secret files 2024-02-10 09:54:59 +01:00
Alejandro Celaya
deef938e97
Merge pull request #1991 from acelaya-forks/feature/remove-league-uri
Feature/remove league uri
2024-02-05 23:12:17 +01:00
Alejandro Celaya
e014cfa72a Remove dependency on league/uri 2024-02-05 23:05:31 +01:00
Alejandro Celaya
aa242eba25 Remove League\Uri from ShortUrlRedirectionBuilder 2024-02-05 22:13:59 +01:00
Alejandro Celaya
0ac5569d60
Merge pull request #1989 from acelaya-forks/feature/request-id-lib
Feature/request id lib
2024-02-04 14:38:49 +01:00
Alejandro Celaya
7c3e3442c2 Update changelog 2024-02-04 14:18:16 +01:00
Alejandro Celaya
0f894dcdfe Replace request-id middleware dependency with userland code 2024-02-04 14:16:42 +01:00
Alejandro Celaya
361d987f47
Merge pull request #1970 from shlinkio/develop
Release 3.7.3
2024-01-04 14:07:53 +01:00
Alejandro Celaya
6017db260a Add v3.7.3 to changelog 2024-01-04 14:02:00 +01:00
Alejandro Celaya
f9c9b3d981
Merge pull request #1969 from acelaya-forks/feature/mountable-data-dir
Feature/mountable data dir
2024-01-04 08:42:41 +01:00
Alejandro Celaya
e7b876f4e6 Update changelog 2024-01-03 19:42:33 +01:00
Alejandro Celaya
554b948775 Create data directories in docker entry point if they don't exist 2024-01-03 19:22:33 +01:00
Alejandro Celaya
9bdbb59401 Update shlinkio/shlink-testing-utils 2024-01-03 10:08:03 +01:00
Alejandro Celaya
377861c5f1 Move migrations to module/Core 2024-01-02 17:55:23 +01:00
Alejandro Celaya
26c2aaf567
Merge pull request #1963 from shlinkio/develop
Release 3.7.2
2023-12-26 16:23:49 +01:00
Alejandro Celaya
62b54ceaaf Add v3.7.2 to changelog 2023-12-26 16:16:10 +01:00
Alejandro Celaya
625eba76c7
Merge pull request #1962 from acelaya-forks/feature/disabled-qr-codes
Allow QR codes to be generated for disabled short URLs
2023-12-24 16:55:52 +01:00
Alejandro Celaya
e12bda3f42 Add API test to verify QR codes return a 404 for disabled short URLs 2023-12-24 10:37:09 +01:00
Alejandro Celaya
0f0301ae5c Update changelog 2023-12-24 10:27:25 +01:00
Alejandro Celaya
8d1776af98 Test error when short URLs cannot be resolved 2023-12-24 10:25:58 +01:00
Alejandro Celaya
c597738915 Test how URLs are resolved in QrCodeAction 2023-12-24 10:13:19 +01:00
Alejandro Celaya
639329dbe4 Update installer 2023-12-24 09:48:44 +01:00
Alejandro Celaya
92b0525b6e
Update Twitter badge 2023-12-23 11:14:12 +01:00
Alejandro Celaya
06306aabd5 Allow QR codes to be generated for disabled short URLs 2023-12-22 13:29:22 +01:00
Alejandro Celaya
225905fcdb update changelog 2023-12-19 11:22:40 +01:00
Alejandro Celaya
8ca2b3c641
Merge pull request #1955 from acelaya-forks/feature/artifact-actions
Update artifact GitHub actions
2023-12-19 11:19:34 +01:00
Alejandro Celaya
ac1737492b Update artifact GitHub actions 2023-12-19 11:13:13 +01:00
Alejandro Celaya
a63075eb4c
Merge pull request #1953 from shlinkio/develop
Release 3.7.1
2023-12-17 20:06:25 +01:00
Alejandro Celaya
97e9dfad67
Merge pull request #1952 from shlinkio/feature/rr-logs-improvement
Feature/rr logs improvement
2023-12-17 19:59:21 +01:00
Alejandro Celaya
17c4f13568 Set fixed versions for Shlink dependencies 2023-12-17 19:49:50 +01:00
Alejandro Celaya
3b5243689b Fine-tune RoadRunner logs to avoid too many useless info 2023-12-17 19:26:28 +01:00
Alejandro Celaya
4d28adf4a7
Merge pull request #1948 from acelaya-forks/feature/fix-postgres-import
Fix error when importing short URLs while using Postgres
2023-12-16 20:38:46 +01:00
Alejandro Celaya
1b14bb07b1 Fix error when importing short URLs while using Postgres 2023-12-16 20:22:39 +01:00
Alejandro Celaya
3a43aa4d41
Merge pull request #1942 from acelaya-forks/feature/geoip-3
Update to geolite2 v3
2023-12-07 07:52:58 +01:00
Alejandro Celaya
2340b4f601 Update to geolite2 v3 2023-12-06 21:48:54 +01:00
Alejandro Celaya
664886eddf Support laminas-diactoros 3 2023-11-30 22:10:41 +01:00
Alejandro Celaya
d3570dac0b
Merge pull request #1937 from acelaya-forks/feature/remove-functional
Feature/remove functional
2023-11-30 18:53:21 +01:00
Alejandro Celaya
1854cc2f19 Remove last references to functional-php 2023-11-30 18:39:27 +01:00
Alejandro Celaya
bff4bd12ae Removed more functional-php usages 2023-11-30 14:34:44 +01:00
Alejandro Celaya
549c6605f0 Replaced usage of Functional\contians 2023-11-30 09:13:29 +01:00
Alejandro Celaya
f50263d2d9 Remove usage of Functional\map function 2023-11-29 12:34:13 +01:00
Alejandro Celaya
c80ec54508
Merge pull request #1933 from shlinkio/develop
Release 3.7.0
2023-11-25 20:22:38 +01:00
Alejandro Celaya
a91a560651 Fix typo in version contraint 2023-11-25 20:12:41 +01:00
Alejandro Celaya
a931c60230 Point to actual versions on shlink deps 2023-11-25 20:08:29 +01:00
Alejandro Celaya
479a331008
Merge pull request #1932 from acelaya-forks/feature/ssl-connections
Feature/ssl connections
2023-11-25 18:11:30 +01:00
Alejandro Celaya
5d99b1aef0 Update changelog 2023-11-25 13:08:15 +01:00
Alejandro Celaya
17e0c9176e Add support for SSL on Redis and RabbitMQ connections 2023-11-25 13:04:30 +01:00
Alejandro Celaya
48d7388bdc
Merge pull request #1931 from acelaya-forks/feature/update-installer
Update to installer with runtime question
2023-11-25 10:01:19 +01:00
Alejandro Celaya
aa01c034db Update to installer with runtime question 2023-11-25 09:55:01 +01:00
Alejandro Celaya
9035161b65
Merge pull request #1928 from acelaya-forks/feature/redis-urlencoded
Allow redis credentials be URL-decoded before passing them to connection
2023-11-23 11:29:46 +01:00
Alejandro Celaya
df57ca5edb Allow redis credentials be URL-decoded before passing them to connection 2023-11-23 11:22:23 +01:00
Alejandro Celaya
0511c73cc8
Merge pull request #1926 from acelaya-forks/feature/geolite-download-warn
Print a warning when manually running visit:download-db with no license
2023-11-23 09:42:31 +01:00
Alejandro Celaya
a3554eaf74 Print a warning when manually running visit:download-db with no license 2023-11-23 09:31:02 +01:00
Alejandro Celaya
cb0bac55d2
Merge pull request #1920 from acelaya-forks/feature/matomo-integration
Feature/matomo integration
2023-11-22 18:59:45 +01:00
Alejandro Celaya
bd5d3f6897 Update changelog 2023-11-22 18:51:47 +01:00
Alejandro Celaya
5e6e386c5a Add matomo dev config 2023-11-22 18:30:03 +01:00
Alejandro Celaya
e783bdc456 Set referrer when sending visits to Matomo 2023-11-21 10:01:27 +01:00
Alejandro Celaya
316b88cea6 Add 10 second timeout to matomo requests 2023-11-21 08:34:37 +01:00
Alejandro Celaya
c03eea789c Fix LocateVisitTest 2023-11-21 08:25:58 +01:00
Alejandro Celaya
bd5d3cb6fa Create SendVisitToMatomoTest 2023-11-20 10:11:15 +01:00
Alejandro Celaya
e1f2dcc136 Create MatomoTrackerBuilderTest 2023-11-17 23:31:23 +01:00
Alejandro Celaya
5e6ebfa5a9 Update shlink-event-dispatcher 2023-11-17 09:32:07 +01:00
Alejandro Celaya
a7ed14a1c9 Enhance EnableListenerCheckerTest with support for matomo listener 2023-11-16 09:24:52 +01:00
Alejandro Celaya
f88d57b2b6 Do not dispatch async job for matomo if disabled 2023-11-15 20:02:35 +01:00
Alejandro Celaya
9dbd15bc0c Add logic to send visits to a matomo instance 2023-11-15 19:57:58 +01:00
Alejandro Celaya
0edb3e5c2c Update to installer with support for matomo 2023-11-11 20:12:39 +01:00
Alejandro Celaya
7501eca71e Update matomo container 2023-11-09 09:04:41 +01:00
Alejandro Celaya
b145d106b0 Add matomo env vars and config 2023-11-09 08:59:34 +01:00
Alejandro Celaya
b4386a3508 Add matomo container 2023-11-09 08:58:58 +01:00
Alejandro Celaya
36e2a9387d
Merge pull request #1917 from acelaya-forks/feature/php-8.3-deps
Update native deps for PHP 8.3 preparation
2023-11-08 19:13:29 +01:00
Alejandro Celaya
14c68b4bbe Update native deps for PHP 8.3 preparation 2023-11-08 18:51:03 +01:00
Alejandro Celaya
d6fedaf926
Merge pull request #1913 from acelaya-forks/feature/fix-delete-multi-segment-visits
Fix short URL visits deletion when multi-segment slugs are enabled
2023-11-08 09:20:06 +01:00
Alejandro Celaya
8d35c1dde2 Fix short URL visits deletion when multi-segment slugs are enabled 2023-11-08 09:06:12 +01:00
Alejandro Celaya
85b5f760e5 Update dev swagger UI 2023-11-05 10:58:41 +01:00
Alejandro Celaya
1a4a107952
Merge pull request #1911 from acelaya-forks/feature/slug-url-chars
Feature/slug url chars
2023-11-05 10:52:46 +01:00
Alejandro Celaya
e431395a12 Update changelog 2023-11-05 10:31:51 +01:00
Alejandro Celaya
cfc3d54122 Do not allow URL reserved characters in custom slugs 2023-11-05 10:30:40 +01:00
Alejandro Celaya
d9d6d5bd9c
Merge pull request #1907 from acelaya-forks/feature/php-8.3
Add support for PHP 8.3
2023-11-04 13:30:31 +01:00
Alejandro Celaya
32f465f7a6 Add PHP 8.3 to building pipeline 2023-11-04 13:15:15 +01:00
Alejandro Celaya
4cddb573a0 Ignore all platform reqs on PHP 8.3, as openswoole cannot be installed there 2023-11-04 13:03:10 +01:00
Alejandro Celaya
2cb8486bb3 Add support for PHP 8.3 2023-11-04 12:42:31 +01:00
Alejandro Celaya
2a782ab60b
Merge pull request #1897 from acelaya-forks/feature/disable-health-endpoint-logs
Do not log requests to the health endpoint
2023-10-20 20:44:49 +02:00
Alejandro Celaya
5bde273d59 Fix Rest's ConfigProvider test 2023-10-20 09:42:48 +02:00
Alejandro Celaya
41e322fd47 Update changelog 2023-10-20 09:34:20 +02:00
Alejandro Celaya
55885b0f25 Do not log requests to the health endpoint 2023-10-20 09:33:29 +02:00
Alejandro Celaya
d419b9d62d
Merge pull request #1891 from acelaya-forks/feature/customizable-cache-namespace
Feature/customizable cache namespace
2023-10-07 11:33:40 +02:00
Alejandro Celaya
3bdc05fbc4 Fix CliTestUtils for PHPUnit 10.4 2023-10-07 10:56:04 +02:00
Alejandro Celaya
57053d66a4 Update changelog 2023-10-06 09:21:53 +02:00
Alejandro Celaya
9d8ea0a4f6 Allow cache namespace to be customizable via env var 2023-10-06 09:19:55 +02:00
Alejandro Celaya
46354baae9
Merge pull request #1886 from acelaya-forks/feature/chronos-3
Update to chronos 3
2023-09-30 21:19:01 +02:00
Alejandro Celaya
27c48414da Update to chronos 3 2023-09-30 21:03:17 +02:00
Alejandro Celaya
25b1138000 Fix merge conflicts 2023-09-23 09:06:38 +02:00
Alejandro Celaya
4cf3bc08f9
Merge pull request #1883 from shlinkio/release/v3.6.4
Release 3.6.4
2023-09-23 08:57:10 +02:00
Alejandro Celaya
7e093a3fd8 Fix date in changelog 2023-09-23 08:41:57 +02:00
Alejandro Celaya
abecf3be02
Merge pull request #1882 from acelaya-forks/feature/create-api-key
Feature/create api key
2023-09-23 08:40:53 +02:00
Alejandro Celaya
3d9b48c5fd Create InitialApiKeyCommand cli test 2023-09-23 08:28:57 +02:00
Alejandro Celaya
ba4a66f772 Add InitialApiKeyCommand unit test 2023-09-23 08:16:22 +02:00
Alejandro Celaya
ec839183e8 Add unit test for ApiKeyService::createInitial 2023-09-23 08:01:10 +02:00
Alejandro Celaya
b0ec0601c1 Update to latest shlink-installer 2023-09-22 10:00:19 +02:00
Alejandro Celaya
637d8334f4 New CLI command to create the initial API key idempotently 2023-09-21 09:47:21 +02:00
Alejandro Celaya
6db46b50e9 Roll back change to allow creating API keys with custom value 2023-09-21 08:58:05 +02:00
Alejandro Celaya
f6b1cc7556 Test API key creation with custom key 2023-09-19 10:14:04 +02:00
Alejandro Celaya
65a0a90a51 Allow custom API keys to be created 2023-09-19 09:10:17 +02:00
Alejandro Celaya
38a7872fbf
Merge pull request #1878 from acelaya-forks/feature/add-swagger-ui-dev
Add a swagger ui container for dev env
2023-09-17 12:01:05 +02:00
Alejandro Celaya
5839cc5926 Add a swagger ui container for dev env 2023-09-17 11:59:23 +02:00
Alejandro Celaya
49bd230474
Merge pull request #1874 from acelaya-forks/feature/redis-lock-namespace
Make sure locks include the same cache namespace when sent to Redis
2023-09-12 21:44:45 +02:00
Alejandro Celaya
074f2135f6 Make sure locks include the same cache namespace when sent to Redis 2023-09-12 21:20:38 +02:00
Alejandro Celaya
ef073d59ca
Merge pull request #1872 from acelaya-forks/bugfix/db-commands-timeout
Fix incorrect timeout in init commands
2023-09-12 08:33:13 +02:00
Alejandro Celaya
a3b2f94339 Make sure local config is not loaded in tests 2023-09-12 08:21:34 +02:00
Alejandro Celaya
b17c576a30 Fix incorrect timeout in init commands 2023-09-11 09:07:18 +02:00
Alejandro Celaya
bc4156ca3c
Merge pull request #1858 from acelaya-forks/feature/update-deps
Update dependencies
2023-08-19 12:51:02 +02:00
Alejandro Celaya
b747b8448e Update dependencies 2023-08-19 12:03:29 +02:00
Alejandro Celaya
aa4b9fc27e Replace references to docker-compose with docker compose 2023-08-03 09:10:05 +02:00
Alejandro Celaya
3f3c2c3d1e Add form config for Feature Request issues 2023-08-03 09:08:35 +02:00
Alejandro Celaya
4b49f8fb7f Use issue form for bugs 2023-07-25 08:45:24 +02:00
Alejandro Celaya
550f3b28ea Use textarea instead of markdown for main field in help-wanted discussion 2023-07-15 11:09:36 +02:00
Alejandro Celaya
6d4c232345
Merge pull request #1844 from acelaya-forks/feature/help-discussion-template
Add discussion template for 'Help wanted'
2023-07-15 10:59:51 +02:00
Alejandro Celaya
2d085ad6f4 Add discussion template for 'Help wanted' 2023-07-15 10:59:39 +02:00
Alejandro Celaya
3ea83f5cc3
Merge pull request #1836 from acelaya-forks/feature/oas-3.1
Feature/oas 3.1
2023-07-12 19:42:42 +02:00
Alejandro Celaya
b47bd0fc7a Use stable version of devizzent/cebe-php-openapi 2023-07-12 11:33:58 +02:00
Alejandro Celaya
27e90c4c26 Update changelog 2023-07-12 11:30:12 +02:00
Alejandro Celaya
ad1a846d8e Remove references to nullable in OAS 2023-07-12 11:29:44 +02:00
Alejandro Celaya
78f75a06df Updated swagger docs to v3.1, and fixed some 'required' definitions 2023-07-12 11:29:44 +02:00
Alejandro Celaya
262d714751 Add ADR for latest docker image publishing change 2023-07-09 11:31:13 +02:00
Alejandro Celaya
f71c3bba5c
Merge pull request #1842 from acelaya-forks/feature/docker-build-on-tag
Build docker image only on tags
2023-07-09 09:59:25 +02:00
Alejandro Celaya
8b495064b2 Build docker image only on tags 2023-07-09 09:45:46 +02:00
Alejandro Celaya
57a36204db
Merge pull request #1840 from acelaya-forks/feature/docker-no-interactive-init
Improve verbosity hint when an error occurs during docker init
2023-07-06 09:11:04 +02:00
Alejandro Celaya
7cc1722858 Improve verbosity hint when an error occurs during docker init 2023-07-05 09:58:51 +02:00
Alejandro Celaya
af50887361 Fix typo 2023-07-01 16:33:52 +02:00
Alejandro Celaya
99c8c6c8d4
Merge pull request #1832 from acelaya-forks/feature/migrations-config
Refactor cli-config file as it's currently used by doctrine migrations only
2023-06-23 22:05:24 +02:00
Alejandro Celaya
1d7c9fd553 Refactor cli-config file as it's currently used by doctrine migrations only 2023-06-23 09:16:33 +02:00
Alejandro Celaya
274c454fa4
Merge pull request #1827 from acelaya-forks/feature/question-discussion
Make sure people asking questions opens a discussion instead of an issue
2023-06-21 08:55:07 +02:00
Alejandro Celaya
453fcc4675 Make sure people asking questions opens a discussion instead of an issue 2023-06-21 08:54:03 +02:00
Alejandro Celaya
42427bfd74
Merge pull request #1824 from acelaya-forks/feature/api-coverage-fix
Update shlink-test-utils to fix coverage ID on API tests
2023-06-18 19:24:03 +02:00
Alejandro Celaya
33eedd2270 Update shlink-test-utils to fix coverage ID on API tests 2023-06-18 18:59:15 +02:00
Alejandro Celaya
edaf9e34f4
Merge pull request #1823 from acelaya-forks/feature/external-data-providers
Feature/external data providers
2023-06-18 11:06:24 +02:00
Alejandro Celaya
965325aa7c Replace traits with static classes in CLI unit tests 2023-06-18 10:51:59 +02:00
Alejandro Celaya
bdf2bbd0f1 Replace traits with external data providers in Core unit tests 2023-06-18 10:41:24 +02:00
Alejandro Celaya
dc4aab2cab Replace traits with external data providers in API tests 2023-06-18 10:36:45 +02:00
Alejandro Celaya
3b1f6c69de
Merge pull request #1822 from acelaya-forks/feature/fix-installer-command-timeouts
Fix incorrect timeout in init commands
2023-06-15 19:07:32 +02:00
Alejandro Celaya
cdf5082cff Fix incorrect timeout in init commands 2023-06-15 18:53:42 +02:00
Alejandro Celaya
61686ed6ea Fix JamesIves/github-pages-deploy-action version 2023-06-14 18:27:03 +02:00
Alejandro Celaya
f63b96fd05 Fix merge conflicts 2023-06-14 18:25:09 +02:00
Alejandro Celaya
228bd83b75
Merge pull request #1818 from acelaya-forks/feature/fix-sqlite-db-creation
Fix Shlink trying to create SQLite database tables even if they already exist
2023-06-14 18:22:39 +02:00
Alejandro Celaya
a21dcb852a Fix Shlink trying to create SQLite database tables even if they already exist 2023-06-14 18:08:39 +02:00
Alejandro Celaya
6558c37b9a Fix merge conflicts 2023-06-11 20:10:29 +02:00
Alejandro Celaya
e6720cce12
Merge pull request #1814 from acelaya-forks/feature/update-test-utils
Update to latest test utils lib
2023-06-11 20:05:45 +02:00
Alejandro Celaya
22d039c550 Update to latest test utils lib 2023-06-11 19:54:33 +02:00
Alejandro Celaya
a21fcd72ce
Merge pull request #1807 from acelaya-forks/feature/mercure-options
Use MercureOptions instead of raw config, where possible
2023-06-08 19:00:43 +02:00
Alejandro Celaya
058391cf06
Merge pull request #1809 from acelaya-forks/feature/fix-rr-download
Update to a shlink-installer version that fixes rr download
2023-06-08 18:59:28 +02:00
Alejandro Celaya
24e6acc6e8 Update to a shlink-installer version that fixes rr download 2023-06-08 18:47:55 +02:00
Alejandro Celaya
8e3508f28d Use MercureOptions instead of raw config, where possible 2023-06-06 20:25:14 +02:00
Alejandro Celaya
e72b424968 Fix merge conflicts 2023-06-04 09:33:16 +02:00
Alejandro Celaya
56d299a7dc
Merge pull request #1804 from acelaya-forks/feature/release-3.6.1
Feature/release 3.6.1
2023-06-04 09:30:19 +02:00
Alejandro Celaya
575e6bf707 Downgrade PHPUnit to avoid infection error 2023-06-04 09:13:37 +02:00
Alejandro Celaya
e50c21440f Define default values for env vars used in rr prod config 2023-06-04 09:07:41 +02:00
Alejandro Celaya
7cff11080d Update changelog 2023-06-04 08:57:07 +02:00
Alejandro Celaya
72381f9844 Change order to create initial database to avoid permission errors 2023-06-04 08:54:08 +02:00
Alejandro Celaya
7c649e7497
Merge pull request #1801 from acelaya-forks/feature/no-run-disabled-tasks
Feature/no run disabled tasks
2023-06-03 19:19:08 +02:00
Alejandro Celaya
eff308cd43 Update changelog 2023-06-03 17:58:26 +02:00
Alejandro Celaya
bd3745118e Add logic to prevent roadrunner/openswoole jobs for tasks that will do nothing 2023-06-03 17:56:52 +02:00
Alejandro Celaya
602ebef02a
Merge pull request #1800 from acelaya-forks/feature/deprecate-openswoole
Deprecate support for openswoole
2023-06-03 10:06:03 +02:00
Alejandro Celaya
9040937376 Stick with PHPUnit 10.1 until API tests coverage is fixed 2023-06-03 09:24:43 +02:00
Alejandro Celaya
a11be5b2ff Deprecate support for openswoole 2023-06-03 09:08:07 +02:00
Alejandro Celaya
6351d0b87d
Merge pull request #1797 from acelaya-forks/feature/improve-new-db-check
Feature/improve new db check
2023-06-01 20:01:39 +02:00
Alejandro Celaya
fae3434393 Update changelog 2023-06-01 19:28:15 +02:00
Alejandro Celaya
4013ae87dd Change order to create initial database to avoid permission errors 2023-06-01 19:27:04 +02:00
Alejandro Celaya
cb4ba58b08
Merge pull request #1795 from acelaya-forks/feature/non-orphan-role
Feature/non orphan role
2023-05-31 09:43:18 +02:00
Alejandro Celaya
8c94452348 Fix CLI tests 2023-05-31 09:33:05 +02:00
Alejandro Celaya
ea96a00b12 Update changelog 2023-05-31 09:24:23 +02:00
Alejandro Celaya
be26dd58c3 Add API tests to cover usage of orphan visits restricted keys 2023-05-31 09:22:40 +02:00
Alejandro Celaya
eaba5edf7f Restrict interaction with orphan visits when API key has that role 2023-05-31 09:11:20 +02:00
Alejandro Celaya
12da04ef37 Add ApiKey check to tell if it has any role that is short-url restrictive 2023-05-30 09:32:44 +02:00
Alejandro Celaya
8b03532ddb Add ORPHAN_VISITS_EXCLUDED API key role 2023-05-30 09:15:35 +02:00
Alejandro Celaya
112b54ec7d
Merge pull request #1793 from acelaya-forks/feature/drop-php-8.1
Drop support for PHP 8.1
2023-05-29 21:53:30 +02:00
Alejandro Celaya
ee6a8ede0a Drop support for PHP 8.1 2023-05-29 09:43:12 +02:00
Alejandro Celaya
07ce5f05a2 Add missing entry to v3.6.0 changelog 2023-05-29 09:02:59 +02:00
Alejandro Celaya
7b04016ca2 Fix version number on JamesIves/github-pages-deploy-action GitHub action 2023-05-24 08:59:21 +02:00
Alejandro Celaya
b6792d3fb8
Merge pull request #1792 from shlinkio/develop
Release 3.6.0
2023-05-24 08:46:25 +02:00
Alejandro Celaya
2f0d658432
Merge pull request #1791 from acelaya-forks/feature/fix-cpu-100
Update changelog
2023-05-23 23:25:39 +02:00
Alejandro Celaya
8c1865c3ec Update changelog 2023-05-23 23:15:59 +02:00
Alejandro Celaya
096d2098d6 Update installer 2023-05-23 18:42:50 +02:00
Alejandro Celaya
882d64ae11 Add deprecation note for ENABLE_PERIODIC_VISIT_LOCATE env var 2023-05-23 10:55:49 +02:00
Alejandro Celaya
3352bcd186
Merge pull request #1789 from acelaya-forks/feature/improved-dependency-locks
Feature/improved dependency locks
2023-05-21 18:44:10 +02:00
Alejandro Celaya
9743c1624d Update changelog 2023-05-21 18:10:08 +02:00
Alejandro Celaya
e85d59c5a4 Add locks when creating short URL dependencies, to avoid race condition 2023-05-21 18:08:17 +02:00
Alejandro Celaya
ac0ff8fb94
Merge pull request #1787 from acelaya-forks/feature/shlink-init-command
Feature/shlink init command
2023-05-21 14:44:08 +02:00
Alejandro Celaya
90f93ee4ec Update changelog 2023-05-21 14:32:00 +02:00
Alejandro Celaya
794d926e3a Update docker entry point to use new shlink-installer init command 2023-05-21 14:30:20 +02:00
Alejandro Celaya
bd41ebef9f
Merge pull request #1785 from acelaya-forks/feature/non-root-support
Allow running docker container as non-root
2023-05-19 20:29:40 +02:00
Alejandro Celaya
725370704f Update changelog 2023-05-19 19:50:05 +02:00
Alejandro Celaya
f03b7689ce Allow running docker container as non-root 2023-05-19 19:48:20 +02:00
Alejandro Celaya
fb31e2a5e4
Merge pull request #1782 from acelaya-forks/feature/clear-orphan-visits
Feature/clear orphan visits
2023-05-18 09:49:31 +02:00
Alejandro Celaya
d688c6da7e Update changelog 2023-05-18 09:36:50 +02:00
Alejandro Celaya
618784dc3b Create command to delete all orphan visits 2023-05-18 09:35:42 +02:00
Alejandro Celaya
9d64d4ed1d Create abstract base class for commands deleting visits 2023-05-18 09:33:15 +02:00
Alejandro Celaya
7f02243c6c Rename short-url:delete-visits to short-url:visits-delete for consistency with other commands 2023-05-18 09:19:01 +02:00
Alejandro Celaya
3916c68126 Add DeleteOrphanVisitsTest API test 2023-05-18 09:09:44 +02:00
Alejandro Celaya
a6f0c66331 Document endpoint to delete orphan visits 2023-05-18 09:06:52 +02:00
Alejandro Celaya
bdfb220126 Create REST action to delete orphan visits 2023-05-18 09:04:28 +02:00
Alejandro Celaya
abcf2f86be Create service to delete orphan visits 2023-05-18 09:01:57 +02:00
Alejandro Celaya
a4d8ebdfc9 Create DB logic to delete orphan visits 2023-05-18 08:58:07 +02:00
Alejandro Celaya
b51c149c30
Merge pull request #1779 from acelaya-forks/feature/clear-short-url-visits
Feature/clear short url visits
2023-05-17 09:20:28 +02:00
Alejandro Celaya
39095a3098 Fix coding styles 2023-05-17 08:57:36 +02:00
Alejandro Celaya
765199727e Update changelog 2023-05-16 09:29:22 +02:00
Alejandro Celaya
c7043af853 Create DeleteShortUrlVisitsCommandTest 2023-05-16 09:26:29 +02:00
Alejandro Celaya
02a8ef7dd9 Create DeleteShortUrlVisitsCommand 2023-05-15 09:48:24 +02:00
Alejandro Celaya
6bb8c1b2f5 Rename CLI Option namespace to Input 2023-05-15 09:02:23 +02:00
Alejandro Celaya
3cf253fd0f Document short URLs visits deletion endpoint 2023-05-14 18:25:27 +02:00
Alejandro Celaya
0365728337 Create DeleteShortUrlVisitsTest 2023-05-14 13:35:15 +02:00
Alejandro Celaya
b8143a5bb4 Create VisitDeleterRepositoryTest 2023-05-14 13:04:45 +02:00
Alejandro Celaya
531a19dde9 Refactor short URL visits deletion layers 2023-05-14 13:04:17 +02:00
Alejandro Celaya
69ff7de481 Create ShortUrlVisitsDeleterTest 2023-05-14 12:32:54 +02:00
Alejandro Celaya
ffc0555c7c Create DeleteShortUrlVisitsActionTest 2023-05-14 12:15:35 +02:00
Alejandro Celaya
84a7981dfa Create REST action to delete short URL visits 2023-05-14 12:00:08 +02:00
Alejandro Celaya
2573c2bf98 Update roadrunner config 2023-05-14 11:56:49 +02:00
Alejandro Celaya
3b4c1501f3
Set platforms to be used for openswoole docker image 2023-05-07 17:13:26 +02:00
Alejandro Celaya
e836bedecc
Merge pull request #1775 from acelaya-forks/feature/default-roadrunner
Feature/default roadrunner
2023-05-07 13:34:53 +02:00
Alejandro Celaya
a797b74a70 Standardize logger for all Shlink execution contexts 2023-05-07 13:18:19 +02:00
Alejandro Celaya
ab497403ca
Merge pull request #1773 from acelaya-forks/feature/rr-friendly-installer
Update shlink-installer
2023-05-06 18:07:57 +02:00
Alejandro Celaya
d4dea9a1d2 Update shlink-installer 2023-05-06 10:12:42 +02:00
Alejandro Celaya
28d93ea5e0 Update changelog 2023-05-03 08:59:47 +02:00
Alejandro Celaya
e6a31b16ed Switch to roadrunner as default docker runtime 2023-05-03 08:59:09 +02:00
Alejandro Celaya
9553192281
Merge pull request #1766 from acelaya-forks/feature/rr-cli-2.5
Update to rr-cli 2.5, and do not generate config
2023-05-02 20:01:51 +02:00
Alejandro Celaya
74069f2d24 Skip API tests fetching Twitter during CI 2023-05-02 19:51:37 +02:00
Alejandro Celaya
b4b00a57c1 Update chrome user agent used for anti-bots 2023-05-02 19:40:23 +02:00
Alejandro Celaya
a516ef691d Update to rr-cli 2.5, and do not generate config 2023-05-02 08:43:14 +02:00
Alejandro Celaya
e80b7448f5
Merge pull request #1761 from acelaya-forks/feature/null-default-domain
Feature/null default domain
2023-04-23 15:57:02 +02:00
Alejandro Celaya
f129544f83 Update changelog 2023-04-23 15:22:40 +02:00
Alejandro Celaya
9fa291a32f Update shlink-common 2023-04-23 15:20:33 +02:00
Alejandro Celaya
d06e92ffc2 Created CLI test for short URL importing 2023-04-23 13:26:59 +02:00
Alejandro Celaya
1b83344995 Create CLI test checking default domain is ignored even if explicitly provided 2023-04-23 11:20:54 +02:00
Alejandro Celaya
cf49393ef2 Add --show-domain flag to list short URLs command 2023-04-23 11:19:05 +02:00
Alejandro Celaya
f2ecbceae9 Update changelog 2023-04-22 19:46:28 +02:00
Alejandro Celaya
c582eba753 Make sure short URL domain is resolved as null when default one is provided 2023-04-22 19:44:04 +02:00
Alejandro Celaya
de86b62cdd
Merge pull request #1759 from acelaya-forks/feature/fix-docker-build
Fix docker image build
2023-04-20 09:00:39 +02:00
Alejandro Celaya
73150471e9 Fix docker image build 2023-04-19 18:57:35 +02:00
Alejandro Celaya
ec751f4ac2
Merge pull request #1758 from acelaya-forks/feature/roadrunner-2023
Feature/roadrunner 2023
2023-04-19 08:11:18 +02:00
Alejandro Celaya
e652166289 Update changelog 2023-04-18 23:24:21 +02:00
Alejandro Celaya
a671d555cb Update to roadrunner 2023 2023-04-18 23:22:48 +02:00
Alejandro Celaya
6240554f4c
Merge pull request #1757 from acelaya-forks/feature/shlink-json
Migrate to shlinkio/shlink-json
2023-04-18 23:14:11 +02:00
Alejandro Celaya
4ee9c9bbe3 Migrate to shlinkio/shlink-json 2023-04-18 23:04:58 +02:00
Alejandro Celaya
c830439085
Merge pull request #1752 from acelaya-forks/feature/phpunit-10.1
Update phpunit configs to fulfil v10.1
2023-04-14 09:55:38 +02:00
Alejandro Celaya
f2196583c8 Update phpunit configs to fulfil v10.1 2023-04-14 09:44:01 +02:00
Alejandro Celaya
3dbca2115c
Merge pull request #1751 from acelaya-forks/feature/openswoole-22
Add support for openswoole 22
2023-04-14 09:16:47 +02:00
Alejandro Celaya
b45d8de27d Ignore openswoole dep on roadrunner tests CI 2023-04-14 09:02:17 +02:00
Alejandro Celaya
3ba46bbbfa Add support for openswoole 22 2023-04-14 08:58:54 +02:00
Alejandro Celaya
06f3f0c86c
Merge pull request #1750 from acelaya-forks/feature/update-delete-artifacts
Update to geekyeggo/delete-artifact@2
2023-04-13 08:58:24 +02:00
Alejandro Celaya
06f07e3e40 Update to geekyeggo/delete-artifact@2 2023-04-12 19:13:35 +02:00
Alejandro Celaya
740740b8c6 Update to latest JamesIves/github-pages-deploy-action 2023-04-12 19:11:06 +02:00
Alejandro Celaya
b6ed39b18b
Merge pull request #1749 from shlinkio/develop
Release 3.5.4
2023-04-12 19:03:25 +02:00
Alejandro Celaya
958c4704f8
Merge pull request #1748 from acelaya-forks/feature/create-error
Feature/create error
2023-04-12 18:52:18 +02:00
Alejandro Celaya
ef075fb0ce Fix test when CLI output viewport is too narrow 2023-04-12 18:36:28 +02:00
Alejandro Celaya
556520583a Update changelog 2023-04-12 18:31:57 +02:00
Alejandro Celaya
399c56a097 Print warning when trying to create short URL from CLI on openswoole in verbose mode 2023-04-12 18:30:02 +02:00
Alejandro Celaya
f078d95588 Capture error on real-time update when creating short URL 2023-04-12 09:25:01 +02:00
Alejandro Celaya
33911afcd6
Merge pull request #1744 from acelaya-forks/feature/regression-fix
Feature/regression fix
2023-04-11 19:13:08 +02:00
Alejandro Celaya
ae8d31e83f Add test case for deeplink long URLs 2023-04-11 17:24:38 +02:00
Alejandro Celaya
72c4052012 Be less restrictive when validating long URLs 2023-04-10 18:05:57 +02:00
Alejandro Celaya
f713a1fa7e
Merge pull request #1737 from shlinkio/develop
Release 3.5.3
2023-03-31 22:07:51 +02:00
Alejandro Celaya
62488ac4e5
Merge pull request #1739 from acelaya-forks/feature/import-memory-leak
Feature/import memory leak
2023-03-31 10:00:36 +02:00
Alejandro Celaya
ab4c6e5fca Update changelog 2023-03-31 09:48:08 +02:00
Alejandro Celaya
26f4a969c9 Fix memory leak when importing big amounts of visits 2023-03-31 09:46:05 +02:00
Alejandro Celaya
703965915d
Merge pull request #1736 from acelaya-forks/feature/lcobucci-jwt-5
Update to latest shlink-common
2023-03-30 18:45:39 +02:00
Alejandro Celaya
24e38a3cf9 Update to latest shlink-common 2023-03-30 18:33:53 +02:00
Alejandro Celaya
b12cfaedf3
Merge pull request #1730 from acelaya-forks/feature/validate-uris
Feature/validate uris
2023-03-25 13:29:36 +01:00
Alejandro Celaya
71807e698c Update changelog 2023-03-25 11:23:01 +01:00
Alejandro Celaya
1d155298c1 Fix API tests 2023-03-25 11:23:01 +01:00
Alejandro Celaya
4dfc5ae681 Fix DB tests 2023-03-25 11:23:01 +01:00
Alejandro Celaya
26f237069c Fixed unit tests 2023-03-25 11:23:01 +01:00
Alejandro Celaya
b6e1c65c4c Enforce a schema to be provided when short URLs are created 2023-03-25 11:23:00 +01:00
Alejandro Celaya
11f94b8306
Merge pull request #1723 from acelaya-forks/feature/tags-list-performance-join-tags
Feature/tags list performance join tags
2023-03-16 21:57:43 +01:00
Alejandro Celaya
01bcedef7a Simplify how ordering field is resolved in tags list 2023-03-04 11:54:30 +01:00
Alejandro Celaya
e51384fcc0 Reduce duplicated logic when checking if an API key is admin 2023-03-04 10:22:46 +01:00
Alejandro Celaya
83c53c8b2e Add correct index on visits potential_bot column 2023-03-04 09:51:14 +01:00
Alejandro Celaya
1afe08caed Simplify how limits are applied to tags query 2023-03-04 09:50:38 +01:00
Alejandro Celaya
7289833928 Move join on short URLs to tags sub-query 2023-03-03 12:10:41 +01:00
Alejandro Celaya
f4d10df0f3 Delete no longer used spec file 2023-02-27 09:28:27 +01:00
Alejandro Celaya
652b0df054 Use native query builders for all queries/sub-queries in tags list 2023-02-27 09:21:11 +01:00
Alejandro Celaya
0e9ea5027c
Merge pull request #1705 from shlinkio/develop
Release 3.5.2
2023-02-16 19:36:59 +01:00
Alejandro Celaya
658303d375
Merge pull request #1706 from acelaya-forks/feature/fix-ms-ci
Comment-out unixodbc-dev installation in CI, as it's already present …
2023-02-16 19:33:08 +01:00
Alejandro Celaya
ccc3a4b584 Comment-out unixodbc-dev installation in CI, as it's already present in Ubuntu 22.04 2023-02-16 19:24:09 +01:00
Alejandro Celaya
ef5ac86e0a
Add v3.5.2 to changelog 2023-02-15 20:25:55 +01:00
Alejandro Celaya
91b90b276a
Merge pull request #1704 from acelaya-forks/feature/stronger-db-detection
Feature/stronger db detection
2023-02-15 19:19:11 +01:00
Alejandro Celaya
85c32c3c9a Fix CreateDatabaseCommandTest 2023-02-15 18:55:25 +01:00
Alejandro Celaya
40838255a7 Make sure database detection is not affected by the existence of foreign tables 2023-02-15 08:52:17 +01:00
Alejandro Celaya
a67ccb384f
Merge pull request #1697 from acelaya-forks/feature/phpunit-10
Feature/phpunit 10
2023-02-13 19:15:33 +01:00
Alejandro Celaya
cb31e5a581 Update to phpcov 9 2023-02-13 19:05:27 +01:00
Alejandro Celaya
3c12a55872 Merge branch 'develop' into feature/phpunit-10 2023-02-13 11:54:49 +01:00
Alejandro Celaya
41aec15fab Migrate new test to PHPUnit 10 2023-02-10 20:45:09 +01:00
Alejandro Celaya
245cb0e35d Fixed merge conflicts 2023-02-10 20:44:05 +01:00
Alejandro Celaya
97e965157b Update changelog 2023-02-09 20:43:07 +01:00
Alejandro Celaya
04bbd471ff Migrate from PHPUnit annotations to native attributes 2023-02-09 20:42:18 +01:00
Alejandro Celaya
650a286982 Update to PHPUnit 10 2023-02-09 09:32:38 +01:00
Alejandro Celaya
9cd97c2f1e
Merge pull request #1691 from shlinkio/develop
Release 3.5.1
2023-02-04 17:58:27 +01:00
Alejandro Celaya
5cec697be3
Merge pull request #1683 from shlinkio/develop
Release 3.5.0
2023-01-28 11:10:49 +01:00
Alejandro Celaya
067d1cc41c
Merge pull request #1637 from shlinkio/develop
Release 3.4.0
2022-12-16 22:55:02 +01:00
815 changed files with 23691 additions and 15564 deletions

View File

@ -1,5 +1,6 @@
bin/rr
config/autoload/*local*
config/params/shlink_dev_env.*
data/infra
data/cache/*
data/log/*
@ -19,7 +20,6 @@ indocker
docker-*
phpstan.neon
php*xml*
infection*
**/test*
build*
**/.*

1
.gitattributes vendored
View File

@ -13,7 +13,6 @@
.travis.yml export-ignore
build.sh export-ignore
CHANGELOG.md export-ignore
docker-compose.override.yml.dist export-ignore
docker-compose.yml export-ignore
indocker export-ignore
phpcs.xml export-ignore

2
.github/FUNDING.yml vendored
View File

@ -1,2 +1,2 @@
github: ['acelaya']
custom: ['https://acel.me/donate']
custom: ['https://slnk.to/donate']

View File

@ -1,7 +0,0 @@
<!--
Before opening an issue, just take into account that this is a completely free of charge and open source project.
I'm always happy to help and provide support, but some understanding will be expected.
I do this in my own free time, so expect some delays when implementing new features and fixing bugs, and don't take it personally if an issue gets eventually closed.
You may also be asked to provide tests or ways to reproduce reported bugs.
Try to be polite, and understand it is impossible for an OSS project to cover all use cases.
-->

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Something on shlink is broken or not working as documented?
labels: bug
---
<!--
Before opening an issue, just take into account that this is a completely free of charge and open source project.
I'm always happy to help and provide support, but some understanding will be expected.
I do this in my own free time, so expect some delays when implementing new features and fixing bugs, and don't take it personally if an issue gets eventually closed.
You may also be asked to provide tests or ways to reproduce reported bugs.
Try to be polite, and understand it is impossible for an OSS project to cover all use cases.
With that said, please fill in the information requested next. More information might be requested next (like logs or system configs).
-->
#### How Shlink is set up
* Shlink Version: x.y.z
* PHP Version: x.y.z
* How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted openswoole|Self-hosted RoadRunner|Openswoole Docker image|RoadRunner Docker image
* Database engine used: MySQL|MariaDB|PostgreSQL|MicrosoftSQL|SQLite (x.y.z)
#### Summary
<!-- Provide a summary describing the problem you are experiencing. -->
#### Current behavior
<!-- How is it actually behaving (and it shouldn't)? -->
#### Expected behavior
<!-- How did you expect it to behave? -->
#### How to reproduce
<!-- Provide steps to reproduce the bug. -->

71
.github/ISSUE_TEMPLATE/Bug.yml vendored Normal file
View File

@ -0,0 +1,71 @@
name: Bug report
description: Something on Shlink is broken or not working as documented?
labels: ['bug']
body:
- type: input
validations:
required: true
attributes:
label: Shlink version
placeholder: x.y.z
- type: input
validations:
required: true
attributes:
label: PHP version
placeholder: x.y.z
- type: dropdown
validations:
required: true
attributes:
label: How do you serve Shlink
options:
- Self-hosted Apache
- Self-hosted nginx
- Self-hosted RoadRunner
- Docker image
- Other (explain in summary)
- type: dropdown
validations:
required: true
attributes:
label: Database engine
options:
- MySQL
- MariaDB
- PostgreSQL
- MicrosoftSQL
- SQLite
- type: input
validations:
required: true
attributes:
label: Database version
placeholder: x.y.z
- type: textarea
validations:
required: true
attributes:
label: Current behavior
value: '<!-- How is it actually behaving (and it should not)? -->'
- type: textarea
validations:
required: true
attributes:
label: Expected behavior
value: '<!-- How did you expect it to behave? -->'
- type: textarea
validations:
required: true
attributes:
label: Minimum steps to reproduce
value: |
<!--
Simple but detailed way to reproduce the bug:
* Avoid things like "create a kubernetes cluster", or anything related with cloud providers, as that is rarely the root cause.
* Avoid too vague steps or one-liners like "Update from v1 to v2".
* Providing the reproduction in the form of a self-contained docker-composer is desirable.
Failing in any of these will cause the issue to be closed as "not reproducible".
-->

View File

@ -1,19 +0,0 @@
---
name: Feature request
about: Do you find shlink is missing some important feature that would make it more useful?
labels: feature
---
<!--
Before opening an issue, just take into account that this is a completely free of charge and open source project.
I'm always happy to help and provide support, but some understanding will be expected.
I do this in my own free time, so expect some delays when implementing new features and fixing bugs, and don't take it personally if an issue gets eventually closed.
You may also be asked to provide tests or ways to reproduce reported bugs.
Try to be polite, and understand it is impossible for an OSS project to cover all use cases.
With that said, please fill in the information requested next. More information might be requested next (like logs or system configs).
-->
#### Summary
<!-- Describe the new feature you would like to request. -->

View File

@ -0,0 +1,16 @@
name: Feature request
description: Do you find Shlink is missing some important feature that would make it more useful?
labels: ['feature']
body:
- type: textarea
validations:
required: true
attributes:
label: Summary
value: '<!-- Describe the new feature you would like to request. -->'
- type: textarea
validations:
required: true
attributes:
label: Use case
value: '<!-- Explain why do you think this feature would be useful, and what problems would it help to solve. -->'

View File

@ -1,26 +0,0 @@
---
name: Question - Support
about: Do you have a problem setting up or using shlink?
labels: question
---
<!--
Before opening an issue, just take into account that this is a completely free of charge and open source project.
I'm always happy to help and provide support, but some understanding will be expected.
I do this in my own free time, so expect some delays when implementing new features and fixing bugs, and don't take it personally if an issue gets eventually closed.
You may also be asked to provide tests or ways to reproduce reported bugs.
Try to be polite, and understand it is impossible for an OSS project to cover all use cases.
With that said, please fill in the information requested next. More information might be requested next (like logs or system configs).
-->
#### How Shlink is set up
* Shlink Version: x.y.z
* PHP Version: x.y.z
* How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted openswoole|Self-hosted RoadRunner|Openswoole Docker image|RoadRunner Docker image
* Database engine used: MySQL|MariaDB|PostgreSQL|MicrosoftSQL|SQLite (x.y.z)
#### Summary
<!-- Describe the issue you are facing here. -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Question - Support
about: Do you need help setting up or using Shlink?
url: https://github.com/orgs/shlinkio/discussions/new?category=help-wanted

View File

@ -12,7 +12,6 @@ inputs:
php-extensions:
description: 'The PHP extensions to install'
required: false
default: ''
extensions-cache-key:
description: 'The key used to cache PHP extensions. If empty value is provided, extension caching is disabled'
required: true
@ -21,6 +20,7 @@ runs:
using: composite
steps:
- name: Setup cache environment
if: ${{ inputs.php-extensions }}
id: extcache
uses: shivammathur/cache-extensions@v1
with:
@ -28,7 +28,8 @@ runs:
extensions: ${{ inputs.php-extensions }}
key: ${{ inputs.extensions-cache-key }}
- name: Cache extensions
uses: actions/cache@v3
if: ${{ inputs.php-extensions }}
uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
@ -39,8 +40,7 @@ runs:
php-version: ${{ inputs.php-version }}
tools: composer
extensions: ${{ inputs.php-extensions }}
coverage: pcov
ini-values: pcov.directory=module
coverage: xdebug
- name: Install dependencies
if: ${{ inputs.install-deps == 'yes' }}
run: composer install --no-interaction --prefer-dist

View File

@ -10,33 +10,33 @@ on:
jobs:
db-tests:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1', '8.2']
php-version: ['8.4', '8.5']
env:
LC_ALL: C
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
- name: Install MSSQL ODBC
if: ${{ inputs.platform == 'ms' }}
run: sudo ./data/infra/ci/install-ms-odbc.sh
- name: Start database server
if: ${{ inputs.platform != 'sqlite:ci' }}
run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_${{ inputs.platform }}
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_${{ inputs.platform }}
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1, pdo_sqlsrv-5.10.1
php-extensions: pdo_sqlsrv-5.12.0
extensions-cache-key: db-tests-extensions-${{ matrix.php-version }}-${{ inputs.platform }}
- name: Create test database
if: ${{ inputs.platform == 'ms' }}
run: docker-compose exec -T shlink_db_ms /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Passw0rd!' -Q "CREATE DATABASE shlink_test;"
run: docker compose exec -T shlink_db_ms /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Passw0rd!' -Q "CREATE DATABASE shlink_test;"
- name: Run tests
run: composer test:db:${{ inputs.platform }}
- name: Upload code coverage
uses: actions/upload-artifact@v3
if: ${{ matrix.php-version == '8.1' && inputs.platform == 'sqlite:ci' }}
uses: actions/upload-artifact@v5
if: ${{ matrix.php-version == '8.4' && inputs.platform == 'sqlite:ci' }}
with:
name: coverage-db
path: |

View File

@ -1,4 +1,4 @@
name: Build docker image
name: Test docker image build
on:
pull_request:
@ -7,8 +7,6 @@ on:
jobs:
build-docker-image:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v3
- run: docker build -t shlink-docker-image:temp .
uses: shlinkio/github-actions/.github/workflows/docker-image-build-ci.yml@main
with:
platforms: 'linux/arm64/v8,linux/amd64'

View File

@ -1,45 +0,0 @@
name: Mutation tests
on:
workflow_call:
inputs:
test-group:
type: string
required: true
description: One of unit, db, api or cli
jobs:
mutation-tests:
runs-on: ubuntu-22.04
strategy:
matrix:
php-version: ['8.1', '8.2']
steps:
- uses: actions/checkout@v3
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1
extensions-cache-key: mutation-tests-extensions-${{ matrix.php-version }}-${{ inputs.test-group }}
- uses: actions/download-artifact@v3
with:
name: coverage-${{ inputs.test-group }}
path: build
- name: Resolve infection args
id: infection_args
run: echo "args=--logger-github=false" >> $GITHUB_OUTPUT
# TODO Try to filter mutation tests to improve execution times. Investigate why --git-diff-lines --git-diff-base=develop does not work
# run: |
# BRANCH="${GITHUB_REF#refs/heads/}" |
# if [[ $BRANCH == 'main' || $BRANCH == 'develop' ]]; then
# echo "args=--logger-github=false" >> $GITHUB_OUTPUT
# else
# echo "args=--logger-github=false --git-diff-lines --git-diff-base=develop" >> $GITHUB_OUTPUT
# fi;
shell: bash
- if: ${{ inputs.test-group == 'unit' }}
run: composer infect:ci:unit -- ${{ steps.infection_args.outputs.args }}
env:
INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }}
- if: ${{ inputs.test-group != 'unit' }}
run: composer infect:ci:${{ inputs.test-group }} -- ${{ steps.infection_args.outputs.args }}

View File

@ -10,26 +10,30 @@ on:
jobs:
tests:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1', '8.2']
php-version: ['8.4', '8.5']
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # rr get-binary picks this env automatically
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
- name: Start postgres database server
if: ${{ inputs.test-group == 'api' }}
run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres
- name: Start maria database server
if: ${{ inputs.test-group == 'cli' }}
run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_maria
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_maria
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1
extensions-cache-key: tests-extensions-${{ matrix.php-version }}-${{ inputs.test-group }}
- name: Download RoadRunner binary
if: ${{ inputs.test-group == 'api' }}
run: ./vendor/bin/rr get --no-interaction --no-config --location bin/ && chmod +x bin/rr
- run: composer test:${{ inputs.test-group }}:ci
- uses: actions/upload-artifact@v3
if: ${{ matrix.php-version == '8.1' }}
- uses: actions/upload-artifact@v5
if: ${{ matrix.php-version == '8.4' }}
with:
name: coverage-${{ inputs.test-group }}
path: |

View File

@ -8,7 +8,6 @@ on:
- '*.md'
- '*.xml'
- '*.yml*'
- '*.json5'
- '*.neon'
push:
branches:
@ -21,22 +20,20 @@ on:
- '*.md'
- '*.xml'
- '*.yml*'
- '*.json5'
- '*.neon'
jobs:
static-analysis:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1']
command: ['cs', 'stan', 'swagger:validate']
php-version: ['8.4']
command: ['cs', 'stan', 'openapi:validate']
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1
extensions-cache-key: tests-extensions-${{ matrix.php-version }}-${{ matrix.command }}
- run: composer ${{ matrix.command }}
@ -50,128 +47,55 @@ jobs:
with:
test-group: cli
openswoole-api-tests:
api-tests:
uses: './.github/workflows/ci-tests.yml'
with:
test-group: api
roadrunner-api-tests:
runs-on: ubuntu-22.04
db-tests:
strategy:
matrix:
php-version: ['8.1', '8.2']
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # rr get-binary picks this env automatically
steps:
- uses: actions/checkout@v3
- run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
tools: composer
- run: composer install --no-interaction --prefer-dist
- run: ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr
- run: composer test:api:rr
sqlite-db-tests:
platform: ['sqlite:ci', 'mysql', 'maria', 'postgres', 'ms']
uses: './.github/workflows/ci-db-tests.yml'
with:
platform: 'sqlite:ci'
mysql-db-tests:
uses: './.github/workflows/ci-db-tests.yml'
with:
platform: 'mysql'
maria-db-tests:
uses: './.github/workflows/ci-db-tests.yml'
with:
platform: 'maria'
postgres-db-tests:
uses: './.github/workflows/ci-db-tests.yml'
with:
platform: 'postgres'
ms-db-tests:
uses: './.github/workflows/ci-db-tests.yml'
with:
platform: 'ms'
unit-mutation-tests:
needs:
- unit-tests
uses: './.github/workflows/ci-mutation-tests.yml'
with:
test-group: unit
db-mutation-tests:
needs:
- sqlite-db-tests
uses: './.github/workflows/ci-mutation-tests.yml'
with:
test-group: db
api-mutation-tests:
needs:
- openswoole-api-tests
uses: './.github/workflows/ci-mutation-tests.yml'
with:
test-group: api
cli-mutation-tests:
needs:
- cli-tests
uses: './.github/workflows/ci-mutation-tests.yml'
with:
test-group: cli
platform: ${{ matrix.platform }}
upload-coverage:
needs:
- unit-tests
- openswoole-api-tests
- api-tests
- cli-tests
- sqlite-db-tests
runs-on: ubuntu-22.04
- db-tests
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1']
php-version: ['8.4']
steps:
- name: Checkout code
uses: actions/checkout@v3
- uses: actions/checkout@v5
- name: Use PHP
uses: shivammathur/setup-php@v2
uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
coverage: pcov
ini-values: pcov.directory=module
- uses: actions/download-artifact@v3
extensions-cache-key: tests-extensions-${{ matrix.php-version }}
- uses: actions/download-artifact@v6
with:
path: build
- run: mv build/coverage-unit/coverage-unit.cov build/coverage-unit.cov
- run: mv build/coverage-db/coverage-db.cov build/coverage-db.cov
- run: mv build/coverage-api/coverage-api.cov build/coverage-api.cov
- run: mv build/coverage-cli/coverage-cli.cov build/coverage-cli.cov
- run: wget https://phar.phpunit.de/phpcov-8.2.1.phar
- run: php phpcov-8.2.1.phar merge build --clover build/clover.xml
- run: vendor/bin/phpcov merge build --clover build/clover.xml
- name: Publish coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v5
with:
file: ./build/clover.xml
files: ./build/clover.xml
delete-artifacts:
needs:
- unit-mutation-tests
- db-mutation-tests
- api-mutation-tests
- cli-mutation-tests
- upload-coverage
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: geekyeggo/delete-artifact@v1
- uses: geekyeggo/delete-artifact@v5
with:
name: |
coverage-unit
coverage-db
coverage-api
coverage-cli
coverage-*

View File

@ -2,34 +2,25 @@ name: Build and publish docker image
on:
push:
branches:
- develop
paths-ignore:
- 'LICENSE'
- '.*'
- '*.md'
- '*.xml'
- '*.yml*'
- '*.json5'
- '*.neon'
tags:
- 'v*'
jobs:
build-openswoole:
uses: shlinkio/github-actions/.github/workflows/docker-build-and-publish.yml@main
build-image:
strategy:
matrix:
include:
- runtime: 'rr'
platforms: 'linux/arm64/v8,linux/amd64'
- runtime: 'rr'
tag-suffix: 'roadrunner'
platforms: 'linux/arm64/v8,linux/amd64'
uses: shlinkio/github-actions/.github/workflows/docker-publish-image.yml@main
secrets: inherit
with:
image-name: shlinkio/shlink
version-arg-name: SHLINK_VERSION
build-roadrunner:
uses: shlinkio/github-actions/.github/workflows/docker-build-and-publish.yml@main
secrets: inherit
with:
image-name: shlinkio/shlink
version-arg-name: SHLINK_VERSION
platforms: 'linux/arm64/v8,linux/amd64'
tags-suffix: roadrunner
platforms: ${{ matrix.platforms }}
tags-suffix: ${{ matrix.tag-suffix }}
extra-build-args: |
SHLINK_RUNTIME=rr
SHLINK_RUNTIME=${{ matrix.runtime }}

View File

@ -1,4 +1,4 @@
name: Publish swagger spec
name: Publish openapi spec
on:
push:
@ -7,12 +7,12 @@ on:
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1']
php-version: ['8.4']
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
- name: Determine version
id: determine_version
run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
@ -20,13 +20,12 @@ jobs:
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1
extensions-cache-key: publish-swagger-spec-extensions-${{ matrix.php-version }}
- run: composer swagger:inline
extensions-cache-key: publish-openapi-spec-extensions-${{ matrix.php-version }}
- run: composer openapi:inline
- run: mkdir ${{ steps.determine_version.outputs.version }}
- run: mv docs/swagger/swagger-inlined.json ${{ steps.determine_version.outputs.version }}/open-api-spec.json
- run: mv docs/swagger/openapi-inlined.json ${{ steps.determine_version.outputs.version }}/open-api-spec.json
- name: Publish spec
uses: JamesIves/github-pages-deploy-action@4.1.7
uses: JamesIves/github-pages-deploy-action@v4
with:
token: ${{ secrets.OAS_PUBLISH_TOKEN }}
repository-name: 'shlinkio/shlink-open-api-specs'

View File

@ -7,34 +7,29 @@ on:
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.1', '8.2']
swoole: ['yes', 'no']
php-version: ['8.4', '8.4', '8.5']
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
- uses: './.github/actions/ci-setup'
with:
php-version: ${{ matrix.php-version }}
php-extensions: openswoole-4.12.1
extensions-cache-key: publish-swagger-spec-extensions-${{ matrix.php-version }}
install-deps: 'no'
- if: ${{ matrix.swoole == 'yes' }}
run: ./build.sh ${GITHUB_REF#refs/tags/v}
- if: ${{ matrix.swoole == 'no' }}
run: ./build.sh ${GITHUB_REF#refs/tags/v} --no-swoole
- uses: actions/upload-artifact@v3
- run: ./build.sh ${GITHUB_REF#refs/tags/v}
- uses: actions/upload-artifact@v5
with:
name: dist-files-${{ matrix.php-version }}-${{ matrix.swoole }}
name: dist-files-${{ matrix.php-version }}
path: build
publish:
needs: ['build']
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
- uses: actions/checkout@v5
- uses: actions/download-artifact@v6
with:
path: build
- name: Publish release with assets
@ -48,12 +43,8 @@ jobs:
delete-artifacts:
needs: ['publish']
runs-on: ubuntu-22.04
strategy:
matrix:
php-version: ['8.1', '8.2']
swoole: ['yes', 'no']
runs-on: ubuntu-24.04
steps:
- uses: geekyeggo/delete-artifact@v1
- uses: geekyeggo/delete-artifact@v5
with:
name: dist-files-${{ matrix.php-version }}-${{ matrix.swoole }}
name: dist-files-*

8
.gitignore vendored
View File

@ -1,7 +1,6 @@
.idea
bin/.rr.*
bin/rr
config/roadrunner/.pid
.pid
build
!docker/build
composer.lock
@ -10,8 +9,7 @@ vendor/
data/database.sqlite
data/shlink-tests.db
data/GeoLite2-City.*
docs/swagger-ui*
data/infra/matomo
docs/mercure.html
docker-compose.override.yml
.phpunit.result.cache
docs/swagger/swagger-inlined.json
docs/swagger/openapi-inlined.json

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,9 @@ You will also see how to ensure the code fulfills the expected code checks, and
## System dependencies
The project provides all its dependencies as docker containers through a docker-compose configuration.
The project provides all its dependencies as docker containers through a `docker compose` configuration.
Because of this, the only actual dependencies are [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/).
Because of this, the only actual dependencies are [docker](https://docs.docker.com/get-docker/) and [docker compose](https://docs.docker.com/compose/install/).
## Setting up the project
@ -16,12 +16,15 @@ The first thing you need to do is fork the repository, and clone it in your loca
Then you will have to follow these steps:
* Copy all files with `.local.php.dist` extension from `config/autoload` by removing the dist extension.
* Copy the `config/params/shlink_dev_env.php.dist` in the same directory, but removing the `.dist` extension:
For example the `common.local.php.dist` file should be copied as `common.local.php`.
```
cp config/params/shlink_dev_env.php.dist config/params/shlink_dev_env.php
```
* Copy the file `docker-compose.override.yml.dist` by also removing the `dist` extension.
* Start-up the project by running `docker-compose up`.
The `shlink_dev_env.php` file is gitignored, so you can customize it as you want. For example, by adding your own GeoLite license key.
* Start-up the project by running `docker compose up`.
The first time this command is run, it will create several containers that are used during development, so it may take some time.
@ -31,7 +34,7 @@ Then you will have to follow these steps:
* Run `./indocker bin/cli db:migrate` to get database migrations up to date.
* Run `./indocker bin/cli api-key:generate` to get your first API key generated.
Once you finish this, you will have the project exposed in ports `8000` through nginx+php-fpm and `8080` through openswoole.
Once you finish this, you will have the project exposed in ports `8800` through RoadRunner and `8000` through nginx+php-fpm.
> Note: The `indocker` shell script is a helper tool used to run commands inside the main docker container.
@ -46,17 +49,18 @@ This is a simplified version of the project structure:
```
shlink
├── bin
│ └── cli
│ ├── cli
│ └── [...]
├── config
│ ├── autoload
│ ├── params
│ ├── config.php
│ └── container.php
│ ├── container.php
│ └── [...]
├── data
│ ├── cache
│ ├── locks
│ ├── log
│ ├── migrations
│ └── proxies
├── docs
│ ├── adr
@ -67,18 +71,19 @@ shlink
│ ├── Core
│ └── Rest
├── public
│ └── [...]
├── composer.json
└── README.md
```
The purposes of every folder are:
* `bin`: It contains the CLI tools. The `cli` one is the main entry point to run shlink from the command line.
* `bin`: It contains the CLI tools. The `cli` one is the main entry point to run Shlink from the command line.
* `config`: Contains application-wide configurations, which are later merged with the ones provided by every module.
* `data`: Common runtime-generated git-ignored assets, like logs, caches, etc.
* `data`: Common git-ignored assets, like logs, caches, lock files, GeoLite DB files, etc. It's the only location where Shlink may need to write at runtime.
* `docs`: Any project documentation is stored here, like API spec definitions or architectural decision records.
* `module`: Contains a sub-folder for every module in the project. Modules contain the source code, tests and configurations for every context in the project.
* `public`: Few assets (like `favicon.ico` or `robots.txt`) and the web entry point are stored here. This web entry point is not used when serving the app with openswoole.
* `public`: Few assets (like `favicon.ico` or `robots.txt`) and the web entry point are stored here. This web entry point is not used when serving the app with RoadRunner.
## Project tests
@ -94,7 +99,7 @@ In order to ensure stability and no regressions are introduced while developing
The project provides some tooling to run them against any of the supported database engines.
* **API tests**: These are E2E tests that spin up an instance of the app with openswoole, and test it from the outside by interacting with the REST API.
* **API tests**: These are E2E tests that spin up an instance of the app with RoadRunner, and test it from the outside by interacting with the REST API.
These are the best tests to catch regressions, and to verify everything behaves as expected.
@ -122,9 +127,14 @@ Depending on the kind of contribution, maybe not all kinds of tests are needed,
* Run `./indocker composer test:api` to run API E2E tests. For these, the Postgres database engine is used.
* Run `./indocker composer test:cli` to run CLI E2E tests. For these, the Maria DB database engine is used.
* Run `./indocker composer infect:test` to run both unit and database tests (over sqlite) and then apply mutations to them with [infection](https://infection.github.io/).
* Run `./indocker composer ci` to run all previous commands together, parallelizing non-conflicting tasks as much as possible.
## Testing endpoints
The project provides a Swagger UI container for dev envs, which can be accessed in http://localhost:8005.
It will automatically load the contents of `docs/swagger`, so you can make any updates and they will get reflected.
## Pull request process
**Important!**: Before starting to work on a pull request, make sure you always [open an issue](https://github.com/shlinkio/shlink/issues/new/choose) first.

View File

@ -1,34 +1,31 @@
FROM php:8.2-alpine3.17 as base
FROM php:8.4-alpine3.21 AS base
ARG SHLINK_VERSION=latest
ENV SHLINK_VERSION ${SHLINK_VERSION}
ARG SHLINK_RUNTIME=openswoole
ENV SHLINK_RUNTIME ${SHLINK_RUNTIME}
ENV OPENSWOOLE_VERSION 4.12.1
ENV PDO_SQLSRV_VERSION 5.10.1
ENV MS_ODBC_DOWNLOAD 'b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486'
ENV MS_ODBC_SQL_VERSION 18_18.1.1.1
ENV LC_ALL "C"
ENV SHLINK_VERSION=${SHLINK_VERSION}
ARG SHLINK_RUNTIME=rr
ENV SHLINK_RUNTIME=${SHLINK_RUNTIME}
ENV USER_ID='1001'
ENV PDO_SQLSRV_VERSION='5.12.0'
ENV MS_ODBC_DOWNLOAD='7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8'
ENV MS_ODBC_SQL_VERSION='18_18.4.1.1'
ENV LC_ALL='C'
WORKDIR /etc/shlink
# Install required PHP extensions
RUN \
# Temp install dev dependencies needed to compile the extensions
apk add --no-cache --virtual .dev-deps sqlite-dev postgresql-dev icu-dev libzip-dev zlib-dev libpng-dev linux-headers && \
docker-php-ext-install -j"$(nproc)" pdo_mysql pdo_pgsql intl calendar sockets bcmath zip gd && \
apk add --no-cache --virtual .dev-deps sqlite-dev postgresql-dev icu-dev libzip-dev zlib-dev linux-headers && \
docker-php-ext-install -j"$(nproc)" pdo_mysql pdo_pgsql intl calendar sockets bcmath zip && \
apk add --no-cache sqlite-libs && \
docker-php-ext-install -j"$(nproc)" pdo_sqlite && \
# Remove temp dev extensions, and install prod equivalents that are required at runtime
apk del .dev-deps && \
apk add --no-cache postgresql icu libzip libpng
# Install openswoole and sqlsrv driver for x86_64 builds
# Install sqlsrv driver for x86_64 builds
RUN apk add --no-cache --virtual .phpize-deps ${PHPIZE_DEPS} unixodbc-dev && \
if [ "$SHLINK_RUNTIME" == 'openswoole' ]; then \
pecl install openswoole-${OPENSWOOLE_VERSION} && \
docker-php-ext-enable openswoole ; \
fi; \
if [ $(uname -m) == "x86_64" ]; then \
wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --allow-untrusted msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
@ -39,29 +36,24 @@ RUN apk add --no-cache --virtual .phpize-deps ${PHPIZE_DEPS} unixodbc-dev && \
apk del .phpize-deps
# Install shlink
FROM base as builder
FROM base AS builder
COPY . .
COPY --from=composer:2 /usr/bin/composer ./composer.phar
RUN apk add --no-cache git && \
php composer.phar install --no-dev --prefer-dist --optimize-autoloader --no-progress --no-interaction && \
if [ "$SHLINK_RUNTIME" == 'openswoole' ]; then \
php composer.phar remove spiral/roadrunner spiral/roadrunner-jobs --with-all-dependencies --update-no-dev --optimize-autoloader --no-progress --no-interactionc ; \
elif [ $SHLINK_RUNTIME == 'rr' ]; then \
php composer.phar remove mezzio/mezzio-swoole --with-all-dependencies --update-no-dev --optimize-autoloader --no-progress --no-interaction ; \
fi; \
php composer.phar clear-cache && \
rm -r docker composer.* && \
sed -i "s/%SHLINK_VERSION%/${SHLINK_VERSION}/g" config/autoload/app_options.global.php
sed -i "s/%SHLINK_VERSION%/${SHLINK_VERSION}/g" module/Core/src/Config/Options/AppOptions.php
# Prepare final image
FROM base
LABEL maintainer="Alejandro Celaya <alejandro@alejandrocelaya.com>"
COPY --from=builder /etc/shlink .
COPY --from=builder --chown=${USER_ID} /etc/shlink .
RUN ln -s /etc/shlink/bin/cli /usr/local/bin/shlink && \
if [ "$SHLINK_RUNTIME" == 'rr' ]; then \
php ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr ; \
php ./vendor/bin/rr get --no-interaction --no-config --location bin/ && chmod +x bin/rr ; \
fi;
# Expose default port
@ -69,17 +61,8 @@ EXPOSE 8080
# Copy config specific for the image
COPY docker/docker-entrypoint.sh docker-entrypoint.sh
COPY docker/config/shlink_in_docker.local.php config/autoload/shlink_in_docker.local.php
COPY docker/config/php.ini ${PHP_INI_DIR}/conf.d/
# Change the ownership of /etc/shlink/data to be writable, then change the user to non-root
# FIXME Disabled for now, as it conflicts with ENABLE_PERIODIC_VISIT_LOCATE, which is used to configure a cron as root.
# Ref: https://github.com/shlinkio/shlink/issues/1132
#RUN chown 1001 /etc/shlink/data
#RUN chown 1001 /etc/shlink/data/locks
#RUN chown 1001 /etc/shlink/data/proxies
#RUN chown 1001 /etc/shlink/data/cache
#RUN chown 1001 /etc/shlink/data/log
#USER 1001
USER ${USER_ID}
ENTRYPOINT ["/bin/sh", "./docker-entrypoint.sh"]

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016-2023 Alejandro Celaya
Copyright (c) 2016-2024 Alejandro Celaya
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -2,12 +2,12 @@
[![Build Status](https://img.shields.io/github/actions/workflow/status/shlinkio/shlink/ci.yml?branch=develop&logo=github&style=flat-square)](https://github.com/shlinkio/shlink/actions/workflows/ci.yml?query=workflow%3A%22Continuous+integration%22)
[![Code Coverage](https://img.shields.io/codecov/c/gh/shlinkio/shlink/develop?style=flat-square)](https://app.codecov.io/gh/shlinkio/shlink)
[![Infection MSI](https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fshlinkio%2Fshlink%2Fdevelop)](https://dashboard.stryker-mutator.io/reports/github.com/shlinkio/shlink/develop)
[![Latest Stable Version](https://img.shields.io/github/release/shlinkio/shlink.svg?style=flat-square)](https://packagist.org/packages/shlinkio/shlink)
[![Docker pulls](https://img.shields.io/docker/pulls/shlinkio/shlink.svg?logo=docker&style=flat-square)](https://hub.docker.com/r/shlinkio/shlink/)
[![License](https://img.shields.io/github/license/shlinkio/shlink.svg?style=flat-square)](https://github.com/shlinkio/shlink/blob/main/LICENSE)
[![Twitter](https://img.shields.io/badge/follow-shlinkio-blue.svg?style=flat-square&logo=twitter&color=blue)](https://twitter.com/shlinkio)
[![Mastodon](https://img.shields.io/mastodon/follow/109329425426175098?color=%236364ff&domain=https%3A%2F%2Ffosstodon.org&label=follow&logo=mastodon&logoColor=white&style=flat-square)](https://fosstodon.org/@shlinkio)
[![Bluesky](https://img.shields.io/badge/follow-shlinkio-0285FF.svg?style=flat-square&logo=bluesky&logoColor=white)](https://bsky.app/profile/shlink.io)
[![Paypal donate](https://img.shields.io/badge/Donate-paypal-blue.svg?style=flat-square&logo=paypal&colorA=aaaaaa)](https://slnk.to/donate)
A PHP-based self-hosted URL shortener that can be used to serve shortened URLs under your own domain.
@ -32,18 +32,16 @@ You can learn how to use the official docker image by reading [the docs](https:/
The idea is that you can just generate a container using the image and provide the custom config via env vars.
## Self hosted
## Self-hosted
First, make sure the host where you are going to run shlink fulfills these requirements:
* PHP 8.1 or 8.2
* PHP 8.4 or 8.5
* The next PHP extensions: json, curl, pdo, intl, gd and gmp/bcmath.
* apcu extension is recommended if you don't plan to use openswoole.
* xml extension is required if you want to generate QR codes in svg format.
* apcu extension is recommended if you don't plan to use RoadRunner.
* sockets and bcmath extensions are required if you want to integrate with a RabbitMQ instance.
* MySQL, MariaDB, PostgreSQL, MicrosoftSQL or SQLite.
* You will also need the corresponding pdo variation for the database you are planning to use: `pdo_mysql`, `pdo_pgsql`, `pdo_sqlsrv` or `pdo_sqlite`.
* The [openswoole](https://openswoole.com/) PHP extension (if you plan to serve Shlink with openswoole) or the web server of your choice with PHP integration (like Apache or Nginx).
### Download
@ -53,7 +51,7 @@ In order to run Shlink, you will need a built version of the project. There are
The easiest way to install shlink is by using one of the pre-bundled distributable packages.
Go to the [latest version](https://github.com/shlinkio/shlink/releases/latest) and download the `shlink*_dist.zip` file that suits your needs. You will find one for every supported PHP version and with/without openswoole integration.
Go to the [latest version](https://github.com/shlinkio/shlink/releases/latest) and download the `shlink*_dist.zip` file that suits your needs. You will find one for every supported PHP version.
Finally, decompress the file in the location of your choice.
@ -100,6 +98,12 @@ Both the API and CLI allow you to do mostly the same operations, except for API
If you are trying to find out how to run the project in development mode or how to provide contributions, read the [CONTRIBUTING](CONTRIBUTING.md) doc.
## Powered by
Thanks to [JetBrains](https://www.jetbrains.com/) for their continuous support to this project in the form of IDE licenses.
![JetBrains logo](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)
---
> This product includes GeoLite2 data created by MaxMind, available from [https://www.maxmind.com](https://www.maxmind.com)

View File

@ -1,5 +1,55 @@
# Upgrading
## From v3.x to v4.x
### General
* Swoole and Openswoole are no longer officially supported runtimes. The recommended alternative is RoadRunner.
* Dist files for swoole/openswoole are no longer published.
* Webhooks are no longer supported. Migrate to one of the other [real-time updates](https://shlink.io/documentation/advanced/real-time-updates/) mechanisms.
* When using RoadRunner, the amount of web workers, task workers and the port number can no longer be provided via config options. Use `WEB_WORKER_NUM`, `TASK_WORKER_NUM` and `PORT` env vars instead.
### Changes in URL shortener
* The short URLs `loosely` mode is no longer supported, as it was a typo. Use `loose` mode instead.
* QR codes URLs now work by default, even for short URLs that cannot be visited due to max visits or date range limitations.
If you want to keep previous behavior, pass `QR_CODE_FOR_DISABLED_SHORT_URLS=false` or the equivalent configuration option.
* Long URL title resolution is now enabled by default. You can still disable it by passing `AUTO_RESOLVE_TITLES=false` or the equivalent configuration option.
* Shlink no longer allows to opt-in for long URL verification. Long URLs are unconditionally considered correct during short URL creation/edition.
* Device long URLs have been migrated to the new Dynamic rule-based redirects system and will continue to work as expected, but the API surface has changed.
If you use shlink-web-client and rely on this feature when creating/updating short URLs, **DO NOT UPDATE YET**. Support for dynamic rule-based redirects will be added to shlink-web-client soon, in v4.1.0
### Changes in REST API
* REST API v1/v2 now behave like v3. This only affects error codes, which are now proper URIs.
* `INVALID_ARGUMENT` -> `https://shlink.io/api/error/invalid-data`
* `INVALID_SHORT_URL_DELETION` -> `https://shlink.io/api/error/invalid-short-url-deletion`
* `DOMAIN_NOT_FOUND` -> `https://shlink.io/api/error/domain-not-found`
* `FORBIDDEN_OPERATION` -> `https://shlink.io/api/error/forbidden-tag-operation`
* `INVALID_SLUG` -> `https://shlink.io/api/error/non-unique-slug`
* `INVALID_SHORTCODE` -> `https://shlink.io/api/error/short-url-not-found`
* `TAG_CONFLICT` -> `https://shlink.io/api/error/tag-conflict`
* `TAG_NOT_FOUND` -> `https://shlink.io/api/error/tag-not-found`
* `MERCURE_NOT_CONFIGURED` -> `https://shlink.io/api/error/mercure-not-configured`
* `INVALID_AUTHORIZATION` -> `https://shlink.io/api/error/missing-authentication`
* `INVALID_API_KEY` -> `https://shlink.io/api/error/invalid-api-key`
* Endpoints previously returning props like `"visitsCount": {number}` no longer do it. There should be an alternative `"visitsSummary": {}` object with the amount nested on it.
* It is no longer possible to order the short URLs list with `orderBy=visitsCount-ASC`/`orderBy=visitsCount-DESC`. Use `orderBy=visits-ASC`/`orderBy=visits-DESC` instead.
* It is no longer possible to get tags with stats using `GET /tags?withStats=true`. Use `GET /tags/stats` endpoint instead.
* The `deviceLongUrls` are ignored when calling `POST /short-urls` or `PATCH /short-urls/{shortCode}`. These should now be configured as dynamic rule-based redirects via `POST /short-urls/{shortCode}/redirect-rules`.
### Changes in Docker image
* Since openswoole is no longer supported, there are no longer image tags suffixed with `openswoole`. You should migrate to the default or `roadrunner` ones.
* The `non-root` docker tag is no longer published, as all docker images are now running without super-user permissions.
* Due to previous point, it is no longer possible to pass `ENABLE_PERIODIC_VISIT_LOCATE=true` in order to configure a cron job that locates visits periodically.
This was not really needed in the docker image, as visits are located on the fly.
### Changes in integrations
* Credentials in redis URLs should now be URL-encoded, as they are unconditionally url-decoded before being used. Previously, it was possible to customize this behavior via `REDIS_DECODE_CREDENTIALS=true|false`.
* Providing redis URIs in the form of `tcp://password@6.6.6.6:6379` is no longer supported. If you want to provide password with no username, do `tcp://:password@6.6.6.6:6379` instead.
## From v2.x to v3.x
### Changes in REST API

36
bin/frankenphp-worker.php Normal file
View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink;
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\HttpHandlerRunner\Emitter\EmitterInterface;
use Mezzio\Application;
use Psr\Container\ContainerInterface;
use function frankenphp_handle_request;
use function gc_collect_cycles;
(static function (): void {
/** @var ContainerInterface $container */
$container = include __DIR__ . '/../config/container.php';
$app = $container->get(Application::class);
$responseEmitter = $container->get(EmitterInterface::class);
$handler = static function () use ($app, $responseEmitter): void {
$response = $app->handle(ServerRequestFactory::fromGlobals());
$responseEmitter->emit($response);
};
$maxRequests = (int) ($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
$keepRunning = frankenphp_handle_request($handler);
// Call the garbage collector to reduce the chances of it being triggered in the middle of a page generation
gc_collect_cycles();
if (! $keepRunning) {
break;
}
}
})();

View File

@ -2,17 +2,22 @@
declare(strict_types=1);
namespace Shlinkio\Shlink;
use Mezzio\Application;
use Psr\Container\ContainerInterface;
use Shlinkio\Shlink\Common\Middleware\RequestIdMiddleware;
use Shlinkio\Shlink\EventDispatcher\RoadRunner\RoadRunnerTaskConsumerToListener;
use Spiral\RoadRunner\Http\PSR7Worker;
use function gc_collect_cycles;
use function Shlinkio\Shlink\Config\env;
(static function (): void {
/** @var ContainerInterface $container */
$container = include __DIR__ . '/../config/container.php';
$rrMode = env('RR_MODE');
$gcCollectCycles = env('GC_COLLECT_CYCLES', default: false);
if ($rrMode === 'http') {
// This was spin-up as a web worker
@ -24,9 +29,16 @@ use function Shlinkio\Shlink\Config\env;
$worker->respond($app->handle($req));
} catch (Throwable $e) {
$worker->getWorker()->error((string) $e);
} finally {
if ($gcCollectCycles) {
gc_collect_cycles();
}
}
}
} else {
$container->get(RoadRunnerTaskConsumerToListener::class)->listenForTasks();
$requestIdMiddleware = $container->get(RequestIdMiddleware::class);
$container->get(RoadRunnerTaskConsumerToListener::class)->listenForTasks(
fn (string $requestId) => $requestIdMiddleware->setCurrentRequestId($requestId),
);
}
})();

View File

@ -2,10 +2,12 @@
export APP_ENV=test
export TEST_ENV=api
export TEST_RUNTIME="${TEST_RUNTIME:-"openswoole"}"
export TEST_RUNTIME="${TEST_RUNTIME:-"rr"}" # rr is the only runtime currently supported
export DB_DRIVER="${DB_DRIVER:-"postgres"}"
export GENERATE_COVERAGE="${GENERATE_COVERAGE:-"no"}"
[ "$GENERATE_COVERAGE" != 'no' ] && export XDEBUG_MODE=coverage
# Reset logs
OUTPUT_LOGS=data/log/api-tests/output.log
rm -rf data/log/api-tests
@ -13,26 +15,19 @@ mkdir data/log/api-tests
touch $OUTPUT_LOGS
# Try to stop server just in case it hanged in last execution
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:stop
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -f
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -f -w .
echo 'Starting server...'
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:start -d
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr serve -p -c=config/roadrunner/.rr.dev.yml \
-o=http.address=0.0.0.0:9999 \
-o=logs.encoding=json \
-o=logs.channels.http.encoding=json \
-o=logs.channels.server.encoding=json \
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr serve -p -w . -c=config/roadrunner/.rr.test.yml \
-o=logs.output="${PWD}/${OUTPUT_LOGS}" \
-o=logs.channels.http.output="${PWD}/${OUTPUT_LOGS}" \
-o=logs.channels.server.output="${PWD}/${OUTPUT_LOGS}" &
sleep 2 # Let's give the server a couple of seconds to start
vendor/bin/phpunit --order-by=random -c phpunit-api.xml --testdox --colors=always --log-junit=build/coverage-api/junit.xml $*
testsExitCode=$?
vendor/bin/phpunit --order-by=random -c phpunit-api.xml --testdox --testdox-summary $*
TESTS_EXIT_CODE=$?
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:stop
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -c config/roadrunner/.rr.dev.yml -o=http.address=0.0.0.0:9999
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -w .
# Exit this script with the same code as the tests. If tests failed, this script has to fail
exit $testsExitCode
exit $TESTS_EXIT_CODE

14
bin/test/run-cli-tests.sh Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env sh
export APP_ENV=test
export TEST_ENV=cli
export DB_DRIVER="${DB_DRIVER:-"maria"}"
export GENERATE_COVERAGE="${GENERATE_COVERAGE:-"no"}"
[ "$GENERATE_COVERAGE" != 'no' ] && export XDEBUG_MODE=coverage
vendor/bin/phpunit --order-by=random --testdox --testdox-summary -c phpunit-cli.xml $*
TESTS_EXIT_CODE=$?
# Exit this script with the same code as the tests. If tests failed, this script has to fail
exit $TESTS_EXIT_CODE

View File

@ -1,17 +1,15 @@
#!/usr/bin/env bash
set -e
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ] || ([ "$#" == 2 ] && [ "$2" != "--no-swoole" ]); then
if [ "$#" -lt 1 ]; then
echo "Usage:" >&2
echo " $0 {version} [--no-swoole]" >&2
echo " $0 {version}" >&2
exit 1
fi
version=$1
noSwoole=$2
phpVersion=$(php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;')
[[ $noSwoole ]] && swooleSuffix="" || swooleSuffix="_openswoole"
distId="shlink${version}_php${phpVersion}${swooleSuffix}_dist"
distId="shlink${version}_php${phpVersion}_dist"
builtContent="./build/${distId}"
projectdir=$(pwd)
[[ -f ./composer.phar ]] && composerBin='./composer.phar' || composerBin='composer'
@ -30,24 +28,15 @@ cd "${builtContent}"
# Install dependencies
echo "Installing dependencies with $composerBin..."
composerFlags="--optimize-autoloader --no-progress --no-interaction"
${composerBin} self-update
${composerBin} install --no-dev --prefer-dist $composerFlags
if [[ $noSwoole ]]; then
# If generating a dist not for openswoole, uninstall mezzio-swoole
${composerBin} remove mezzio/mezzio-swoole --with-all-dependencies --update-no-dev $composerFlags
else
# If generating a dist for openswoole, uninstall RoadRunner
${composerBin} remove spiral/roadrunner spiral/roadrunner-jobs --with-all-dependencies --update-no-dev $composerFlags
fi
${composerBin} install --no-dev --prefer-dist --optimize-autoloader --no-progress --no-interaction
# Delete development files
echo 'Deleting dev files...'
rm composer.*
# Update shlink version in config
sed -i "s/%SHLINK_VERSION%/${version}/g" config/autoload/app_options.global.php
# Update Shlink version
sed -i "s/%SHLINK_VERSION%/${version}/g" module/Core/src/Config/Options/AppOptions.php
# Compressing file
echo 'Compressing files...'

View File

@ -12,71 +12,70 @@
}
],
"require": {
"php": "^8.1",
"php": "^8.4",
"ext-curl": "*",
"ext-gd": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
"akrabat/ip-address-middleware": "^2.1",
"cakephp/chronos": "^2.3",
"doctrine/migrations": "^3.5",
"doctrine/orm": "^2.13.3",
"endroid/qr-code": "^4.6",
"geoip2/geoip2": "^2.13",
"guzzlehttp/guzzle": "^7.5",
"happyr/doctrine-specification": "^2.0",
"jaybizzle/crawler-detect": "^1.2.112",
"laminas/laminas-config": "^3.7",
"laminas/laminas-config-aggregator": "^1.11",
"laminas/laminas-diactoros": "^2.19",
"laminas/laminas-inputfilter": "^2.22",
"laminas/laminas-servicemanager": "^3.19",
"laminas/laminas-stdlib": "^3.15",
"lcobucci/jwt": "^4.2",
"league/uri": "^6.8",
"lstrojny/functional-php": "^1.17",
"mezzio/mezzio": "^3.13",
"mezzio/mezzio-fastroute": "^3.7",
"mezzio/mezzio-problem-details": "^1.7",
"mezzio/mezzio-swoole": "^4.5",
"mlocati/ip-lib": "^1.18",
"mobiledetect/mobiledetectlib": "^3.74",
"ocramius/proxy-manager": "^2.14",
"pagerfanta/core": "^3.6",
"php-middleware/request-id": "^4.1",
"pugx/shortid-php": "^1.1",
"ramsey/uuid": "^4.5",
"shlinkio/shlink-common": "^5.3.1",
"shlinkio/shlink-config": "^2.4",
"shlinkio/shlink-event-dispatcher": "^2.6",
"shlinkio/shlink-importer": "^5.0",
"shlinkio/shlink-installer": "^8.3",
"shlinkio/shlink-ip-geolocation": "^3.2",
"spiral/roadrunner": "^2.11",
"spiral/roadrunner-jobs": "^2.5",
"symfony/console": "^6.1",
"symfony/filesystem": "^6.1",
"symfony/lock": "^6.1",
"symfony/process": "^6.1",
"symfony/string": "^6.1"
"akrabat/ip-address-middleware": "^2.6",
"cakephp/chronos": "^3.1",
"doctrine/dbal": "^4.3",
"doctrine/migrations": "^3.9",
"doctrine/orm": "^3.5",
"donatj/phpuseragentparser": "^1.10",
"friendsofphp/proxy-manager-lts": "^1.0",
"geoip2/geoip2": "^3.1",
"guzzlehttp/guzzle": "^7.9",
"hidehalo/nanoid-php": "^2.0",
"jaybizzle/crawler-detect": "^1.3",
"laminas/laminas-config-aggregator": "^1.17",
"laminas/laminas-diactoros": "^3.5",
"laminas/laminas-inputfilter": "^2.31",
"laminas/laminas-servicemanager": "^3.23",
"laminas/laminas-stdlib": "^3.20",
"matomo/matomo-php-tracker": "^3.3",
"mezzio/mezzio": "^3.20",
"mezzio/mezzio-fastroute": "^3.12",
"mezzio/mezzio-problem-details": "^1.15",
"mlocati/ip-lib": "^1.18.1",
"pagerfanta/core": "^3.8",
"ramsey/uuid": "^4.7",
"shlinkio/doctrine-specification": "^2.2",
"shlinkio/shlink-common": "dev-main#f2550b5 as 7.3.0",
"shlinkio/shlink-config": "dev-main#fb186e4 as 4.1.0",
"shlinkio/shlink-event-dispatcher": "dev-main#54d4701 as 4.4.0",
"shlinkio/shlink-importer": "dev-main#4498f0a as 5.7.0",
"shlinkio/shlink-installer": "dev-develop#40e08cb as 10.0.0",
"shlinkio/shlink-ip-geolocation": "dev-main#e0c45b2 as 5.0.0",
"shlinkio/shlink-json": "dev-main#7c096d6 as 1.3.0",
"spiral/roadrunner": "^2025.1",
"spiral/roadrunner-cli": "^2.7",
"spiral/roadrunner-http": "^3.5",
"spiral/roadrunner-jobs": "^4.6",
"symfony/console": "^8.0 || ^7.4",
"symfony/filesystem": "^8.0",
"symfony/lock": "^8.0",
"symfony/process": "^8.0",
"symfony/string": "^8.0"
},
"require-dev": {
"cebe/php-openapi": "^1.7",
"devizzent/cebe-php-openapi": "^1.1.2",
"devster/ubench": "^2.1",
"dms/phpunit-arraysubset-asserts": "^0.4.0",
"infection/infection": "^0.26.15",
"openswoole/ide-helper": "~4.11.5",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-doctrine": "^1.3",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-symfony": "^1.2",
"phpunit/php-code-coverage": "^9.2",
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-doctrine": "^2.0",
"phpstan/phpstan-phpunit": "^2.0.5",
"phpstan/phpstan-symfony": "^2.0",
"phpunit/php-code-coverage": "^12.0",
"phpunit/phpcov": "^11.0",
"phpunit/phpunit": "^12.0.10",
"roave/security-advisories": "dev-master",
"shlinkio/php-coding-standard": "~2.3.0",
"shlinkio/shlink-test-utils": "^3.4",
"symfony/var-dumper": "^6.1",
"veewee/composer-run-parallel": "^1.1"
"shlinkio/php-coding-standard": "~2.5.0",
"shlinkio/shlink-test-utils": "^4.4",
"symfony/var-dumper": "^8.0",
"veewee/composer-run-parallel": "^1.4"
},
"conflict": {
"symfony/var-exporter": ">=6.3.9,<=6.4.0"
},
"autoload": {
"psr-4": {
@ -86,6 +85,7 @@
},
"files": [
"config/constants.php",
"module/Core/functions/array-utils.php",
"module/Core/functions/functions.php"
]
},
@ -106,96 +106,62 @@
},
"scripts": {
"ci": [
"@parallel cs stan swagger:validate test:unit:ci test:db:sqlite:ci test:db:mysql test:db:maria test:db:postgres test:db:ms",
"@parallel infect:test:api infect:test:cli infect:ci:unit infect:ci:db"
"@parallel cs stan openapi:validate test:unit:ci test:db:sqlite:ci test:db:postgres test:db:mysql test:db:maria test:db:ms",
"@parallel test:api:ci test:cli:ci"
],
"cs": "phpcs",
"cs": "phpcs -s",
"cs:fix": "phpcbf",
"stan": "APP_ENV=test php vendor/bin/phpstan analyse module/*/src module/*/test* module/*/config config docker/config data/migrations --level=8",
"stan": ["@putenv APP_ENV=test", "phpstan analyse"],
"test": [
"@parallel test:unit test:db",
"@parallel test:api test:cli"
],
"test:unit": "@php vendor/bin/phpunit --order-by=random --colors=always --testdox",
"test:unit:ci": "@test:unit --coverage-php=build/coverage-unit.cov --coverage-xml=build/coverage-unit/coverage-xml --log-junit=build/coverage-unit/junit.xml",
"test:unit:pretty": "@test:unit --coverage-html build/coverage-unit/coverage-html",
"test:unit": ["@putenv COLUMNS=120", "phpunit --order-by=random --testdox --testdox-summary"],
"test:unit:ci": ["@putenv XDEBUG_MODE=coverage", "@test:unit --coverage-php=build/coverage-unit.cov"],
"test:unit:pretty": ["@putenv XDEBUG_MODE=coverage", "@test:unit --coverage-html build/coverage-unit/coverage-html"],
"test:db": "@parallel test:db:sqlite:ci test:db:mysql test:db:maria test:db:postgres test:db:ms",
"test:db:sqlite": "APP_ENV=test php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-db.xml",
"test:db:sqlite:ci": "@test:db:sqlite --coverage-php build/coverage-db.cov --coverage-xml=build/coverage-db/coverage-xml --log-junit=build/coverage-db/junit.xml",
"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:db:ms": "DB_DRIVER=mssql composer test:db:sqlite",
"test:db:sqlite": ["@putenv APP_ENV=test", "phpunit --order-by=random --testdox --testdox-summary -c phpunit-db.xml"],
"test:db:sqlite:ci": ["@putenv XDEBUG_MODE=coverage", "@test:db:sqlite --coverage-php build/coverage-db.cov"],
"test:db:mysql": ["@putenv DB_DRIVER=mysql", "@test:db:sqlite"],
"test:db:maria": ["@putenv DB_DRIVER=maria", "@test:db:sqlite"],
"test:db:postgres": ["@putenv DB_DRIVER=postgres", "@test:db:sqlite"],
"test:db:ms": ["@putenv DB_DRIVER=mssql", "@test:db:sqlite"],
"test:api": "bin/test/run-api-tests.sh",
"test:api:rr": "TEST_RUNTIME=rr bin/test/run-api-tests.sh",
"test:api:ci": "GENERATE_COVERAGE=yes composer test:api",
"test:api:pretty": "GENERATE_COVERAGE=pretty composer test:api",
"test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml --log-junit=build/coverage-cli/junit.xml",
"test:cli:ci": "GENERATE_COVERAGE=yes composer test:cli",
"test:cli:pretty": "GENERATE_COVERAGE=pretty composer test:cli",
"infect:ci:base": "infection --threads=max --only-covered --only-covering-test-cases --skip-initial-tests",
"infect:ci:unit": "@infect:ci:base --coverage=build/coverage-unit --min-msi=80",
"infect:ci:db": "@infect:ci:base --coverage=build/coverage-db --min-msi=95 --configuration=infection-db.json5",
"infect:ci:api": "@infect:ci:base --coverage=build/coverage-api --min-msi=80 --configuration=infection-api.json5",
"infect:ci:cli": "@infect:ci:base --coverage=build/coverage-cli --min-msi=90 --configuration=infection-cli.json5",
"infect:ci": "@parallel infect:ci:unit infect:ci:db infect:ci:api infect:ci:cli",
"infect:test": [
"@parallel test:unit:ci test:db:sqlite:ci test:api:ci",
"@infect:ci"
"test:api:sqlite": ["@putenv DB_DRIVER=sqlite", "@test:api"],
"test:api:mysql": ["@putenv DB_DRIVER=mysql", "@test:api"],
"test:api:maria": ["@putenv DB_DRIVER=maria", "@test:api"],
"test:api:mssql": ["@putenv DB_DRIVER=mssql", "@test:api"],
"test:api:ci": [
"@putenv GENERATE_COVERAGE=yes",
"@test:api",
"phpcov merge build/coverage-api --php build/coverage-api.cov && rm build/coverage-api/*.cov"
],
"infect:test:unit": [
"@test:unit:ci",
"@infect:ci:unit"
"test:api:pretty": [
"@putenv GENERATE_COVERAGE=yes",
"@test:api",
"phpcov merge build/coverage-api --html build/coverage-api/coverage-html && rm build/coverage-api/*.cov"
],
"infect:test:api": [
"@test:api:ci",
"@infect:ci:api"
"test:cli": "bin/test/run-cli-tests.sh",
"test:cli:ci": [
"@putenv GENERATE_COVERAGE=yes",
"@test:cli",
"@php -d memory_limit=-1 vendor/bin/phpcov merge build/coverage-cli --php build/coverage-cli.cov && rm build/coverage-cli/*.cov"
],
"infect:test:cli": [
"@test:cli:ci",
"@infect:ci:cli"
"test:cli:pretty": [
"@putenv GENERATE_COVERAGE=yes",
"@test:cli",
"@php -d memory_limit=-1 phpcov merge build/coverage-cli --html build/coverage-cli/coverage-html && rm build/coverage-cli/*.cov"
],
"swagger:validate": "php-openapi validate docs/swagger/swagger.json",
"swagger:inline": "php-openapi inline docs/swagger/swagger.json docs/swagger/swagger-inlined.json",
"openapi:validate": "php-openapi validate docs/swagger/swagger.json",
"openapi:inline": "php-openapi inline docs/swagger/swagger.json docs/swagger/openapi-inlined.json",
"clean:dev": "rm -f data/database.sqlite && rm -f config/params/generated_config.php"
},
"scripts-descriptions": {
"ci": "<fg=blue;options=bold>Alias for \"cs\", \"stan\", \"swagger:validate\", \"test:ci\" and \"infect:ci\"</>",
"cs": "<fg=blue;options=bold>Checks coding styles</>",
"cs:fix": "<fg=blue;options=bold>Fixes coding styles, when possible</>",
"stan": "<fg=blue;options=bold>Inspects code with phpstan</>",
"test": "<fg=blue;options=bold>Runs all test suites</>",
"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:unit:pretty": "<fg=blue;options=bold>Runs unit test suites and generates an HTML code coverage report</>",
"test:db": "<fg=blue;options=bold>Runs database test suites on a SQLite, MySQL, MariaDB, PostgreSQL and MsSQL</>",
"test:db:sqlite": "<fg=blue;options=bold>Runs database test suites on a SQLite database</>",
"test:db:sqlite:ci": "<fg=blue;options=bold>Runs database test suites on a SQLite database, generating all needed reports and logs for CI envs</>",
"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:db:ms": "<fg=blue;options=bold>Runs database test suites on a Microsoft SQL Server database</>",
"test:api": "<fg=blue;options=bold>Runs API test suites</>",
"test:api:ci": "<fg=blue;options=bold>Runs API test suites, and generates code coverage for CI</>",
"test:api:pretty": "<fg=blue;options=bold>Runs API test suites, and generates code coverage in HTML format</>",
"test:cli": "<fg=blue;options=bold>Runs CLI test suites</>",
"test:cli:ci": "<fg=blue;options=bold>Runs CLI test suites, and generates code coverage for CI</>",
"test:cli:pretty": "<fg=blue;options=bold>Runs CLI test suites, and generates code coverage in HTML format</>",
"infect:ci": "<fg=blue;options=bold>Checks unit and db tests quality applying mutation testing with existing reports and logs</>",
"infect:ci:unit": "<fg=blue;options=bold>Checks unit tests quality applying mutation testing with existing reports and logs</>",
"infect:ci:db": "<fg=blue;options=bold>Checks db tests quality applying mutation testing with existing reports and logs</>",
"infect:test": "<fg=blue;options=bold>Runs unit and db tests, then checks tests quality applying mutation testing</>",
"swagger:validate": "<fg=blue;options=bold>Validates the swagger docs, making sure they fulfil the spec</>",
"swagger:inline": "<fg=blue;options=bold>Inlines swagger docs in a single file</>",
"clean:dev": "<fg=blue;options=bold>Deletes artifacts which are gitignored and could affect dev env</>"
},
"config": {
"sort-packages": true,
"platform-check": false,
"allow-plugins": {
"composer/package-versions-deprecated": true,
"dealerdirect/phpcodesniffer-composer-installer": true,
"infection/extension-installer": true,
"veewee/composer-run-parallel": true
}
}

View File

@ -1,2 +0,0 @@
local.php
*.local.php

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
return [
'app_options' => [
'name' => 'Shlink',
'version' => '%SHLINK_VERSION%',
],
];

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
return [
'app_options' => [
'version' => 'latest',
],
];

View File

@ -6,17 +6,19 @@ use Shlinkio\Shlink\Core\Config\EnvVars;
return (static function (): array {
$redisServers = EnvVars::REDIS_SERVERS->loadFromEnv();
$redis = ['pub_sub_enabled' => $redisServers !== null && EnvVars::REDIS_PUB_SUB_ENABLED->loadFromEnv(false)];
$redis = ['pub_sub_enabled' => $redisServers !== null && EnvVars::REDIS_PUB_SUB_ENABLED->loadFromEnv()];
$cacheRedisBlock = $redisServers === null ? [] : [
'redis' => [
'servers' => $redisServers,
'sentinel_service' => EnvVars::REDIS_SENTINEL_SERVICE->loadFromEnv(),
'username' => EnvVars::REDIS_SERVERS_USER->loadFromEnv(),
'password' => EnvVars::REDIS_SERVERS_PASSWORD->loadFromEnv(),
],
];
return [
'cache' => [
'namespace' => 'Shlink',
'namespace' => EnvVars::CACHE_NAMESPACE->loadFromEnv(),
...$cacheRedisBlock,
],
'redis' => $redis,

View File

@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
return [
'ip_address_resolution' => [
'headers_to_inspect' => [
'CF-Connecting-IP',
'X-Forwarded-For',
'X-Forwarded',
'Forwarded',
'True-Client-IP',
'X-Real-IP',
'X-Cluster-Client-Ip',
'Client-Ip',
],
],
];

View File

@ -3,13 +3,18 @@
declare(strict_types=1);
use Laminas\ConfigAggregator\ConfigAggregator;
use Shlinkio\Shlink\Core\Config\EnvVars;
return [
return (function () {
$isDev = EnvVars::isDevEnv();
'debug' => false,
return [
// Disabling config cache for cli, ensures it's never used for openswoole/RoadRunner, and also that console
// commands don't generate a cache file that's then used by php-fpm web executions
ConfigAggregator::ENABLE_CACHE => PHP_SAPI !== 'cli',
'debug' => $isDev,
];
// Disabling config cache for cli, ensures it's never used for RoadRunner, and also that console
// commands don't generate a cache file that's then used by php-fpm web executions
ConfigAggregator::ENABLE_CACHE => ! $isDev && PHP_SAPI !== 'cli',
];
})();

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
use Laminas\ConfigAggregator\ConfigAggregator;
return [
'debug' => true,
ConfigAggregator::ENABLE_CACHE => false,
];

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
return [
'cors' => [
'max_age' => 3600,
],
];

View File

@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink;
use Shlinkio\Shlink\Core\Config\EnvVars;
return (static function (): array {
$threshold = EnvVars::DELETE_SHORT_URL_THRESHOLD->loadFromEnv();
return [
'delete_short_urls' => [
'check_visits_threshold' => $threshold !== null,
'visits_threshold' => (int) ($threshold ?? DEFAULT_DELETE_SHORT_URL_THRESHOLD),
],
];
})();

View File

@ -4,23 +4,28 @@ declare(strict_types=1);
use GuzzleHttp\Client;
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use Laminas\ServiceManager\Factory\InvokableFactory;
use Mezzio\Application;
use Mezzio\Container;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Spiral\RoadRunner\Http\PSR7Worker;
use Spiral\RoadRunner\WorkerInterface;
use Symfony\Component\Filesystem\Filesystem;
return [
'dependencies' => [
'factories' => [
PSR7Worker::class => ConfigAbstractFactory::class,
Filesystem::class => InvokableFactory::class,
],
'delegators' => [
Mezzio\Application::class => [
Application::class => [
Container\ApplicationConfigInjectionDelegator::class,
],
],
@ -32,7 +37,7 @@ return [
'lazy_services' => [
'proxies_target_dir' => 'data/proxies',
'proxies_namespace' => 'ShlinkProxy',
'write_proxy_files' => true,
'write_proxy_files' => EnvVars::isProdEnv(),
],
],

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
use Psr\Container\ContainerInterface;
use Psr\Log;
return [
'dependencies' => [
'lazy_services' => [
'write_proxy_files' => false,
],
'initializers' => [
function (ContainerInterface $container, $instance): void {
if ($instance instanceof Log\LoggerAwareInterface) {
$instance->setLogger($container->get(Log\LoggerInterface::class));
}
},
],
],
];

View File

@ -2,49 +2,62 @@
declare(strict_types=1);
use Doctrine\ORM\Events;
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepository;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\Visit\Listener\OrphanVisitsCountTracker;
use Shlinkio\Shlink\Core\Visit\Listener\ShortUrlVisitsCountTracker;
use function Functional\contains;
use function Shlinkio\Shlink\Core\ArrayUtils\contains;
return (static function (): array {
$driver = EnvVars::DB_DRIVER->loadFromEnv();
$isMysqlCompatible = contains(['maria', 'mysql'], $driver);
$useEncryption = (bool) EnvVars::DB_USE_ENCRYPTION->loadFromEnv();
$isMysqlCompatible = contains($driver, ['maria', 'mysql']);
$resolveDriver = static fn () => match ($driver) {
$doctrineDriver = match ($driver) {
'postgres' => 'pdo_pgsql',
'mssql' => 'pdo_sqlsrv',
default => 'pdo_mysql',
};
$resolveDefaultPort = static fn () => match ($driver) {
'postgres' => '5432',
'mssql' => '1433',
default => '3306',
$readCredentialAsString = static function (EnvVars $envVar): string|null {
$value = $envVar->loadFromEnv();
return $value === null ? null : (string) $value;
};
$resolveCharset = static fn () => match ($driver) {
$charset = match ($driver) {
// This does not determine charsets or collations in tables or columns, but the charset used in the data
// flowing in the connection, so it has to match what has been set in the database.
'maria', 'mysql' => 'utf8mb4',
'postgres' => 'utf8',
default => null,
};
$resolveConnection = static fn () => match ($driver) {
$driverOptions = match ($driver) {
'mssql' => ['TrustServerCertificate' => 'true'],
'maria', 'mysql' => ! $useEncryption ? [] : [
1007 => true, // PDO::MYSQL_ATTR_SSL_KEY: Require using SSL
1014 => false, // PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT: Trust any certificate
],
'postgres' => ! $useEncryption ? [] : [
'sslmode' => 'require', // Require connections to be encrypted
'sslrootcert' => '', // Allow any certificate
],
default => [],
};
$connection = match ($driver) {
null, 'sqlite' => [
'driver' => 'pdo_sqlite',
'path' => 'data/database.sqlite',
],
default => [
'driver' => $resolveDriver(),
'dbname' => EnvVars::DB_NAME->loadFromEnv('shlink'),
'user' => EnvVars::DB_USER->loadFromEnv(),
'password' => EnvVars::DB_PASSWORD->loadFromEnv(),
'host' => EnvVars::DB_HOST->loadFromEnv(EnvVars::DB_UNIX_SOCKET->loadFromEnv()),
'port' => EnvVars::DB_PORT->loadFromEnv($resolveDefaultPort()),
'driver' => $doctrineDriver,
'dbname' => EnvVars::DB_NAME->loadFromEnv(),
'user' => $readCredentialAsString(EnvVars::DB_USER),
'password' => $readCredentialAsString(EnvVars::DB_PASSWORD),
'host' => EnvVars::DB_HOST->loadFromEnv(),
'port' => EnvVars::DB_PORT->loadFromEnv(),
'unix_socket' => $isMysqlCompatible ? EnvVars::DB_UNIX_SOCKET->loadFromEnv() : null,
'charset' => $resolveCharset(),
'driverOptions' => $driver !== 'mssql' ? [] : [
'TrustServerCertificate' => 'true',
],
'charset' => $charset,
'driverOptions' => $driverOptions,
],
};
@ -55,8 +68,12 @@ return (static function (): array {
'proxies_dir' => 'data/proxies',
'load_mappings_using_functional_style' => true,
'default_repository_classname' => EntitySpecificationRepository::class,
'listeners' => [
Events::onFlush => [ShortUrlVisitsCountTracker::class, OrphanVisitsCountTracker::class],
Events::postFlush => [ShortUrlVisitsCountTracker::class, OrphanVisitsCountTracker::class],
],
],
'connection' => $resolveConnection(),
'connection' => $connection,
],
];

View File

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
return [
'entity_manager' => [
'connection' => [
'user' => 'root',
'password' => 'root',
'driver' => 'pdo_mysql',
'host' => 'shlink_db_mysql',
'dbname' => 'shlink',
'charset' => 'utf8mb4',
],
],
];

View File

@ -8,7 +8,7 @@ return [
'geolite2' => [
'db_location' => __DIR__ . '/../../data/GeoLite2-City.mmdb',
'temp_dir' => __DIR__ . '/../../data',
'temp_dir' => __DIR__ . '/../../data/temp-geolite',
'license_key' => EnvVars::GEOLITE_LICENSE_KEY->loadFromEnv(),
],

View File

@ -11,6 +11,9 @@ return [
'installer' => [
'enabled_options' => [
Option\Server\RuntimeConfigOption::class,
Option\Server\MemoryLimitConfigOption::class,
Option\Server\LogsFormatConfigOption::class,
Option\Database\DatabaseDriverConfigOption::class,
Option\Database\DatabaseNameConfigOption::class,
Option\Database\DatabaseHostConfigOption::class,
@ -18,20 +21,20 @@ return [
Option\Database\DatabaseUserConfigOption::class,
Option\Database\DatabasePasswordConfigOption::class,
Option\Database\DatabaseUnixSocketConfigOption::class,
Option\Database\DatabaseUseEncryptionConfigOption::class,
Option\UrlShortener\ShortDomainHostConfigOption::class,
Option\UrlShortener\ShortDomainSchemaConfigOption::class,
Option\Visit\VisitsWebhooksConfigOption::class,
Option\Visit\OrphanVisitsWebhooksConfigOption::class,
Option\Redirect\BaseUrlRedirectConfigOption::class,
Option\Redirect\InvalidShortUrlRedirectConfigOption::class,
Option\Redirect\Regular404RedirectConfigOption::class,
Option\Visit\VisitsThresholdConfigOption::class,
Option\BasePathConfigOption::class,
Option\TimezoneConfigOption::class,
Option\Worker\TaskWorkerNumConfigOption::class,
Option\Worker\WebWorkerNumConfigOption::class,
Option\Cache\CacheNamespaceConfigOption::class,
Option\Redis\RedisServersConfigOption::class,
Option\Redis\RedisSentinelServiceConfigOption::class,
Option\Redis\RedisServersUserConfigOption::class,
Option\Redis\RedisServersPasswordConfigOption::class,
Option\Redis\RedisPubSubConfigOption::class,
Option\UrlShortener\ShortCodeLengthOption::class,
Option\Mercure\EnableMercureConfigOption::class,
@ -41,11 +44,14 @@ return [
Option\UrlShortener\GeoLiteLicenseKeyConfigOption::class,
Option\UrlShortener\RedirectStatusCodeConfigOption::class,
Option\UrlShortener\RedirectCacheLifeTimeConfigOption::class,
Option\UrlShortener\RedirectCacheVisibilityConfigOption::class,
Option\UrlShortener\AutoResolveTitlesConfigOption::class,
Option\UrlShortener\AppendExtraPathConfigOption::class,
Option\UrlShortener\ExtraPathModeConfigOption::class,
Option\UrlShortener\EnableMultiSegmentSlugsConfigOption::class,
Option\UrlShortener\EnableTrailingSlashConfigOption::class,
Option\UrlShortener\ShortUrlModeConfigOption::class,
Option\Robots\RobotsAllowAllShortUrlsConfigOption::class,
Option\Robots\RobotsUserAgentsConfigOption::class,
Option\Tracking\IpAnonymizationConfigOption::class,
Option\Tracking\OrphanVisitsTrackingConfigOption::class,
Option\Tracking\DisableTrackParamConfigOption::class,
@ -54,17 +60,22 @@ return [
Option\Tracking\DisableIpTrackingConfigOption::class,
Option\Tracking\DisableReferrerTrackingConfigOption::class,
Option\Tracking\DisableUaTrackingConfigOption::class,
Option\QrCode\DefaultSizeConfigOption::class,
Option\QrCode\DefaultMarginConfigOption::class,
Option\QrCode\DefaultFormatConfigOption::class,
Option\QrCode\DefaultErrorCorrectionConfigOption::class,
Option\QrCode\DefaultRoundBlockSizeConfigOption::class,
Option\RabbitMq\RabbitMqEnabledConfigOption::class,
Option\RabbitMq\RabbitMqHostConfigOption::class,
Option\RabbitMq\RabbitMqUseSslConfigOption::class,
Option\RabbitMq\RabbitMqPortConfigOption::class,
Option\RabbitMq\RabbitMqUserConfigOption::class,
Option\RabbitMq\RabbitMqPasswordConfigOption::class,
Option\RabbitMq\RabbitMqVhostConfigOption::class,
Option\Matomo\MatomoEnabledConfigOption::class,
Option\Matomo\MatomoBaseUrlConfigOption::class,
Option\Matomo\MatomoSiteIdConfigOption::class,
Option\Matomo\MatomoApiTokenConfigOption::class,
Option\RealTimeUpdates\RealTimeUpdatesTopicsConfigOption::class,
Option\Cors\CorsAllowOriginConfigOption::class,
Option\Cors\CorsAllowCredentialsConfigOption::class,
Option\Cors\CorsMaxAgeConfigOption::class,
Option\TrustedProxiesConfigOption::class,
],
'installation_commands' => [
@ -86,6 +97,9 @@ return [
InstallationCommand::API_KEY_GENERATE->value => [
'command' => 'bin/cli ' . Command\Api\GenerateKeyCommand::NAME,
],
InstallationCommand::API_KEY_CREATE->value => [
'command' => 'bin/cli ' . Command\Api\InitialApiKeyCommand::NAME,
],
],
],

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
use RKA\Middleware\IpAddress;
use RKA\Middleware\Mezzio\IpAddressFactory;
use Shlinkio\Shlink\Core\Config\EnvVars;
use function Shlinkio\Shlink\Core\splitByComma;
use const Shlinkio\Shlink\IP_ADDRESS_REQUEST_ATTRIBUTE;
return (static function (): array {
$trustedProxies = EnvVars::TRUSTED_PROXIES->loadFromEnv();
$proxiesIsHopCount = is_numeric($trustedProxies);
return [
// Configuration for RKA\Middleware\IpAddress
'rka' => [
'ip_address' => [
'attribute_name' => IP_ADDRESS_REQUEST_ATTRIBUTE,
'check_proxy_headers' => true,
// List of trusted proxies
'trusted_proxies' => $proxiesIsHopCount ? [] : splitByComma($trustedProxies),
// Amount of addresses to skip from the right, before finding the visitor IP address
'hop_count' => $proxiesIsHopCount ? (int) $trustedProxies : 0,
'headers_to_inspect' => [
'CF-Connecting-IP',
'X-Forwarded-For',
'X-Forwarded',
'Forwarded',
'True-Client-IP',
'X-Real-IP',
'X-Cluster-Client-Ip',
'Client-Ip',
],
],
],
'dependencies' => [
'factories' => [
IpAddress::class => IpAddressFactory::class,
],
],
];
})();

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use Shlinkio\Shlink\Common\Cache\RedisFactory;
use Shlinkio\Shlink\Common\Lock\NamespacedStore;
use Shlinkio\Shlink\Common\Logger\LoggerAwareDelegatorFactory;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Symfony\Component\Lock;
@ -22,11 +23,12 @@ return [
Lock\Store\RedisStore::class => ConfigAbstractFactory::class,
Lock\LockFactory::class => ConfigAbstractFactory::class,
LOCAL_LOCK_FACTORY => ConfigAbstractFactory::class,
NamespacedStore::class => ConfigAbstractFactory::class,
],
'aliases' => [
'lock_store' => EnvVars::REDIS_SERVERS->existsInEnv() ? 'redis_lock_store' : 'local_lock_store',
'redis_lock_store' => Lock\Store\RedisStore::class,
'redis_lock_store' => NamespacedStore::class,
'local_lock_store' => Lock\Store\FlockStore::class,
],
'delegators' => [
@ -39,6 +41,8 @@ return [
ConfigAbstractFactory::class => [
Lock\Store\FlockStore::class => ['config.locks.locks_dir'],
Lock\Store\RedisStore::class => [RedisFactory::SERVICE_NAME],
NamespacedStore::class => [Lock\Store\RedisStore::class, 'config.cache.namespace'],
Lock\LockFactory::class => ['lock_store'],
LOCAL_LOCK_FACTORY => ['local_lock_store'],
],

View File

@ -4,51 +4,77 @@ declare(strict_types=1);
namespace Shlinkio\Shlink;
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use Laminas\ServiceManager\Factory\InvokableFactory;
use Monolog\Level;
use Monolog\Logger;
use PhpMiddleware\RequestId;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Shlinkio\Shlink\Common\Logger\LoggerFactory;
use Shlinkio\Shlink\Common\Logger\LoggerType;
use Shlinkio\Shlink\Common\Middleware\AccessLogMiddleware;
use Shlinkio\Shlink\Common\Middleware\RequestIdMiddleware;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\EventDispatcher\Helper\RequestIdProvider;
use Shlinkio\Shlink\EventDispatcher\Util\RequestIdProviderInterface;
$common = [
'level' => Level::Info->value,
'processors' => [RequestId\MonologProcessor::class],
'line_format' => '[%datetime%] [%extra.request_id%] %channel%.%level_name% - %message%',
];
use function Shlinkio\Shlink\Config\env;
use function Shlinkio\Shlink\Config\runningInRoadRunner;
return [
'logger' => [
'Shlink' => [
'type' => LoggerType::FILE->value,
...$common,
return (static function (): array {
$isDev = EnvVars::isDevEnv();
$format = EnvVars::LOGS_FORMAT->loadFromEnv();
$buildCommonConfig = static fn (bool $addNewLine = false) => [
'level' => $isDev ? Level::Debug->value : Level::Info->value,
'processors' => [RequestIdMiddleware::class],
'formatter' => [
'type' => $format,
'add_new_line' => $addNewLine,
'line_format' =>
'[%datetime%] [%extra.' . RequestIdMiddleware::ATTRIBUTE . '%] %channel%.%level_name% - %message%',
],
'Access' => [
'type' => LoggerType::STREAM->value,
...$common,
],
],
];
'dependencies' => [
'factories' => [
'Logger_Shlink' => [LoggerFactory::class, 'Shlink'],
'Logger_Access' => [LoggerFactory::class, 'Access'],
],
'aliases' => [
'logger' => 'Logger_Shlink',
Logger::class => 'Logger_Shlink',
LoggerInterface::class => 'Logger_Shlink',
],
],
// In dev env or the docker container, stream Shlink logs to stderr, otherwise send them to a file
$useStreamForShlinkLogger = $isDev || env('SHLINK_RUNTIME') !== null;
'mezzio-swoole' => [
'swoole-http-server' => [
'logger' => [
'logger-name' => 'Logger_Access',
'format' => '%u "%r" %>s %B',
return [
'logger' => [
'Shlink' => $useStreamForShlinkLogger ? [
'type' => LoggerType::STREAM->value,
'destination' => 'php://stderr',
...$buildCommonConfig(),
] : [
'type' => LoggerType::FILE->value,
...$buildCommonConfig(),
],
'Access' => [
'type' => LoggerType::STREAM->value,
'destination' => 'php://stderr',
...$buildCommonConfig(! runningInRoadRunner()),
],
],
],
];
'dependencies' => [
'factories' => [
'Logger_Shlink' => [LoggerFactory::class, 'Shlink'],
'Logger_Access' => [LoggerFactory::class, 'Access'],
NullLogger::class => InvokableFactory::class,
RequestIdProvider::class => ConfigAbstractFactory::class,
],
'aliases' => [
'logger' => 'Logger_Shlink',
Logger::class => 'Logger_Shlink',
LoggerInterface::class => 'Logger_Shlink',
AccessLogMiddleware::LOGGER_SERVICE_NAME => 'Logger_Access',
RequestIdProviderInterface::class => RequestIdProvider::class,
],
],
ConfigAbstractFactory::class => [
RequestIdProvider::class => [RequestIdMiddleware::class],
],
];
})();

View File

@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
use Monolog\Level;
use Shlinkio\Shlink\Common\Logger\LoggerType;
use function Shlinkio\Shlink\Config\runningInOpenswoole;
$logToStream = runningInOpenswoole();
return [
'logger' => [
'Shlink' => [
// For openswoole, send logs as stream
'type' => $logToStream ? LoggerType::STREAM->value : LoggerType::FILE->value,
'level' => Level::Debug->value,
],
],
];

View File

@ -8,34 +8,32 @@ use Shlinkio\Shlink\Core\Config\EnvVars;
use Symfony\Component\Mercure\Hub;
use Symfony\Component\Mercure\HubInterface;
return (static function (): array {
$publicUrl = EnvVars::MERCURE_PUBLIC_HUB_URL->loadFromEnv();
return [
return [
// This config is used by shlink-common. Do not delete
'mercure' => [
'enabled' => EnvVars::MERCURE_ENABLED->loadFromEnv(),
'public_hub_url' => EnvVars::MERCURE_PUBLIC_HUB_URL->loadFromEnv(),
'internal_hub_url' => EnvVars::MERCURE_INTERNAL_HUB_URL->loadFromEnv(),
'jwt_secret' => EnvVars::MERCURE_JWT_SECRET->loadFromEnv(),
'jwt_issuer' => 'Shlink',
],
'mercure' => [
'public_hub_url' => $publicUrl,
'internal_hub_url' => EnvVars::MERCURE_INTERNAL_HUB_URL->loadFromEnv($publicUrl),
'jwt_secret' => EnvVars::MERCURE_JWT_SECRET->loadFromEnv(),
'jwt_issuer' => 'Shlink',
],
'dependencies' => [
'delegators' => [
LcobucciJwtProvider::class => [
LazyServiceFactory::class,
],
Hub::class => [
LazyServiceFactory::class,
],
'dependencies' => [
'delegators' => [
LcobucciJwtProvider::class => [
LazyServiceFactory::class,
],
'lazy_services' => [
'class_map' => [
LcobucciJwtProvider::class => LcobucciJwtProvider::class,
Hub::class => HubInterface::class,
],
Hub::class => [
LazyServiceFactory::class,
],
],
'lazy_services' => [
'class_map' => [
LcobucciJwtProvider::class => LcobucciJwtProvider::class,
Hub::class => HubInterface::class,
],
],
],
];
})();
];

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
return [
'mercure' => [
'public_hub_url' => 'http://localhost:8001',
'internal_hub_url' => 'http://shlink_mercure_proxy',
'jwt_secret' => 'mercure_jwt_key_long_enough_to_avoid_error',
],
];

View File

@ -7,15 +7,18 @@ namespace Shlinkio\Shlink;
use Laminas\Stratigility\Middleware\ErrorHandler;
use Mezzio\ProblemDetails;
use Mezzio\Router;
use PhpMiddleware\RequestId\RequestIdMiddleware;
use RKA\Middleware\IpAddress;
use Shlinkio\Shlink\Common\Middleware\AccessLogMiddleware;
use Shlinkio\Shlink\Common\Middleware\ContentLengthMiddleware;
use Shlinkio\Shlink\Common\Middleware\RequestIdMiddleware;
use Shlinkio\Shlink\Core\Geolocation\Middleware\IpGeolocationMiddleware;
return [
'middleware_pipeline' => [
'error-handler' => [
'middleware' => [
AccessLogMiddleware::class,
ContentLengthMiddleware::class,
RequestIdMiddleware::class,
ErrorHandler::class,
@ -45,7 +48,6 @@ return [
'rest' => [
'path' => '/rest',
'middleware' => [
Rest\Middleware\ErrorHandler\BackwardsCompatibleProblemDetailsHandler::class,
Router\Middleware\ImplicitOptionsMiddleware::class,
Rest\Middleware\BodyParserMiddleware::class,
Rest\Middleware\AuthenticationMiddleware::class,
@ -66,8 +68,11 @@ return [
],
'not-found' => [
'middleware' => [
// This middleware is in front of tracking actions explicitly. Putting here for orphan visits tracking
// These two middlewares are in front of other tracking actions.
// Putting them here for orphan visits tracking
IpAddress::class,
IpGeolocationMiddleware::class,
Core\ErrorHandler\NotFoundTypeResolverMiddleware::class,
Core\ShortUrl\Middleware\ExtraPathRedirectMiddleware::class,
Core\ErrorHandler\NotFoundTrackerMiddleware::class,

View File

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ERROR_CORRECTION;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_FORMAT;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_MARGIN;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ROUND_BLOCK_SIZE;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_SIZE;
return [
'qr_codes' => [
'size' => (int) EnvVars::DEFAULT_QR_CODE_SIZE->loadFromEnv(DEFAULT_QR_CODE_SIZE),
'margin' => (int) EnvVars::DEFAULT_QR_CODE_MARGIN->loadFromEnv(DEFAULT_QR_CODE_MARGIN),
'format' => EnvVars::DEFAULT_QR_CODE_FORMAT->loadFromEnv(DEFAULT_QR_CODE_FORMAT),
'error_correction' => EnvVars::DEFAULT_QR_CODE_ERROR_CORRECTION->loadFromEnv(
DEFAULT_QR_CODE_ERROR_CORRECTION,
),
'round_block_size' => (bool) EnvVars::DEFAULT_QR_CODE_ROUND_BLOCK_SIZE->loadFromEnv(
DEFAULT_QR_CODE_ROUND_BLOCK_SIZE,
),
],
];

View File

@ -6,16 +6,15 @@ use Shlinkio\Shlink\Core\Config\EnvVars;
return [
// This config is used by shlink-common. Do not delete
'rabbitmq' => [
'enabled' => (bool) EnvVars::RABBITMQ_ENABLED->loadFromEnv(false),
'enabled' => (bool) EnvVars::RABBITMQ_ENABLED->loadFromEnv(),
'host' => EnvVars::RABBITMQ_HOST->loadFromEnv(),
'port' => (int) EnvVars::RABBITMQ_PORT->loadFromEnv('5672'),
'use_ssl' => (bool) EnvVars::RABBITMQ_USE_SSL->loadFromEnv(),
'port' => (int) EnvVars::RABBITMQ_PORT->loadFromEnv(),
'user' => EnvVars::RABBITMQ_USER->loadFromEnv(),
'password' => EnvVars::RABBITMQ_PASSWORD->loadFromEnv(),
'vhost' => EnvVars::RABBITMQ_VHOST->loadFromEnv('/'),
// Deprecated
'legacy_visits_publishing' => (bool) EnvVars::RABBITMQ_LEGACY_VISITS_PUBLISHING->loadFromEnv(false),
'vhost' => EnvVars::RABBITMQ_VHOST->loadFromEnv(),
],
];

View File

@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
return [
'rabbitmq' => [
'enabled' => true,
'host' => 'shlink_rabbitmq',
'user' => 'rabbit',
'password' => 'rabbit',
],
];

View File

@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
use const Shlinkio\Shlink\DEFAULT_REDIRECT_CACHE_LIFETIME;
use const Shlinkio\Shlink\DEFAULT_REDIRECT_STATUS_CODE;
return [
'not_found_redirects' => [
'invalid_short_url' => EnvVars::DEFAULT_INVALID_SHORT_URL_REDIRECT->loadFromEnv(),
'regular_404' => EnvVars::DEFAULT_REGULAR_404_REDIRECT->loadFromEnv(),
'base_url' => EnvVars::DEFAULT_BASE_URL_REDIRECT->loadFromEnv(),
],
'redirects' => [
'redirect_status_code' => (int) EnvVars::REDIRECT_STATUS_CODE->loadFromEnv(DEFAULT_REDIRECT_STATUS_CODE->value),
'redirect_cache_lifetime' => (int) EnvVars::REDIRECT_CACHE_LIFETIME->loadFromEnv(
DEFAULT_REDIRECT_CACHE_LIFETIME,
),
],
];

View File

@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
return [
'cache' => [
'redis' => [
'servers' => 'tcp://shlink_redis:6379',
// 'servers' => 'tcp://barbar@shlink_redis_acl:6379',
// 'servers' => 'tcp://foo:bar@shlink_redis_acl:6379',
],
],
'redis' => [
'pub_sub_enabled' => true,
],
'dependencies' => [
'aliases' => [
// With this config, a user could alias 'lock_store' => 'redis_lock_store' to override the default
// 'lock_store' => 'redis_lock_store',
],
],
];

View File

@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use Laminas\ServiceManager\Factory\InvokableFactory;
use PhpMiddleware\RequestId;
use Shlinkio\Shlink\Common\Logger\Processor\BackwardsCompatibleMonologProcessorDelegator;
return [
'request_id' => [
'allow_override' => true,
'header_name' => 'X-Request-Id',
],
'dependencies' => [
'factories' => [
RequestId\Generator\RamseyUuid4StaticGenerator::class => InvokableFactory::class,
RequestId\RequestIdProviderFactory::class => ConfigAbstractFactory::class,
RequestId\RequestIdMiddleware::class => ConfigAbstractFactory::class,
RequestId\MonologProcessor::class => ConfigAbstractFactory::class,
],
'delegators' => [
RequestId\MonologProcessor::class => [
BackwardsCompatibleMonologProcessorDelegator::class,
],
],
],
ConfigAbstractFactory::class => [
RequestId\RequestIdProviderFactory::class => [
RequestId\Generator\RamseyUuid4StaticGenerator::class,
'config.request_id.allow_override',
'config.request_id.header_name',
],
RequestId\RequestIdMiddleware::class => [
RequestId\RequestIdProviderFactory::class,
'config.request_id.header_name',
],
RequestId\MonologProcessor::class => [RequestId\RequestIdMiddleware::class],
],
];

View File

@ -8,10 +8,12 @@ use Shlinkio\Shlink\Core\Config\EnvVars;
return [
'router' => [
'base_path' => EnvVars::BASE_PATH->loadFromEnv(''),
'base_path' => EnvVars::BASE_PATH->loadFromEnv(),
'fastroute' => [
FastRouteRouter::CONFIG_CACHE_ENABLED => true,
// Disabling config cache for cli, ensures it's never used for RoadRunner, and also that console
// commands don't generate a cache file that's then used by php-fpm web executions
FastRouteRouter::CONFIG_CACHE_ENABLED => EnvVars::isProdEnv() && PHP_SAPI !== 'cli',
FastRouteRouter::CONFIG_CACHE_FILE => 'data/cache/fastroute_cached_routes.php',
],
],

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Mezzio\Router\FastRouteRouter;
return [
'router' => [
// 'base_path' => '',
'fastroute' => [
FastRouteRouter::CONFIG_CACHE_ENABLED => false,
],
],
];

View File

@ -8,6 +8,7 @@ use Fig\Http\Message\RequestMethodInterface;
use RKA\Middleware\IpAddress;
use Shlinkio\Shlink\Core\Action as CoreAction;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\Geolocation\Middleware\IpGeolocationMiddleware;
use Shlinkio\Shlink\Core\ShortUrl\Middleware\TrimTrailingSlashMiddleware;
use Shlinkio\Shlink\Rest\Action;
use Shlinkio\Shlink\Rest\ConfigProvider;
@ -17,12 +18,9 @@ use Shlinkio\Shlink\Rest\Middleware\Mercure\NotConfiguredMercureErrorHandler;
use function sprintf;
return (static function (): array {
$contentNegotiationMiddleware = Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class;
$dropDomainMiddleware = Middleware\ShortUrl\DropDefaultDomainFromRequestMiddleware::class;
$overrideDomainMiddleware = Middleware\ShortUrl\OverrideDomainMiddleware::class;
// TODO This should be based on config, not the env var
$shortUrlRouteSuffix = EnvVars::SHORT_URL_TRAILING_SLASH->loadFromEnv(false) ? '[/]' : '';
$shortUrlRouteSuffix = EnvVars::SHORT_URL_TRAILING_SLASH->loadFromEnv() ? '[/]' : '';
return [
@ -32,23 +30,31 @@ return (static function (): array {
...ConfigProvider::applyRoutesPrefix([
Action\HealthAction::getRouteDef(),
// Visits
// Visits and rules routes must go first, as they have a more specific path, otherwise, when
// multi-segment slugs are enabled, routes with a less-specific path might match first
// Visits.
Action\Visit\ShortUrlVisitsAction::getRouteDef([$dropDomainMiddleware]),
Action\ShortUrl\DeleteShortUrlVisitsAction::getRouteDef([$dropDomainMiddleware]),
Action\Visit\TagVisitsAction::getRouteDef(),
Action\Visit\DomainVisitsAction::getRouteDef(),
Action\Visit\GlobalVisitsAction::getRouteDef(),
Action\Visit\OrphanVisitsAction::getRouteDef(),
Action\Visit\DeleteOrphanVisitsAction::getRouteDef(),
Action\Visit\NonOrphanVisitsAction::getRouteDef(),
//Redirect rules
Action\RedirectRule\ListRedirectRulesAction::getRouteDef([$dropDomainMiddleware]),
Action\RedirectRule\SetRedirectRulesAction::getRouteDef([$dropDomainMiddleware]),
// Short URLs
Action\ShortUrl\CreateShortUrlAction::getRouteDef([
$contentNegotiationMiddleware,
$dropDomainMiddleware,
$overrideDomainMiddleware,
Middleware\ShortUrl\DefaultShortCodesLengthMiddleware::class,
]),
Action\ShortUrl\SingleStepCreateShortUrlAction::getRouteDef([
$contentNegotiationMiddleware,
Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class,
$overrideDomainMiddleware,
]),
Action\ShortUrl\EditShortUrlAction::getRouteDef([$dropDomainMiddleware]),
@ -83,23 +89,17 @@ return (static function (): array {
'path' => '/{shortCode}/track',
'middleware' => [
IpAddress::class,
IpGeolocationMiddleware::class,
CoreAction\PixelAction::class,
],
'allowed_methods' => [RequestMethodInterface::METHOD_GET],
],
[
'name' => CoreAction\QrCodeAction::class,
'path' => '/{shortCode}/qr-code',
'middleware' => [
CoreAction\QrCodeAction::class,
],
'allowed_methods' => [RequestMethodInterface::METHOD_GET],
],
[
'name' => CoreAction\RedirectAction::class,
'path' => sprintf('/{shortCode}%s', $shortUrlRouteSuffix),
'middleware' => [
IpAddress::class,
IpGeolocationMiddleware::class,
TrimTrailingSlashMiddleware::class,
CoreAction\RedirectAction::class,
],

View File

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
use function Shlinkio\Shlink\Config\getOpenswooleConfigFromEnv;
use const Shlinkio\Shlink\MIN_TASK_WORKERS;
return (static function (): array {
$taskWorkers = (int) EnvVars::TASK_WORKER_NUM->loadFromEnv(16);
return [
'mezzio-swoole' => [
// Setting this to true can have unexpected behaviors when running several concurrent slow DB queries
'enable_coroutine' => false,
'swoole-http-server' => [
'host' => '0.0.0.0',
'port' => (int) EnvVars::PORT->loadFromEnv(8080),
'process-name' => 'shlink',
'options' => [
...getOpenswooleConfigFromEnv(),
'worker_num' => (int) EnvVars::WEB_WORKER_NUM->loadFromEnv(16),
'task_worker_num' => max($taskWorkers, MIN_TASK_WORKERS),
],
],
],
];
})();

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
return [
'mezzio-swoole' => [
'hot-code-reload' => [
'enable' => true,
],
],
];

View File

@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
return (static function (): array {
/** @var string|null $disableTrackingFrom */
$disableTrackingFrom = EnvVars::DISABLE_TRACKING_FROM->loadFromEnv();
return [
'tracking' => [
// Tells if IP addresses should be anonymized before persisting, to fulfil data protection regulations
// This applies only if IP address tracking is enabled
'anonymize_remote_addr' => (bool) EnvVars::ANONYMIZE_REMOTE_ADDR->loadFromEnv(true),
// Tells if visits to not-found URLs should be tracked. The disable_tracking option takes precedence
'track_orphan_visits' => (bool) EnvVars::TRACK_ORPHAN_VISITS->loadFromEnv(true),
// A query param that, if provided, will disable tracking of one particular visit. Always takes precedence
'disable_track_param' => EnvVars::DISABLE_TRACK_PARAM->loadFromEnv(),
// If true, visits will not be tracked at all
'disable_tracking' => (bool) EnvVars::DISABLE_TRACKING->loadFromEnv(false),
// If true, visits will be tracked, but neither the IP address, nor the location will be resolved
'disable_ip_tracking' => (bool) EnvVars::DISABLE_IP_TRACKING->loadFromEnv(false),
// If true, the referrer will not be tracked
'disable_referrer_tracking' => (bool) EnvVars::DISABLE_REFERRER_TRACKING->loadFromEnv(false),
// If true, the user agent will not be tracked
'disable_ua_tracking' => (bool) EnvVars::DISABLE_UA_TRACKING->loadFromEnv(false),
// A list of IP addresses, patterns or CIDR blocks from which tracking is disabled by default
'disable_tracking_from' => $disableTrackingFrom === null
? []
: array_map(trim(...), explode(',', $disableTrackingFrom)),
],
];
})();

View File

@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode;
use const Shlinkio\Shlink\DEFAULT_SHORT_CODES_LENGTH;
use const Shlinkio\Shlink\MIN_SHORT_CODES_LENGTH;
return (static function (): array {
$shortCodesLength = max(
(int) EnvVars::DEFAULT_SHORT_CODES_LENGTH->loadFromEnv(DEFAULT_SHORT_CODES_LENGTH),
MIN_SHORT_CODES_LENGTH,
);
$modeFromEnv = EnvVars::SHORT_URL_MODE->loadFromEnv(ShortUrlMode::STRICT->value);
$mode = ShortUrlMode::tryDeprecated($modeFromEnv) ?? ShortUrlMode::STRICT;
return [
'url_shortener' => [
'domain' => [ // TODO Refactor this structure to url_shortener.schema and url_shortener.default_domain
'schema' => ((bool) EnvVars::IS_HTTPS_ENABLED->loadFromEnv(true)) ? 'https' : 'http',
'hostname' => EnvVars::DEFAULT_DOMAIN->loadFromEnv(''),
],
'default_short_codes_length' => $shortCodesLength,
'auto_resolve_titles' => (bool) EnvVars::AUTO_RESOLVE_TITLES->loadFromEnv(false),
'append_extra_path' => (bool) EnvVars::REDIRECT_APPEND_EXTRA_PATH->loadFromEnv(false),
'multi_segment_slugs_enabled' => (bool) EnvVars::MULTI_SEGMENT_SLUGS_ENABLED->loadFromEnv(false),
'trailing_slash_enabled' => (bool) EnvVars::SHORT_URL_TRAILING_SLASH->loadFromEnv(false),
'mode' => $mode,
],
];
})();

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
use function Shlinkio\Shlink\Config\runningInOpenswoole;
use function Shlinkio\Shlink\Config\runningInRoadRunner;
return [
'url_shortener' => [
'domain' => [
'schema' => 'http',
'hostname' => sprintf('localhost:%s', match (true) {
runningInRoadRunner() => '8800',
runningInOpenswoole() => '8080',
default => '8000',
}),
],
'auto_resolve_titles' => true,
// 'multi_segment_slugs_enabled' => true,
// 'trailing_slash_enabled' => true,
],
];

View File

@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
// Deprecated. Webhooks are no longer supported. To be removed in Shlink 4.0.0
return (static function (): array {
$webhooks = EnvVars::VISITS_WEBHOOKS->loadFromEnv();
return [
'visits_webhooks' => [
'webhooks' => $webhooks === null ? [] : explode(',', $webhooks),
'notify_orphan_visits_to_webhooks' =>
(bool) EnvVars::NOTIFY_ORPHAN_VISITS_TO_WEBHOOKS->loadFromEnv(false),
],
];
})();

View File

@ -2,11 +2,26 @@
declare(strict_types=1);
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\Migrations\Configuration\EntityManager\ExistingEntityManager;
use Doctrine\Migrations\Configuration\Migration\ConfigurationArray;
use Doctrine\Migrations\DependencyFactory;
// This file is currently used by doctrine migrations only
return (static function () {
/** @var EntityManager $em */
$migrationsConfig = [
'migrations_paths' => [
'ShlinkMigrations' => 'module/Core/migrations',
],
'table_storage' => [
'table_name' => 'migrations',
],
'custom_template' => 'data/migrations_template.txt',
];
$em = include __DIR__ . '/entity-manager.php';
return ConsoleRunner::createHelperSet($em);
return DependencyFactory::fromEntityManager(
new ConfigurationArray($migrationsConfig),
new ExistingEntityManager($em),
);
})();

View File

@ -8,48 +8,35 @@ use Laminas\ConfigAggregator;
use Laminas\Diactoros;
use Mezzio;
use Mezzio\ProblemDetails;
use Mezzio\Swoole;
use Shlinkio\Shlink\Config\ConfigAggregator\EnvVarLoaderProvider;
use Shlinkio\Shlink\Core\Config\EnvVars;
use function class_exists;
use function Shlinkio\Shlink\Config\env;
use function Shlinkio\Shlink\Config\openswooleIsInstalled;
use function Shlinkio\Shlink\Config\runningInRoadRunner;
use function Shlinkio\Shlink\Core\enumValues;
use const PHP_SAPI;
$isTestEnv = env('APP_ENV') === 'test';
$enableSwoole = PHP_SAPI === 'cli' && openswooleIsInstalled() && ! runningInRoadRunner();
return (new ConfigAggregator\ConfigAggregator([
! $isTestEnv
? new EnvVarLoaderProvider('config/params/generated_config.php', enumValues(Core\Config\EnvVars::class))
: new ConfigAggregator\ArrayProvider([]),
Mezzio\ConfigProvider::class,
Mezzio\Router\ConfigProvider::class,
Mezzio\Router\FastRouteRouter\ConfigProvider::class,
$enableSwoole && class_exists(Swoole\ConfigProvider::class)
? Swoole\ConfigProvider::class
: new ConfigAggregator\ArrayProvider([]),
ProblemDetails\ConfigProvider::class,
Diactoros\ConfigProvider::class,
Common\ConfigProvider::class,
Config\ConfigProvider::class,
Importer\ConfigProvider::class,
IpGeolocation\ConfigProvider::class,
EventDispatcher\ConfigProvider::class,
Core\ConfigProvider::class,
CLI\ConfigProvider::class,
Rest\ConfigProvider::class,
new ConfigAggregator\PhpFileProvider('config/autoload/{{,*.}global,{,*.}local}.php'),
$isTestEnv
? new ConfigAggregator\PhpFileProvider('config/test/*.global.php')
: new ConfigAggregator\ArrayProvider([]),
// Routes have to be loaded last
new ConfigAggregator\PhpFileProvider('config/autoload/routes.config.php'),
], 'data/cache/app_config.php', [
Core\Config\PostProcessor\BasePathPrefixer::class,
Core\Config\PostProcessor\MultiSegmentSlugProcessor::class,
Core\Config\PostProcessor\ShortUrlMethodsProcessor::class,
]))->getMergedConfig();
return new ConfigAggregator\ConfigAggregator(
providers: [
Mezzio\ConfigProvider::class,
Mezzio\Router\ConfigProvider::class,
Mezzio\Router\FastRouteRouter\ConfigProvider::class,
ProblemDetails\ConfigProvider::class,
Diactoros\ConfigProvider::class,
Common\ConfigProvider::class,
Config\ConfigProvider::class,
Importer\ConfigProvider::class,
IpGeolocation\ConfigProvider::class,
EventDispatcher\ConfigProvider::class,
Core\ConfigProvider::class,
CLI\ConfigProvider::class,
Rest\ConfigProvider::class,
new ConfigAggregator\PhpFileProvider('config/autoload/{,*.}global.php'),
// Test config should be loaded ONLY during tests
EnvVars::isTestEnv()
? new ConfigAggregator\PhpFileProvider('config/test/*.global.php')
: new ConfigAggregator\ArrayProvider([]),
// Routes have to be loaded last
new ConfigAggregator\PhpFileProvider('config/autoload/routes.config.php'),
],
cachedConfigFile: 'data/cache/app_config.php',
postProcessors: [
Core\Config\PostProcessor\BasePathPrefixer::class,
Core\Config\PostProcessor\MultiSegmentSlugProcessor::class,
Core\Config\PostProcessor\ShortUrlMethodsProcessor::class,
],
)->getMergedConfig();

View File

@ -9,14 +9,32 @@ use Shlinkio\Shlink\Core\Util\RedirectStatus;
const DEFAULT_DELETE_SHORT_URL_THRESHOLD = 15;
const DEFAULT_SHORT_CODES_LENGTH = 5;
const MIN_SHORT_CODES_LENGTH = 4;
const DEFAULT_REDIRECT_STATUS_CODE = RedirectStatus::STATUS_302; // Deprecated. Default to 307 for Shlink v4
const DEFAULT_REDIRECT_STATUS_CODE = RedirectStatus::STATUS_302;
const DEFAULT_REDIRECT_CACHE_LIFETIME = 30;
const DEFAULT_REDIRECT_CACHE_VISIBILITY = 'private';
const LOCAL_LOCK_FACTORY = 'Shlinkio\Shlink\LocalLockFactory';
const TITLE_TAG_VALUE = '/<title[^>]*>(.*?)<\/title>/i'; // Matches the value inside a html title tag
const DEFAULT_QR_CODE_SIZE = 300;
const DEFAULT_QR_CODE_MARGIN = 0;
const DEFAULT_QR_CODE_FORMAT = 'png';
const DEFAULT_QR_CODE_ERROR_CORRECTION = 'l';
const DEFAULT_QR_CODE_ROUND_BLOCK_SIZE = true;
const MIN_TASK_WORKERS = 4;
const MIGRATIONS_TABLE = 'migrations';
const LOOSE_URI_MATCHER = '/(.+)\:(.+)/i'; // Matches anything starting with a schema.
const IP_ADDRESS_REQUEST_ATTRIBUTE = 'remote_address';
const REDIRECT_URL_REQUEST_ATTRIBUTE = 'redirect_url';
/**
* List of ISO 3166-1 alpha-2 two-letter country codes https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
*/
const ISO_COUNTRY_CODES = [
'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ',
'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', 'BV', 'BR',
'IO', 'BN', 'BG', 'BF', 'BI', 'CV', 'KH', 'CM', 'CA', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC',
'CO', 'KM', 'CG', 'CD', 'CK', 'CR', 'CI', 'HR', 'CU', 'CW', 'CY', 'CZ', 'DK', 'DJ', 'DM', 'DO',
'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'SZ', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF',
'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY',
'HT', 'HM', 'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL', 'IT', 'JM',
'JP', 'JE', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY',
'LI', 'LT', 'LU', 'MO', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX',
'FM', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI',
'NE', 'NG', 'NU', 'NF', 'MK', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH',
'PN', 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF', 'PM', 'VC',
'WS', 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL', 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS',
'SS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK',
'TO', 'TT', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU',
'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW',
];

View File

@ -6,14 +6,29 @@ use Laminas\ServiceManager\ServiceManager;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Symfony\Component\Lock;
use function Shlinkio\Shlink\Config\loadEnvVarsFromConfig;
use function Shlinkio\Shlink\Core\enumValues;
use const Shlinkio\Shlink\LOCAL_LOCK_FACTORY;
// Set current directory to the project's root directory
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
// This is one of the first files loaded. Configure the timezone here
date_default_timezone_set(EnvVars::TIMEZONE->loadFromEnv(date_default_timezone_get()));
// Promote env vars from installer, dev config or test config
loadEnvVarsFromConfig(
EnvVars::isTestEnv() ? 'config/test/shlink_test_env.php' : 'config/params/*.php',
enumValues(EnvVars::class),
);
// This is one of the first files loaded. Set global configuration here
error_reporting(
// Set a less strict error reporting for prod, where deprecation warnings should be ignored
EnvVars::isProdEnv() ? E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED : E_ALL,
);
ini_set('memory_limit', EnvVars::MEMORY_LIMIT->loadFromEnv());
date_default_timezone_set(EnvVars::TIMEZONE->loadFromEnv());
// This class alias tricks the ConfigAbstractFactory to return Lock\Factory instances even with a different service name
// It needs to be placed here as individual config files will not be loaded once config is cached
@ -21,7 +36,6 @@ if (! class_exists(LOCAL_LOCK_FACTORY)) {
class_alias(Lock\LockFactory::class, LOCAL_LOCK_FACTORY);
}
// Build container
return (static function (): ServiceManager {
$config = require __DIR__ . '/config.php';
$container = new ServiceManager($config['dependencies']);

View File

@ -1,2 +1,3 @@
*
!.gitignore
!*.dist

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
use function Shlinkio\Shlink\Config\runningInRoadRunner;
return [
EnvVars::APP_ENV->value => 'dev',
// EnvVars::GEOLITE_LICENSE_KEY->value => '',
// URL shortener
EnvVars::DEFAULT_DOMAIN->value => runningInRoadRunner() ? 'localhost:8800' : 'localhost:8008',
EnvVars::IS_HTTPS_ENABLED->value => false,
// Database - MySQL
EnvVars::DB_DRIVER->value => 'mysql',
EnvVars::DB_USER->value => 'root',
EnvVars::DB_PASSWORD->value => 'root',
EnvVars::DB_NAME->value => 'shlink',
// EnvVars::DB_NAME->value => 'shlink_foo',
EnvVars::DB_HOST->value => 'shlink_db_mysql',
// Database - Maria
// EnvVars::DB_DRIVER->value => 'maria',
// EnvVars::DB_USER->value => 'root',
// EnvVars::DB_PASSWORD->value => 'root',
// EnvVars::DB_NAME->value => 'shlink_foo',
// EnvVars::DB_HOST->value => 'shlink_db_maria',
// Database - Postgres
// EnvVars::DB_DRIVER->value => 'postgres',
// EnvVars::DB_USER->value => 'postgres',
// EnvVars::DB_PASSWORD->value => 'root',
// EnvVars::DB_NAME->value => 'shlink_foo',
// EnvVars::DB_HOST->value => 'shlink_db_postgres',
// Database - MSSQL
// EnvVars::DB_DRIVER->value => 'mssql',
// EnvVars::DB_USER->value => 'sa',
// EnvVars::DB_PASSWORD->value => 'Passw0rd!',
// EnvVars::DB_NAME->value => 'shlink_foo',
// EnvVars::DB_HOST->value => 'shlink_db_ms',
// Matomo
// Dev matomo instance needs to be manually configured once before enabling the configuration below:
// 1. Go to http://localhost:8003 and follow the installation instructions.
// 2. Open data/infra/matomo/config/config.ini.php and replace `trusted_hosts[] = "localhost"` with
// `trusted_hosts[] = "localhost:8003"` (see https://github.com/matomo-org/matomo/issues/9549)
// 3. Go to http://localhost:8003/index.php?module=SitesManager&action=index and paste the ID for the site you just
// created into the `MATOMO_SITE_ID` var below.
// 4. Go to http://localhost:8003/index.php?module=UsersManager&action=userSecurity, scroll down, click
// "Create new token" and once generated, paste the token into the `MATOMO_API_TOKEN` var below.
// 5. Copy the config below and paste it in a new shlink-dev.local.env file.
EnvVars::MATOMO_ENABLED->value => false,
EnvVars::MATOMO_BASE_URL->value => 'http://shlink_matomo',
// EnvVars::MATOMO_SITE_ID->value => ,
// EnvVars::MATOMO_API_TOKEN->value => ,
// Mercure
EnvVars::MERCURE_ENABLED->value => true,
EnvVars::MERCURE_PUBLIC_HUB_URL->value => 'http://localhost:8002',
EnvVars::MERCURE_INTERNAL_HUB_URL->value => 'http://shlink_mercure_proxy',
EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error',
// RabbitMQ
EnvVars::RABBITMQ_ENABLED->value => true,
EnvVars::RABBITMQ_HOST->value => 'shlink_rabbitmq',
EnvVars::RABBITMQ_PORT->value => 5672,
EnvVars::RABBITMQ_USER->value => 'rabbit',
EnvVars::RABBITMQ_PASSWORD->value => 'rabbit',
// Redis
EnvVars::REDIS_PUB_SUB_ENABLED->value => true,
EnvVars::REDIS_SERVERS->value => 'tcp://shlink_redis:6379',
];

View File

@ -1,4 +1,4 @@
version: '2.7'
version: '3'
rpc:
listen: tcp://127.0.0.1:6001
@ -14,10 +14,12 @@ http:
forbid: ['.php', '.htaccess']
pool:
num_workers: 1
debug: true
jobs:
pool:
num_workers: 1
debug: true
timeout: 300
consume: ['shlink']
pipelines:
@ -28,22 +30,17 @@ jobs:
prefetch: 10
logs:
encoding: console
mode: development
channels:
http:
level: debug
mode: 'off' # Disable logging as Shlink handles it internally
server:
level: debug
encoding: console
level: info
metrics:
encoding: console
level: debug
reload:
interval: 1s
patterns: ['.php']
services:
http:
dirs: ['../../bin', '../../config', '../../data/migrations', '../../module', '../../vendor']
recursive: true
jobs:
dirs: ['../../bin', '../../config', '../../data/migrations', '../../module', '../../vendor']
recursive: true
encoding: console
level: debug

View File

@ -0,0 +1,50 @@
version: '3'
############################################################################################
# Routes here need to be relative to the project root, as API tests are run with `-w .` #
# See https://github.com/orgs/roadrunner-server/discussions/1440#discussioncomment-8486186 #
############################################################################################
rpc:
listen: tcp://127.0.0.1:6001
server:
command: 'php ./bin/roadrunner-worker.php'
http:
address: '0.0.0.0:9999'
middleware: ['static']
static:
dir: './public'
forbid: ['.php', '.htaccess']
pool:
num_workers: 1
debug: false
jobs:
pool:
num_workers: 1
debug: false
timeout: 300
consume: ['shlink']
pipelines:
shlink:
driver: memory
config:
priority: 10
prefetch: 10
logs:
encoding: console
mode: development
channels:
http:
mode: 'off' # Disable logging as Shlink handles it internally
server:
encoding: console
level: info
metrics:
level: panic
jobs:
encoding: console
level: panic

View File

@ -1,4 +1,4 @@
version: '2.7'
version: '3'
rpc:
listen: tcp://127.0.0.1:6001
@ -7,18 +7,20 @@ server:
command: 'php -dopcache.enable_cli=1 -dopcache.validate_timestamps=0 ../../bin/roadrunner-worker.php'
http:
address: '0.0.0.0:${PORT}'
address: '${ADDRESS:-0.0.0.0}:${PORT:-8080}'
middleware: ['static']
static:
dir: '../../public'
forbid: ['.php', '.htaccess']
pool:
num_workers: ${WEB_WORKER_NUM}
num_workers: ${WEB_WORKER_NUM:-0}
max_jobs: 250 # Restart worker after processing this amount of requests to mitigate memory leaks
jobs:
timeout: 300 # 5 minutes
pool:
num_workers: ${TASK_WORKER_NUM}
num_workers: ${TASK_WORKER_NUM:-0}
max_jobs: 250 # Restart worker after processing this amount of jobs to mitigate memory leaks
consume: ['shlink']
pipelines:
shlink:
@ -28,9 +30,14 @@ jobs:
prefetch: 10
logs:
encoding: ${LOGS_FORMAT:-console}
mode: production
channels:
http:
level: info # Log all http requests, set to info to disable
mode: 'off' # Disable logging as Shlink handles it internally
server:
level: debug # Everything written to worker stderr is logged
encoding: ${LOGS_FORMAT:-console}
level: info
jobs:
encoding: ${LOGS_FORMAT:-console}
level: debug

View File

@ -7,12 +7,6 @@ namespace Shlinkio\Shlink\TestUtils;
use Doctrine\ORM\EntityManager;
use Psr\Container\ContainerInterface;
use function register_shutdown_function;
use function sprintf;
use const ShlinkioTest\Shlink\API_TESTS_HOST;
use const ShlinkioTest\Shlink\API_TESTS_PORT;
/** @var ContainerInterface $container */
$container = require __DIR__ . '/../container.php';
$testHelper = $container->get(Helper\TestHelper::class);
@ -20,19 +14,11 @@ $config = $container->get('config');
$em = $container->get(EntityManager::class);
$httpClient = $container->get('shlink_test_api_client');
// Dump code coverage when process shuts down
register_shutdown_function(function () use ($httpClient): void {
$httpClient->request(
'GET',
sprintf('http://%s:%s/api-tests/stop-coverage', API_TESTS_HOST, API_TESTS_PORT),
);
});
$testHelper->createTestDb(
['bin/cli', 'db:create'],
['bin/cli', 'db:migrate'],
['bin/doctrine', 'orm:schema-tool:drop'],
['bin/doctrine', 'dbal:run-sql'],
createDbCommand: ['bin/cli', 'db:create'],
migrateDbCommand: ['bin/cli', 'db:migrate'],
dropSchemaCommand: ['bin/doctrine', 'orm:schema-tool:drop'],
runSqlCommand: ['bin/doctrine', 'dbal:run-sql'],
);
ApiTest\ApiTestCase::setApiClient($httpClient);
ApiTest\ApiTestCase::setSeedFixturesCallback(fn () => $testHelper->seedFixtures($em, $config['data_fixtures'] ?? []));

View File

@ -23,10 +23,10 @@ if (file_exists($covFile)) {
}
$testHelper->createTestDb(
['bin/cli', 'db:create'],
['bin/cli', 'db:migrate'],
['bin/doctrine', 'orm:schema-tool:drop'],
['bin/doctrine', 'dbal:run-sql'],
createDbCommand: ['bin/cli', 'db:create'],
migrateDbCommand: ['bin/cli', 'db:migrate'],
dropSchemaCommand: ['bin/doctrine', 'orm:schema-tool:drop'],
runSqlCommand: ['bin/doctrine', 'dbal:run-sql'],
);
CliTest\CliTestCase::setSeedFixturesCallback(
static fn () => $testHelper->seedFixtures($em, $config['data_fixtures'] ?? []),

View File

@ -9,9 +9,9 @@ use Psr\Container\ContainerInterface;
/** @var ContainerInterface $container */
$container = require __DIR__ . '/../container.php';
$container->get(Helper\TestHelper::class)->createTestDb(
['bin/cli', 'db:create'],
['bin/cli', 'db:migrate'],
['bin/doctrine', 'orm:schema-tool:drop'],
['bin/doctrine', 'dbal:run-sql'],
createDbCommand: ['bin/cli', 'db:create'],
migrateDbCommand: ['bin/cli', 'db:migrate'],
dropSchemaCommand: ['bin/doctrine', 'orm:schema-tool:drop'],
runSqlCommand: ['bin/doctrine', 'dbal:run-sql'],
);
DbTest\DatabaseTestCase::setEntityManager($container->get('em'));

View File

@ -11,5 +11,11 @@ const ANDROID_USER_AGENT = 'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (
. 'Chrome/109.0.5414.86 Mobile Safari/537.36';
const IOS_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 '
. '(KHTML, like Gecko) FxiOS/109.0 Mobile/15E148 Safari/605.1.15';
const DESKTOP_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like '
. 'Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.61';
const WINDOWS_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
. 'Chrome/138.0.0.0 Safari/537.36 Edg/138.0.3351.95';
const LINUX_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
. 'HeadlessChrome/81.0.4044.113 Safari/537.36';
const MACOS_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) '
. 'Version/18.4 Safari/605.1.15';
const CHROMEOS_USER_AGENT = 'Mozilla/5.0 (X11; CrOS x86_64 16181.61.0) AppleWebKit/537.36 (KHTML, like Gecko) '
. 'Chrome/134.0.6998.198 Safari/537.36';

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Shlinkio\Shlink\Core\Config\EnvVars;
return [
EnvVars::APP_ENV->value => 'test',
// URL shortener
EnvVars::DEFAULT_DOMAIN->value => 's.test',
EnvVars::IS_HTTPS_ENABLED->value => false,
];

View File

@ -6,75 +6,38 @@ namespace Shlinkio\Shlink;
use GuzzleHttp\Client;
use Laminas\ConfigAggregator\ConfigAggregator;
use Laminas\Diactoros\Response\EmptyResponse;
use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\ServiceManager\Factory\InvokableFactory;
use League\Event\EventDispatcher;
use Mezzio\Router\FastRouteRouter;
use Monolog\Level;
use PHPUnit\Runner\Version;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\Selector;
use SebastianBergmann\CodeCoverage\Filter;
use SebastianBergmann\CodeCoverage\Report\Html\Facade as Html;
use SebastianBergmann\CodeCoverage\Report\PHP;
use SebastianBergmann\CodeCoverage\Report\Xml\Facade as Xml;
use Shlinkio\Shlink\Common\Logger\LoggerType;
use Shlinkio\Shlink\TestUtils\ApiTest\CoverageMiddleware;
use Shlinkio\Shlink\TestUtils\CliTest\CliCoverageDelegator;
use Shlinkio\Shlink\TestUtils\Helper\CoverageHelper;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use function file_exists;
use function Functional\contains;
use function Laminas\Stratigility\middleware;
use function Shlinkio\Shlink\Config\env;
use function sleep;
use function sprintf;
use function sys_get_temp_dir;
use const ShlinkioTest\Shlink\API_TESTS_HOST;
use const ShlinkioTest\Shlink\API_TESTS_PORT;
$isApiTest = env('TEST_ENV') === 'api';
$isCliTest = env('TEST_ENV') === 'cli';
$testEnv = env('TEST_ENV');
$isApiTest = $testEnv === 'api';
$isCliTest = $testEnv === 'cli';
$isE2eTest = $isApiTest || $isCliTest;
$coverageType = env('GENERATE_COVERAGE');
$generateCoverage = contains(['yes', 'pretty'], $coverageType);
$coverage = null;
if ($isE2eTest && $generateCoverage) {
$filter = new Filter();
$filter->includeDirectory(__DIR__ . '/../../module/Core/src');
$filter->includeDirectory(__DIR__ . '/../../module/' . ($isApiTest ? 'Rest' : 'CLI') . '/src');
$coverage = new CodeCoverage((new Selector())->forLineCoverage($filter), $filter);
}
/**
* @param 'api'|'cli' $type
*/
$exportCoverage = static function (string $type = 'api') use (&$coverage, $coverageType): void {
if ($coverage === null) {
return;
}
$basePath = __DIR__ . '/../../build/coverage-' . $type;
$covPath = $basePath . '.cov';
// Every CLI test runs on its own process and dumps the coverage afterwards.
// Try to load it and merge it, so that we end up with the whole coverage at the end.
if ($type === 'cli' && file_exists($covPath)) {
$coverage->merge(require $covPath);
}
if ($coverageType === 'pretty') {
(new Html())->process($coverage, $basePath . '/coverage-html');
} else {
(new PHP())->process($coverage, $covPath);
(new Xml(Version::getVersionString()))->process($coverage, $basePath . '/coverage-xml');
}
};
$generateCoverage = $coverageType === 'yes';
$coverage = $isE2eTest && $generateCoverage ? CoverageHelper::createCoverageForDirectories(
[
__DIR__ . '/../../module/Core/src',
__DIR__ . '/../../module/' . ($isApiTest ? 'Rest' : 'CLI') . '/src',
],
__DIR__ . '/../../build/coverage-' . $testEnv,
) : null;
$buildDbConnection = static function (): array {
$driver = env('DB_DRIVER', 'sqlite');
@ -89,7 +52,7 @@ $buildDbConnection = static function (): array {
'postgres' => [
'driver' => 'pdo_pgsql',
'host' => $isCi ? '127.0.0.1' : 'shlink_db_postgres',
'port' => $isCi ? '5433' : '5432',
'port' => $isCi ? '5434' : '5432',
'user' => 'postgres',
'password' => 'root',
'dbname' => 'shlink_test',
@ -121,72 +84,35 @@ $buildTestLoggerConfig = static fn (string $filename) => [
'level' => Level::Debug->value,
'type' => LoggerType::STREAM->value,
'destination' => sprintf('data/log/api-tests/%s', $filename),
'add_new_line' => true,
];
return [
'debug' => true,
ConfigAggregator::ENABLE_CACHE => false,
FastRouteRouter::CONFIG_CACHE_ENABLED => false,
'url_shortener' => [
'domain' => [
'schema' => 'http',
'hostname' => 's.test',
],
],
'mezzio-swoole' => [
'enable_coroutine' => false,
'swoole-http-server' => [
'host' => API_TESTS_HOST,
'port' => API_TESTS_PORT,
'process-name' => 'shlink_test',
'options' => [
'pid_file' => sys_get_temp_dir() . '/shlink-test-swoole.pid',
'log_file' => __DIR__ . '/../../data/log/api-tests/output.log',
'enable_coroutine' => false,
],
],
],
'routes' => !$isApiTest ? [] : [
'routes' => [
// This route is used to test that title resolution is skipped if the long URL times out
[
'name' => 'dump_coverage',
'path' => '/api-tests/stop-coverage',
'middleware' => middleware(static function () use ($exportCoverage) {
// TODO I have tried moving this block to a listener so that it's invoked automatically,
// but then the coverage is generated empty ¯\_(ツ)_/¯
$exportCoverage();
return new EmptyResponse();
}),
'name' => 'long_url_with_timeout',
'path' => '/api-tests/long-url-with-timeout',
'allowed_methods' => ['GET'],
'middleware' => middleware(static function () {
sleep(5); // Title resolution times out at 3 seconds
return new HtmlResponse('<title>The title</title>');
}),
],
],
'middleware_pipeline' => !$isApiTest ? [] : [
'capture_code_coverage' => [
'middleware' => middleware(static function (
ServerRequestInterface $req,
RequestHandlerInterface $handler,
) use (&$coverage): ResponseInterface {
$coverage?->start($req->getHeaderLine('x-coverage-id'));
try {
return $handler->handle($req);
} finally {
$coverage?->stop();
}
}),
'middleware' => new CoverageMiddleware($coverage),
'priority' => 9999,
],
],
'mercure' => [
'public_hub_url' => null,
'internal_hub_url' => null,
'jwt_secret' => null,
],
'dependencies' => [
'services' => [
'shlink_test_api_client' => new Client([
@ -199,58 +125,7 @@ return [
],
'delegators' => $isCliTest ? [
Application::class => [
static function (
ContainerInterface $c,
string $serviceName,
callable $callback,
) use (
&$coverage,
$exportCoverage,
) {
/** @var Application $app */
$app = $callback();
$wrappedEventDispatcher = new EventDispatcher();
// When the command starts, start collecting coverage
$wrappedEventDispatcher->subscribeTo(
ConsoleCommandEvent::class,
static function () use (&$coverage): void {
$id = env('COVERAGE_ID');
if ($id === null) {
return;
}
$coverage?->start($id);
},
);
// When the command ends, stop collecting coverage
$wrappedEventDispatcher->subscribeTo(
ConsoleTerminateEvent::class,
static function () use (&$coverage, $exportCoverage): void {
$id = env('COVERAGE_ID');
if ($id === null) {
return;
}
$coverage?->stop();
$exportCoverage('cli');
},
);
$app->setDispatcher(new class ($wrappedEventDispatcher) implements EventDispatcherInterface {
public function __construct(private EventDispatcher $wrappedDispatcher)
{
}
public function dispatch(object $event, ?string $eventName = null): object
{
$this->wrappedDispatcher->dispatch($event);
return $event;
}
});
return $app;
},
new CliCoverageDelegator($coverage),
],
] : [],
],
@ -261,7 +136,7 @@ return [
'data_fixtures' => [
'paths' => [
// TODO These are used for CLI tests too, so maybe should be somewhere else
// TODO These are used for other module's tests, so maybe should be somewhere else
__DIR__ . '/../../module/Rest/test-api/Fixtures',
],
],

View File

@ -3,7 +3,7 @@
set -ex
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/22.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
curl https://packages.microsoft.com/config/ubuntu/24.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
apt-get update
ACCEPT_EULA=Y apt-get install msodbcsql18
apt-get install unixodbc-dev
# apt-get install unixodbc-dev

View File

@ -11,7 +11,7 @@ server {
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
}

View File

@ -1,13 +0,0 @@
/var/log/shlink/shlink_openswoole.log {
su root root
daily
missingok
rotate 120
compress
delaycompress
notifempty
create 0640 root root
postrotate
/etc/init.d/shlink_openswoole restart
endscript
}

View File

@ -1,54 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: shlink_openswoole
# Required-Start: $local_fs $network $named $time $syslog
# Required-Stop: $local_fs $network $named $time $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Shlink non-blocking server with openswoole
### END INIT INFO
SCRIPT=/path/to/shlink/vendor/bin/laminas\ mezzio:swoole:start
RUNAS=root
PIDFILE=/var/run/shlink_openswoole.pid
LOGDIR=/var/log/shlink
LOGFILE=${LOGDIR}/shlink_openswoole.log
start() {
if [[ -f "$PIDFILE" ]] && kill -0 $(cat "$PIDFILE"); then
echo 'Shlink with openswoole already running' >&2
return 1
fi
echo 'Starting shlink with openswoole' >&2
mkdir -p "$LOGDIR"
touch "$LOGFILE"
local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
echo 'Shlink started' >&2
}
stop() {
if [[ ! -f "$PIDFILE" ]] || ! kill -0 $(cat "$PIDFILE"); then
echo 'Shlink with openswoole not running' >&2
return 1
fi
echo 'Stopping shlink with openswoole' >&2
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
echo 'Shlink stopped' >&2
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac

View File

@ -0,0 +1,52 @@
FROM dunglas/frankenphp:1-php8.4-alpine
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
ENV PDO_SQLSRV_VERSION='5.12.0'
ENV MS_ODBC_DOWNLOAD='7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8'
ENV MS_ODBC_SQL_VERSION='18_18.4.1.1'
RUN apk update
# Install common php extensions
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install calendar
RUN apk add --no-cache oniguruma-dev
RUN docker-php-ext-install mbstring
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 icu-dev
RUN docker-php-ext-install intl
RUN apk add --no-cache libzip-dev zlib-dev
RUN docker-php-ext-install zip
RUN apk add --no-cache postgresql-dev
RUN docker-php-ext-install pdo_pgsql
RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS linux-headers && \
docker-php-ext-install sockets && \
apk del .phpize-deps
RUN docker-php-ext-install bcmath
# Install xdebug and sqlsrv driver
RUN apk add --update linux-headers && \
wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --allow-untrusted msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} xdebug && \
docker-php-ext-enable pdo_sqlsrv xdebug && \
apk del .phpize-deps && \
rm msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk
# Install composer
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
# Make home directory writable by anyone
RUN chmod 777 /home
VOLUME /home/shlink
WORKDIR /home/shlink

View File

@ -0,0 +1,2 @@
*
!.gitignore

2
data/infra/frankenphp_caddy_data/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -1,10 +1,10 @@
FROM php:8.2-fpm-alpine3.17
FROM php:8.4-fpm-alpine3.21
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
ENV APCU_VERSION 5.1.21
ENV PDO_SQLSRV_VERSION 5.10.1
ENV MS_ODBC_DOWNLOAD 'b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486'
ENV MS_ODBC_SQL_VERSION 18_18.1.1.1
ENV APCU_VERSION='5.1.24'
ENV PDO_SQLSRV_VERSION='5.12.0'
ENV MS_ODBC_DOWNLOAD='7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8'
ENV MS_ODBC_SQL_VERSION='18_18.4.1.1'
RUN apk update
@ -25,9 +25,6 @@ RUN docker-php-ext-install intl
RUN apk add --no-cache libzip-dev zlib-dev
RUN docker-php-ext-install zip
RUN apk add --no-cache libpng-dev
RUN docker-php-ext-install gd
RUN apk add --no-cache postgresql-dev
RUN docker-php-ext-install pdo_pgsql
@ -46,12 +43,13 @@ RUN mkdir -p /usr/src/php/ext/apcu \
&& rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini \
&& echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini
# Install pcov and sqlsrv driver
RUN wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
# Install xdebug and sqlsrv driver
RUN apk add --update linux-headers && \
wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --allow-untrusted msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} pcov && \
docker-php-ext-enable pdo_sqlsrv pcov && \
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} xdebug && \
docker-php-ext-enable pdo_sqlsrv xdebug && \
apk del .phpize-deps && \
rm msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk

View File

@ -1,8 +1,4 @@
display_errors=On
error_reporting=-1
memory_limit=-1
log_errors_max_len=0
zend.assertions=1
assert.exception=1
pcov.enabled=1
pcov.directory=module

View File

@ -1,10 +1,9 @@
FROM php:8.2-alpine3.17
FROM php:8.4-alpine3.21
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
ENV APCU_VERSION 5.1.21
ENV PDO_SQLSRV_VERSION 5.10.1
ENV MS_ODBC_DOWNLOAD 'b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486'
ENV MS_ODBC_SQL_VERSION 18_18.1.1.1
ENV PDO_SQLSRV_VERSION='5.12.0'
ENV MS_ODBC_DOWNLOAD='7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8'
ENV MS_ODBC_SQL_VERSION='18_18.4.1.1'
RUN apk update
@ -25,9 +24,6 @@ RUN docker-php-ext-install intl
RUN apk add --no-cache libzip-dev zlib-dev
RUN docker-php-ext-install zip
RUN apk add --no-cache libpng-dev
RUN docker-php-ext-install gd
RUN apk add --no-cache postgresql-dev
RUN docker-php-ext-install pdo_pgsql
@ -36,22 +32,13 @@ RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS linux-headers && \
apk del .phpize-deps
RUN docker-php-ext-install bcmath
# Install APCu extension
ADD https://pecl.php.net/get/apcu-$APCU_VERSION.tgz /tmp/apcu.tar.gz
RUN mkdir -p /usr/src/php/ext/apcu \
&& tar xf /tmp/apcu.tar.gz -C /usr/src/php/ext/apcu --strip-components=1 \
&& docker-php-ext-configure apcu \
&& docker-php-ext-install apcu \
&& rm /tmp/apcu.tar.gz \
&& rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini \
&& echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini
# Install pcov and sqlsrv driver
RUN wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
# Install xdebug and sqlsrv driver
RUN apk add --update linux-headers && \
wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --allow-untrusted msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} pcov && \
docker-php-ext-enable pdo_sqlsrv pcov && \
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} xdebug && \
docker-php-ext-enable pdo_sqlsrv xdebug && \
apk del .phpize-deps && \
rm msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk
@ -71,6 +58,8 @@ CMD \
# Install dependencies if the vendor dir does not exist
if [[ ! -d "./vendor" ]]; then /usr/local/bin/composer install ; fi && \
# Download roadrunner binary
if [[ ! -f "./bin/rr" ]]; then ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr ; fi && \
# This forces the app to be started every second until the exit code is 0
until ./bin/rr serve -c config/roadrunner/.rr.dev.yml; do sleep 1 ; done
if [[ ! -f "./bin/rr" ]]; then ./vendor/bin/rr get --no-interaction --no-config --location bin/ && chmod +x bin/rr ; fi && \
# Create env file if it does not exist yet
if [[ ! -f "./config/params/shlink_dev_env.php" ]]; then cp ./config/params/shlink_dev_env.php.dist ./config/params/shlink_dev_env.php ; fi && \
# Run with `exec` so that signals are properly handled
exec ./bin/rr serve -c config/roadrunner/.rr.dev.yml

View File

@ -1,85 +0,0 @@
FROM php:8.2-alpine3.17
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
ENV APCU_VERSION 5.1.21
ENV INOTIFY_VERSION 3.0.0
ENV OPENSWOOLE_VERSION 4.12.1
ENV PDO_SQLSRV_VERSION 5.10.1
ENV MS_ODBC_DOWNLOAD 'b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486'
ENV MS_ODBC_SQL_VERSION 18_18.1.1.1
RUN apk update
# Install common php extensions
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install calendar
RUN apk add --no-cache oniguruma-dev
RUN docker-php-ext-install mbstring
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 icu-dev
RUN docker-php-ext-install intl
RUN apk add --no-cache libzip-dev zlib-dev
RUN docker-php-ext-install zip
RUN apk add --no-cache libpng-dev
RUN docker-php-ext-install gd
RUN apk add --no-cache postgresql-dev
RUN docker-php-ext-install pdo_pgsql
RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS linux-headers && \
docker-php-ext-install sockets && \
apk del .phpize-deps
RUN docker-php-ext-install bcmath
# Install APCu extension
ADD https://pecl.php.net/get/apcu-$APCU_VERSION.tgz /tmp/apcu.tar.gz
RUN mkdir -p /usr/src/php/ext/apcu \
&& tar xf /tmp/apcu.tar.gz -C /usr/src/php/ext/apcu --strip-components=1 \
&& docker-php-ext-configure apcu \
&& docker-php-ext-install apcu \
&& rm /tmp/apcu.tar.gz \
&& rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini \
&& echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini
# Install inotify extension
ADD https://pecl.php.net/get/inotify-$INOTIFY_VERSION.tgz /tmp/inotify.tar.gz
RUN mkdir -p /usr/src/php/ext/inotify \
&& tar xf /tmp/inotify.tar.gz -C /usr/src/php/ext/inotify --strip-components=1 \
&& docker-php-ext-configure inotify \
&& docker-php-ext-install inotify \
&& rm /tmp/inotify.tar.gz
# Install openswoole, pcov and mssql driver
RUN wget https://download.microsoft.com/download/${MS_ODBC_DOWNLOAD}/msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --allow-untrusted msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \
pecl install openswoole-${OPENSWOOLE_VERSION} pdo_sqlsrv-${PDO_SQLSRV_VERSION} pcov && \
docker-php-ext-enable openswoole pdo_sqlsrv pcov && \
apk del .phpize-deps && \
rm msodbcsql${MS_ODBC_SQL_VERSION}-1_amd64.apk
# Install composer
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
# Make home directory writable by anyone
RUN chmod 777 /home
VOLUME /home/shlink
WORKDIR /home/shlink
# Expose openswoole port
EXPOSE 8080
CMD \
# Install dependencies if the vendor dir does not exist
if [[ ! -d "./vendor" ]]; then /usr/local/bin/composer install ; fi && \
# When restarting the container, openswoole might think it is already in execution
# This forces the app to be started every second until the exit code is 0
until php ./vendor/bin/laminas mezzio:swoole:start; do sleep 1 ; done

View File

@ -1,14 +0,0 @@
server {
listen 80 default_server;
error_log /home/shlink/www/data/infra/nginx/swoole_proxy.error.log;
location / {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://shlink_swoole:8080;
proxy_read_timeout 90s;
}
}

View File

@ -1,49 +0,0 @@
<?php
declare(strict_types=1);
namespace ShlinkMigrations;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\Migrations\AbstractMigration;
use function is_subclass_of;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20160819142757 extends AbstractMigration
{
/**
* @throws Exception
* @throws SchemaException
*/
public function up(Schema $schema): void
{
$platformClass = $this->connection->getDatabasePlatform();
$table = $schema->getTable('short_urls');
$column = $table->getColumn('short_code');
match (true) {
is_subclass_of($platformClass, MySQLPlatform::class) => $column
->setPlatformOption('charset', 'utf8mb4')
->setPlatformOption('collation', 'utf8mb4_bin'),
is_subclass_of($platformClass, SqlitePlatform::class) => $column->setPlatformOption('collate', 'BINARY'),
default => null,
};
}
public function down(Schema $schema): void
{
// Nothing to roll back
}
public function isTransactional(): bool
{
return ! ($this->connection->getDatabasePlatform() instanceof MySQLPlatform);
}
}

View File

@ -1,82 +0,0 @@
<?php
declare(strict_types=1);
namespace ShlinkMigrations;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Types;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20160820191203 extends AbstractMigration
{
public function up(Schema $schema): void
{
// Check if the tables already exist
$tables = $schema->getTables();
foreach ($tables as $table) {
if ($table->getName() === 'tags') {
return;
}
}
$this->createTagsTable($schema);
$this->createShortUrlsInTagsTable($schema);
}
private function createTagsTable(Schema $schema): void
{
$table = $schema->createTable('tags');
$table->addColumn('id', Types::BIGINT, [
'unsigned' => true,
'autoincrement' => true,
'notnull' => true,
]);
$table->addColumn('name', Types::STRING, [
'length' => 255,
'notnull' => true,
]);
$table->addUniqueIndex(['name']);
$table->setPrimaryKey(['id']);
}
private function createShortUrlsInTagsTable(Schema $schema): void
{
$table = $schema->createTable('short_urls_in_tags');
$table->addColumn('short_url_id', Types::BIGINT, [
'unsigned' => true,
'notnull' => true,
]);
$table->addColumn('tag_id', Types::BIGINT, [
'unsigned' => true,
'notnull' => true,
]);
$table->addForeignKeyConstraint('tags', ['tag_id'], ['id'], [
'onDelete' => 'CASCADE',
'onUpdate' => 'RESTRICT',
]);
$table->addForeignKeyConstraint('short_urls', ['short_url_id'], ['id'], [
'onDelete' => 'CASCADE',
'onUpdate' => 'RESTRICT',
]);
$table->setPrimaryKey(['short_url_id', 'tag_id']);
}
public function down(Schema $schema): void
{
$schema->dropTable('short_urls_in_tags');
$schema->dropTable('tags');
}
public function isTransactional(): bool
{
return ! ($this->connection->getDatabasePlatform() instanceof MySQLPlatform);
}
}

View File

@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace ShlinkMigrations;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Types\Types;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20171021093246 extends AbstractMigration
{
/**
* @throws SchemaException
*/
public function up(Schema $schema): void
{
$shortUrls = $schema->getTable('short_urls');
if ($shortUrls->hasColumn('valid_since')) {
return;
}
$shortUrls->addColumn('valid_since', Types::DATETIME_MUTABLE, [
'notnull' => false,
]);
$shortUrls->addColumn('valid_until', Types::DATETIME_MUTABLE, [
'notnull' => false,
]);
}
/**
* @throws SchemaException
*/
public function down(Schema $schema): void
{
$shortUrls = $schema->getTable('short_urls');
if (! $shortUrls->hasColumn('valid_since')) {
return;
}
$shortUrls->dropColumn('valid_since');
$shortUrls->dropColumn('valid_until');
}
public function isTransactional(): bool
{
return ! ($this->connection->getDatabasePlatform() instanceof MySQLPlatform);
}
}

View File

@ -1,51 +0,0 @@
<?php
declare(strict_types=1);
namespace ShlinkMigrations;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Types\Types;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20171022064541 extends AbstractMigration
{
/**
* @throws SchemaException
*/
public function up(Schema $schema): void
{
$shortUrls = $schema->getTable('short_urls');
if ($shortUrls->hasColumn('max_visits')) {
return;
}
$shortUrls->addColumn('max_visits', Types::INTEGER, [
'unsigned' => true,
'notnull' => false,
]);
}
/**
* @throws SchemaException
*/
public function down(Schema $schema): void
{
$shortUrls = $schema->getTable('short_urls');
if (! $shortUrls->hasColumn('max_visits')) {
return;
}
$shortUrls->dropColumn('max_visits');
}
public function isTransactional(): bool
{
return ! ($this->connection->getDatabasePlatform() instanceof MySQLPlatform);
}
}

Some files were not shown because too many files have changed in this diff Show More