Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated setting of site and root_url variables #5

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 115 additions & 69 deletions invitation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,9 @@
if getattr(settings, 'INVITATION_USE_ALLAUTH', False):
import re
SHA1_RE = re.compile('^[a-f0-9]{40}$')
else:
else:
from registration.models import SHA1_RE

# prevent error on initial syncdb for apps that incorporate django-invitaion
try:
site = Site.objects.get_current()
root_url = 'http://%s' % site.domain
except:
connection.close()


class InvitationKeyManager(models.Manager):
def get_key(self, invitation_key):
"""
Expand All @@ -49,9 +41,9 @@ def get_key(self, invitation_key):
key = self.get(key=invitation_key)
except self.model.DoesNotExist:
return None

return key

def is_key_valid(self, invitation_key):
"""
Check if an ``InvitationKey`` is valid or not, returning a valid key
Expand All @@ -62,22 +54,44 @@ def is_key_valid(self, invitation_key):
return invitation_key
return False

def create_invitation(self, user, recipient=('[email protected]', 'Sirname', 'Lastname' ), save=True):
def create_invitation(
self,
user,
recipient=('[email protected]', 'Sirname', 'Lastname'),
save=True
):
"""
Create an ``InvitationKey`` and returns it.
The key for the ``InvitationKey`` will be a SHA1 hash, generated

The key for the ``InvitationKey`` will be a SHA1 hash, generated
from a combination of the ``User``'s username and a random salt.
"""
salt = sha_constructor(str(random.random())).hexdigest()[:5]
key = sha_constructor("%s%s%s" % (datetime.datetime.now(), salt, user.username)).hexdigest()
key = sha_constructor("%s%s%s" % (
datetime.datetime.now(),
salt,
user.username
)).hexdigest()
if not save:
return InvitationKey(from_user=user, key='previewkey00000000', recipient=recipient, date_invited=datetime.datetime.now())
return InvitationKey(
from_user=user,
key='previewkey00000000',
recipient=recipient,
date_invited=datetime.datetime.now()
)
return self.create(from_user=user, key=key, recipient=recipient)

def create_bulk_invitation(self, user, key, uses, recipient):
""" Create a set of invitation keys - these can be used by anyone, not just a specific recipient """
return self.create(from_user=user, key=key, uses_left=uses, recipient=None)
"""
Create a set of invitation keys - these can be used by anyone,
not just a specific recipient
"""
return self.create(
from_user=user,
key=key,
uses_left=uses,
recipient=None
)

def remaining_invitations_for_user(self, user):
"""
Expand All @@ -96,43 +110,49 @@ def delete_expired_keys(self):

class InvitationKey(models.Model):
key = models.CharField(_('invitation key'), max_length=40)
date_invited = models.DateTimeField(_('date invited'),
date_invited = models.DateTimeField(_('date invited'),
auto_now_add=True)
from_user = models.ForeignKey(User,
from_user = models.ForeignKey(User,
related_name='invitations_sent')
registrant = models.ManyToManyField(User, null=True, blank=True,
registrant = models.ManyToManyField(User, null=True, blank=True,
related_name='invitations_used')
uses_left = models.IntegerField(default=1)

objects = InvitationKeyManager()

recipient = PickledObjectField(default=None, null=True)


def __init__(self, *args, **kwargs):
super(InvitationKey, self).__init__(*args, **kwargs)
self.site = Site.objects.get_current()
self.root_url = 'http://%s' % self.site.domain


def __unicode__(self):
return u"Invitation from %s on %s (%s)" % (self.from_user.username, self.date_invited, self.key)

def is_usable(self):
"""
Return whether this key is still valid for registering a new user.
Return whether this key is still valid for registering a new user.
"""
return self.uses_left > 0 and not self.key_expired()

def key_expired(self):
"""
Determine whether this ``InvitationKey`` has expired, returning
Determine whether this ``InvitationKey`` has expired, returning
a boolean -- ``True`` if the key has expired.
The date the key has been created is incremented by the number of days
specified in the setting ``ACCOUNT_INVITATION_DAYS`` (which should be

The date the key has been created is incremented by the number of days
specified in the setting ``ACCOUNT_INVITATION_DAYS`` (which should be
the number of days after invite during which a user is allowed to
create their account); if the result is less than or equal to the
create their account); if the result is less than or equal to the
current date, the key has expired and this method returns ``True``.

"""
expiration_date = datetime.timedelta(days=settings.ACCOUNT_INVITATION_DAYS)
return self.date_invited + expiration_date <= now()
key_expired.boolean = True

def mark_used(self, registrant):
"""
Note that this key has been used to register a new user.
Expand All @@ -141,62 +161,79 @@ def mark_used(self, registrant):
self.registrant.add(registrant)
default_storage.delete('tokens/%s.png' % self.key)
self.save()

def get_context(self, sender_note=None):
invitation_url = root_url + reverse('invitation_invited', kwargs={'invitation_key':self.key})
invitation_url = self.root_url + reverse('invitation_invited', kwargs={'invitation_key':self.key})
exp_date = self.date_invited + datetime.timedelta(days=settings.ACCOUNT_INVITATION_DAYS)
context = { 'invitation_key': self,
'expiration_days': settings.ACCOUNT_INVITATION_DAYS,
'from_user': self.from_user,
'sender_note': sender_note,
'site': site,
'root_url': root_url,
'expiration_date': exp_date,
'recipient': self.recipient,
'token': self.generate_token(invitation_url),
'invitation_url':invitation_url}
context = {
'invitation_key': self,
'expiration_days': settings.ACCOUNT_INVITATION_DAYS,
'from_user': self.from_user,
'sender_note': sender_note,
'site': self.site,
'root_url': self.root_url,
'expiration_date': exp_date,
'recipient': self.recipient,
'token': self.generate_token(invitation_url),
'invitation_url': invitation_url
}
return context

def send_to(self, from_email=settings.DEFAULT_FROM_EMAIL, sender_note=None,):

def send_to(
self,
from_email=settings.DEFAULT_FROM_EMAIL,
sender_note=None
):
"""
Send an invitation email to ``email``.
"""
context = self.get_context(sender_note)

subject = render_to_string('invitation/invitation_email_subject.txt', context)

subject = render_to_string(
'invitation/invitation_email_subject.txt',
context
)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())

message_html = render_to_string('invitation/invitation_email.html',context)
message_html = render_to_string(
'invitation/invitation_email.html',
context
)
context.update({'sender_note':mark_safe(strip_tags(sender_note))})
message = render_to_string('invitation/invitation_email.txt',context)
msg = EmailMultiAlternatives(subject, message, from_email, [self.recipient[0]])
message = render_to_string('invitation/invitation_email.txt', context)
msg = EmailMultiAlternatives(
subject,
message,
from_email,
[self.recipient[0]]
)
msg.attach_alternative(message_html, "text/html")
msg.send()

def generate_token(self, invitation_url):
def stamp(image, text, offset):
f = ImageFont.load_default()
txt_img=Image.new('RGBA', f.getsize(text))
txt_img = Image.new('RGBA', f.getsize(text))
d = ImageDraw.Draw(txt_img)
d.text( (0, 0), text, font=f, fill="#888")
exp_img_r = txt_img.rotate(0, expand=1)
d.text((0, 0), text, font=f, fill="#888")
exp_img_r = txt_img.rotate(0, expand=1)
iw, ih = image.size
tw, th = txt_img.size
x = iw/2 - tw/2
y = ih/2 - th/2
image.paste( exp_img_r, (x,y+offset), exp_img_r)
image.paste(exp_img_r, (x, y+offset), exp_img_r)
return offset+th

#normalize sataic url
r_parse = urlparse(root_url, 'http')
r_parse = urlparse(self.root_url, 'http')
s_parse = urlparse(settings.STATIC_URL, 'http')
s_parts = (s_parse.scheme, s_parse.netloc or r_parse.netloc, s_parse.path, s_parse.params, s_parse.query, s_parse.fragment)
static_url = urlunparse(s_parts)

#open base token image
img_url = static_url+'notification/img/token-invite.png'
temp_img = NamedTemporaryFile()
temp_img = NamedTemporaryFile()
temp_img.write(urllib2.urlopen(img_url).read())
temp_img.flush()
image = Image.open(temp_img.name)
Expand All @@ -214,18 +251,18 @@ def stamp(image, text, offset):
image.save(temp_img.name, "PNG", quality=95)
if not default_storage.exists('tokens/%s.png' % self.key):
default_storage.save('tokens/%s.png' % self.key, File(temp_img))
get_token_url = root_url+reverse('invitation_token', kwargs={'key':self.key})
get_token_url = self.root_url+reverse('invitation_token', kwargs={'key':self.key})
token_html = '<a style="display: inline-block;" href="'+invitation_url+'"><img width="100" height="100" class="token" src="'+get_token_url+'" alt="invitation token"></a>'
return token_html

class InvitationUser(models.Model):
inviter = models.ForeignKey(User, unique=True)
invitations_remaining = models.IntegerField()

def __unicode__(self):
return u"InvitationUser for %s" % self.inviter.username


def user_post_save(sender, instance, created, **kwargs):
"""Create InvitationUser for user when User is created."""
if created:
Expand All @@ -243,12 +280,17 @@ def user_post_save(sender, instance, created, **kwargs):
def invitation_key_post_save(sender, instance, created, **kwargs):
"""Decrement invitations_remaining when InvitationKey is created."""
if created:
invitation_user = InvitationUser.objects.get(inviter=instance.from_user)
invitation_user = InvitationUser.objects.get(
inviter=instance.from_user
)
remaining = invitation_user.invitations_remaining
invitation_user.invitations_remaining = remaining-1
invitation_user.save()

models.signals.post_save.connect(invitation_key_post_save, sender=InvitationKey)
models.signals.post_save.connect(
invitation_key_post_save,
sender=InvitationKey
)

def invitation_key_pre_delete(sender, instance, **kwargs):
"""Delete token image."""
Expand All @@ -257,4 +299,8 @@ def invitation_key_pre_delete(sender, instance, **kwargs):
except:
pass

models.signals.post_delete.connect(invitation_key_pre_delete, sender=InvitationKey)
models.signals.post_delete.connect(
invitation_key_pre_delete,
sender=InvitationKey
)