plain.redirection 0.32.0__tar.gz → 0.33.0__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 (18) hide show
  1. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/PKG-INFO +3 -3
  2. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/CHANGELOG.md +22 -0
  3. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/admin.py +1 -1
  4. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/middleware.py +3 -1
  5. plain_redirection-0.33.0/plain/redirection/migrations/0001_initial.py +98 -0
  6. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/models.py +20 -20
  7. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/pyproject.toml +2 -2
  8. plain_redirection-0.32.0/plain/redirection/migrations/0001_initial.py +0 -97
  9. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/.gitignore +0 -0
  10. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/LICENSE +0 -0
  11. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/README.md +0 -0
  12. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/README.md +0 -0
  13. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/__init__.py +0 -0
  14. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/chores.py +0 -0
  15. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/config.py +0 -0
  16. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/default_settings.py +0 -0
  17. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/migrations/__init__.py +0 -0
  18. {plain_redirection-0.32.0 → plain_redirection-0.33.0}/plain/redirection/templates/admin/plainredirection/redirect_form.html +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.redirection
3
- Version: 0.32.0
3
+ Version: 0.33.0
4
4
  Summary: A flexible URL redirection system with admin interface and logging.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-Expression: BSD-3-Clause
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.13
9
- Requires-Dist: plain-models<1.0.0
10
- Requires-Dist: plain<1.0.0,>=0.116.0
9
+ Requires-Dist: plain-postgres<1.0.0,>=0.84.0
10
+ Requires-Dist: plain<1.0.0,>=0.123.0
11
11
  Description-Content-Type: text/markdown
12
12
 
13
13
  # plain.redirection
@@ -1,5 +1,27 @@
1
1
  # plain-redirection changelog
2
2
 
3
+ ## [0.33.0](https://github.com/dropseed/plain/releases/plain-redirection@0.33.0) (2026-03-12)
4
+
5
+ ### What's changed
6
+
7
+ - Updated all imports from `plain.models` to `plain.postgres` in admin, models, and migrations.
8
+ - Updated `pyproject.toml` dependency from `plain.models` to `plain.postgres`.
9
+
10
+ ### Upgrade instructions
11
+
12
+ - Update imports: `from plain.models` to `from plain.postgres`, `from plain import models` to `from plain import postgres`.
13
+ - Update dependency declarations: `plain.models` to `plain.postgres` in `pyproject.toml`.
14
+
15
+ ## [0.32.1](https://github.com/dropseed/plain/releases/plain-redirection@0.32.1) (2026-03-11)
16
+
17
+ ### What's changed
18
+
19
+ - Added `allow_external=True` to redirect middleware responses, since database-configured redirects can legitimately target external URLs ([5edfb2bedf90](https://github.com/dropseed/plain/commit/5edfb2bedf90))
20
+
21
+ ### Upgrade instructions
22
+
23
+ - Requires `plain>=0.123.0`. No other changes required.
24
+
3
25
  ## [0.32.0](https://github.com/dropseed/plain/releases/plain-redirection@0.32.0) (2026-03-06)
4
26
 
5
27
  ### What's changed
@@ -8,7 +8,7 @@ from plain.admin.views import (
8
8
  AdminViewset,
9
9
  register_viewset,
10
10
  )
11
- from plain.models.forms import ModelForm
11
+ from plain.postgres.forms import ModelForm
12
12
 
13
13
  from .models import NotFoundLog, Redirect, RedirectLog
14
14
 
@@ -17,7 +17,9 @@ class RedirectionMiddleware(HttpMiddleware):
17
17
  redirect_log = RedirectLog.from_redirect(redirect, request)
18
18
  # Then redirect
19
19
  return RedirectResponse(
20
- str(redirect_log.to_url), status_code=redirect.http_status
20
+ str(redirect_log.to_url),
21
+ status_code=redirect.http_status,
22
+ allow_external=True,
21
23
  )
22
24
 
23
25
  # Nothing matched, just log the 404
@@ -0,0 +1,98 @@
1
+ # Generated by Plain 0.52.2 on 2025-07-08 01:17
2
+
3
+ import plain.postgres.deletion
4
+ from plain import postgres
5
+ from plain.postgres import migrations
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ initial = True
10
+
11
+ dependencies = []
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name="Redirect",
16
+ fields=[
17
+ ("id", postgres.PrimaryKeyField()),
18
+ ("from_pattern", postgres.CharField(max_length=255)),
19
+ ("to_pattern", postgres.CharField(max_length=255)),
20
+ ("http_status", postgres.PositiveSmallIntegerField(default=301)),
21
+ ("created_at", postgres.DateTimeField(auto_now_add=True)),
22
+ ("updated_at", postgres.DateTimeField(auto_now=True)),
23
+ ("order", postgres.PositiveSmallIntegerField(default=0)),
24
+ ("enabled", postgres.BooleanField(default=True)),
25
+ ("is_regex", postgres.BooleanField(default=False)),
26
+ ],
27
+ options={
28
+ "ordering": ["order", "-created_at"],
29
+ },
30
+ ),
31
+ migrations.CreateModel(
32
+ name="RedirectLog",
33
+ fields=[
34
+ ("id", postgres.PrimaryKeyField()),
35
+ ("from_url", postgres.URLField(max_length=512)),
36
+ ("to_url", postgres.URLField(max_length=512)),
37
+ ("http_status", postgres.PositiveSmallIntegerField(default=301)),
38
+ ("ip_address", postgres.GenericIPAddressField()),
39
+ ("user_agent", postgres.CharField(max_length=512, required=False)),
40
+ ("referrer", postgres.CharField(max_length=512, required=False)),
41
+ ("created_at", postgres.DateTimeField(auto_now_add=True)),
42
+ ],
43
+ options={
44
+ "ordering": ["-created_at"],
45
+ },
46
+ ),
47
+ migrations.CreateModel(
48
+ name="NotFoundLog",
49
+ fields=[
50
+ ("id", postgres.PrimaryKeyField()),
51
+ ("url", postgres.URLField(max_length=512)),
52
+ ("ip_address", postgres.GenericIPAddressField()),
53
+ ("user_agent", postgres.CharField(max_length=512, required=False)),
54
+ ("referrer", postgres.CharField(max_length=512, required=False)),
55
+ ("created_at", postgres.DateTimeField(auto_now_add=True)),
56
+ ],
57
+ options={
58
+ "ordering": ["-created_at"],
59
+ },
60
+ ),
61
+ migrations.AddIndex(
62
+ model_name="redirect",
63
+ index=postgres.Index(fields=["order"], name="plainredire_order_44dde0_idx"),
64
+ ),
65
+ migrations.AddIndex(
66
+ model_name="redirect",
67
+ index=postgres.Index(
68
+ fields=["created_at"], name="plainredire_created_18c288_idx"
69
+ ),
70
+ ),
71
+ migrations.AddConstraint(
72
+ model_name="redirect",
73
+ constraint=postgres.UniqueConstraint(
74
+ fields=("from_pattern",),
75
+ name="plainredirects_redirect_unique_from_pattern",
76
+ ),
77
+ ),
78
+ migrations.AddField(
79
+ model_name="redirectlog",
80
+ name="redirect",
81
+ field=postgres.ForeignKeyField(
82
+ on_delete=plain.postgres.deletion.CASCADE,
83
+ to="plainredirection.redirect",
84
+ ),
85
+ ),
86
+ migrations.AddIndex(
87
+ model_name="notfoundlog",
88
+ index=postgres.Index(
89
+ fields=["created_at"], name="plainredire_created_d5f0c7_idx"
90
+ ),
91
+ ),
92
+ migrations.AddIndex(
93
+ model_name="redirectlog",
94
+ index=postgres.Index(
95
+ fields=["created_at"], name="plainredire_created_5d75f4_idx"
96
+ ),
97
+ ),
98
+ ]
@@ -4,8 +4,8 @@ import re
4
4
  from datetime import datetime
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- from plain import models
8
- from plain.models import types
7
+ from plain import postgres
8
+ from plain.postgres import types
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from plain.http import Request
@@ -13,8 +13,8 @@ if TYPE_CHECKING:
13
13
  __all__ = ["NotFoundLog", "Redirect", "RedirectLog"]
14
14
 
15
15
 
16
- @models.register_model
17
- class Redirect(models.Model):
16
+ @postgres.register_model
17
+ class Redirect(postgres.Model):
18
18
  from_pattern: str = types.CharField(max_length=255)
19
19
  to_pattern: str = types.CharField(max_length=255)
20
20
  http_status: int = types.PositiveSmallIntegerField(
@@ -30,16 +30,16 @@ class Redirect(models.Model):
30
30
  # logged in or not? auth not required necessarily...
31
31
  # headers?
32
32
 
33
- query: models.QuerySet[Redirect] = models.QuerySet()
33
+ query: postgres.QuerySet[Redirect] = postgres.QuerySet()
34
34
 
35
- model_options = models.Options(
35
+ model_options = postgres.Options(
36
36
  ordering=["order", "-created_at"],
37
37
  indexes=[
38
- models.Index(fields=["order"]),
39
- models.Index(fields=["created_at"]),
38
+ postgres.Index(fields=["order"]),
39
+ postgres.Index(fields=["created_at"]),
40
40
  ],
41
41
  constraints=[
42
- models.UniqueConstraint(
42
+ postgres.UniqueConstraint(
43
43
  fields=["from_pattern"],
44
44
  name="plainredirects_redirect_unique_from_pattern",
45
45
  ),
@@ -80,9 +80,9 @@ class Redirect(models.Model):
80
80
  return re.sub(self.from_pattern, self.to_pattern, url)
81
81
 
82
82
 
83
- @models.register_model
84
- class RedirectLog(models.Model):
85
- redirect: Redirect = types.ForeignKeyField(Redirect, on_delete=models.CASCADE)
83
+ @postgres.register_model
84
+ class RedirectLog(postgres.Model):
85
+ redirect: Redirect = types.ForeignKeyField(Redirect, on_delete=postgres.CASCADE)
86
86
 
87
87
  # The actuals that were used to redirect
88
88
  from_url: str = types.URLField(max_length=512)
@@ -96,12 +96,12 @@ class RedirectLog(models.Model):
96
96
 
97
97
  created_at: datetime = types.DateTimeField(auto_now_add=True)
98
98
 
99
- query: models.QuerySet[RedirectLog] = models.QuerySet()
99
+ query: postgres.QuerySet[RedirectLog] = postgres.QuerySet()
100
100
 
101
- model_options = models.Options(
101
+ model_options = postgres.Options(
102
102
  ordering=["-created_at"],
103
103
  indexes=[
104
- models.Index(fields=["created_at"]),
104
+ postgres.Index(fields=["created_at"]),
105
105
  ],
106
106
  )
107
107
 
@@ -127,8 +127,8 @@ class RedirectLog(models.Model):
127
127
  )
128
128
 
129
129
 
130
- @models.register_model
131
- class NotFoundLog(models.Model):
130
+ @postgres.register_model
131
+ class NotFoundLog(postgres.Model):
132
132
  url: str = types.URLField(max_length=512)
133
133
 
134
134
  # Request metadata
@@ -138,12 +138,12 @@ class NotFoundLog(models.Model):
138
138
 
139
139
  created_at: datetime = types.DateTimeField(auto_now_add=True)
140
140
 
141
- query: models.QuerySet[NotFoundLog] = models.QuerySet()
141
+ query: postgres.QuerySet[NotFoundLog] = postgres.QuerySet()
142
142
 
143
- model_options = models.Options(
143
+ model_options = postgres.Options(
144
144
  ordering=["-created_at"],
145
145
  indexes=[
146
- models.Index(fields=["created_at"]),
146
+ postgres.Index(fields=["created_at"]),
147
147
  ],
148
148
  )
149
149
 
@@ -1,12 +1,12 @@
1
1
  [project]
2
2
  name = "plain.redirection"
3
- version = "0.32.0"
3
+ version = "0.33.0"
4
4
  description = "A flexible URL redirection system with admin interface and logging."
5
5
  authors = [{ name = "Dave Gaeddert", email = "dave.gaeddert@dropseed.dev" }]
6
6
  readme = "README.md"
7
7
  license = "BSD-3-Clause"
8
8
  requires-python = ">=3.13"
9
- dependencies = ["plain>=0.116.0,<1.0.0", "plain.models<1.0.0"]
9
+ dependencies = ["plain>=0.123.0,<1.0.0", "plain.postgres>=0.84.0,<1.0.0"]
10
10
 
11
11
  [tool.hatch.build.targets.wheel]
12
12
  packages = ["plain"]
@@ -1,97 +0,0 @@
1
- # Generated by Plain 0.52.2 on 2025-07-08 01:17
2
-
3
- import plain.models.deletion
4
- from plain import models
5
- from plain.models import migrations
6
-
7
-
8
- class Migration(migrations.Migration):
9
- initial = True
10
-
11
- dependencies = []
12
-
13
- operations = [
14
- migrations.CreateModel(
15
- name="Redirect",
16
- fields=[
17
- ("id", models.PrimaryKeyField()),
18
- ("from_pattern", models.CharField(max_length=255)),
19
- ("to_pattern", models.CharField(max_length=255)),
20
- ("http_status", models.PositiveSmallIntegerField(default=301)),
21
- ("created_at", models.DateTimeField(auto_now_add=True)),
22
- ("updated_at", models.DateTimeField(auto_now=True)),
23
- ("order", models.PositiveSmallIntegerField(default=0)),
24
- ("enabled", models.BooleanField(default=True)),
25
- ("is_regex", models.BooleanField(default=False)),
26
- ],
27
- options={
28
- "ordering": ["order", "-created_at"],
29
- },
30
- ),
31
- migrations.CreateModel(
32
- name="RedirectLog",
33
- fields=[
34
- ("id", models.PrimaryKeyField()),
35
- ("from_url", models.URLField(max_length=512)),
36
- ("to_url", models.URLField(max_length=512)),
37
- ("http_status", models.PositiveSmallIntegerField(default=301)),
38
- ("ip_address", models.GenericIPAddressField()),
39
- ("user_agent", models.CharField(max_length=512, required=False)),
40
- ("referrer", models.CharField(max_length=512, required=False)),
41
- ("created_at", models.DateTimeField(auto_now_add=True)),
42
- ],
43
- options={
44
- "ordering": ["-created_at"],
45
- },
46
- ),
47
- migrations.CreateModel(
48
- name="NotFoundLog",
49
- fields=[
50
- ("id", models.PrimaryKeyField()),
51
- ("url", models.URLField(max_length=512)),
52
- ("ip_address", models.GenericIPAddressField()),
53
- ("user_agent", models.CharField(max_length=512, required=False)),
54
- ("referrer", models.CharField(max_length=512, required=False)),
55
- ("created_at", models.DateTimeField(auto_now_add=True)),
56
- ],
57
- options={
58
- "ordering": ["-created_at"],
59
- },
60
- ),
61
- migrations.AddIndex(
62
- model_name="redirect",
63
- index=models.Index(fields=["order"], name="plainredire_order_44dde0_idx"),
64
- ),
65
- migrations.AddIndex(
66
- model_name="redirect",
67
- index=models.Index(
68
- fields=["created_at"], name="plainredire_created_18c288_idx"
69
- ),
70
- ),
71
- migrations.AddConstraint(
72
- model_name="redirect",
73
- constraint=models.UniqueConstraint(
74
- fields=("from_pattern",),
75
- name="plainredirects_redirect_unique_from_pattern",
76
- ),
77
- ),
78
- migrations.AddField(
79
- model_name="redirectlog",
80
- name="redirect",
81
- field=models.ForeignKeyField(
82
- on_delete=plain.models.deletion.CASCADE, to="plainredirection.redirect"
83
- ),
84
- ),
85
- migrations.AddIndex(
86
- model_name="notfoundlog",
87
- index=models.Index(
88
- fields=["created_at"], name="plainredire_created_d5f0c7_idx"
89
- ),
90
- ),
91
- migrations.AddIndex(
92
- model_name="redirectlog",
93
- index=models.Index(
94
- fields=["created_at"], name="plainredire_created_5d75f4_idx"
95
- ),
96
- ),
97
- ]