Skip to content

Commit

Permalink
Merge pull request #5 from emencia/0.1.6
Browse files Browse the repository at this point in the history
0.1.6
  • Loading branch information
sam-b0t authored Jul 18, 2024
2 parents c83d1cf + c1c09c7 commit 7f43e77
Show file tree
Hide file tree
Showing 25 changed files with 547 additions and 89 deletions.
9 changes: 9 additions & 0 deletions docs/firm_info/admin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _intro_firm-admin:

=====
Admin
=====

.. automodule:: firm_info.admin
:members: UniqueModelAdmin
:exclude-members: has_add_permission
4 changes: 2 additions & 2 deletions docs/firm_info/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ Exceptions
==========

.. automodule:: firm_info.exceptions
:members: SerializeFirmError
:exclude-members: MyAppBaseException
:members:
:exclude-members:
9 changes: 9 additions & 0 deletions docs/firm_info/factories.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _intro_firm-factories:

=========
Factories
=========

.. automodule:: firm_info.factories
:members:
:exclude-members:
6 changes: 6 additions & 0 deletions docs/firm_info/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Django firm info

models.rst

admin.rst

factories.rst

settings.rst

serializers.rst

templatetags.rst
Expand Down
2 changes: 1 addition & 1 deletion docs/firm_info/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ Models
======

.. automodule:: firm_info.models
:members: FirmContact, Link, SocialSharing, Tracking, AppsBanner,
:members:
:exclude-members: DoesNotExist, MultipleObjectsReturned
2 changes: 1 addition & 1 deletion docs/firm_info/serializers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ Serializers
===========

.. automodule:: firm_info.serializers
:members: _format_address, serialize_firm_info, serialize_firm_social, serialize_firm_description, serialize_firm_social_sharing, serialize_firm_apps_banner
:members:
:exclude-members: DoesNotExist, MultipleObjectsReturned
9 changes: 9 additions & 0 deletions docs/firm_info/settings.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _intro_firm-settings:

========
Settings
========

.. automodule:: firm_info.settings
:members:
:exclude-members:
2 changes: 1 addition & 1 deletion docs/firm_info/templatetags.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ Templatetags
============

.. automodule:: firm_info.templatetags.firm_info
:members: firm_contact, firm_social_links, firm_description, firm_logos, firm_social_shares, firm_tag_analytic, app_banner
:members:
:exclude-members: DoesNotExist, MultipleObjectsReturned
44 changes: 28 additions & 16 deletions firm_info/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@
from .models import AppsBanner, FirmContact, Link, SocialSharing, Tracking


class UniqueModelAdmin(admin.ModelAdmin):
"""
A custom ModelAdmin that restricts the addition of model instances to only one.
This admin class overrides the default add permission to ensure that only one
instance of the associated model can exist at any given time.
If an instance already exists, it prohibits adding new instances.
"""

def has_add_permission(self, request):
existing_count = self.model.objects.count()
if existing_count == 0:
return super().has_add_permission(request)
else:
return False

def clean(self):
existing_count = self.model.objects.count()
if existing_count > 1:
# raise validation error if there is more than one firm contact
raise ValidationError(
_("Only one {} instance allowed.").format(self.model.__name__)
)


@admin.register(Link)
class LinkAdmin(admin.ModelAdmin):
pass
Expand All @@ -17,31 +42,18 @@ class LinkInline(admin.TabularInline):


@admin.register(FirmContact)
class ClientContactAdmin(admin.ModelAdmin):
class ClientContactAdmin(UniqueModelAdmin):
inlines = [LinkInline]
formfield_overrides = SmartModelAdmin.formfield_overrides

def has_add_permission(self, request):
existing_count = FirmContact.objects.count()
if existing_count == 0:
return super().has_add_permission(request)
else:
return False

def clean(self):
existing_count = FirmContact.objects.count()
if existing_count > 1:
# raise validation error if there is more than one firm contact
raise ValidationError(_("Only one FirmContact instance allowed."))


@admin.register(SocialSharing)
class SocialSharingAdmin(admin.ModelAdmin):
class SocialSharingAdmin(UniqueModelAdmin):
pass


@admin.register(Tracking)
class TrackingAdmin(admin.ModelAdmin):
class TrackingAdmin(UniqueModelAdmin):
pass


Expand Down
9 changes: 3 additions & 6 deletions firm_info/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""


class MyAppBaseException(Exception):
class FirmInfoException(Exception):
"""
Exception base.
Expand All @@ -13,9 +13,6 @@ class MyAppBaseException(Exception):
pass


class SerializeFirmError(MyAppBaseException):
"""
Exceptions related to FirmContact serialization errors
during template tag generation.
"""
class SerializeFirmError(FirmInfoException):
"""Exception raised when serializing firm data encounters an error."""
pass
41 changes: 38 additions & 3 deletions firm_info/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
from django.core.files import File

import factory
from firm_info.models import Tracking

from .models import AppsBanner, FirmContact
from firm_info.models import (
AppsBanner,
FirmContact,
SocialSharing,
Tracking
)


def create_image_file(filename=None, size=(100, 100), color="blue",
Expand Down Expand Up @@ -83,13 +87,21 @@ class Meta:
model = Tracking


def get_application_type(choice):
return choice[0]


class AppsBannerFactory(factory.django.DjangoModelFactory):
"""
Factory to create instance of a AppsBanner.
"""

title = factory.Faker("text", max_nb_chars=150)
description = factory.Faker("text", max_nb_chars=150)
application_type = factory.Iterator(
AppsBanner.APPS_CHOICES,
getter=get_application_type
)

class Meta:
model = AppsBanner
Expand All @@ -113,7 +125,7 @@ class FirmContactFactory(factory.django.DjangoModelFactory):

phone_number = factory.Faker("phone_number")
email = factory.Faker("email")
address = factory.Faker("address")
address = factory.Faker("street_address")
postal_code = factory.Faker("postcode")
city = factory.Faker("city")
country = factory.Faker("country")
Expand All @@ -134,3 +146,26 @@ def logo_invert(self):
@factory.lazy_attribute
def favicon(self):
return create_image_file()


class SocialSharingFactory(factory.django.DjangoModelFactory):
"""
Factory to create instance of a AppsBanner.
"""

og_twitter_site = factory.Faker("text", max_nb_chars=100)
og_description = factory.Faker("text", max_nb_chars=180)

class Meta:
model = SocialSharing

@factory.lazy_attribute
def og_image(self):
"""
Fill file field with generated image.
Returns:
django.core.files.File: File object.
"""

return create_image_file()
6 changes: 4 additions & 2 deletions firm_info/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from django.utils.translation import gettext_lazy as _


SINGLETON_ERROR = _("Model {model_name} has already one instance")


class SingletonManager(models.Manager):
"""
A manager to ensure that only one instance of the model exists.
Expand All @@ -16,8 +19,7 @@ class SingletonManager(models.Manager):
"""
def create(self, **kwargs):
if self.model.objects.exists():
error_message = _("Model {model_name} has already one instance")
raise ValueError(
error_message.format(model_name=self.model._meta.verbose_name)
SINGLETON_ERROR.format(model_name=self.model._meta.verbose_name)
)
return super().create(**kwargs)
12 changes: 6 additions & 6 deletions firm_info/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ class FirmContact(models.Model):
"""
Represents the contact information for a firm.
Args:
models.Model: The base model class provided by Django.
Attributes:
phone_number (CharField): The phone number of the firm.
email (EmailField): The email address of the firm.
Expand Down Expand Up @@ -131,6 +128,7 @@ class SocialSharing(models.Model):
og_image (SmartMediaField): The OG image for social media sharing.
og_description (TextField): The OG description for social media sharing.
og_twitter_site (CharField): The OG Twitter site for social media sharing.
objects (SingletonManager): The manager for the FirmContact model.
"""

og_image = SmartMediaField(
Expand All @@ -154,6 +152,8 @@ class SocialSharing(models.Model):
verbose_name=_("OG Twitter Site"),
)

objects = SingletonManager()

class Meta:
verbose_name = _("Social media share")
verbose_name_plural = _("Social media shares")
Expand All @@ -180,6 +180,7 @@ class Tracking(models.Model):
Attributes:
tag_analytic (CharField): The tag analytic for tracking.
objects (SingletonManager): The manager for the FirmContact model.
"""

tag_analytic = models.CharField(
Expand All @@ -190,6 +191,8 @@ class Tracking(models.Model):
verbose_name=_("Tag Analytic"),
)

objects = SingletonManager()

class Meta:
verbose_name = _("Tracking")
verbose_name_plural = _("Tracks")
Expand All @@ -199,9 +202,6 @@ class AppsBanner(models.Model):
"""
Represents an app banner in the Django firm_info models.
Args:
models.Model: The base model class provided by Django.
Attributes:
APPS_CHOICES (list): A list of tuples representing the available choices for
the application type.
Expand Down
Loading

0 comments on commit 7f43e77

Please sign in to comment.