-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5e3b61b
commit fe0078b
Showing
27 changed files
with
556 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.idea | ||
.vscode | ||
.env | ||
.DS_Store | ||
.pytest_cache | ||
.coverage | ||
coverage.xml | ||
*.egg-info | ||
*.pyc | ||
*.pyo | ||
*.sqlite* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
repos: | ||
- repo: https://github.com/pycqa/isort | ||
rev: 5.12.0 | ||
hooks: | ||
- id: isort | ||
args: [ "--profile", "black", "--filter-files" ] | ||
|
||
- repo: https://github.com/psf/black | ||
rev: 23.10.0 # Replace by any tag/version: https://github.com/psf/black/tags | ||
hooks: | ||
- id: black | ||
language_version: python3 # Should be a command that runs python3.6.2+ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,98 @@ | |
|
||
Django module to store contact request in a structured yet generic manner within the database. | ||
|
||
### Installation | ||
|
||
1. Install using pip: | ||
|
||
```shell | ||
pip install django-generic-contact | ||
``` | ||
|
||
2. Integrate `django_generic_contact` into your `settings.py` | ||
|
||
```python | ||
INSTALLED_APPS = [ | ||
# ... | ||
'django_generic_contact', | ||
# ... | ||
] | ||
``` | ||
|
||
### Usage | ||
|
||
The package provides you with a `Contact` model which expects `data` (dict) and the `name` of the requester, | ||
an optional `message` can be added: | ||
|
||
``` | ||
from django_generic_contact.models import Contact | ||
contact = Contact.objects.create( | ||
name="Mr. Tester", | ||
message="Please contact me via email or phone.", | ||
data={ | ||
"email": "[email protected]", | ||
"phone": "123456", | ||
} | ||
) | ||
``` | ||
|
||
#### JSON Schema validation | ||
|
||
The contents of `data` will be validated against a [json schema](https://json-schema.org/) defined in your project's | ||
`settings.py` (if provided). If needed you can define `GENERIC_CONTACT_DATA_SCHEMA` to check all relevant input | ||
according to the expected structure, e.g.: | ||
|
||
``` | ||
GENERIC_CONTACT_DATA_SCHEMA = { | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"type": "object", | ||
"properties": { | ||
"email": {"type": "string", "format": "email"}, | ||
"phone": {"type": "integer"}, | ||
}, | ||
} | ||
``` | ||
|
||
See more examples of `GENERIC_CONTACT_DATA_SCHEMA` in `tests/testapp/tests/test_model.py`. | ||
|
||
#### Customizing the Contact model | ||
The base model `GenericContact` only requires the `data`. Thus you can let your own models inherit from this and extend | ||
it according to your project's needs, e.g.: | ||
|
||
``` | ||
from django_generic_contact.models import GenericContact | ||
class CustomContact(GenericContact): | ||
birth_date = models.Datetime(_("birth date")) | ||
zip = models.CharField(_("zip")) | ||
``` | ||
|
||
## Unit Tests | ||
|
||
See folder [tests/](tests/). The provided tests cover these criteria: | ||
* success: | ||
* Contact model instance creation | ||
* project's jsonschema validation | ||
* failure: | ||
* project's jsonschema validation | ||
* exemplary custom jsonschema validation | ||
|
||
Follow below instructions to run the tests. | ||
You may exchange the installed Django and DRF versions according to your requirements. | ||
:warning: Depending on your local environment settings you might need to explicitly call `python3` instead of `python`. | ||
```bash | ||
# install dependencies | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
|
||
# setup environment | ||
pip install -e . | ||
|
||
# run tests | ||
cd tests && python manage.py test | ||
``` | ||
|
||
### Contributing | ||
|
||
Contributions are welcomed! Read the [Contributing Guide](CONTRIBUTING.md) for more information. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Schema configuration | ||
|
||
The `data` field on the `Contact` model can be optionally extended by providing a Schema according to | ||
[jsonschema](https://json-schema.org/) | ||
|
||
``` | ||
GENERIC_CONTACT_DATA_SCHEMA = { | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"type": "object", | ||
"properties": { | ||
"email": { | ||
"format": "email" | ||
}, | ||
}, | ||
"unevaluatedProperties": { | ||
"type": ["integer", "string"] | ||
} | ||
} | ||
``` | ||
|
||
The app makes use of the [python implementation](https://python-jsonschema.readthedocs.io/en/stable/) of jsonschema | ||
and supports format checking according to the library implementation. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from django import forms | ||
from django.contrib import admin | ||
from django_generic_contact.models import Contact | ||
from django_generic_contact.utils import get_help_text, get_validators | ||
|
||
|
||
class ContactAdminForm(forms.ModelForm): | ||
def __init__(self, *args, **kwargs): | ||
super(ContactAdminForm, self).__init__(*args, **kwargs) | ||
self.fields["data"].help_text = get_help_text() | ||
self.fields["data"].validators = get_validators() | ||
|
||
class Meta: | ||
model = Contact | ||
exclude = () | ||
|
||
|
||
@admin.register(Contact) | ||
class ContactAdmin(admin.ModelAdmin): | ||
list_display = [ | ||
"creation_date", | ||
"name", | ||
] | ||
form = ContactAdminForm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class DjangoGenericContactConfig(AppConfig): | ||
default_auto_field = "django.db.models.BigAutoField" | ||
name = "django_generic_contact" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Generated by Django 3.2.8 on 2021-10-05 14:13 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Contact", | ||
fields=[ | ||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), | ||
("creation_date", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), | ||
("data", models.JSONField(default=dict, verbose_name="meta data")), | ||
("name", models.CharField(max_length=255, verbose_name="name")), | ||
("message", models.TextField(verbose_name="message")), | ||
], | ||
options={ | ||
"abstract": False, | ||
}, | ||
), | ||
] |
18 changes: 18 additions & 0 deletions
18
django_generic_contact/migrations/0002_alter_contact_message.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 3.2.8 on 2021-10-07 08:08 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("django_generic_contact", "0001_initial"), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name="contact", | ||
name="message", | ||
field=models.TextField(blank=True, verbose_name="message"), | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from django.conf import settings | ||
from django.db import models | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
GENERIC_CONTACT_DATA_SCHEMA = getattr(settings, "GENERIC_CONTACT_DATA_SCHEMA", {}) | ||
|
||
|
||
class GenericContact(models.Model): | ||
|
||
creation_date = models.DateTimeField( | ||
verbose_name=_("Creation date"), | ||
blank=False, | ||
null=False, | ||
auto_now_add=True, | ||
) | ||
|
||
data = models.JSONField( | ||
_("meta data"), | ||
default=dict, | ||
) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
|
||
class Contact(GenericContact): | ||
|
||
name = models.CharField(_("name"), max_length=255) | ||
|
||
message = models.TextField(_("message"), blank=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.utils.translation import gettext_lazy as _ | ||
from django_generic_contact.models import GENERIC_CONTACT_DATA_SCHEMA | ||
from django_generic_contact.validators import JSONSchemaValidator | ||
|
||
|
||
def get_help_text(): | ||
return _("Meta data according to Schema: {schema}").format(schema=GENERIC_CONTACT_DATA_SCHEMA) | ||
|
||
|
||
def get_validators(): | ||
return [JSONSchemaValidator(limit_value=GENERIC_CONTACT_DATA_SCHEMA)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import jsonschema | ||
from django.core.exceptions import ValidationError | ||
from django.core.validators import BaseValidator | ||
|
||
|
||
class JSONSchemaValidator(BaseValidator): | ||
def compare(self, value, schema): | ||
try: | ||
jsonschema.validate(value, schema, format_checker=jsonschema.draft202012_format_checker) | ||
except jsonschema.exceptions.ValidationError as e: | ||
raise ValidationError(str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Package and package dependencies | ||
-e . | ||
|
||
# Development dependencies | ||
setuptools>=68.2.2,<68.3 | ||
wheel>=0.41.2,<0.42 | ||
twine>=4.0.2,<4.1 | ||
coverage>=7.3.2,<7.4 | ||
|
||
# Linters and formatters | ||
pre-commit>=3.5.0,<3.6 | ||
|
||
# TestApp dependencies | ||
django>=3.2,<4.3 | ||
jsonschema>=4.19.1,<4.20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import os | ||
|
||
from setuptools import find_packages, setup | ||
|
||
with open(os.path.join(os.path.dirname(__file__), "README.md")) as readme: | ||
README = readme.read() | ||
|
||
# allow setup.py to be run from any path | ||
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) | ||
|
||
setup( | ||
name="django-generic-contact", | ||
version=os.getenv("PACKAGE_VERSION", "1.0.0").replace("refs/tags/", ""), | ||
packages=find_packages(), | ||
include_package_data=True, | ||
license="MIT License", | ||
description="Django module to store contact request in a structured yet generic manner.", | ||
long_description=README, | ||
long_description_content_type="text/markdown", | ||
url="https://github.com/anexia/django-generic-contact", | ||
author="Alexandra Bruckner", | ||
author_email="[email protected]", | ||
install_requires=[], | ||
classifiers=[ | ||
"Development Status :: 5 - Production/Stable", | ||
"Framework :: Django", | ||
"Framework :: Django :: 3.2", | ||
"Framework :: Django :: 4.1", | ||
"Framework :: Django :: 4.2", | ||
"Intended Audience :: Developers", | ||
"License :: OSI Approved :: MIT License", | ||
"Operating System :: OS Independent", | ||
"Programming Language :: Python", | ||
"Programming Language :: Python :: 3", | ||
"Programming Language :: Python :: 3.8", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
], | ||
) |
Empty file.
Oops, something went wrong.