datawinners/entity/view/send_sms.py
import ast
import json
import datetime
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.generic import View
from datawinners import utils
from datawinners.accountmanagement.decorators import session_not_expired, is_not_expired, is_datasender
from datawinners.accountmanagement.models import OrganizationSetting, NGOUserProfile
from datawinners.main.database import get_database_manager
from datawinners.project.helper import broadcast_message
from datawinners.scheduler.smsclient import NoSMSCException
from datawinners.search.all_datasender_search import get_all_datasenders_search_results
from datawinners.search.datasender_index import update_datasender_index_by_id
from datawinners.search.index_utils import safe_getattr
from datawinners.sent_message.models import PollInfo
from datawinners.utils import strip_accents, lowercase_and_strip_accents, get_organization_from_manager
from mangrove.datastore.entity import contact_by_short_code
from mangrove.form_model.project import Project
class SendSMS(View):
def _other_numbers(self, request):
if request.POST['recipient'] == 'others':
numbers = map(lambda i: i.strip(), request.POST['others'].split(","))
return list(set(numbers))
return []
def _mobile_numbers_for_questionnaire(self, dbm, questionnaire_names):
search_parameters = {'void': False, 'search_filters': {'projects': questionnaire_names}}
return _get_all_contacts_mobile_numbers(dbm, search_parameters)
def get_contact_details(self, dbm, request):
questionnaire_names = map(lambda item: lowercase_and_strip_accents(item),
json.loads(request.POST['questionnaire-names']))
search_parameters = {'void': False, 'search_filters': {'projects': questionnaire_names}}
mobile_numbers, contact_display_list = _get_all_contacts_details(dbm, search_parameters)
return mobile_numbers, contact_display_list
def _mobile_numbers_for_groups(self, dbm, group_names):
search_parameters = {'void': False, 'search_filters': {'group_names': group_names}}
return _get_all_contacts_mobile_numbers(dbm, search_parameters)
def _get_mobile_number_for_contacts(self, dbm, poll_recipients, recipient_option):
if recipient_option == 'poll_recipients':
poll_recipients = ast.literal_eval(poll_recipients)
mobile_numbers = []
for poll_recipient in poll_recipients:
contact = contact_by_short_code(dbm, poll_recipient)
mobile_numbers.append(contact.data.get('mobile_number')['value'])
return mobile_numbers
else:
return []
def _get_mobile_numbers_for_registered_data_senders(self, dbm, request):
if request.POST['recipient'] == 'linked':
questionnaire_names = map(lambda item: lowercase_and_strip_accents(item),
json.loads(request.POST['questionnaire-names']))
mobile_numbers = self._mobile_numbers_for_questionnaire(dbm, questionnaire_names)
return mobile_numbers
else:
return []
def _get_mobile_numbers_for_specific_contacts(self, dbm, request):
if request.POST['recipient'] == 'specific-contacts':
numbers = map(lambda i: i.strip(), request.POST['others'].split(","))
return numbers
else:
return []
def _get_mobile_numbers_for_groups(self, dbm, request):
if request.POST['recipient'] == 'group':
group_names = json.loads(request.POST['group-names'])
mobile_numbers = self._mobile_numbers_for_groups(dbm, group_names)
return mobile_numbers
else:
return []
def _get_sender_details(self, organization_setting):
return NGOUserProfile.objects.filter(org_id=organization_setting.organization.org_id)[
0].user.first_name + " ("+ \
NGOUserProfile.objects.filter(org_id=organization_setting.organization.org_id)[0].reporter_id + ")"
def _associate_datasender_to_poll_questionnaire(self, current_project_id, dbm, short_codes):
questionnaire = Project.get(dbm, current_project_id)
questionnaire.associate_data_sender_to_project(dbm, short_codes)
questionnaire.save()
for short_code in short_codes:
update_datasender_index_by_id(short_code, dbm)
def _log_poll_questionnaire_sent_messages(self, dbm, organization, organization_setting, request, sms_text, current_project_id, failed_numbers):
mobile_numbers, contact_dict, short_codes = get_contact_details(dbm, request, failed_numbers)
user_profile = self._get_sender_details(organization_setting)
if mobile_numbers:
self._associate_datasender_to_poll_questionnaire(current_project_id, dbm, short_codes)
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self._save_sent_message_info(organization.org_id, current_time, sms_text, contact_dict,
user_profile, current_project_id)
def post(self, request, *args, **kwargs):
dbm = get_database_manager(request.user)
sms_text = request.POST['sms-text']
other_numbers = self._other_numbers(request)
organization = utils.get_organization(request)
organization_setting = OrganizationSetting.objects.get(organization=organization)
current_month = datetime.date(datetime.datetime.now().year, datetime.datetime.now().month, 1)
message_tracker = organization._get_message_tracker(current_month)
no_smsc = False
mobile_numbers_for_ds_linked_to_questionnaire = self._get_mobile_numbers_for_registered_data_senders(dbm,
request)
mobile_numbers_for_specific_contacts = self._get_mobile_numbers_for_specific_contacts(dbm, request)
mobile_numbers_for_ds_linked_to_group = self._get_mobile_numbers_for_groups(dbm, request)
mobile_numbers_for_ds = self._get_mobile_number_for_contacts(dbm, request.POST['my_poll_recipients'], request.POST['recipient'] )
mobile_numbers = mobile_numbers_for_ds_linked_to_questionnaire + mobile_numbers_for_ds_linked_to_group + \
mobile_numbers_for_specific_contacts + mobile_numbers_for_ds
failed_numbers = []
try:
failed_numbers = broadcast_message(mobile_numbers, sms_text,
organization_setting.get_organisation_sms_number()[0],
other_numbers, message_tracker,
country_code=organization.get_phone_country_code())
# log sent messages only for poll questionnaire
current_project_id = json.loads(request.POST['project_id'])
if current_project_id != "":
self._log_poll_questionnaire_sent_messages(dbm, organization, organization_setting, request, sms_text, current_project_id, failed_numbers)
except NoSMSCException:
no_smsc = True
successful = len(failed_numbers) == 0 and not no_smsc
return HttpResponse(json.dumps({'successful': successful, 'nosmsc': no_smsc, 'failednumbers': failed_numbers}))
@method_decorator(login_required)
@method_decorator(session_not_expired)
@method_decorator(is_not_expired)
def dispatch(self, *args, **kwargs):
return super(SendSMS, self).dispatch(*args, **kwargs)
def _save_sent_message_info(self, org_id, sent_on, sms_text, to_mobile_numbers, from_mobile_numbers, questionnaire_name):
poll_info_message = PollInfo(org_id=org_id, sent_on=sent_on, message=sms_text,
recipients=str(to_mobile_numbers), sender=str(from_mobile_numbers), questionnaire_id=questionnaire_name)
poll_info_message.save()
def _get_all_contacts_mobile_numbers(dbm, search_parameters):
search_parameters['response_fields'] = ['mobile_number']
search_results = get_all_datasenders_search_results(dbm, search_parameters)
return [safe_getattr(item, 'mobile_number')[0] for item in search_results.hits]
def get_name_short_code_mobile_numbers_for_contacts(dbm, poll_recipients, failed_numbers):
short_codes = []
poll_recipients = ast.literal_eval(poll_recipients)
mobile_numbers = []
contact_dict_list = []
for poll_recipient in poll_recipients:
contact = contact_by_short_code(dbm, poll_recipient)
contact_mobile_number = contact.data.get('mobile_number')['value']
if contact_mobile_number not in failed_numbers:
mobile_numbers.append(contact.data.get('mobile_number')['value'])
if contact.name != "":
contact_dict_list.append("%s (%s)" % (contact.name, contact.short_code))
else:
contact_dict_list.append("%s (%s)" % (contact.data['mobile_number']['value'], contact.short_code))
short_codes.append(contact.short_code)
return mobile_numbers, contact_dict_list, short_codes
def _get_contact_details_for_questionnaire(dbm, failed_numbers, request):
questionnaire_names = map(lambda item: lowercase_and_strip_accents(item),
json.loads(request.POST['questionnaire-names']))
search_parameters = {'void': False, 'search_filters': {'projects': questionnaire_names}}
mobile_numbers, contact_display_list, short_codes = _get_all_contacts_details_with_mobile_number(dbm, search_parameters,
failed_numbers)
return contact_display_list, mobile_numbers, short_codes
def _get_contact_details_for_group_names(dbm, failed_numbers, request):
group_names = json.loads(request.POST['group-names'])
search_parameters = {'void': False, 'search_filters': {'group_names': group_names}}
mobile_numbers, contact_display_list, short_codes = _get_all_contacts_details_with_mobile_number(dbm, search_parameters,
failed_numbers)
return contact_display_list, mobile_numbers, short_codes
def get_contact_details(dbm, request, failed_numbers):
mobile_numbers = []
contact_display_list = []
short_codes = []
if request.POST['recipient'] == 'linked':
contact_display_list, mobile_numbers, short_codes = _get_contact_details_for_questionnaire(dbm, failed_numbers, request)
elif request.POST['recipient'] == 'group':
contact_display_list, mobile_numbers, short_codes = _get_contact_details_for_group_names(dbm, failed_numbers, request)
elif request.POST['recipient'] == 'poll_recipients':
mobile_numbers, contact_display_list, short_codes = get_name_short_code_mobile_numbers_for_contacts(dbm, request.POST['my_poll_recipients'], failed_numbers)
return mobile_numbers, contact_display_list, short_codes
def _get_all_contacts_details(dbm, search_parameters):
search_parameters['response_fields'] = ['short_code', 'name', 'mobile_number']
search_results = get_all_datasenders_search_results(dbm, search_parameters)
mobile_numbers, contact_display_list = [], []
for entry in search_results.hits:
mobile_numbers.append(safe_getattr(entry, 'mobile_number')[0])
display_prefix = safe_getattr(entry, 'name')[0] if safe_getattr(entry, 'name') else safe_getattr(entry, 'mobile_number')[0]
short_code = (safe_getattr(entry, 'short_code')[0])
contact_display_list.append("%s (%s)" % (display_prefix, short_code))
return mobile_numbers, contact_display_list
def _get_all_contacts_details_with_mobile_number(dbm, search_parameters, failed_numbers):
short_codes = []
search_parameters['response_fields'] = ['short_code', 'name', 'mobile_number']
search_results = get_all_datasenders_search_results(dbm, search_parameters)
mobile_numbers, contact_display_list = [], []
for entry in search_results.hits:
mobile_number = safe_getattr(entry, 'mobile_number')[0]
if mobile_number not in failed_numbers:
mobile_numbers.append(mobile_number)
display_prefix = safe_getattr(entry, 'name')[0] if safe_getattr(entry, 'name') else mobile_number
short_code = safe_getattr(entry, 'short_code')[0] if safe_getattr(entry, 'short_code') else safe_getattr(entry, 'short_code')
contact_display_list.append("%s (%s)" % (display_prefix, short_code))
short_codes.append(short_code)
return mobile_numbers, contact_display_list, short_codes
@login_required
@session_not_expired
@is_datasender
@is_not_expired
def get_all_mobile_numbers(request):
dbm = get_database_manager(request.user)
search_parameters = {'group_name': request.POST.get('group_name'), 'query_string': request.POST.get('search_query')}
mobile_numbers, contact_display_list = _get_all_contacts_details(dbm, search_parameters)
response = {'mobile_numbers': ", ".join(mobile_numbers), 'contact_display_list': ", ".join(contact_display_list)}
return HttpResponse(json.dumps(response))