Skip to content

Commit a909243

Browse files
committed
Switch to standard STORAGES setting
Switch from our own custom settings to Django's new standard STORAGE settings. Implements: #187
1 parent b79e013 commit a909243

File tree

4 files changed

+76
-32
lines changed

4 files changed

+76
-32
lines changed

django_afip/migrations/0004_storages_and_help_texts.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class Migration(migrations.Migration):
1919
blank=True,
2020
help_text="The actual file which contains the PDF data.",
2121
null=True,
22-
storage=django_afip.models._get_storage_from_settings(
23-
"AFIP_PDF_STORAGE"
24-
),
22+
storage=django_afip.models._get_storage_from_settings("afip_pdfs"),
2523
upload_to=django_afip.models.ReceiptPDF.upload_to,
2624
verbose_name="pdf file",
2725
),
@@ -32,9 +30,7 @@ class Migration(migrations.Migration):
3230
field=models.FileField(
3331
blank=True,
3432
null=True,
35-
storage=django_afip.models._get_storage_from_settings(
36-
"AFIP_CERT_STORAGE"
37-
),
33+
storage=django_afip.models._get_storage_from_settings("afip_certs"),
3834
upload_to="afip/taxpayers/certs/",
3935
verbose_name="certificate",
4036
),
@@ -45,9 +41,7 @@ class Migration(migrations.Migration):
4541
field=models.FileField(
4642
blank=True,
4743
null=True,
48-
storage=django_afip.models._get_storage_from_settings(
49-
"AFIP_KEY_STORAGE"
50-
),
44+
storage=django_afip.models._get_storage_from_settings("afip_keys"),
5145
upload_to="afip/taxpayers/keys/",
5246
verbose_name="key",
5347
),
@@ -59,9 +53,7 @@ class Migration(migrations.Migration):
5953
blank=True,
6054
help_text="A logo to use when generating printable receipts.",
6155
null=True,
62-
storage=django_afip.models._get_storage_from_settings(
63-
"AFIP_LOGO_STORAGE"
64-
),
56+
storage=django_afip.models._get_storage_from_settings("afip_logos"),
6557
upload_to="afip/taxpayers/logos/",
6658
verbose_name="logo",
6759
),

django_afip/models.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import random
77
import re
88
import warnings
9+
from contextlib import suppress
910
from datetime import datetime
1011
from datetime import timedelta
1112
from datetime import timezone
@@ -16,12 +17,16 @@
1617
from typing import BinaryIO
1718
from typing import ClassVar
1819
from typing import Generic
20+
from typing import Literal
1921
from typing import TypeVar
2022
from uuid import uuid4
2123

2224
from django.conf import settings
2325
from django.core import management
2426
from django.core.files import File
27+
from django.core.files.storage import InvalidStorageError
28+
from django.core.files.storage import default_storage
29+
from django.core.files.storage import storages
2530
from django.core.validators import MinValueValidator
2631
from django.db import connection
2732
from django.db import models
@@ -126,13 +131,30 @@ def first_currency() -> int | None:
126131
return None
127132

128133

129-
def _get_storage_from_settings(setting_name: str) -> Storage:
130-
path = getattr(settings, setting_name, None)
131-
if not path:
132-
from django.core.files.storage import default_storage
134+
_DEPRECATED_STORAGE_SETTINGS = {
135+
"afip_keys": "AFIP_KEY_STORAGE",
136+
"afip_certs": "AFIP_CERT_STORAGE",
137+
"afip_pdfs": "AFIP_PDF_STORAGE",
138+
"afip_logos": "AFIP_LOGO_STORAGE",
139+
}
133140

134-
return default_storage
135-
return import_string(path)
141+
142+
def _get_storage_from_settings(
143+
alias: Literal["afip_keys" | "afip_certs" | "afip_pdfs" | "afip_logos"],
144+
) -> Storage:
145+
with suppress(InvalidStorageError):
146+
return storages[alias]
147+
148+
old_setting = _DEPRECATED_STORAGE_SETTINGS[alias]
149+
if path := getattr(settings, old_setting, None):
150+
warnings.warn(
151+
f"{old_setting} is deprecated. Use STORAGES['{alias}'] instead.",
152+
DeprecationWarning,
153+
stacklevel=2,
154+
)
155+
return import_string(path)
156+
157+
return default_storage
136158

137159

138160
_T = TypeVar("_T", bound="GenericAfipType", covariant=True)
@@ -386,14 +408,14 @@ class TaxPayer(models.Model):
386408
key = models.FileField(
387409
verbose_name=_("key"),
388410
upload_to="afip/taxpayers/keys/",
389-
storage=_get_storage_from_settings("AFIP_KEY_STORAGE"),
411+
storage=_get_storage_from_settings("afip_keys"),
390412
blank=True,
391413
null=True,
392414
)
393415
certificate = models.FileField(
394416
verbose_name=_("certificate"),
395417
upload_to="afip/taxpayers/certs/",
396-
storage=_get_storage_from_settings("AFIP_CERT_STORAGE"),
418+
storage=_get_storage_from_settings("afip_certs"),
397419
blank=True,
398420
null=True,
399421
)
@@ -423,7 +445,7 @@ class TaxPayer(models.Model):
423445
logo = models.ImageField(
424446
verbose_name=_("logo"),
425447
upload_to="afip/taxpayers/logos/",
426-
storage=_get_storage_from_settings("AFIP_LOGO_STORAGE"),
448+
storage=_get_storage_from_settings("afip_logos"),
427449
blank=True,
428450
null=True,
429451
help_text=_("A logo to use when generating printable receipts."),
@@ -1542,7 +1564,7 @@ class ReceiptPDF(models.Model):
15421564
pdf_file = models.FileField(
15431565
verbose_name=_("pdf file"),
15441566
upload_to=_receipt_pdf_upload_to,
1545-
storage=_get_storage_from_settings("AFIP_PDF_STORAGE"),
1567+
storage=_get_storage_from_settings("afip_pdfs"),
15461568
blank=True,
15471569
null=True,
15481570
help_text=_("The actual file which contains the PDF data."),

docs/changelog.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,28 @@ Any breaking changes which require intervention will be mentioned here.
2323
- Drop support for Python 3.9.
2424
- In order to align with Django's coding style conventions, the following
2525
fields no longer support ``NULL`` values. Use an empty string instead:
26+
2627
- ``PointOfSales.issuing_name``
2728
- ``PointOfSales.issuing_address``
2829
- ``PointOfSales.issuing_email``
2930
- ``PointOfSales.vat_condition``
3031
- ``PointOfSales.gross_income_condition``
3132
- ``PointOfSales.sales_terms``
3233
- ``ReceiptPDF.issuing_email``
34+
3335
- Remove ``ReceiptValidation.result``, ``ReceiptValidation.RESULT_APPROVED``
3436
and ``ReceiptValidation.RESULT_REJECTED``. Rejected validation requests were
3537
never saved. All validations created were of type ``RESULT_APPROVED``,
3638
making this field completely redundant.
39+
- Migrate to Django's :setting:`STORAGES` setting (introduced in Django 4.2)
40+
for custom storage backends. The old names are deprecated and will be removed
41+
in a future version. Use the following settings:
42+
43+
- ``AFIP_KEY_STORAGE`` → ``STORAGES["afip_keys"]``
44+
- ``AFIP_CERT_STORAGE`` → ``STORAGES["afip_certs"]``
45+
- ``AFIP_PDF_STORAGE`` → ``STORAGES["afip_pdfs"]``
46+
- ``AFIP_LOGO_STORAGE`` → ``STORAGES["afip_logos"]``
47+
3748

3849
13.2.2
3950
------

docs/installation.rst

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,40 @@ También es posible (y opcional) definir varios :doc:`Storage
7676
<django:ref/files/storage>` para los archivos de la app. Si no están definidos,
7777
se usará el Storage predeterminado.
7878

79-
El valor de estos ajustes debería ser un ``str`` con el path a una instancia
80-
del storage a usar. (eg: ``'myapp.storages.my_private_storage'``). Tanto S3
81-
como el storage predeterminado han sido testeados ampliamente, aunque cualquier
82-
storage compatible con django debería funcionar sin dramas.
79+
Podés configurar storages personalizados usando el setting :setting:`STORAGES`
80+
de Django con los siguientes alias:
8381

8482
.. code-block:: python
8583
86-
AFIP_KEY_STORAGE # Clave para autenticación con el AFIP. (TaxPayer.key)
87-
AFIP_CERT_STORAGE # Certificados para autenticación con el AFIP (TaxPayer.certificate)
88-
AFIP_PDF_STORAGE # PDFs generados para comprobantes (ReceiptPDF.pdf_file)
89-
AFIP_LOGO_STORAGE # Logos usados para comprobantes (TaxPayer.logo)
84+
STORAGES = {
85+
# …default storages…
86+
"afip_keys": { # Clave para autenticación con el AFIP. (TaxPayer.key)
87+
"BACKEND": "myapp.storages.PrivateStorage",
88+
},
89+
"afip_certs": { # Certificados para autenticación con el AFIP (TaxPayer.certificate)
90+
"BACKEND": "myapp.storages.PrivateStorage",
91+
},
92+
"afip_pdfs": { # PDFs generados para comprobantes (ReceiptPDF.pdf_file)
93+
"BACKEND": "myapp.storages.ClientStorage",
94+
},
95+
"afip_logos": { # Logos usados para comprobantes (TaxPayer.logo)
96+
"BACKEND": "django.core.files.storage.FileSystemStorage",
97+
},
98+
}
9099
91100
Si estás exponiendo tu Storage predeterminado a la web (que suele ser el caso
92-
en muchas aplicaciones), es recomendable, como mínimo, redefinir
93-
``AFIP_KEY_STORAGE`` para evitar exponer tu claves a la web.
101+
en muchas aplicaciones), es importante, como mínimo, redefinir ``afip_keys``
102+
para evitar exponer tu claves a la web.
103+
104+
.. deprecated:: 14.0
105+
106+
Los siguientes settings están deprecados y serán removidos en una versión
107+
futura. Usá :setting:`STORAGES` de Django en su lugar:
108+
109+
- ``AFIP_KEY_STORAGE`` → ``STORAGES["afip_keys"]``
110+
- ``AFIP_CERT_STORAGE`` → ``STORAGES["afip_certs"]``
111+
- ``AFIP_PDF_STORAGE`` → ``STORAGES["afip_pdfs"]``
112+
- ``AFIP_LOGO_STORAGE`` → ``STORAGES["afip_logos"]``
94113

95114
Versionado
96115
----------

0 commit comments

Comments
 (0)