eea.api.redirector 0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. eea_api_redirector-0.1/CONTRIBUTING.md +49 -0
  2. eea_api_redirector-0.1/MANIFEST.in +8 -0
  3. eea_api_redirector-0.1/PKG-INFO +352 -0
  4. eea_api_redirector-0.1/README.rst +285 -0
  5. eea_api_redirector-0.1/docs/HISTORY.txt +32 -0
  6. eea_api_redirector-0.1/docs/LICENSE.GPL +339 -0
  7. eea_api_redirector-0.1/docs/LICENSE.txt +19 -0
  8. eea_api_redirector-0.1/eea/__init__.py +4 -0
  9. eea_api_redirector-0.1/eea/api/__init__.py +4 -0
  10. eea_api_redirector-0.1/eea/api/redirector/README.txt +16 -0
  11. eea_api_redirector-0.1/eea/api/redirector/__init__.py +9 -0
  12. eea_api_redirector-0.1/eea/api/redirector/browser/__init__.py +1 -0
  13. eea_api_redirector-0.1/eea/api/redirector/browser/configure.zcml +13 -0
  14. eea_api_redirector-0.1/eea/api/redirector/browser/controlpanel.py +19 -0
  15. eea_api_redirector-0.1/eea/api/redirector/configure.zcml +14 -0
  16. eea_api_redirector-0.1/eea/api/redirector/interfaces.py +20 -0
  17. eea_api_redirector-0.1/eea/api/redirector/locales/__init__.py +1 -0
  18. eea_api_redirector-0.1/eea/api/redirector/locales/bg/LC_MESSAGES/eea.po +0 -0
  19. eea_api_redirector-0.1/eea/api/redirector/locales/bg/LC_MESSAGES/plone.po +0 -0
  20. eea_api_redirector-0.1/eea/api/redirector/locales/cs/LC_MESSAGES/eea.po +0 -0
  21. eea_api_redirector-0.1/eea/api/redirector/locales/cs/LC_MESSAGES/plone.po +0 -0
  22. eea_api_redirector-0.1/eea/api/redirector/locales/da/LC_MESSAGES/eea.po +0 -0
  23. eea_api_redirector-0.1/eea/api/redirector/locales/da/LC_MESSAGES/plone.po +0 -0
  24. eea_api_redirector-0.1/eea/api/redirector/locales/de/LC_MESSAGES/eea.po +0 -0
  25. eea_api_redirector-0.1/eea/api/redirector/locales/de/LC_MESSAGES/plone.po +0 -0
  26. eea_api_redirector-0.1/eea/api/redirector/locales/eea.pot +0 -0
  27. eea_api_redirector-0.1/eea/api/redirector/locales/el/LC_MESSAGES/eea.po +0 -0
  28. eea_api_redirector-0.1/eea/api/redirector/locales/el/LC_MESSAGES/plone.po +0 -0
  29. eea_api_redirector-0.1/eea/api/redirector/locales/en/LC_MESSAGES/eea.po +0 -0
  30. eea_api_redirector-0.1/eea/api/redirector/locales/en/LC_MESSAGES/plone.po +0 -0
  31. eea_api_redirector-0.1/eea/api/redirector/locales/es/LC_MESSAGES/eea.po +0 -0
  32. eea_api_redirector-0.1/eea/api/redirector/locales/es/LC_MESSAGES/plone.po +0 -0
  33. eea_api_redirector-0.1/eea/api/redirector/locales/et/LC_MESSAGES/eea.po +0 -0
  34. eea_api_redirector-0.1/eea/api/redirector/locales/et/LC_MESSAGES/plone.po +0 -0
  35. eea_api_redirector-0.1/eea/api/redirector/locales/eu/LC_MESSAGES/eea.po +0 -0
  36. eea_api_redirector-0.1/eea/api/redirector/locales/eu/LC_MESSAGES/plone.po +0 -0
  37. eea_api_redirector-0.1/eea/api/redirector/locales/fi/LC_MESSAGES/eea.po +0 -0
  38. eea_api_redirector-0.1/eea/api/redirector/locales/fi/LC_MESSAGES/plone.po +0 -0
  39. eea_api_redirector-0.1/eea/api/redirector/locales/fr/LC_MESSAGES/eea.po +0 -0
  40. eea_api_redirector-0.1/eea/api/redirector/locales/fr/LC_MESSAGES/plone.po +0 -0
  41. eea_api_redirector-0.1/eea/api/redirector/locales/hr/LC_MESSAGES/eea.po +0 -0
  42. eea_api_redirector-0.1/eea/api/redirector/locales/hr/LC_MESSAGES/plone.po +0 -0
  43. eea_api_redirector-0.1/eea/api/redirector/locales/hu/LC_MESSAGES/eea.po +0 -0
  44. eea_api_redirector-0.1/eea/api/redirector/locales/hu/LC_MESSAGES/plone.po +0 -0
  45. eea_api_redirector-0.1/eea/api/redirector/locales/is/LC_MESSAGES/eea.po +0 -0
  46. eea_api_redirector-0.1/eea/api/redirector/locales/is/LC_MESSAGES/plone.po +0 -0
  47. eea_api_redirector-0.1/eea/api/redirector/locales/it/LC_MESSAGES/eea.po +0 -0
  48. eea_api_redirector-0.1/eea/api/redirector/locales/it/LC_MESSAGES/plone.po +0 -0
  49. eea_api_redirector-0.1/eea/api/redirector/locales/kl/LC_MESSAGES/eea.po +0 -0
  50. eea_api_redirector-0.1/eea/api/redirector/locales/kl/LC_MESSAGES/plone.po +0 -0
  51. eea_api_redirector-0.1/eea/api/redirector/locales/lt/LC_MESSAGES/eea.po +0 -0
  52. eea_api_redirector-0.1/eea/api/redirector/locales/lt/LC_MESSAGES/plone.po +0 -0
  53. eea_api_redirector-0.1/eea/api/redirector/locales/lv/LC_MESSAGES/eea.po +0 -0
  54. eea_api_redirector-0.1/eea/api/redirector/locales/lv/LC_MESSAGES/plone.po +0 -0
  55. eea_api_redirector-0.1/eea/api/redirector/locales/mt/LC_MESSAGES/eea.po +0 -0
  56. eea_api_redirector-0.1/eea/api/redirector/locales/mt/LC_MESSAGES/plone.po +0 -0
  57. eea_api_redirector-0.1/eea/api/redirector/locales/nl/LC_MESSAGES/eea.po +0 -0
  58. eea_api_redirector-0.1/eea/api/redirector/locales/nl/LC_MESSAGES/plone.po +0 -0
  59. eea_api_redirector-0.1/eea/api/redirector/locales/no/LC_MESSAGES/eea.po +0 -0
  60. eea_api_redirector-0.1/eea/api/redirector/locales/no/LC_MESSAGES/plone.po +0 -0
  61. eea_api_redirector-0.1/eea/api/redirector/locales/pl/LC_MESSAGES/eea.po +0 -0
  62. eea_api_redirector-0.1/eea/api/redirector/locales/pl/LC_MESSAGES/plone.po +0 -0
  63. eea_api_redirector-0.1/eea/api/redirector/locales/plone-manual.pot +0 -0
  64. eea_api_redirector-0.1/eea/api/redirector/locales/pt/LC_MESSAGES/eea.po +0 -0
  65. eea_api_redirector-0.1/eea/api/redirector/locales/pt/LC_MESSAGES/plone.po +0 -0
  66. eea_api_redirector-0.1/eea/api/redirector/locales/pt_BR/LC_MESSAGES/eea.po +0 -0
  67. eea_api_redirector-0.1/eea/api/redirector/locales/pt_BR/LC_MESSAGES/plone.po +0 -0
  68. eea_api_redirector-0.1/eea/api/redirector/locales/ro/LC_MESSAGES/eea.po +0 -0
  69. eea_api_redirector-0.1/eea/api/redirector/locales/ro/LC_MESSAGES/plone.po +0 -0
  70. eea_api_redirector-0.1/eea/api/redirector/locales/ru/LC_MESSAGES/eea.po +0 -0
  71. eea_api_redirector-0.1/eea/api/redirector/locales/ru/LC_MESSAGES/plone.po +0 -0
  72. eea_api_redirector-0.1/eea/api/redirector/locales/sk/LC_MESSAGES/eea.po +0 -0
  73. eea_api_redirector-0.1/eea/api/redirector/locales/sk/LC_MESSAGES/plone.po +0 -0
  74. eea_api_redirector-0.1/eea/api/redirector/locales/sl/LC_MESSAGES/eea.po +0 -0
  75. eea_api_redirector-0.1/eea/api/redirector/locales/sl/LC_MESSAGES/plone.po +0 -0
  76. eea_api_redirector-0.1/eea/api/redirector/locales/sv/LC_MESSAGES/eea.po +0 -0
  77. eea_api_redirector-0.1/eea/api/redirector/locales/sv/LC_MESSAGES/plone.po +0 -0
  78. eea_api_redirector-0.1/eea/api/redirector/locales/tr/LC_MESSAGES/eea.po +0 -0
  79. eea_api_redirector-0.1/eea/api/redirector/locales/tr/LC_MESSAGES/plone.po +0 -0
  80. eea_api_redirector-0.1/eea/api/redirector/locales/update.sh +6 -0
  81. eea_api_redirector-0.1/eea/api/redirector/locales/zh_TW/LC_MESSAGES/eea.po +0 -0
  82. eea_api_redirector-0.1/eea/api/redirector/locales/zh_TW/LC_MESSAGES/plone.po +0 -0
  83. eea_api_redirector-0.1/eea/api/redirector/profiles/default/browserlayer.xml +7 -0
  84. eea_api_redirector-0.1/eea/api/redirector/profiles/default/controlpanel.xml +18 -0
  85. eea_api_redirector-0.1/eea/api/redirector/profiles/default/metadata.xml +4 -0
  86. eea_api_redirector-0.1/eea/api/redirector/profiles/default/registry.xml +4 -0
  87. eea_api_redirector-0.1/eea/api/redirector/profiles/uninstall/browserlayer.xml +8 -0
  88. eea_api_redirector-0.1/eea/api/redirector/profiles.zcml +33 -0
  89. eea_api_redirector-0.1/eea/api/redirector/restapi/__init__.py +1 -0
  90. eea_api_redirector-0.1/eea/api/redirector/restapi/add.py +115 -0
  91. eea_api_redirector-0.1/eea/api/redirector/restapi/configure.zcml +49 -0
  92. eea_api_redirector-0.1/eea/api/redirector/restapi/controlpanel.py +17 -0
  93. eea_api_redirector-0.1/eea/api/redirector/restapi/delete.py +90 -0
  94. eea_api_redirector-0.1/eea/api/redirector/restapi/get.py +73 -0
  95. eea_api_redirector-0.1/eea/api/redirector/restapi/statistics.py +27 -0
  96. eea_api_redirector-0.1/eea/api/redirector/setuphandlers.py +25 -0
  97. eea_api_redirector-0.1/eea/api/redirector/tests/__init__.py +1 -0
  98. eea_api_redirector-0.1/eea/api/redirector/tests/base.py +51 -0
  99. eea_api_redirector-0.1/eea/api/redirector/tests/test_doctests.py +31 -0
  100. eea_api_redirector-0.1/eea/api/redirector/upgrades/__init__.py +1 -0
  101. eea_api_redirector-0.1/eea/api/redirector/upgrades/configure.zcml +18 -0
  102. eea_api_redirector-0.1/eea/api/redirector/utilities/__init__.py +1 -0
  103. eea_api_redirector-0.1/eea/api/redirector/utilities/configure.zcml +23 -0
  104. eea_api_redirector-0.1/eea/api/redirector/utilities/errors.py +51 -0
  105. eea_api_redirector-0.1/eea/api/redirector/utilities/storage.py +521 -0
  106. eea_api_redirector-0.1/eea/api/redirector/version.txt +1 -0
  107. eea_api_redirector-0.1/eea.api.redirector.egg-info/PKG-INFO +352 -0
  108. eea_api_redirector-0.1/eea.api.redirector.egg-info/SOURCES.txt +114 -0
  109. eea_api_redirector-0.1/eea.api.redirector.egg-info/dependency_links.txt +1 -0
  110. eea_api_redirector-0.1/eea.api.redirector.egg-info/entry_points.txt +2 -0
  111. eea_api_redirector-0.1/eea.api.redirector.egg-info/namespace_packages.txt +2 -0
  112. eea_api_redirector-0.1/eea.api.redirector.egg-info/not-zip-safe +1 -0
  113. eea_api_redirector-0.1/eea.api.redirector.egg-info/requires.txt +5 -0
  114. eea_api_redirector-0.1/eea.api.redirector.egg-info/top_level.txt +1 -0
  115. eea_api_redirector-0.1/setup.cfg +4 -0
  116. eea_api_redirector-0.1/setup.py +54 -0
@@ -0,0 +1,49 @@
1
+ # How to contribute
2
+
3
+ To start, is important to mention that we keep all EEA pacakges under EEA Organisation
4
+ on GitHub (https://github.com/eea) and we fork them to Collective so everyone can
5
+ contribute to them. We keep the repositories from Collective and EEA in sync.
6
+
7
+ We want to keep it as easy as possible to contribute changes that
8
+ get things working. There are a few guidelines that we
9
+ need contributors to follow so that we can have a chance of keeping on
10
+ top of things.
11
+
12
+ ## Getting Started
13
+
14
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
15
+ * If you need to submit a ticket do it under EEA Organisation area (https://github.com/eea)
16
+ under the respective package, e.g. https://github.com/eea/eea.api.redirector/issues
17
+ * Submit a ticket for your issue, assuming one does not already exist.
18
+ * Clearly describe the issue including steps to reproduce when it is a bug.
19
+ * If case state the browser and operating system used.
20
+ * We also keep a discussion lists for most of the public packages under Google Groups.
21
+
22
+ Please note that adding a bug report or feature request in the EEA github does not
23
+ automatically mean that EEA will work on them, since there are budget implications.
24
+
25
+ The issues/features registered in github are regarded only as community requests and
26
+ here to facilitate the Plone community contributions.
27
+
28
+ EEA will work directly on the Plone community's requests when they coincide with
29
+ EEA's planned projects. In this case we will transfer the ticket to the EEA
30
+ official issue register.
31
+
32
+ ## Making Changes
33
+
34
+ * Fork the repository from EEA or directly commit within Collective fork
35
+ * Make sure you added an entry under HISTORY.txt describing your changes
36
+ * Make sure you have added the necessary tests for your changes (do not forget major browsers).
37
+ * Make sure you have updated and added documentation when necessary.
38
+ * Run _all_ the tests to assure nothing else was accidentally broken.
39
+
40
+ ## Submitting Changes
41
+
42
+ * Push your changes in your fork of the repository.
43
+ * Submit a pull request to the upstream repository (EEA).
44
+
45
+ # Additional Resources
46
+
47
+ * [General GitHub documentation](http://help.github.com/)
48
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
49
+ * [EEA packages](https://eea.github.io/docs/IT-systems/)
@@ -0,0 +1,8 @@
1
+ include *.md *.rst *.txt
2
+ graft docs
3
+ graft eea
4
+ global-exclude *pyc
5
+ global-exclude *~
6
+ global-exclude *.un~
7
+
8
+ global-include *.mo
@@ -0,0 +1,352 @@
1
+ Metadata-Version: 2.4
2
+ Name: eea.api.redirector
3
+ Version: 0.1
4
+ Summary: Plone Redirector extension to get redirect URLs also from Redis
5
+ Home-page: https://github.com/eea/eea.api.redirector
6
+ Author: European Environment Agency: IDM2 A-Team
7
+ Author-email: eea-edw-a-team-alerts@googlegroups.com
8
+ License: GPL version 2
9
+ Keywords: EEA Add-ons Plone Zope
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Plone
12
+ Classifier: Framework :: Plone :: Addon
13
+ Classifier: Framework :: Plone :: 6.1
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
18
+ Description-Content-Type: text/x-rst
19
+ Requires-Dist: setuptools
20
+ Requires-Dist: redis
21
+ Provides-Extra: test
22
+ Requires-Dist: plone.app.testing; extra == "test"
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-dist
33
+ Dynamic: summary
34
+
35
+ ==========================
36
+ eea.api.redirector
37
+ ==========================
38
+ .. image:: https://ci.eionet.europa.eu/buildStatus/icon?job=eea/eea.api.redirector/develop
39
+ :target: https://ci.eionet.europa.eu/job/eea/job/eea.api.redirector/job/develop/display/redirect
40
+ :alt: Develop
41
+ .. image:: https://ci.eionet.europa.eu/buildStatus/icon?job=eea/eea.api.redirector/master
42
+ :target: https://ci.eionet.europa.eu/job/eea/job/eea.api.redirector/job/master/display/redirect
43
+ :alt: Master
44
+
45
+ The eea.api.redirector is a Plone add-on that extends Plone's native redirect system with Redis-based URL redirects, enabling high-performance redirect lookups and external redirect management.
46
+
47
+ .. contents::
48
+
49
+
50
+ Main features
51
+ =============
52
+
53
+ 1. **Redis-backed redirects**: Store and retrieve URL redirects from Redis in addition to Plone's database
54
+ 2. **REST API endpoints**: Full CRUD operations for managing redirects via ``@redirects`` endpoint
55
+ 3. **Control panel integration**: Web UI for managing redirects (requires `volto-redirector <https://github.com/eea/volto-redirector>`_ frontend)
56
+ 4. **High-performance statistics**: Redis pipelining for calculating statistics on 100k+ redirects in ~2 seconds
57
+ 5. **Advanced search**: Search both old and new URLs using simple or regex patterns (e.g., ``^/publications``, ``example.com``)
58
+ 6. **Fallback mechanism**: Automatically checks Redis when redirects are not found in Plone storage
59
+ 7. **Graceful error handling**: Redis connection failures don't break the redirection system
60
+ 8. **API endpoint support**: Intelligent hierarchical URL matching for API services and endpoints
61
+ 9. **Proper HTTP status codes**: Returns 410 Gone for permanently deleted resources (empty redirect targets)
62
+ 10. **Redirect loop prevention**: Built-in protection against circular redirects
63
+ 11. **Easy configuration**: Simple environment variable setup for Redis connections
64
+ 12. **Non-intrusive**: Extends existing Plone functionality without replacing it
65
+
66
+
67
+ Install
68
+ =======
69
+
70
+ * Via pip::
71
+
72
+ $ pip install eea.api.redirector
73
+
74
+ * Or via docker-compose::
75
+
76
+ $ docker-compose up -d
77
+
78
+ This will start both Plone 6 and Redis services with the add-on pre-configured.
79
+
80
+ * Install *eea.api.redirector* within Site Setup > Add-ons
81
+
82
+
83
+ Configuration
84
+ =============
85
+
86
+ Redis connection settings are configured via environment variables:
87
+
88
+ * ``REDIS_SERVER`` - Redis server hostname (default: ``localhost``)
89
+ * ``REDIS_PORT`` - Redis server port (default: ``6379``)
90
+ * ``REDIS_DB`` - Redis database index (default: ``0``)
91
+ * ``REDIS_TIMEOUT`` - Connection timeout in seconds (default: ``5``)
92
+
93
+ The included ``docker-compose.yml`` demonstrates how to configure these settings. The Plone service connects to Redis using::
94
+
95
+ environment:
96
+ REDIS_SERVER: "redis"
97
+ REDIS_PORT: "6379"
98
+ REDIS_DB: "0"
99
+ REDIS_TIMEOUT: "5"
100
+
101
+
102
+ How it works
103
+ ============
104
+
105
+ The add-on extends Plone's built-in ``plone.app.redirector`` by:
106
+
107
+ 1. **Storage Integration**: Adds a Redis storage utility alongside Plone's database storage
108
+ 2. **Fallback Lookup**: When a redirect is not found in Plone's database, it checks Redis
109
+ 3. **API Support**: Custom error handling for API endpoints with hierarchical URL matching
110
+ 4. **Non-blocking**: If Redis is unavailable, the system continues using Plone's standard redirects
111
+
112
+ This design allows you to:
113
+
114
+ * Manage redirects externally via Redis while maintaining Plone's UI-based redirect management
115
+ * Share redirects across multiple Plone instances using a common Redis server
116
+ * Achieve faster redirect lookups for high-traffic sites
117
+ * Store temporary or dynamic redirects that don't need to persist in Plone's database
118
+
119
+
120
+ REST API Endpoints
121
+ ==================
122
+
123
+ The add-on provides REST API endpoints for managing redirects:
124
+
125
+ **GET /@redirects**
126
+
127
+ List redirects with pagination and search support.
128
+
129
+ Query parameters:
130
+
131
+ * ``q`` - Search query for old or new URL paths (supports regex: ``^/publications``, ``.*\.pdf$``)
132
+ * ``b_size`` - Batch size (default: 25, options: 10, 25, 50, 100, 500, 1000)
133
+ * ``b_start`` - Batch start offset (default: 0)
134
+ * ``search_scope`` - Where to search: ``old_url`` (default), ``new_url``, or ``both``
135
+
136
+ Example::
137
+
138
+ GET /Plone/@redirects?q=/themes&b_size=25&b_start=0&search_scope=old_url
139
+
140
+ Response::
141
+
142
+ {
143
+ "@id": "http://localhost:8080/Plone/@redirects",
144
+ "items": [
145
+ {
146
+ "path": "/old-path",
147
+ "redirect-to": "/new-path"
148
+ },
149
+ {
150
+ "path": "/deleted-page",
151
+ "redirect-to": ""
152
+ }
153
+ ],
154
+ "items_total": 187520
155
+ }
156
+
157
+ **GET /@redirects-statistics**
158
+
159
+ Get statistics for redirects.
160
+
161
+ Query parameters:
162
+
163
+ * ``q`` - Optional search query to filter statistics
164
+
165
+ Example::
166
+
167
+ GET /Plone/@redirects-statistics?q=/themes
168
+
169
+ Response::
170
+
171
+ {
172
+ "@id": "http://localhost:8080/Plone/@redirects-statistics",
173
+ "statistics": {
174
+ "total": 187520,
175
+ "internal": 32935,
176
+ "external": 1611,
177
+ "gone": 152974
178
+ }
179
+ }
180
+
181
+ Statistics categories:
182
+
183
+ * **total** - Total number of redirects
184
+ * **internal** - Redirects to internal paths (starting with ``/``)
185
+ * **external** - Redirects to external URLs (starting with ``http://`` or ``https://``)
186
+ * **gone** - Empty redirects for permanently deleted content (HTTP 410)
187
+
188
+ **POST /@redirects**
189
+
190
+ Add new redirects.
191
+
192
+ Request body::
193
+
194
+ {
195
+ "items": [
196
+ {
197
+ "path": "/old-path",
198
+ "redirect-to": "/new-path"
199
+ },
200
+ {
201
+ "path": "/deleted-page",
202
+ "redirect-to": ""
203
+ }
204
+ ]
205
+ }
206
+
207
+ Notes:
208
+
209
+ * Empty ``redirect-to`` marks content as permanently deleted (returns HTTP 410 Gone)
210
+ * Paths are automatically trimmed of whitespace
211
+ * Self-redirects are prevented (path cannot equal redirect-to)
212
+
213
+ Response::
214
+
215
+ {
216
+ "success": 2,
217
+ "failed": []
218
+ }
219
+
220
+ **DELETE /@redirects**
221
+
222
+ Remove redirects.
223
+
224
+ Request body::
225
+
226
+ {
227
+ "items": [
228
+ {"path": "/old-path"}
229
+ ]
230
+ }
231
+
232
+ Response::
233
+
234
+ {
235
+ "success": 1,
236
+ "failed": []
237
+ }
238
+
239
+
240
+ Performance
241
+ ===========
242
+
243
+ The add-on uses Redis pipelining for optimal performance:
244
+
245
+ * **Statistics calculation**: ~2 seconds for 187,000 redirects (42x faster than individual GET operations)
246
+ * **List pagination**: Scans keys only, fetches values only for requested page
247
+ * **Search queries**: Uses Redis SCAN with pattern matching for efficient filtering
248
+
249
+ Benchmark results (187,520 redirects):
250
+
251
+ * SCAN all keys: 0.36s
252
+ * Statistics with pipelining: 1.8s
253
+ * Individual GET operations: 77s (not used)
254
+
255
+
256
+ HTTP 410 Gone Support
257
+ =====================
258
+
259
+ Redirects with empty targets (``redirect-to: ""``) return HTTP 410 Gone status, indicating the resource has been permanently deleted. This is the proper HTTP status code for removed content that will not return.
260
+
261
+ The frontend (`volto-redirector <https://github.com/eea/volto-redirector>`_) can display a custom 410 Gone page with:
262
+
263
+ * Information about the deleted resource
264
+ * Link to Wayback Machine for archived versions
265
+ * Helpful navigation options
266
+
267
+
268
+ Source code
269
+ ===========
270
+
271
+ - `eea.api.redirector (backend) <https://github.com/eea/eea.api.redirector>`_
272
+ - `volto-redirector (frontend) <https://github.com/eea/volto-redirector>`_
273
+
274
+
275
+ Eggs repository
276
+ ===============
277
+
278
+ - https://pypi.python.org/pypi/eea.api.redirector
279
+ - http://eggrepo.eea.europa.eu/simple
280
+
281
+
282
+ Plone versions
283
+ ==============
284
+ It has been developed and tested for Plone 6. See section above.
285
+
286
+
287
+ How to contribute
288
+ =================
289
+ See the `contribution guidelines (CONTRIBUTING.md) <https://github.com/eea/eea.api.redirector/blob/master/CONTRIBUTING.md>`_.
290
+
291
+ Copyright and license
292
+ =====================
293
+
294
+ eea.api.redirector (the Original Code) is free software; you can
295
+ redistribute it and/or modify it under the terms of the
296
+ GNU General Public License as published by the Free Software Foundation;
297
+ either version 2 of the License, or (at your option) any later version.
298
+
299
+ This program is distributed in the hope that it will be useful, but
300
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
301
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
302
+ for more details.
303
+
304
+ You should have received a copy of the GNU General Public License along
305
+ with this program; if not, write to the Free Software Foundation, Inc., 59
306
+ Temple Place, Suite 330, Boston, MA 02111-1307 USA.
307
+
308
+ The Initial Owner of the Original Code is European Environment Agency (EEA).
309
+ Portions created by Eau de Web are Copyright (C) 2009 by
310
+ European Environment Agency. All Rights Reserved.
311
+
312
+
313
+ Funding
314
+ =======
315
+
316
+ EEA_ - European Environment Agency (EU)
317
+
318
+ .. _EEA: https://www.eea.europa.eu/
319
+ .. _`EEA Web Systems Training`: http://www.youtube.com/user/eeacms/videos?view=1
320
+
321
+ Changelog
322
+ =========
323
+
324
+ 0.1 - (2025-11-28)
325
+ -----------------------
326
+
327
+ * Feature: Redis-backed URL redirects with high-performance lookups
328
+ [avoinea - refs $293748]
329
+ * Feature: REST API endpoints (@redirects, @redirects-statistics) for full CRUD operations
330
+ [avoinea - refs $293748]
331
+ * Feature: Advanced search with regex support and search scope selector (old_url, new_url, both)
332
+ [avoinea - refs $293748]
333
+ * Feature: HTTP 410 Gone support for permanently deleted content (empty redirect targets)
334
+ [avoinea - refs $293748]
335
+ * Feature: High-performance statistics using Redis pipelining (~2s for 100k+ redirects)
336
+ [avoinea - refs $293748]
337
+ * Feature: Pagination support with configurable batch sizes (10, 25, 50, 100, 500, 1000)
338
+ [avoinea - refs $293748]
339
+ * Feature: Alphabetical sorting of redirects for consistent display
340
+ [avoinea - refs $293748]
341
+ * Feature: Bulk import/export via REST API (CSV support in frontend)
342
+ [avoinea - refs $293748]
343
+ * Feature: Fallback mechanism to check Redis when redirects not found in Plone storage
344
+ [avoinea - refs $293748]
345
+ * Feature: Graceful error handling - Redis failures don't break redirection system
346
+ [avoinea - refs $293748]
347
+ * Feature: API endpoint support with intelligent hierarchical URL matching
348
+ [avoinea - refs $293748]
349
+ * Feature: Redirect loop prevention
350
+ [avoinea - refs $293748]
351
+ * Feature: Easy configuration via environment variables (REDIS_SERVER, REDIS_PORT, REDIS_DB, REDIS_TIMEOUT)
352
+ [avoinea - refs $293748]
@@ -0,0 +1,285 @@
1
+ ==========================
2
+ eea.api.redirector
3
+ ==========================
4
+ .. image:: https://ci.eionet.europa.eu/buildStatus/icon?job=eea/eea.api.redirector/develop
5
+ :target: https://ci.eionet.europa.eu/job/eea/job/eea.api.redirector/job/develop/display/redirect
6
+ :alt: Develop
7
+ .. image:: https://ci.eionet.europa.eu/buildStatus/icon?job=eea/eea.api.redirector/master
8
+ :target: https://ci.eionet.europa.eu/job/eea/job/eea.api.redirector/job/master/display/redirect
9
+ :alt: Master
10
+
11
+ The eea.api.redirector is a Plone add-on that extends Plone's native redirect system with Redis-based URL redirects, enabling high-performance redirect lookups and external redirect management.
12
+
13
+ .. contents::
14
+
15
+
16
+ Main features
17
+ =============
18
+
19
+ 1. **Redis-backed redirects**: Store and retrieve URL redirects from Redis in addition to Plone's database
20
+ 2. **REST API endpoints**: Full CRUD operations for managing redirects via ``@redirects`` endpoint
21
+ 3. **Control panel integration**: Web UI for managing redirects (requires `volto-redirector <https://github.com/eea/volto-redirector>`_ frontend)
22
+ 4. **High-performance statistics**: Redis pipelining for calculating statistics on 100k+ redirects in ~2 seconds
23
+ 5. **Advanced search**: Search both old and new URLs using simple or regex patterns (e.g., ``^/publications``, ``example.com``)
24
+ 6. **Fallback mechanism**: Automatically checks Redis when redirects are not found in Plone storage
25
+ 7. **Graceful error handling**: Redis connection failures don't break the redirection system
26
+ 8. **API endpoint support**: Intelligent hierarchical URL matching for API services and endpoints
27
+ 9. **Proper HTTP status codes**: Returns 410 Gone for permanently deleted resources (empty redirect targets)
28
+ 10. **Redirect loop prevention**: Built-in protection against circular redirects
29
+ 11. **Easy configuration**: Simple environment variable setup for Redis connections
30
+ 12. **Non-intrusive**: Extends existing Plone functionality without replacing it
31
+
32
+
33
+ Install
34
+ =======
35
+
36
+ * Via pip::
37
+
38
+ $ pip install eea.api.redirector
39
+
40
+ * Or via docker-compose::
41
+
42
+ $ docker-compose up -d
43
+
44
+ This will start both Plone 6 and Redis services with the add-on pre-configured.
45
+
46
+ * Install *eea.api.redirector* within Site Setup > Add-ons
47
+
48
+
49
+ Configuration
50
+ =============
51
+
52
+ Redis connection settings are configured via environment variables:
53
+
54
+ * ``REDIS_SERVER`` - Redis server hostname (default: ``localhost``)
55
+ * ``REDIS_PORT`` - Redis server port (default: ``6379``)
56
+ * ``REDIS_DB`` - Redis database index (default: ``0``)
57
+ * ``REDIS_TIMEOUT`` - Connection timeout in seconds (default: ``5``)
58
+
59
+ The included ``docker-compose.yml`` demonstrates how to configure these settings. The Plone service connects to Redis using::
60
+
61
+ environment:
62
+ REDIS_SERVER: "redis"
63
+ REDIS_PORT: "6379"
64
+ REDIS_DB: "0"
65
+ REDIS_TIMEOUT: "5"
66
+
67
+
68
+ How it works
69
+ ============
70
+
71
+ The add-on extends Plone's built-in ``plone.app.redirector`` by:
72
+
73
+ 1. **Storage Integration**: Adds a Redis storage utility alongside Plone's database storage
74
+ 2. **Fallback Lookup**: When a redirect is not found in Plone's database, it checks Redis
75
+ 3. **API Support**: Custom error handling for API endpoints with hierarchical URL matching
76
+ 4. **Non-blocking**: If Redis is unavailable, the system continues using Plone's standard redirects
77
+
78
+ This design allows you to:
79
+
80
+ * Manage redirects externally via Redis while maintaining Plone's UI-based redirect management
81
+ * Share redirects across multiple Plone instances using a common Redis server
82
+ * Achieve faster redirect lookups for high-traffic sites
83
+ * Store temporary or dynamic redirects that don't need to persist in Plone's database
84
+
85
+
86
+ REST API Endpoints
87
+ ==================
88
+
89
+ The add-on provides REST API endpoints for managing redirects:
90
+
91
+ **GET /@redirects**
92
+
93
+ List redirects with pagination and search support.
94
+
95
+ Query parameters:
96
+
97
+ * ``q`` - Search query for old or new URL paths (supports regex: ``^/publications``, ``.*\.pdf$``)
98
+ * ``b_size`` - Batch size (default: 25, options: 10, 25, 50, 100, 500, 1000)
99
+ * ``b_start`` - Batch start offset (default: 0)
100
+ * ``search_scope`` - Where to search: ``old_url`` (default), ``new_url``, or ``both``
101
+
102
+ Example::
103
+
104
+ GET /Plone/@redirects?q=/themes&b_size=25&b_start=0&search_scope=old_url
105
+
106
+ Response::
107
+
108
+ {
109
+ "@id": "http://localhost:8080/Plone/@redirects",
110
+ "items": [
111
+ {
112
+ "path": "/old-path",
113
+ "redirect-to": "/new-path"
114
+ },
115
+ {
116
+ "path": "/deleted-page",
117
+ "redirect-to": ""
118
+ }
119
+ ],
120
+ "items_total": 187520
121
+ }
122
+
123
+ **GET /@redirects-statistics**
124
+
125
+ Get statistics for redirects.
126
+
127
+ Query parameters:
128
+
129
+ * ``q`` - Optional search query to filter statistics
130
+
131
+ Example::
132
+
133
+ GET /Plone/@redirects-statistics?q=/themes
134
+
135
+ Response::
136
+
137
+ {
138
+ "@id": "http://localhost:8080/Plone/@redirects-statistics",
139
+ "statistics": {
140
+ "total": 187520,
141
+ "internal": 32935,
142
+ "external": 1611,
143
+ "gone": 152974
144
+ }
145
+ }
146
+
147
+ Statistics categories:
148
+
149
+ * **total** - Total number of redirects
150
+ * **internal** - Redirects to internal paths (starting with ``/``)
151
+ * **external** - Redirects to external URLs (starting with ``http://`` or ``https://``)
152
+ * **gone** - Empty redirects for permanently deleted content (HTTP 410)
153
+
154
+ **POST /@redirects**
155
+
156
+ Add new redirects.
157
+
158
+ Request body::
159
+
160
+ {
161
+ "items": [
162
+ {
163
+ "path": "/old-path",
164
+ "redirect-to": "/new-path"
165
+ },
166
+ {
167
+ "path": "/deleted-page",
168
+ "redirect-to": ""
169
+ }
170
+ ]
171
+ }
172
+
173
+ Notes:
174
+
175
+ * Empty ``redirect-to`` marks content as permanently deleted (returns HTTP 410 Gone)
176
+ * Paths are automatically trimmed of whitespace
177
+ * Self-redirects are prevented (path cannot equal redirect-to)
178
+
179
+ Response::
180
+
181
+ {
182
+ "success": 2,
183
+ "failed": []
184
+ }
185
+
186
+ **DELETE /@redirects**
187
+
188
+ Remove redirects.
189
+
190
+ Request body::
191
+
192
+ {
193
+ "items": [
194
+ {"path": "/old-path"}
195
+ ]
196
+ }
197
+
198
+ Response::
199
+
200
+ {
201
+ "success": 1,
202
+ "failed": []
203
+ }
204
+
205
+
206
+ Performance
207
+ ===========
208
+
209
+ The add-on uses Redis pipelining for optimal performance:
210
+
211
+ * **Statistics calculation**: ~2 seconds for 187,000 redirects (42x faster than individual GET operations)
212
+ * **List pagination**: Scans keys only, fetches values only for requested page
213
+ * **Search queries**: Uses Redis SCAN with pattern matching for efficient filtering
214
+
215
+ Benchmark results (187,520 redirects):
216
+
217
+ * SCAN all keys: 0.36s
218
+ * Statistics with pipelining: 1.8s
219
+ * Individual GET operations: 77s (not used)
220
+
221
+
222
+ HTTP 410 Gone Support
223
+ =====================
224
+
225
+ Redirects with empty targets (``redirect-to: ""``) return HTTP 410 Gone status, indicating the resource has been permanently deleted. This is the proper HTTP status code for removed content that will not return.
226
+
227
+ The frontend (`volto-redirector <https://github.com/eea/volto-redirector>`_) can display a custom 410 Gone page with:
228
+
229
+ * Information about the deleted resource
230
+ * Link to Wayback Machine for archived versions
231
+ * Helpful navigation options
232
+
233
+
234
+ Source code
235
+ ===========
236
+
237
+ - `eea.api.redirector (backend) <https://github.com/eea/eea.api.redirector>`_
238
+ - `volto-redirector (frontend) <https://github.com/eea/volto-redirector>`_
239
+
240
+
241
+ Eggs repository
242
+ ===============
243
+
244
+ - https://pypi.python.org/pypi/eea.api.redirector
245
+ - http://eggrepo.eea.europa.eu/simple
246
+
247
+
248
+ Plone versions
249
+ ==============
250
+ It has been developed and tested for Plone 6. See section above.
251
+
252
+
253
+ How to contribute
254
+ =================
255
+ See the `contribution guidelines (CONTRIBUTING.md) <https://github.com/eea/eea.api.redirector/blob/master/CONTRIBUTING.md>`_.
256
+
257
+ Copyright and license
258
+ =====================
259
+
260
+ eea.api.redirector (the Original Code) is free software; you can
261
+ redistribute it and/or modify it under the terms of the
262
+ GNU General Public License as published by the Free Software Foundation;
263
+ either version 2 of the License, or (at your option) any later version.
264
+
265
+ This program is distributed in the hope that it will be useful, but
266
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
267
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
268
+ for more details.
269
+
270
+ You should have received a copy of the GNU General Public License along
271
+ with this program; if not, write to the Free Software Foundation, Inc., 59
272
+ Temple Place, Suite 330, Boston, MA 02111-1307 USA.
273
+
274
+ The Initial Owner of the Original Code is European Environment Agency (EEA).
275
+ Portions created by Eau de Web are Copyright (C) 2009 by
276
+ European Environment Agency. All Rights Reserved.
277
+
278
+
279
+ Funding
280
+ =======
281
+
282
+ EEA_ - European Environment Agency (EU)
283
+
284
+ .. _EEA: https://www.eea.europa.eu/
285
+ .. _`EEA Web Systems Training`: http://www.youtube.com/user/eeacms/videos?view=1