Closed abe-101 closed 2 months ago
I am doing something similar with a custom InvitationModel and allauth's user_signed_up
signal. here are some snippets from my code.
class CustomInvitation(TimestampedUUIDModel, AbstractBaseInvitation):
email = models.EmailField(
unique=True,
verbose_name=_("e-mail address"),
max_length=app_settings.EMAIL_MAX_LENGTH,
)
created = models.DateTimeField(verbose_name=_("created"), default=timezone.now)
first_name = models.CharField(max_length=30, verbose_name=_("first name"))
last_name = models.CharField(max_length=30, verbose_name=_("last name"))
phone_number = models.CharField(
max_length=25,
verbose_name=_("phone number"),
blank=True,
)
driving_school = models.ForeignKey(DrivingSchool, on_delete=models.CASCADE, verbose_name=_("Driving School"))
role = models.CharField(max_length=30, choices=User.ROLE_CHOICES, verbose_name=_("Role"))
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
object_id = models.UUIDField(null=True, blank=True, verbose_name=_("Object ID"))
related_object = GenericForeignKey("content_type", "object_id")
invitation = CustomInvitation.create(
self.cleaned_data["contact_email"],
inviter=self.user, # You need to provide the user who sends the invitation
first_name=self.cleaned_data["contact_first_name"],
last_name=self.cleaned_data["contact_last_name"],
phone_number=self.cleaned_data["contact_phone_number"],
driving_school=driving_school,
role=User.ROLE_DRIVING_INSTRUCTOR,
related_object=instructor,
content_type=ContentType.objects.get_for_model(instructor),
object_id=instructor.pk,
)
invitation.sent = timezone.now()
invitation.save()
invitation.send_invitation(self.request)
from allauth.account.signals import user_signed_up
@receiver(user_signed_up)
def create_user_instance_on_signup(sender, **kwargs):
user = kwargs["user"]
try:
invitation = CustomInvitation.objects.get(email__iexact=user.email)
except CustomInvitation.DoesNotExist:
return
# get the role string from the invitation and add the user to the group with the same name
role = invitation.role
group = Group.objects.get(name=role)
user.groups.add(group)
user.first_name = invitation.first_name
user.last_name = invitation.last_name
user.phone_number = invitation.phone_number
user.role = role
# special case for driving school contacts, they are staff members and are allowed to access the admin
if role == User.ROLE_DRIVING_SCHOOL_CONTACT:
user.is_staff = True
elif role == User.ROLE_LEARNER_DRIVER:
license = invitation.related_object.license
# set status to STATUS_REDEEMED
license.status = license.STATUS_REDEEMED
license.redeemed_on = timezone.now()
license.save()
user.save()
related_object = invitation.related_object
related_object.user = user
related_object.save()
Thank you @krystofbe for sharing those snippets They've help me a lot in building my solution
I'm am curious though why you choose to subclass AbstractBaseInvitation
as apposed to Invitation
?
along those lines I'm curious how you went about implementing the create
send_invitation
and key_expired
methods, did you just copy from the Invitation
model?
Hi @abe-101,
There's no particular reason for choosing to subclass AbstractBaseInvitation over Invitation. It was a design choice that could have gone either way. You're absolutely correct that subclassing Invitation would have been just as viable.
Regarding the implementation of the create, send_invitation, and key_expired methods, yes, I initially copied them from the Invitation model. However, I customized them to fit the specific needs of the application I was working on. The idea was to leverage existing functionality while making necessary adjustments to align with the new subclass's requirements.
You've made a good point, and it's definitely something to consider for future design decisions. Subclassing directly from Invitation could simplify the process, especially if the modifications are minimal.
Thanks for your insight!
It looks like you've found a solution to your problem, and you don't need any changes to be made to django-allauth. I'm closing this issue. Let us know if I misunderstood.
@Flimm If you'd liek I can a section to the docs explaining this technique. We can keep this issue open or just open a new one
Hello,
I'm exploring the django-invitations library for a project and I have a specific requirement. I want to be able to invite a user such that when they accept the invitation, a new User instance is automatically created with a foreign key to another model. Additionally, I would like to specify the instance of the associated model at the time the invitation is created.
Is this functionality supported by the library? If not, could you provide guidance on how this might be implemented?
Thank you for your assistance.