def export_contacts(account_key, contact_keys, include_extra=True): """ Export a list of contacts as a CSV file and email to the account holders' email address. :param str account_key: The account holders account key :param str contact_keys: The keys of the contacts to export :param bool include_extra: Whether or not to include the extra data stored in the dynamic field. """ api = VumiUserApi.from_config_sync(account_key, settings.VUMI_API_CONFIG) contact_store = api.contact_store contacts = contacts_by_key(contact_store, *contact_keys) data = contacts_to_csv(contacts, include_extra) file = zipped_file('contacts-export.csv', data) # Get the profile for this user so we can email them when the import # has been completed. user_profile = UserProfile.objects.get(user_account=account_key) email = EmailMessage( 'Contacts export', 'Please find the CSV data for %s contact(s)' % len(contacts), settings.DEFAULT_FROM_EMAIL, [user_profile.user.email]) email.attach('contacts-export.zip', file, 'application/zip') email.send()
def _smart_group(request, contact_store, group): if request.method == 'POST': if '_save_group' in request.POST: smart_group_form = SmartGroupForm(request.POST) if smart_group_form.is_valid(): group.name = smart_group_form.cleaned_data['name'] group.query = smart_group_form.cleaned_data['query'] group.save() return redirect(_group_url(group.key)) elif '_export' in request.POST: tasks.export_group_contacts.delay( request.user_api.user_account_key, group.key, True) messages.info( request, 'The export is scheduled and should ' 'complete within a few minutes.') return redirect(_group_url(group.key)) elif '_delete_group_contacts' in request.POST: tasks.delete_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info(request, "The group's contacts will be deleted shortly.") return redirect(_group_url(group.key)) elif '_delete_group' in request.POST: tasks.delete_group.delay(request.user_api.user_account_key, group.key) messages.info(request, 'The group will be deleted shortly.') return redirect(reverse('contacts:index')) else: # We didn't get any useful POST variables, so just redirect back to # the group page without doing anything. return redirect(_group_url(group.key)) else: smart_group_form = SmartGroupForm({ 'name': group.name, 'query': group.query, }) keys = contact_store.get_contacts_for_group(group) limit = min(int(request.GET.get('limit', 100)), len(keys)) if keys: messages.info( request, "Showing %s of the group's %s contact(s)" % (limit, len(keys))) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) return render( request, 'contacts/smart_group_detail.html', { 'group': group, 'selected_contacts': contacts, 'group_form': smart_group_form, })
def _smart_group(request, contact_store, group): if request.method == 'POST': if '_save_group' in request.POST: smart_group_form = SmartGroupForm(request.POST) if smart_group_form.is_valid(): group.name = smart_group_form.cleaned_data['name'] group.query = smart_group_form.cleaned_data['query'] group.save() return redirect(_group_url(group.key)) elif '_export' in request.POST: tasks.export_group_contacts.delay( request.user_api.user_account_key, group.key, True) messages.info(request, 'The export is scheduled and should ' 'complete within a few minutes.') return redirect(_group_url(group.key)) elif '_delete_group_contacts' in request.POST: tasks.delete_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info( request, "The group's contacts will be deleted shortly.") return redirect(_group_url(group.key)) elif '_delete_group' in request.POST: tasks.delete_group.delay(request.user_api.user_account_key, group.key) messages.info(request, 'The group will be deleted shortly.') return redirect(reverse('contacts:index')) else: # We didn't get any useful POST variables, so just redirect back to # the group page without doing anything. return redirect(_group_url(group.key)) else: smart_group_form = SmartGroupForm({ 'name': group.name, 'query': group.query, }) keys = contact_store.get_contacts_for_group(group) limit = min(int(request.GET.get('limit', 100)), len(keys)) if keys: messages.info( request, "Showing %s of the group's %s contact(s)" % (limit, len(keys))) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) return render(request, 'contacts/smart_group_detail.html', { 'group': group, 'selected_contacts': contacts, 'group_form': smart_group_form, })
def get_group_contacts(contact_store, *groups): contact_keys = [] for group in groups: contact_keys.extend(contact_store.get_contacts_for_group(group)) return contacts_by_key(contact_store, *contact_keys)
def _people(request): contact_store = request.user_api.contact_store upload_contacts_form = None group = None if request.method == 'POST': if '_delete' in request.POST: contacts = request.POST.getlist('contact') for person_key in contacts: contact = contact_store.get_contact_by_key(person_key) contact.delete() messages.info(request, '%d Contacts deleted' % len(contacts)) elif '_export' in request.POST: tasks.export_contacts.delay( request.user_api.user_account_key, request.POST.getlist('contact')) messages.info(request, 'The export is scheduled and should ' 'complete within a few minutes.') elif '_export_all' in request.POST: tasks.export_all_contacts.delay( request.user_api.user_account_key) messages.info(request, 'The export is scheduled and should ' 'complete within a few minutes.') else: # first parse the CSV file and create Contact instances # from them for attaching to a group later upload_contacts_form = UploadContactsForm( request.POST, request.FILES) if upload_contacts_form.is_valid(): # We could be creating a new contact group. if request.POST.get('name'): new_group_form = ContactGroupForm(request.POST) if new_group_form.is_valid(): group = contact_store.new_group( new_group_form.cleaned_data['name']) # We could be using an existing contact group. elif request.POST.get('contact_group'): select_group_form = SelectContactGroupForm( request.POST, groups=contact_store.list_groups()) if select_group_form.is_valid(): group = contact_store.get_group( select_group_form.cleaned_data['contact_group']) if group is None: messages.error(request, 'Please select a group or provide ' 'a new group name.') else: file_object = upload_contacts_form.cleaned_data['file'] file_name, file_path = utils.store_temporarily(file_object) utils.store_file_hints_in_session( request, file_name, file_path) return redirect(_group_url(group.key)) else: messages.error( request, 'Something went wrong with the upload.') select_contact_group_form = SelectContactGroupForm( groups=contact_store.list_groups()) # TODO: A lot of this stuff is duplicated from the similar group search # in the groups() view. We need a function that does that to avoid # the duplication. user_query = request.GET.get('q', '') query = user_query if query: if not ':' in query: query = 'name:%s' % (query,) keys = contact_store.contacts.raw_search(query).get_keys() else: keys = contact_store.list_contacts() limit = min(int(request.GET.get('limit', 100)), len(keys)) messages.info(request, "Showing %s of %s contact(s)" % (limit, len(keys))) smart_group_form = SmartGroupForm(initial={'query': query}) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) return render(request, 'contacts/contact_list.html', { 'query': user_query, 'selected_contacts': contacts, 'smart_group_form': smart_group_form, 'upload_contacts_form': upload_contacts_form or UploadContactsForm(), 'select_contact_group_form': select_contact_group_form, })
def _static_group(request, contact_store, group): if group is None: raise Http404 if request.method == 'POST': group_form = ContactGroupForm(request.POST) if '_save_group' in request.POST: if group_form.is_valid(): group.name = group_form.cleaned_data['name'] group.save() messages.info(request, 'The group name has been updated') return redirect(_group_url(group.key)) elif '_export' in request.POST: tasks.export_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info(request, 'The export is scheduled and should ' 'complete within a few minutes.') return redirect(_group_url(group.key)) elif '_remove' in request.POST: contacts = request.POST.getlist('contact') for person_key in contacts: contact = contact_store.get_contact_by_key(person_key) contact.groups.remove(group) contact.save() messages.info( request, '%d Contacts removed from group' % len(contacts)) return redirect(_group_url(group.key)) elif '_delete_group_contacts' in request.POST: tasks.delete_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info(request, "The group's contacts will be deleted shortly.") return redirect(_group_url(group.key)) elif '_delete_group' in request.POST: tasks.delete_group.delay(request.user_api.user_account_key, group.key) messages.info(request, 'The group will be deleted shortly.') return redirect(reverse('contacts:index')) elif '_complete_contact_upload' in request.POST: try: import_rule = request.POST.get('import_rule') import_handler = { 'existing_is_truth': handle_import_existing_is_truth, 'upload_is_truth': handle_import_upload_is_truth, }.get(import_rule, handle_import_new_contacts) import_handler(request, group) messages.info( request, 'The contacts are being imported. ' 'We will notify you via email when the import ' 'has been completed') except (ContactParserException,): messages.error(request, 'Something is wrong with the file') _, file_path = utils.get_file_hints_from_session(request) default_storage.delete(file_path) return redirect(_group_url(group.key)) else: upload_contacts_form = UploadContactsForm(request.POST, request.FILES) if upload_contacts_form.is_valid(): file_object = upload_contacts_form.cleaned_data['file'] file_name, file_path = utils.store_temporarily(file_object) utils.store_file_hints_in_session( request, file_name, file_path) return redirect(_group_url(group.key)) else: # We didn't get any useful POST variables, so just redirect # back to the group page without doing anything. return redirect(_group_url(group.key)) else: group_form = ContactGroupForm({ 'name': group.name, }) context = { 'group': group, 'group_form': group_form, } if 'clear-upload' in request.GET: # FIXME this is a debug statement utils.clear_file_hints_from_session(request) if utils.has_uncompleted_contact_import(request): try: file_name, file_path = utils.get_file_hints_from_session(request) file_type, parser = ContactFileParser.get_parser(file_name) has_header, headers, row = parser.guess_headers_and_row(file_path) context.update({ 'contact_data_headers': headers, 'field_normalizer': FieldNormalizer(), 'contact_data_row': row, # NOTE: Only if we have a key (contact UUID) value in the # row we can look at updating contacts instead of # only writing new ones. 'can_update_contacts': 'key' in row, }) except (ValueError, ContactParserException): messages.error(request, 'Something is wrong with the file') utils.clear_file_hints_from_session(request) default_storage.delete(file_path) query = request.GET.get('q', '') if query: if not ':' in query: query = 'name:%s' % (query,) keys = contact_store.contacts.raw_search(query).get_keys() else: keys = contact_store.get_contacts_for_group(group) limit = min(int(request.GET.get('limit', 100)), len(keys)) if keys: messages.info( request, "Showing %s of the group's %s contact(s)" % (limit, len(keys))) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) context.update({ 'query': request.GET.get('q'), 'selected_contacts': contacts, 'member_count': contact_store.count_contacts_for_group(group), }) return render(request, 'contacts/static_group_detail.html', context)
def _people(request): contact_store = request.user_api.contact_store upload_contacts_form = None group = None if request.method == 'POST': if '_delete' in request.POST: contacts = request.POST.getlist('contact') for person_key in contacts: contact = contact_store.get_contact_by_key(person_key) contact.delete() messages.info(request, '%d Contacts deleted' % len(contacts)) elif '_export' in request.POST: tasks.export_contacts.delay(request.user_api.user_account_key, request.POST.getlist('contact')) messages.info( request, 'The export is scheduled and should ' 'complete within a few minutes.') elif '_export_all' in request.POST: tasks.export_all_contacts.delay(request.user_api.user_account_key) messages.info( request, 'The export is scheduled and should ' 'complete within a few minutes.') else: # first parse the CSV file and create Contact instances # from them for attaching to a group later upload_contacts_form = UploadContactsForm(request.POST, request.FILES) if upload_contacts_form.is_valid(): # We could be creating a new contact group. if request.POST.get('name'): new_group_form = ContactGroupForm(request.POST) if new_group_form.is_valid(): group = contact_store.new_group( new_group_form.cleaned_data['name']) # We could be using an existing contact group. elif request.POST.get('contact_group'): select_group_form = SelectContactGroupForm( request.POST, groups=contact_store.list_groups()) if select_group_form.is_valid(): group = contact_store.get_group( select_group_form.cleaned_data['contact_group']) if group is None: messages.error( request, 'Please select a group or provide ' 'a new group name.') else: file_object = upload_contacts_form.cleaned_data['file'] file_name, file_path = utils.store_temporarily(file_object) utils.store_file_hints_in_session(request, file_name, file_path) return redirect(_group_url(group.key)) else: messages.error(request, 'Something went wrong with the upload.') select_contact_group_form = SelectContactGroupForm( groups=contact_store.list_groups()) # TODO: A lot of this stuff is duplicated from the similar group search # in the groups() view. We need a function that does that to avoid # the duplication. user_query = request.GET.get('q', '') query = user_query if query: if not ':' in query: query = 'name:%s' % (query, ) keys = contact_store.contacts.raw_search(query).get_keys() else: keys = contact_store.list_contacts() limit = min(int(request.GET.get('limit', 100)), len(keys)) messages.info(request, "Showing %s of %s contact(s)" % (limit, len(keys))) smart_group_form = SmartGroupForm(initial={'query': query}) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) return render( request, 'contacts/contact_list.html', { 'query': user_query, 'selected_contacts': contacts, 'smart_group_form': smart_group_form, 'upload_contacts_form': upload_contacts_form or UploadContactsForm(), 'select_contact_group_form': select_contact_group_form, })
def _static_group(request, contact_store, group): if group is None: raise Http404 if request.method == 'POST': group_form = ContactGroupForm(request.POST) if '_save_group' in request.POST: if group_form.is_valid(): group.name = group_form.cleaned_data['name'] group.save() messages.info(request, 'The group name has been updated') return redirect(_group_url(group.key)) elif '_export' in request.POST: tasks.export_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info( request, 'The export is scheduled and should ' 'complete within a few minutes.') return redirect(_group_url(group.key)) elif '_remove' in request.POST: contacts = request.POST.getlist('contact') for person_key in contacts: contact = contact_store.get_contact_by_key(person_key) contact.groups.remove(group) contact.save() messages.info(request, '%d Contacts removed from group' % len(contacts)) return redirect(_group_url(group.key)) elif '_delete_group_contacts' in request.POST: tasks.delete_group_contacts.delay( request.user_api.user_account_key, group.key) messages.info(request, "The group's contacts will be deleted shortly.") return redirect(_group_url(group.key)) elif '_delete_group' in request.POST: tasks.delete_group.delay(request.user_api.user_account_key, group.key) messages.info(request, 'The group will be deleted shortly.') return redirect(reverse('contacts:index')) elif '_complete_contact_upload' in request.POST: try: import_rule = request.POST.get('import_rule') import_handler = { 'existing_is_truth': handle_import_existing_is_truth, 'upload_is_truth': handle_import_upload_is_truth, }.get(import_rule, handle_import_new_contacts) import_handler(request, group) messages.info( request, 'The contacts are being imported. ' 'We will notify you via email when the import ' 'has been completed') except (ContactParserException, ): messages.error(request, 'Something is wrong with the file') _, file_path = utils.get_file_hints_from_session(request) default_storage.delete(file_path) return redirect(_group_url(group.key)) else: upload_contacts_form = UploadContactsForm(request.POST, request.FILES) if upload_contacts_form.is_valid(): file_object = upload_contacts_form.cleaned_data['file'] file_name, file_path = utils.store_temporarily(file_object) utils.store_file_hints_in_session(request, file_name, file_path) return redirect(_group_url(group.key)) else: # We didn't get any useful POST variables, so just redirect # back to the group page without doing anything. return redirect(_group_url(group.key)) else: group_form = ContactGroupForm({ 'name': group.name, }) context = { 'group': group, 'group_form': group_form, } if 'clear-upload' in request.GET: # FIXME this is a debug statement utils.clear_file_hints_from_session(request) if utils.has_uncompleted_contact_import(request): try: file_name, file_path = utils.get_file_hints_from_session(request) file_type, parser = ContactFileParser.get_parser(file_name) has_header, headers, row = parser.guess_headers_and_row(file_path) context.update({ 'contact_data_headers': headers, 'field_normalizer': FieldNormalizer(), 'contact_data_row': row, # NOTE: Only if we have a key (contact UUID) value in the # row we can look at updating contacts instead of # only writing new ones. 'can_update_contacts': 'key' in row, }) except (ValueError, ContactParserException): messages.error(request, 'Something is wrong with the file') utils.clear_file_hints_from_session(request) default_storage.delete(file_path) query = request.GET.get('q', '') if query: if not ':' in query: query = 'name:%s' % (query, ) keys = contact_store.contacts.raw_search(query).get_keys() else: keys = contact_store.get_contacts_for_group(group) limit = min(int(request.GET.get('limit', 100)), len(keys)) if keys: messages.info( request, "Showing %s of the group's %s contact(s)" % (limit, len(keys))) contacts = utils.contacts_by_key(contact_store, *keys[:limit]) context.update({ 'query': request.GET.get('q'), 'selected_contacts': contacts, 'member_count': contact_store.count_contacts_for_group(group), }) return render(request, 'contacts/static_group_detail.html', context)