# -*- coding: UTF-8 -*-

# Copyright (C) 2015-2016 Avencall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


from hamcrest import (assert_that,
                      contains,
                      contains_inanyorder,
                      contains_string,
                      empty,
                      equal_to,
                      has_entries,
                      has_item,
                      has_items,
                      has_length,
                      instance_of,
                      is_not,
                      not_none)
from test_api import associations as a
from test_api import confd
from test_api import config
from test_api import fixtures
from test_api import helpers as h
from test_api import provd
from test_api.bus import BusClient

client = h.user_import.csv_client()


def get_import_field(response, fieldname, row_number=1):
    rows = response.item['created']
    return get_field(rows, fieldname, row_number)


def get_update_field(response, fieldname, row_number=1):
    rows = response.item['updated']
    return get_field(rows, fieldname, row_number)


def get_field(rows, fieldname, row_number=1):
    assert_that(rows,
                has_length(row_number),
                "CSV import did not create enough rows")

    row = rows[row_number - 1]
    assert_that(row,
                has_entries({'row_number': row_number,
                             fieldname: not_none()}))

    return row[fieldname]


def assert_error(response, expect):
    response.assert_status(400)
    assert_that(response.json, has_entries(errors=expect))


def has_error_field(fieldname, row_number=1):
    return contains(has_entries(timestamp=instance_of(int),
                                details=has_entries(row_number=row_number),
                                message=contains_string(fieldname)))


def test_given_required_fields_missing_then_error_returned():
    csv = [{"lastname": "missingfirstname"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field("firstname"))


def test_given_entity_id_does_not_exist_then_error_returned():
    csv = [{"firstname": "entityfirstname",
            "entity_id": "999999999"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field("entity"))


def test_given_csv_has_minimal_fields_for_a_user_then_user_imported():
    csv = [{"firstname": "Rîchard"}]

    response = client.post("/users/import", csv)
    user_id = get_import_field(response, 'user_id')
    user_uuid = get_import_field(response, 'user_uuid')

    user = confd.users(user_id).get().item
    assert_that(user, has_entries(firstname="Rîchard", uuid=user_uuid))


def test_given_csv_has_all_fields_for_a_user_then_user_imported():
    csv = [{"firstname": "Rîchard",
            "lastname": "Lâpointe",
            "email": "richard@lapointe.org",
            "entity_id": "1",
            "language": "fr_FR",
            "username": "richardlapointe",
            "password": "secret",
            "outgoing_caller_id": '"Rîchy Cool" <4185551234>',
            "mobile_phone_number": "4181234567",
            "supervision_enabled": "1",
            "call_transfer_enabled": "0",
            "call_record_enabled": "1",
            "online_call_record_enabled": "0",
            "simultaneous_calls": "5",
            "ring_seconds": "10",
            "userfield": "userfield",
            "call_permission_password": "1234",
            "enabled": "1"
            }]

    response = client.post("/users/import", csv)
    user_id = get_import_field(response, 'user_id')
    user_uuid = get_import_field(response, 'user_uuid')

    user = confd.users(user_id).get().item
    assert_that(user, has_entries(firstname="Rîchard",
                                  lastname="Lâpointe",
                                  email="richard@lapointe.org",
                                  language="fr_FR",
                                  username="richardlapointe",
                                  password="secret",
                                  outgoing_caller_id='"Rîchy Cool" <4185551234>',
                                  mobile_phone_number="4181234567",
                                  supervision_enabled=True,
                                  call_transfer_enabled=False,
                                  call_record_enabled=True,
                                  online_call_record_enabled=False,
                                  simultaneous_calls=5,
                                  ring_seconds=10,
                                  userfield="userfield",
                                  call_permission_password='1234',
                                  enabled=True,
                                  uuid=user_uuid))


def test_given_csv_has_cti_username_and_password():
    csv = [{"firstname": "Jean",
            "lastname": "Lefebvre",
            "username": "ctiusername",
            "password": "ctisecret",
            "cti_profile_enabled": 1,
            "cti_profile_name": "Agent"
            }]

    response = client.post("/users/import", csv)

    user_id = get_import_field(response, 'user_id')
    user = confd.users(user_id).get().item
    assert_that(user, has_entries(firstname="Jean",
                                  lastname="Lefebvre",
                                  username="ctiusername",
                                  password="ctisecret"))


def test_given_csv_column_has_wrong_type_then_error_returned():
    csv = [{'firstname': 'invalidbool',
            'supervision_enabled': 'yeah'}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('supervision_enabled'))


def test_given_user_contains_error_then_error_returned():
    csv = [{"firstname": "richard",
            "mobile_phone_number": "blah"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('mobile_phone_number'))


def test_given_import_users_with_duplicate_username_then_error_returned():
    csv = [{"firstname": "Thômas",
            "username": "thomas1",
            "password": "secret",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    duplicate_user = {"firstname": "Thômas",
                      "username": "thomas1",
                      "password": "secret",
                      "cti_profile_enabled": "1",
                      "cti_profile_name": "Client"}

    csv.append(duplicate_user)
    response = client.post("/users/import", csv)
    assert_error(response, has_error_field("User already exists", 2))


def test_given_csv_has_minimal_voicemail_fields_then_voicemail_imported():
    number, context = h.voicemail.generate_number_and_context()
    csv = [{"firstname": "Jôey",
            "voicemail_name": "Jôey VM",
            "voicemail_number": number,
            "voicemail_context": context}]

    response = client.post("/users/import", csv)
    voicemail_id = get_import_field(response, 'voicemail_id')

    voicemail = confd.voicemails(voicemail_id).get().item
    assert_that(voicemail, has_entries(name="Jôey VM",
                                       number=number,
                                       context=context))


def test_given_csv_has_all_voicemail_fields_then_voicemail_imported():
    number, context = h.voicemail.generate_number_and_context()
    csv = [{"firstname": "Jôey",
            "voicemail_name": "Jôey VM",
            "voicemail_number": number,
            "voicemail_context": context,
            "voicemail_password": "1234",
            "voicemail_email": "email@example.com",
            "voicemail_attach_audio": "0",
            "voicemail_delete_messages": "1",
            "voicemail_ask_password": "0",
            }]

    response = client.post("/users/import", csv)
    voicemail_id = get_import_field(response, 'voicemail_id')

    voicemail = confd.voicemails(voicemail_id).get().item
    assert_that(voicemail, has_entries(name="Jôey VM",
                                       number=number,
                                       context=context,
                                       password="1234",
                                       email='email@example.com',
                                       attach_audio=False,
                                       delete_messages=True,
                                       ask_password=False))


def test_given_voicemail_contains_error_then_error_returned():
    csv = [{"firstname": "Jôey",
            "voicemail_name": "Jôey VM",
            "voicemail_number": "%%%$",
            "voicemail_context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('number'))


@fixtures.registrar(id='registrar1')
def test_given_csv_has_minimal_line_fields_then_line_created(registrar):
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "line_site": "registrar1",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    line_id = get_import_field(response, 'line_id')

    line = confd.lines(line_id).get().item
    assert_that(line, has_entries(context=config.CONTEXT,
                                  protocol='sip',
                                  registrar=registrar['id']))


@fixtures.registrar(id='registrar1')
def test_given_csv_has_registrar_in_uppercase_then_line_created(registrar):
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "line_site": "REGISTRAR1",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    line_id = get_import_field(response, 'line_id')

    line = confd.lines(line_id).get().item
    assert_that(line, has_entries(registrar=registrar['id']))


def test_given_csv_has_unknown_registrar_then_error_returned():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "line_site": "registrarX",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)

    assert_error(response, has_error_field('registrar'))


def test_given_line_has_error_then_error_returned():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "context": 'invalidcontext'}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('context'))


def test_given_csv_has_minimal_sip_fields_then_sip_endpoint_created():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip, has_entries(id=sip_id))


def test_given_csv_has_all_sip_fields_then_sip_endpoint_created():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "context": config.CONTEXT,
            "sip_username": "sipusername",
            "sip_secret": "sipsecret"}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip, has_entries(username="sipusername",
                                 secret="sipsecret"))


def test_given_csv_has_uppercase_sip_username():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sip",
            "context": config.CONTEXT,
            "sip_username": "SIPidentity",
            "sip_secret": "sipsecret"}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip, has_entries(username="sipidentity",
                                 secret="sipsecret"))


def test_given_csv_has_user_with_webrtc_activated_is_created():
    csv = [{"firstname": "Chârles WebRTC",
            "line_protocol": "webrtc",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    expected_options = [
        ["webrtc", "yes"],
    ]

    sip_options = confd.endpoints.sip(sip_id).get().item['options']
    assert_that(sip_options, has_items(*expected_options))


def test_given_csv_has_user_with_webrtc_deactivated_is_created_without_webrtc_option():
    csv = [{"firstname": "Chârles No WebRTC",
            "line_protocol": "sip",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    unexpected_option_name = "webrtc"

    sip_options = confd.endpoints.sip(sip_id).get().item['options']
    option_webrtc = [opt for opt in sip_options if unexpected_option_name in opt]
    assert_that(option_webrtc, empty())


def test_given_csv_has_user_with_ua_activated_is_created():
    csv = [{"firstname": "Chârles UA",
            "line_protocol": "ua",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    sip_id = get_import_field(response, 'sip_id')

    expected_options = [
        ["webrtc", "ua"],
    ]

    sip_options = confd.endpoints.sip(sip_id).get().item['options']
    assert_that(sip_options, has_items(*expected_options))


def test_given_csv_has_minimal_sccp_fields_then_sccp_endpoint_created():
    csv = [{"firstname": "Chârles",
            "line_protocol": "sccp",
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    sccp_id = get_import_field(response, 'sccp_id')

    sccp = confd.endpoints.sccp(sccp_id).get().item
    assert_that(sccp, has_entries(id=sccp_id))


def test_given_csv_has_extension_fields_then_extension_created():
    exten = h.extension.find_available_exten(config.CONTEXT)
    csv = [{"firstname": "Géorge",
            "line_protocol": "sip",
            "exten": exten,
            "context": config.CONTEXT}]

    response = client.post("/users/import", csv)
    extension_id = get_import_field(response, 'extension_id')

    extension = confd.extensions(extension_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.CONTEXT))


def test_given_csv_extension_has_errors_then_errors_returned():
    csv = [{"firstname": "Géorge",
            "line_protocol": "sip",
            "exten": "9999",
            "context": "invalid"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('context'))


def test_given_csv_has_minimal_incall_fields_then_incall_created():
    exten = h.extension.find_available_exten(config.INCALL_CONTEXT)
    csv = [{"firstname": "Pâscal",
            "line_protocol": "sccp",
            "context": config.CONTEXT,
            "incall_exten": exten,
            "incall_context": config.INCALL_CONTEXT}]

    response = client.post("/users/import", csv)
    incall_extension_id = get_import_field(response, 'incall_extension_id')

    extension = confd.extensions(incall_extension_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.INCALL_CONTEXT))


def test_given_csv_has_all_incall_fields_then_incall_created():
    exten = h.extension.find_available_exten(config.INCALL_CONTEXT)
    csv = [{"firstname": "Pâscal",
            "line_protocol": "sccp",
            "context": config.CONTEXT,
            "incall_exten": exten,
            "incall_context": config.INCALL_CONTEXT,
            "incall_ring_seconds": "10"}]

    response = client.post("/users/import", csv)
    get_import_field(response, 'incall_extension_id')


def test_given_csv_incall_has_errors_then_errors_returned():
    csv = [{"firstname": "Géorge",
            "line_protocol": "sip",
            "context": config.CONTEXT,
            "incall_exten": "9999",
            "incall_context": "invalid"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('context'))


def test_given_csv_has_cti_fields_then_cti_profile_associated():
    csv = [{"firstname": "Thômas",
            "username": "thomas1",
            "password": "secret",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    response = client.post("/users/import", csv)
    cti_profile_id = get_import_field(response, 'cti_profile_id')
    user_id = get_import_field(response, 'user_id')

    user_cti_profile = confd.users(user_id).cti.get().item
    assert_that(user_cti_profile, has_entries(cti_profile_id=cti_profile_id,
                                              enabled=True))


def test_given_csv_cti_profile_has_errors_then_errors_returned():
    csv = [{"firstname": "Thômas",
            "username": "thomas2",
            "password": "secret",
            "cti_profile_enabled": "1",
            "cti_profile_name": "InvalidProfile"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('CtiProfile'))


def test_given_csv_cti_password_should_be_longer_than_8_chars():
    csv = [{"firstname": "Thômas",
            "username": "thomas3",
            "password": "secret1",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    response = client.post("/users/import", csv)
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain at least 8 characters")))


def test_given_csv_cti_password_should_contain_alphanumeric_chars():
    csv = [{"firstname": "Thômas",
            "username": "thomas4",
            "password": "secretsecret",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    response = client.post("/users/import", csv)
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain alphanumeric characters")))


def test_given_csv_cti_password_does_not_comply_rules():
    csv = [{"firstname": "Thômas",
            "username": "thomas5",
            "password": "secret",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    response = client.post("/users/import", csv)
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain alphanumeric characters")))
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain at least 8 characters")))


@fixtures.csv_entry()
def test_when_updating_user_fields_then_user_resource_updated(entry):
    csv = [{"uuid": entry['user_uuid'],
            "username": "joellachance",
            "password": "secret",
            }]

    response = client.put("/users/import", csv)
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain alphanumeric characters")))
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("Password should contain at least 8 characters")))


def test_given_csv_cti_password_should_return_warnings_per_row():
    csv = [{"firstname": "Thômas",
            "username": "thomas2",
            "password": "secret1",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"},
           {"firstname": "Tomas",
            "username": "tomas2",
            "password": "secret1",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}
           ]

    response = client.post("/users/import", csv)
    assert_that(response.item['warnings'][0],
                has_entries(message=contains_string("['Password should contain at least 8 characters']")))
    assert_that(response.item['warnings'][1],
                has_entries(message=contains_string("['Password should contain at least 8 characters']")))


@fixtures.call_permission()
def test_given_csv_has_call_permission_then_call_permission_associated(call_permission):
    csv = [{"firstname": "Gërtrüde",
            "call_permissions": call_permission['name']}]

    expected = contains(
        has_entries(
            row_number=1,
            call_permission_ids=contains(call_permission['id'])))

    response = client.post("/users/import", csv)
    assert_that(response.item['created'], expected)

    user_id = response.item['created'][0]['user_id']
    user_call_permissions = confd.users(user_id).callpermissions.get().items
    assert_that(user_call_permissions, contains(has_entries(call_permission_id=call_permission['id'],
                                                            user_id=user_id)))


@fixtures.call_permission()
@fixtures.call_permission()
def test_given_csv_has_multiple_call_permissions_then_all_call_permission_associated(perm1, perm2):
    permissions = "{perm1[name]};{perm2[name]}".format(perm1=perm1, perm2=perm2)
    csv = [{"firstname": "Rônald",
            "call_permissions": permissions}]

    expected = contains(
        has_entries(
            row_number=1,
            call_permission_ids=has_items(perm1['id'], perm2['id'])))

    response = client.post("/users/import", csv)
    assert_that(response.item['created'], expected)

    user_id = response.item['created'][0]['user_id']
    user_call_permissions = confd.users(user_id).callpermissions.get().items
    assert_that(user_call_permissions, contains_inanyorder(has_entries(call_permission_id=perm1['id'],
                                                                       user_id=user_id),
                                                           has_entries(call_permission_id=perm2['id'],
                                                                       user_id=user_id)))


def test_given_call_permission_does_not_exist_then_error_raised():
    csv = [{"firstname": "Trévor",
            "call_permissions": "unknownperm"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('CallPermission'))


@fixtures.label()
def test_given_csv_has_label_then_label_associated(label):
    csv = [{"firstname": "Gërtrüde",
            "labels": label['display_name']}]

    response = client.post("/users/import", csv)

    user_id = response.item['created'][0]['user_id']
    user = confd.users(user_id).get().item

    assert_that(user['labels'], contains(label['id']))


@fixtures.label()
@fixtures.label()
def test_given_csv_has_multiple_labels_then_all_labels_associated(label1, label2):
    labels = "{label1};{label2}".format(label1=label1["display_name"],
                                        label2=label2["display_name"])
    csv = [{"firstname": "Rônald",
            "labels": labels}]

    response = client.post("/users/import", csv)

    user_id = response.item['created'][0]['user_id']
    user = confd.users(user_id).get().item
    assert_that(user['labels'], contains_inanyorder(label1['id'], label2['id']))


def test_given_label_does_not_exist_then_error_raised():
    csv = [{"firstname": "Trévor",
            "labels": "unknownlabel"}]

    response = client.post("/users/import", csv)
    assert_error(response, has_error_field('labels'))


def test_given_csv_has_all_resources_then_all_relations_created():
    exten = h.extension.find_available_exten(config.CONTEXT)
    incall_exten = h.extension.find_available_exten(config.INCALL_CONTEXT)
    vm_number = h.voicemail.find_available_number(config.CONTEXT)

    csv = [{"firstname": "Frânçois",
            "exten": exten,
            "context": config.CONTEXT,
            "line_protocol": "sip",
            "incall_exten": incall_exten,
            "incall_context": config.INCALL_CONTEXT,
            "voicemail_name": "francois",
            "voicemail_number": vm_number,
            "voicemail_context": config.CONTEXT,
            "cti_profile_name": "Client",
            }]

    response = client.post("/users/import", csv)

    user_id = get_import_field(response, 'user_id')
    line_id = get_import_field(response, 'line_id')
    voicemail_id = get_import_field(response, 'voicemail_id')
    extension_id = get_import_field(response, 'extension_id')
    incall_extension_id = get_import_field(response, 'incall_extension_id')
    sip_id = get_import_field(response, 'sip_id')
    cti_profile_id = get_import_field(response, 'cti_profile_id')

    response = confd.users(user_id).lines.get()
    assert_that(response.items, contains(has_entries(line_id=line_id)))

    response = confd.lines(line_id).extensions.get()
    assert_that(response.items, has_items(has_entries(extension_id=extension_id),
                                          has_entries(extension_id=incall_extension_id)))

    response = confd.users(user_id).voicemail.get()
    assert_that(response.item, has_entries(voicemail_id=voicemail_id))

    response = confd.lines(line_id).endpoints.sip.get()
    assert_that(response.item, has_entries(endpoint='sip',
                                           endpoint_id=sip_id))

    response = confd.users(user_id).cti.get()
    assert_that(response.item, has_entries(cti_profile_id=cti_profile_id))


@fixtures.sip()
@fixtures.extension()
@fixtures.extension(context=config.INCALL_CONTEXT)
@fixtures.voicemail()
@fixtures.call_permission()
def test_given_resources_already_exist_when_importing_then_resources_associated(sip, extension, incall, voicemail,
                                                                                call_permission):
    cti_profile = h.cti_profile.find_by_name("Client")

    csv = [{"firstname": "importassociate",
            "exten": extension['exten'],
            "context": extension['context'],
            "line_protocol": "sip",
            "sip_username": sip['username'],
            "incall_exten": incall['exten'],
            "incall_context": incall['context'],
            "voicemail_number": voicemail['number'],
            "voicemail_context": voicemail['context'],
            "cti_profile_name": "Client",
            "call_permissions": call_permission['name'],
            }]

    response = client.post("/users/import", csv)

    user_id = get_import_field(response, 'user_id')
    line_id = get_import_field(response, 'line_id')

    response = confd.users(user_id).lines.get()
    assert_that(response.items, contains(has_entries(line_id=line_id)))

    response = confd.lines(line_id).extensions.get()
    assert_that(response.items, has_items(has_entries(extension_id=extension['id']),
                                          has_entries(extension_id=incall['id'])))

    response = confd.users(user_id).voicemail.get()
    assert_that(response.item, has_entries(voicemail_id=voicemail['id']))

    response = confd.lines(line_id).endpoints.sip.get()
    assert_that(response.item, has_entries(endpoint='sip',
                                           endpoint_id=sip['id']))

    response = confd.users(user_id).cti.get()
    assert_that(response.item, has_entries(cti_profile_id=cti_profile['id']))

    response = confd.users(user_id).callpermissions.get()
    assert_that(response.items, contains(has_entries(call_permission_id=call_permission['id'],
                                                     user_id=user_id)))


@fixtures.call_permission()
@fixtures.call_permission()
@fixtures.label()
@fixtures.label()
def test_given_csv_has_more_than_one_entry_then_all_entries_imported(perm1, perm2, label1, label2):
    exten1 = h.extension.find_available_exten(config.CONTEXT)
    incall_exten1 = h.extension.find_available_exten('from-extern')
    vm_number1 = h.voicemail.find_available_number(config.CONTEXT)

    exten2 = h.extension.find_available_exten(config.CONTEXT, exclude=[exten1])
    incall_exten2 = h.extension.find_available_exten('from-extern', exclude=[incall_exten1])
    vm_number2 = h.voicemail.find_available_number(config.CONTEXT, exclude=[vm_number1])

    csv = [
        {"entity_id": "1",
         "firstname": "Jèan",
         "lastname": "Bâptiste",
         "email": "jean@baptiste.st",
         "mobile_phone_number": "5551234567",
         "ring_seconds": "15",
         "simultaneous_calls": "10",
         "language": "fr_FR",
         "outgoing_caller_id": '"Jean Le Grand" <5557654321>',
         "userfield": "userfield",
         "supervision_enabled": "1",
         "call_transfer_enabled": "1",
         "call_record_enabled": "0",
         "online_call_record_enabled": "0",
         "call_permission_password": "1234",
         "enabled": "1",
         "exten": exten1,
         "context": config.CONTEXT,
         "line_protocol": "sip",
         "sip_username": "jeansipusername",
         "sip_secret": "jeansippassword",
         "incall_exten": incall_exten1,
         "incall_context": 'from-extern',
         "incall_ring_seconds": "10",
         "voicemail_name": "jean",
         "voicemail_number": vm_number1,
         "voicemail_context": config.CONTEXT,
         "voicemail_password": "1234",
         "voicemail_email": "test@example.com",
         "voicemail_attach_audio": "1",
         "voicemail_delete_messages": "1",
         "voicemail_ask_password": "1",
         "cti_profile_name": "Client",
         "cti_profile_enabled": "1",
         "username": "jean",
         "password": "secret",
         "call_permissions": perm1['name'],
         "labels": label1['display_name']},
        {"entity_id": "1",
         "firstname": "Moùssa",
         "lastname": "Nôbamgo",
         "email": "moussa@nobamgo.ta",
         "mobile_phone_number": "5553456789",
         "ring_seconds": "20",
         "simultaneous_calls": "8",
         "language": "fr_FR",
         "outgoing_caller_id": '"Mousssssssaaaa" <5557654321>',
         "userfield": "userfield",
         "supervision_enabled": "1",
         "call_transfer_enabled": "1",
         "call_record_enabled": "1",
         "online_call_record_enabled": "1",
         "call_permission_password": "5678",
         "enabled": "0",
         "exten": exten2,
         "context": config.CONTEXT,
         "line_protocol": "sccp",
         "incall_exten": incall_exten2,
         "incall_context": 'from-extern',
         "incall_ring_seconds": "12",
         "voicemail_name": "moussa",
         "voicemail_number": vm_number2,
         "voicemail_context": config.CONTEXT,
         "voicemail_password": "2345",
         "voicemail_email": "test2@example.com",
         "voicemail_attach_audio": "1",
         "voicemail_delete_messages": "1",
         "voicemail_ask_password": "1",
         "cti_profile_name": "Client",
         "cti_profile_enabled": "1",
         "username": "moussa2",
         "password": "secret",
         "call_permissions": perm2['name'],
         "labels": label2['display_name']},
    ]

    response = client.post("/users/import", csv)

    assert_that(len(response.item['created']), equal_to(2))


def test_given_field_group_is_empty_then_resource_is_not_created():
    group = {"cti_profile_enabled": "",
             "cti_profile_name": "",
             "username": "",
             "password": ""}
    yield import_empty_group, group, 'cti_profile_id'

    group = {"voicemail_name": "",
             "voicemail_number": "",
             "voicemail_context": "",
             "voicemail_password": "",
             "voicemail_email": "",
             "voicemail_attach_audio": "",
             "voicemail_delete_messages": "",
             "voicemail_ask_password": ""}
    yield import_empty_group, group, 'voicemail_id'

    group = {"line_protocol": ""}
    yield import_empty_group, group, 'line_id'

    group = {"line_protocol": "sip",
             "exten": "",
             "context": ""}
    yield import_empty_group, group, 'extension_id'

    exten = h.extension.find_available_exten(config.CONTEXT)
    group = {"line_protocol": "sip",
             "exten": exten,
             "context": config.CONTEXT,
             "incall_exten": "",
             "incall_context": ""}
    yield import_empty_group, group, 'incall_extension_id'

    group = {"call_permissions": ""}
    yield import_empty_group, group, 'call_permission_ids', []


def import_empty_group(fields, parameter, expected=None):
    fields['firstname'] = "Abigaël"
    response = client.post("/users/import", [fields])
    entry = response.item['created'][0]
    assert_that(entry, has_entries({parameter: expected}))


def test_given_2_entries_in_csv_imported_then_one_reload_event_published():
    BusClient.listen_delayed_events('config.ipbx.reload')
    csv = [
        {"firstname": "user1"},
        {"firstname": "user2"},
    ]
    all_optimized_commands = ['dialplan reload',
                              'module reload chan_sccp.so',
                              'module reload app_queue.so',
                              'sip reload']
    expected_commands = all_optimized_commands

    client.post("/users/import", csv)

    reload_events = BusClient.drain_events()

    assert_that(reload_events, has_length(1))
    assert_that(reload_events[0]['data']['commands'], contains_inanyorder(*expected_commands))


@fixtures.csv_entry()
def test_when_updating_user_fields_then_user_resource_updated(entry):
    csv = [{"uuid": entry['user_uuid'],
            "firstname": "Joël",
            "lastname": "Làchance",
            "language": "fr_FR",
            "email": "joel@lachance.fr",
            "username": "joellachance",
            "password": "secret",
            "outgoing_caller_id": '"Joël Spîffy" <4185551234>',
            "mobile_phone_number": "4181234567",
            "supervision_enabled": "1",
            "call_transfer_enabled": "0",
            "call_record_enabled": "1",
            "online_call_record_enabled": "0",
            "simultaneous_calls": "5",
            "ring_seconds": "10",
            "userfield": "userfield",
            "call_permission_password": "123",
            "enabled": "0",
            }]

    response = client.put("/users/import", csv)
    user_id = get_update_field(response, 'user_id')
    user_uuid = get_update_field(response, 'user_uuid')

    user = confd.users(user_id).get().item
    assert_that(user, has_entries(firstname="Joël",
                                  lastname="Làchance",
                                  email="joel@lachance.fr",
                                  language="fr_FR",
                                  username="joellachance",
                                  password="secret",
                                  outgoing_caller_id='"Joël Spîffy" <4185551234>',
                                  mobile_phone_number="4181234567",
                                  supervision_enabled=True,
                                  call_transfer_enabled=False,
                                  call_record_enabled=True,
                                  online_call_record_enabled=False,
                                  simultaneous_calls=5,
                                  ring_seconds=10,
                                  userfield="userfield",
                                  call_permission_password='123',
                                  enabled=False,
                                  uuid=user_uuid))


@fixtures.csv_entry(voicemail=True)
def test_when_updating_voicemail_fields_then_voicemail_updated(entry):
    number = h.voicemail.find_available_number(config.CONTEXT)

    csv = [{"uuid": entry["user_uuid"],
            "voicemail_name": "Jôey VM",
            "voicemail_number": number,
            "voicemail_context": config.CONTEXT,
            "voicemail_password": "1234",
            "voicemail_email": "email@example.com",
            "voicemail_attach_audio": "0",
            "voicemail_delete_messages": "1",
            "voicemail_ask_password": "0",
            }]

    response = client.put("/users/import", csv)
    voicemail_id = get_update_field(response, 'voicemail_id')

    voicemail = confd.voicemails(voicemail_id).get().item
    assert_that(voicemail, has_entries(name="Jôey VM",
                                       number=number,
                                       context=config.CONTEXT,
                                       password="1234",
                                       email='email@example.com',
                                       attach_audio=False,
                                       delete_messages=True,
                                       ask_password=False))


@fixtures.csv_entry()
def test_when_adding_voicemail_fields_then_voicemail_created(entry):
    number = h.voicemail.find_available_number(config.CONTEXT)

    csv = [{"uuid": entry['user_uuid'],
            "voicemail_name": "Jôey VM",
            "voicemail_number": number,
            "voicemail_context": config.CONTEXT,
            "voicemail_password": "1234",
            "voicemail_email": "email@example.com",
            "voicemail_attach_audio": "0",
            "voicemail_delete_messages": "1",
            "voicemail_ask_password": "0",
            }]

    response = client.put("/users/import", csv)
    voicemail_id = get_update_field(response, 'voicemail_id')

    voicemail = confd.voicemails(voicemail_id).get().item
    assert_that(voicemail, has_entries(name="Jôey VM",
                                       number=number,
                                       context=config.CONTEXT,
                                       password="1234",
                                       email='email@example.com',
                                       attach_audio=False,
                                       delete_messages=True,
                                       ask_password=False))


@fixtures.csv_entry(line_protocol="sip")
def test_when_updating_sip_line_fields_then_sip_updated(entry):
    csv = [{"uuid": entry["user_uuid"],
            "sip_username": "mynewsipusername",
            "sip_secret": "mynewsippassword",
            }]

    response = client.put("/users/import", csv)
    sip_id = get_update_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip, has_entries(username="mynewsipusername",
                                 secret="mynewsippassword"))


@fixtures.csv_entry(line_protocol="sip")
def test_when_updating_sip_line_webrtc_field_to_yes_then_field_updated(entry):
    csv = [{"uuid": entry["user_uuid"],
            "line_protocol": "webrtc",
            }]

    response = client.put("/users/import", csv)
    sip_id = get_update_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip['options'], has_item(contains("webrtc", "yes")))


@fixtures.csv_entry(line_protocol="sip")
def test_when_updating_sip_line_without_webrtc_field_then_options_not_updated(entry):
    csv = [{"uuid": entry["user_uuid"],
            }]

    response = client.put("/users/import", csv)
    sip_id = get_update_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip['options'], is_not(has_item(has_item("webrtc"))))


@fixtures.user()
@fixtures.line()
@fixtures.sip(options=[["foo", "bar"]])
def test_other_sip_options_are_unchanged_when_adding_webrtc_option(user, line, sip):
    csv = [{"uuid": user["uuid"],
            "line_protocol": "webrtc",
            }]

    expected_options = [
        ["foo", "bar"],
        ["webrtc", "yes"],
    ]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line):
        response = client.put("/users/import", csv)
        sip_id = get_update_field(response, 'sip_id')

        sip_options = confd.endpoints.sip(sip_id).get().item['options']
        assert_that(sip_options, has_items(*expected_options))


@fixtures.user()
@fixtures.line()
@fixtures.sip(options=[["foo", "bar"], ["webrtc", "no"]])
def test_other_sip_options_are_unchanged_when_updating_webrtc_option(user, line, sip):
    csv = [{"uuid": user["uuid"],
            "line_protocol": "webrtc",
            }]

    expected_options = [
        ["foo", "bar"],
        ["webrtc", "yes"],
    ]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line):
        response = client.put("/users/import", csv)
        sip_id = get_update_field(response, 'sip_id')

        sip_options = confd.endpoints.sip(sip_id).get().item['options']
        assert_that(sip_options, has_items(*expected_options))


@fixtures.user()
@fixtures.line()
@fixtures.sip(options=[["foo", "bar"], ["webrtc", "yes"]])
def test_other_sip_options_are_unchanged_when_removing_webrtc_option(user, line, sip):
    csv = [{"uuid": user["uuid"],
            "line_protocol": "sip",
            }]

    expected_options = [
        ["foo", "bar"],
    ]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line):
        response = client.put("/users/import", csv)
        sip_id = get_update_field(response, 'sip_id')

        sip_options = confd.endpoints.sip(sip_id).get().item['options']
        assert_that(sip_options, has_items(*expected_options))


@fixtures.user()
@fixtures.line()
@fixtures.sip(options=[["foo", "bar"], ["webrtc", "yes"]])
def test_webrtc_option_is_removed_when_changing_line_to_sip(user, line, sip):
    csv = [{"uuid": user["uuid"],
            "line_protocol": "sip",
            }]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line):
        response = client.put("/users/import", csv)
        sip_id = get_update_field(response, 'sip_id')

        sip_options = confd.endpoints.sip(sip_id).get().item['options']
        assert_that(sip_options, is_not(has_item(has_item("webrtc"))))


@fixtures.csv_entry(line_protocol="sip")
def test_when_updating_sip_line_webrtc_field_to_ua_then_field_updated(entry):
    csv = [{"uuid": entry["user_uuid"],
            "line_protocol": "ua",
            }]

    response = client.put("/users/import", csv)
    sip_id = get_update_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip['options'], has_item(contains("webrtc", "ua")))


@fixtures.csv_entry()
def test_when_adding_sip_line_then_sip_created(entry):
    csv = [{"uuid": entry["user_uuid"],
            "line_protocol": "sip",
            "sip_username": "createdsipusername",
            "sip_secret": "createdsippassword",
            }]

    response = client.put("/users/import", csv)
    sip_id = get_update_field(response, 'sip_id')

    sip = confd.endpoints.sip(sip_id).get().item
    assert_that(sip, has_entries(username="createdsipusername",
                                 secret="createdsippassword"))


@fixtures.csv_entry()
def test_when_adding_sccp_line_then_sccp_created(entry):
    csv = [{"uuid": entry["user_uuid"],
            "line_protocol": "sccp",
            }]

    response = client.put("/users/import", csv)
    sccp_id = get_update_field(response, 'sccp_id')

    sccp = confd.endpoints.sccp(sccp_id).get().item
    assert_that(sccp, has_entries(id=sccp_id))


@fixtures.csv_entry(line_protocol="sip")
def test_when_changing_line_protocol_then_error_raised(entry):
    csv = [{"uuid": entry["user_uuid"],
            "line_protocol": "sccp",
            }]

    response = client.put("/users/import", csv)

    assert_error(response, has_error_field('endpoint'))


@fixtures.csv_entry(extension=True)
def test_when_updating_extension_then_extension_updated(entry):
    exten = h.extension.find_available_exten(config.CONTEXT)

    csv = [{"uuid": entry["user_uuid"],
            "exten": exten,
            "context": config.CONTEXT,
            }]

    response = client.put("/users/import", csv)
    extension_id = get_update_field(response, 'extension_id')

    extension = confd.extensions(extension_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.CONTEXT))


@fixtures.csv_entry(line_protocol="sip")
def test_when_adding_extension_then_extension_created(entry):
    exten = h.extension.find_available_exten(config.CONTEXT)

    csv = [{"uuid": entry["user_uuid"],
            "exten": exten,
            "context": config.CONTEXT,
            }]

    response = client.put("/users/import", csv)
    extension_id = get_update_field(response, 'extension_id')

    extension = confd.extensions(extension_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.CONTEXT))


@fixtures.csv_entry(incall=True)
def test_when_updating_incall_fields_then_incall_updated(entry):
    exten = h.extension.find_available_exten(config.INCALL_CONTEXT)

    csv = [{"uuid": entry["user_uuid"],
            "incall_exten": exten,
            "incall_context": config.INCALL_CONTEXT,
            "incall_ring_seconds": "10"}]

    response = client.put("/users/import", csv)
    incall_id = get_update_field(response, 'incall_extension_id')

    extension = confd.extensions(incall_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.INCALL_CONTEXT))


@fixtures.csv_entry(line_protocol="sip", extension=True)
def test_when_adding_incall_then_incall_created(entry):
    exten = h.extension.find_available_exten(config.INCALL_CONTEXT)

    csv = [{"uuid": entry["user_uuid"],
            "incall_exten": exten,
            "incall_context": config.INCALL_CONTEXT,
            "incall_ring_seconds": "10"}]

    response = client.put("/users/import", csv)
    incall_id = get_update_field(response, 'incall_extension_id')

    extension = confd.extensions(incall_id).get().item
    assert_that(extension, has_entries(exten=exten,
                                       context=config.INCALL_CONTEXT))


@fixtures.csv_entry(cti_profile=True,
                    cti_profile_name="Client")
def test_when_updating_cti_profile_fields_then_cti_profile_updated(entry):
    csv = [{"uuid": entry['user_uuid'],
            "cti_profile_name": "Agent"}]

    response = client.put("/users/import", csv)
    user_id = get_update_field(response, 'user_id')
    cti_profile_id = h.cti_profile.find_id_for_profile("Agent")

    user_cti_profile = confd.users(user_id).cti.get().item
    assert_that(user_cti_profile, has_entries(cti_profile_id=cti_profile_id,
                                              enabled=True))


@fixtures.csv_entry()
def test_when_adding_cti_profile_fields_then_cti_profile_added(entry):
    csv = [{"uuid": entry['user_uuid'],
            "cti_profile_name": "Agent",
            "cti_profile_enabled": "1"}]

    response = client.put("/users/import", csv)
    user_id = get_update_field(response, 'user_id')

    cti_profile_id = h.cti_profile.find_id_for_profile("Agent")
    user_cti_profile = confd.users(user_id).cti.get().item
    assert_that(user_cti_profile, has_entries(cti_profile_id=cti_profile_id,
                                              enabled=True))


@fixtures.csv_entry(call_permissions=2)
@fixtures.call_permission()
@fixtures.call_permission()
def test_when_updating_call_permission_field_then_call_permissions_updated(entry, perm1, perm2):
    permissions = "{perm1[name]};{perm2[name]}".format(perm1=perm1, perm2=perm2)
    csv = [{"uuid": entry['user_uuid'],
            "call_permissions": permissions}]

    response = client.put("/users/import", csv)

    expected = contains(
        has_entries(
            row_number=1,
            call_permission_ids=has_items(perm1['id'], perm2['id'])))

    assert_that(response.item['updated'], expected)

    old_perm_id1, old_perm_id2 = entry['call_permission_ids']
    user_id = response.item['updated'][0]['user_id']

    response = confd.users(user_id).callpermissions.get()
    assert_that(response.items, contains_inanyorder(has_entries(call_permission_id=perm1['id'],
                                                                user_id=user_id),
                                                    has_entries(call_permission_id=perm2['id'],
                                                                user_id=user_id)))


@fixtures.csv_entry(call_permissions=1)
def test_when_call_permission_column_is_empty_then_call_permission_is_removed(entry):
    csv = [{"uuid": entry['user_uuid'],
            "call_permissions": ""}]

    response = client.put("/users/import", csv)

    expected = contains(
        has_entries(
            row_number=1,
            call_permission_ids=empty()))

    assert_that(response.item['updated'], expected)

    user_id = response.item['updated'][0]['user_id']

    response = confd.users(user_id).callpermissions.get()
    assert_that(response.items, empty())


@fixtures.csv_entry(call_permissions=1)
def test_when_call_permission_column_is_not_in_csv_then_call_permission_remains_unchanged(entry):
    csv = [{"uuid": entry['user_uuid']}]

    perm_id = entry['call_permission_ids'][0]

    response = client.put("/users/import", csv)

    expected = contains(
        has_entries(
            row_number=1,
            call_permission_ids=contains(perm_id)))

    assert_that(response.item['updated'], expected)


@fixtures.csv_entry(labels=2)
@fixtures.label()
@fixtures.label()
def test_when_updating_label_field_then_labels_updated(entry, label1, label2):
    labels = "{label1};{label2}".format(label1=label1["display_name"],
                                        label2=label2["display_name"])
    csv = [{"uuid": entry['user_uuid'],
            "labels": labels}]

    response = client.put("/users/import", csv)

    user_id = response.item['updated'][0]['user_id']
    user_labels = confd.users(user_id).get().item['labels']

    assert_that(user_labels, contains_inanyorder(label1['id'],
                                                 label2['id']))


@fixtures.csv_entry(labels=1)
def test_when_label_column_is_empty_then_label_is_removed(entry):
    csv = [{"uuid": entry['user_uuid'],
            "labels": ""}]

    response = client.put("/users/import", csv)

    user_id = response.item['updated'][0]['user_id']
    user_labels = confd.users(user_id).get().item['labels']

    assert_that(user_labels, empty())


@fixtures.csv_entry(labels=1)
def test_when_label_column_is_not_in_csv_then_label_is_not_removed(entry):
    csv = [{"uuid": entry['user_uuid'],
            "firstname": "Chârles"}]

    response = client.put("/users/import", csv)

    user_id = response.item['updated'][0]['user_id']
    user_labels = confd.users(user_id).get().item['labels']

    assert_that(user_labels, has_length(1))


@fixtures.user(agent_number="456")
def test_when_updating_user_then_agent_not_disassociated(user):
    csv = [{"uuid": user['uuid'],
            "firstname": "Chârles"}]

    client.put("/users/import", csv)

    updated_user = confd.users(user['id']).get().item

    assert_that(updated_user, has_entries(agent_number="456"))


@fixtures.registrar(id='registrar1')
@fixtures.registrar(id='registrar2')
def test_when_updating_registrar_fields_then_registrar_updated(registrar1, registrar2):
    initial_csv = [{"firstname": "Chârles",
                    "line_protocol": "sip",
                    "line_site": "registrar1",
                    "context": config.CONTEXT}]

    response = client.post("/users/import", initial_csv)
    user_uuid = get_import_field(response, 'user_uuid')
    line_id = get_import_field(response, 'line_id')

    line = confd.lines(line_id).get().item

    assert_that(line, has_entries(registrar='registrar1'))

    updated_csv = [{"uuid": user_uuid,
                    "line_protocol": "sip",
                    "line_site": "registrar2"}]

    client.put("/users/import", updated_csv)

    updated_line = confd.lines(line_id).get().item

    assert_that(updated_line, has_entries(registrar='registrar2'))


@fixtures.user()
@fixtures.line()
@fixtures.sip()
@fixtures.extension()
@fixtures.device()
@fixtures.registrar(id='registrar2', registrar_ip='12.0.2.2')
def test_when_updating_registrar_fields_then_provd_updated(user, line, sip, extension, device, registrar):
    csv = [{"uuid": user['uuid'],
            "line_site": "registrar2"}]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line), \
            a.line_extension(line, extension), a.line_device(line, device):
        client.put("/users/import", csv)

        provd_config = provd.configs.get(device['id'])
        sip_line = provd_config['raw_config']['sip_lines']['1']

        assert_that(sip_line['registrar_ip'], equal_to(registrar['registrar_main']))


@fixtures.user()
@fixtures.line()
@fixtures.sip()
@fixtures.extension()
@fixtures.device()
def test_when_updating_exten_fields_then_provd_updated(user, line, sip, extension, device):
    csv = [{"uuid": user['uuid'],
            "exten": "1600"}]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line), \
            a.line_extension(line, extension), a.line_device(line, device):
        client.put("/users/import", csv)

        provd_config = provd.configs.get(device['id'])
        sip_line = provd_config['raw_config']['sip_lines']['1']

        assert_that(sip_line['number'], equal_to('1600'))


@fixtures.user()
@fixtures.line()
@fixtures.sip()
@fixtures.extension()
@fixtures.device()
def test_when_updating_protocol_fields_then_errors_returned(user, line, sip, extension, device):
    csv = [{"uuid": user['uuid'],
            "line_protocol": "sccp"}]

    with a.line_endpoint_sip(line, sip), a.user_line(user, line), \
            a.line_extension(line, extension), a.line_device(line, device):
        response = client.put("/users/import", csv)

        response.assert_status(400)


def check_error_on_update(entry, fields, error):
    entry = dict(entry)
    entry.update(fields)
    entry['uuid'] = entry['user_uuid']
    response = client.put("/users/import", [entry])
    assert_error(response, has_error_field(error))


def test_given_csv_has_errors_then_errors_returned():
    csv = [{"firstname": "Thômas",
            "username": "thomas1",
            "password": "secret",
            "bosssecretary": "no",
            "cti_profile_enabled": "1",
            "cti_profile_name": "Client"}]

    response = client.post("/users/import", csv)
    response.assert_status(400)
    assert_that(response.json[0], contains_string("Input Error"))


@fixtures.csv_entry(extension=True, voicemail=True, incall=True, cti_profile=True, line_protocol="sip")
@fixtures.csv_entry(extension=True, voicemail=True, incall=True, cti_profile=True, line_protocol="sccp")
def test_given_2_entries_in_csv_then_2_entries_updated(entry1, entry2):
    exten1 = h.extension.find_available_exten(config.CONTEXT)
    incall_exten1 = h.extension.find_available_exten(config.INCALL_CONTEXT)
    vm_number1 = h.voicemail.find_available_number(config.CONTEXT)

    exten2 = h.extension.find_available_exten(config.CONTEXT, exclude=[exten1])
    incall_exten2 = h.extension.find_available_exten(config.INCALL_CONTEXT, exclude=[incall_exten1])
    vm_number2 = h.voicemail.find_available_number(config.CONTEXT, exclude=[vm_number1])

    csv = [
        {"uuid": entry1["user_uuid"],
         "entity_id": "1",
         "exten": exten1,
         "context": config.CONTEXT,
         "firstname": "Géorge",
         "lastname": "Bâptiste",
         "email": "george@baptiste.st",
         "mobile_phone_number": "5551234567",
         "ring_seconds": "15",
         "simultaneous_calls": "10",
         "language": "fr_FR",
         "outgoing_caller_id": '"Géorge Le Grand" <5557654321>',
         "userfield": "userfield",
         "supervision_enabled": "1",
         "call_transfer_enabled": "1",
         "call_record_enabled": "0",
         "online_call_record_enabled": "0",
         "call_permission_password": "321",
         "enabled": "1",
         "sip_username": "georgesipusername",
         "sip_secret": "georgesippassword",
         "incall_exten": incall_exten1,
         "incall_context": config.INCALL_CONTEXT,
         "incall_ring_seconds": "10",
         "voicemail_name": "george",
         "voicemail_number": vm_number1,
         "voicemail_context": config.CONTEXT,
         "voicemail_password": "1234",
         "voicemail_email": "test@example.com",
         "voicemail_attach_audio": "1",
         "voicemail_delete_messages": "1",
         "voicemail_ask_password": "1",
         "cti_profile_name": "Agent",
         "cti_profile_enabled": "1",
         "username": "george",
         "password": "secret"},
        {"uuid": entry2['user_uuid'],
         "entity_id": "1",
         "firstname": "Moùssa",
         "lastname": "Nôbamgo",
         "email": "moussa@nobamgo.sd",
         "mobile_phone_number": "5553456789",
         "ring_seconds": "20",
         "simultaneous_calls": "8",
         "language": "fr_FR",
         "outgoing_caller_id": '"Mousssssssaaaa" <5557654321>',
         "userfield": "userfield",
         "supervision_enabled": "1",
         "call_transfer_enabled": "1",
         "call_record_enabled": "1",
         "online_call_record_enabled": "1",
         "call_permission_password": "654",
         "enabled": "0",
         "exten": exten2,
         "context": config.CONTEXT,
         "incall_exten": incall_exten2,
         "incall_context": 'from-extern',
         "incall_ring_seconds": "12",
         "voicemail_name": "moussa",
         "voicemail_number": vm_number2,
         "voicemail_context": config.CONTEXT,
         "voicemail_password": "2345",
         "voicemail_email": "test2@example.com",
         "voicemail_attach_audio": "1",
         "voicemail_delete_messages": "1",
         "voicemail_ask_password": "1",
         "cti_profile_name": "Agent",
         "cti_profile_enabled": "1",
         "username": "moussa1",
         "password": "secret"},
    ]

    response = client.put("/users/import", csv)
    entry = response.item['updated']

    assert_that(entry, has_items(has_entries(user_id=entry1['user_id'],
                                             line_id=entry1['line_id'],
                                             extension_id=entry1['extension_id'],
                                             voicemail_id=entry1['voicemail_id'],
                                             cti_profile_id=entry1['cti_profile_id'],
                                             sip_id=entry1['sip_id'],
                                             incall_extension_id=entry1['incall_extension_id']),
                                 has_entries(user_id=entry2['user_id'],
                                             line_id=entry2['line_id'],
                                             extension_id=entry2['extension_id'],
                                             voicemail_id=entry2['voicemail_id'],
                                             cti_profile_id=entry2['cti_profile_id'],
                                             sccp_id=entry2['sccp_id'],
                                             incall_extension_id=entry2['incall_extension_id'])))


@fixtures.csv_entry(extension=True, line_protocol="sip")
@fixtures.csv_entry(extension=True, line_protocol="sip")
def test_given_2_entries_in_csv_updated_then_one_reload_event_published(entry1, entry2):
    BusClient.listen_delayed_events('config.ipbx.reload')
    csv = [
        {"uuid": entry1["user_uuid"],
         "firstname": "Géorge"},
        {"uuid": entry2['user_uuid'],
         "firstname": "Moùssa"},
    ]
    all_optimized_commands = ['dialplan reload',
                              'module reload chan_sccp.so',
                              'module reload app_queue.so',
                              'sip reload']
    expected_commands = all_optimized_commands

    client.put("/users/import", csv)

    reload_events = BusClient.drain_events()

    assert_that(reload_events, has_length(1))
    assert_that(reload_events[0]['data']['commands'], contains_inanyorder(*expected_commands))


@fixtures.user()
@fixtures.sip()
@fixtures.extension()
@fixtures.extension(context=config.INCALL_CONTEXT)
@fixtures.voicemail()
@fixtures.call_permission()
def test_given_resources_not_associated_when_updating_then_resources_associated(user, sip, extension, incall, voicemail,
                                                                                call_permission):
    csv = [{"uuid": user['uuid'],
            "exten": extension['exten'],
            "context": extension['context'],
            "line_protocol": "sip",
            "sip_username": sip['username'],
            "incall_exten": incall['exten'],
            "incall_context": incall['context'],
            "voicemail_number": voicemail['number'],
            "voicemail_context": voicemail['context'],
            "cti_profile_name": "Client",
            "call_permissions": call_permission['name'],
            }]

    response = client.put("/users/import", csv)

    entry = response.item['updated'][0]

    response = confd.users(entry['user_id']).lines.get()
    assert_that(response.items, contains(has_entries(line_id=entry['line_id'])))

    response = confd.lines(entry['line_id']).extensions.get()
    assert_that(response.items, has_items(has_entries(extension_id=entry['extension_id']),
                                          has_entries(extension_id=entry['incall_extension_id'])))

    response = confd.users(entry['user_id']).voicemail.get()
    assert_that(response.item, has_entries(voicemail_id=entry['voicemail_id']))

    response = confd.lines(entry['line_id']).endpoints.sip.get()
    assert_that(response.item, has_entries(endpoint='sip',
                                           endpoint_id=entry['sip_id']))

    response = confd.users(entry['user_id']).cti.get()
    assert_that(response.item, has_entries(cti_profile_id=entry['cti_profile_id']))

    response = confd.users(entry['user_id']).callpermissions.get()
    assert_that(response.items, contains_inanyorder(has_entries(call_permission_id=call_permission['id'],
                                                                user_id=entry['user_id'])))


@fixtures.csv_entry(extension=True, voicemail=True, incall=True, cti_profile=True, line_protocol="sip",
                    call_permissions=1)
@fixtures.call_permission()
@fixtures.label()
def test_given_each_field_updated_individually_then_entry_updated(entry, call_permission, label):
    exten = h.extension.find_available_exten(config.CONTEXT)
    incall_exten = h.extension.find_available_exten(config.INCALL_CONTEXT)
    vm_number = h.voicemail.find_available_number(config.CONTEXT)

    fields = {"entity_id": "1",
              "exten": exten,
              "context": config.CONTEXT,
              "firstname": "Fàbien",
              "lastname": "Bâptiste",
              "email": "fabien@baptiste.st",
              "mobile_phone_number": "5551234567",
              "ring_seconds": "15",
              "simultaneous_calls": "10",
              "language": "fr_FR",
              "outgoing_caller_id": '"Fàbien Le Grand" <5557654321>',
              "userfield": "userfield",
              "supervision_enabled": "1",
              "call_transfer_enabled": "1",
              "call_record_enabled": "1",
              "online_call_record_enabled": "1",
              "call_permission_password": "542",
              "enabled": "0",
              "sip_username": "fabiensipusername",
              "sip_secret": "fabiensippassword",
              "incall_exten": incall_exten,
              "incall_context": config.INCALL_CONTEXT,
              "incall_ring_seconds": "10",
              "voicemail_name": "fabien",
              "voicemail_number": vm_number,
              "voicemail_context": config.CONTEXT,
              "voicemail_password": "1234",
              "voicemail_email": "test@example.com",
              "voicemail_attach_audio": "1",
              "voicemail_delete_messages": "1",
              "voicemail_ask_password": "1",
              "cti_profile_name": "Agent",
              "cti_profile_enabled": "1",
              "username": "fabien",
              "call_permissions": call_permission['name'],
              "labels": label['display_name'],
              "password": "secret"}

    for name, value in fields.items():
        yield update_csv_field, entry['user_uuid'], name, value


def update_csv_field(uuid, field, value):
    csv = [{'uuid': uuid, field: value}]
    response = client.put("/users/import", csv)
    response.assert_ok()
