Source code for apps.utils.utils

# -*- coding: utf-8 -*-
"""
This module contains functions for sending email and SMS messages
to Remote Care users.

:subtitle:`Function definitions:`
"""
import messagebird
from datetime import date
from core.encryption.hash import create_hmac
from apps.mollie.api import Mollie
from apps.mollie.exceptions import MollieException
from apps.account.models import User
from django.conf import settings

from django.template import loader
from django.core.mail import EmailMultiAlternatives
from django.utils.html import strip_tags
from core.encryption.random import randomkey

from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string


[docs]def send_email_to(email_adres, email_content, subject='Remote Care - notificatie'): ''' Generic function for sending email to email_adres with email_content Args: - email_adres: the receiver of the email - email_content: the body of the email ''' from_email, to = 'remotecare@example.com', email_adres # this strips the html, so people will have the text as well. text_content = strip_tags(email_content) # create the email, and attach the HTML version as well. msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) msg.attach_alternative(email_content, "text/html") msg.send()
[docs]def send_authorisation_sms_to(mobile_number, auth_code): ''' Wrapper function for later usage Args: - mobile_number: the mobile number to sent auth_code to - auth_code: the SMS message to sent ''' send_sms_to(mobile_number, auth_code)
[docs]def send_sms_to_patient(patient, content): ''' Generic function for sending an SMS message to a patient Automatic strips the content so it fits within 160 characters. Args: - patient: the patient to sent the SMS to - content: The content of the SMS message ''' content = str(content) if len(content) > 160: content = content[:160] send_sms_to(patient.user.mobile_number, content)
[docs]def send_sms_to(mobile_number, auth_code): ''' Generic function which sents the sms using Mollie services. Args: - mobile_number: the mobile_number to sent the SMS message to - auth_code: The content of the SMS message ''' succes = False if not settings.MOLLIE_FAKE: # try: # Mollie.sendsms(username=settings.MOLLIE_USERNAME, # password=settings.MOLLIE_PASSWORD, # originator='RemoteCare', # recipients=mobile_number, # message=auth_code, # molliegw=Mollie.SECURE_MOLLIEGW, # gateway=Mollie.DUTCH_GW # ) # succes = True # except MollieException: # raise # succes = False try: client = messagebird.Client(settings.MESSAGE_BIRD_ACCESS_KEY) msg = client.message_create('RemoteCare', mobile_number, auth_code, {'reference': 'RemoteCare'}) print(msg.__dict__) except messagebird.client.ErrorException as e: raise success = False else: settings.SMS_STORE.append({'recipients': mobile_number, 'message': auth_code}) if not settings.AUTOMATIC_TESTING and settings.DEBUG: print(('sms_to: {0}, message: {1}'.format( mobile_number, auth_code))) return succes
[docs]def generic_sent_notification_to_patient(patient, sms_template, email_template, notification_setting): ''' Generic function which is used for sending regular control reminders to a patient Args: - patient: the patient to sent the message(s) to - sms_template: the sms message to sent to a patient - email_template: the email message to sent to a patient ''' current_date = date.today() context = { 'patient': patient, 'current_date': current_date, 'is_male': patient.user.gender == 'male'} do_sms = (notification_setting != 'email_only') do_email = (notification_setting != 'sms_only') if do_sms: sms_template = loader.get_template(sms_template) sms_content = sms_template.render(context) send_sms_to(patient.user.mobile_number, sms_content) if do_email: email_template = loader.get_template(email_template) email_content = email_template.render(context) send_email_to(patient.user.email, email_content)
[docs]def send_notification_of_new_report(patient): ''' Send a notification of a new report to a patient Args: - patient: the patient to sent the message(s) to ''' generic_sent_notification_to_patient( patient, 'utils/sms/report_notify_sms.html', 'utils/email/report_notify_email.html', patient.healthprofessional_handling_notification)
[docs]def send_notification_of_new_message(patient): ''' Send a notification of a new message to a patient Args: - patient: the patient to sent the message(s) to ''' generic_sent_notification_to_patient( patient, 'utils/sms/message_notify_sms.html', 'utils/email/message_notify_email.html', patient.message_notification)
[docs]def get_password_change_request(email_key): ''' Try to get the current password request and automatically remove expired ones. Args: - email_key: The original email_key stored in HMAC format in the\ passwordchangerequest. Returns: The associated PasswordChangeRequest instance or None ''' from apps.account.models import PasswordChangeRequest hmac_email_key = create_hmac(settings.EMAIL_KEY, str(email_key)) # Automatically remove expired requests try: passwordchangerequest = PasswordChangeRequest.objects.get( hmac_email_key=hmac_email_key) if passwordchangerequest.is_expired: passwordchangerequest.delete() return None else: return passwordchangerequest except PasswordChangeRequest.DoesNotExist: return None
[docs]def get_user_for_password_change_request(email_key): ''' Retrieves the user coupled to a password change_request Args: - email_key: The original email_key stored in HMAC format in the\ passwordchangerequest. Returns: The User for the associated PasswordChangeRequest instance or None ''' from apps.account.models import PasswordChangeRequest hmac_email_key = create_hmac(settings.EMAIL_KEY, str(email_key)) passwordchangerequest = PasswordChangeRequest.objects.get( hmac_email_key=hmac_email_key) return passwordchangerequest.user
[docs]def change_password(email_key, password, sms_code): ''' Change password by checking email_key, password and sms_code Args: - email_key: The original email_key stored in HMAC format in the\ passwordchangerequest. - password: the new password to set - sms_code: the SMS authorization code to check Returns: True if the password has been changed else False ''' from apps.account.models import PasswordChangeRequest from apps.account.models import OldPassword hmac_email_key = create_hmac(settings.EMAIL_KEY, str(email_key)) hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) passwordchangerequest = PasswordChangeRequest.objects.get( hmac_email_key=hmac_email_key) # Check if sms code is correct if passwordchangerequest.hmac_sms_code != hmac_sms_code: return False user = passwordchangerequest.user user.changed_by_user = user # Set password and add to old passwords for password validation rules user.set_password(password) OldPassword.objects.create(user=user, password_hash=user.password) user.save() password = None # delete the passwordchangerequest passwordchangerequest.delete() return True
[docs]def sent_password_change_sms(email_key, email, date_of_birth, sent_sms=True, sms_code=None): ''' Sent password change sms, last two parameters are for debugging which can be removed in production stage. Args: - email_key: The original email_key stored in HMAC format in the\ passwordchangerequest. - date_of_birth: the date_of_birth to check - sent_sms: need to sent SMS authorization code? (default=True) - sms_code: override sms authorization code Returns: True if the password change authorization SMS has been sent ''' from apps.account.models import PasswordChangeRequest hmac_email_key = create_hmac(settings.EMAIL_KEY, str(email_key)) passwordchangerequest = PasswordChangeRequest.objects.get( hmac_email_key=hmac_email_key) # Create random sms_code if not provided if not sms_code: sms_code = User.objects.make_random_password(length=8) hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) user = passwordchangerequest.user if user.email != email or user.date_of_birth != date_of_birth: return False passwordchangerequest.hmac_sms_code = hmac_sms_code passwordchangerequest.save() if sent_sms: send_authorisation_sms_to(user.mobile_number, sms_code) # Remove old reference sms_code = None return True
def send_password_change_email(url_prefix, request_id, email_adres, email_key, change_request_by_manager=False, new_account=False): from apps.account.models import PasswordChangeRequest ''' Function which sents the password reset e-mail containing a link to the password reset page. Args: - url_prefix: the url prefix to use in the email - request_id: the PasswordChangeRequest id - email_adres: the email_adres to sent the email to - email_key: the key to include in the email - change_request_by_manager: did a manager requested the change? - new_account: is this a new user? ''' passwordchangerequest = get_object_or_404( PasswordChangeRequest, pk=request_id) context = { 'passwordchangerequest': passwordchangerequest, 'email_key': email_key, 'url_prefix': url_prefix, 'change_request_by_manager': change_request_by_manager, 'new_account': new_account } html_content = render_to_string( 'emails/link_to_change_password_email.html', context=context) send_email_to(email_adres, html_content, 'Remote Care - Wachtwoord instellen')
[docs]def sent_password_change_request(user, url_prefix, change_request_by_manager=False, new_account=False): ''' Sent an e-mail with a password change request to an users e-mail address Args: - user: the user to sent the password change request email to. - url_prefix: the url prefix to use in the email - change_request_by_manager: is this change initialized by a manager? - new_account: is this a new user? ''' from apps.account.models import PasswordChangeRequest email_key = randomkey(40) hmac_email_key = create_hmac(settings.EMAIL_KEY, str(email_key)) passwordchangerequest = PasswordChangeRequest.objects.filter(user=user) # remove all past requests.. for pass_request in passwordchangerequest: pass_request.delete() # Create a new one.. passwordchangerequest = PasswordChangeRequest( user=user, hmac_email_key=hmac_email_key, attempt_nr=None) passwordchangerequest.save() # sent email send_password_change_email( url_prefix, passwordchangerequest.id, user.email, email_key, change_request_by_manager, new_account) # Set current password to invalid user.set_unusable_password() user.save()
# create and send sms_code..
[docs]def create_login_sms_code(user, send_sms=True, sms_code=None): ''' Create and sent a login SMS code to an user the sms_code is stored in HMAC format. Args: - user: the user to sent the login SMS authorization code to. - send_sms: do sent a SMS authorization code? (default=True) - sms_code: override the random sms_code ''' from apps.account.models import LoginSMSCode # Always use the same one, no need to create multiple instances [loginsmscode, created] = LoginSMSCode.objects.get_or_create(user=user) if not sms_code: sms_code = User.objects.make_random_password(length=8) hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) while ((LoginSMSCode.objects.filter( hmac_sms_code=hmac_sms_code).count() != 0)): sms_code = User.objects.make_random_password(length=8) hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) else: # DEBUG!! hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) LoginSMSCode.objects.filter(hmac_sms_code=hmac_sms_code).delete() loginsmscode.hmac_sms_code = hmac_sms_code if send_sms: send_authorisation_sms_to(user.mobile_number, sms_code) sms_code = None loginsmscode.save()
[docs]def check_login_sms_code(sms_code): ''' Check if the sms_code is correct, returns the user coupled to this sms_code which can be further validated. Args: - sms_code: the SMS authorization code sent during login, stored\ in HMAC form in a LoginSMSCode instance. Returns: The User instance for the login SMS authorization code or None ''' from apps.account.models import LoginSMSCode hmac_sms_code = create_hmac(settings.SMS_KEY, str(sms_code)) try: loginsmscode = LoginSMSCode.objects.get(hmac_sms_code=hmac_sms_code) except LoginSMSCode.DoesNotExist: loginsmscode = None if loginsmscode: return loginsmscode.user return None