Exemple #1
0
class PinpointBackendForm(BackendForm):
    project_id = TrimmedCharField(
        label=_("Project ID"),
        required=True
    )
    region = TrimmedCharField(
        label=_("Region"),
        required=True
    )
    access_key = TrimmedCharField(
        label=_("Access Key"),
        required=True
    )
    secret_access_key = TrimmedCharField(
        label=_("Secret Access Key"),
        required=True
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Pinpoint Settings"),
            'project_id',
            'region',
            'access_key',
            'secret_access_key'
        )
Exemple #2
0
class TelerivetBackendForm(BackendForm):
    api_key = TrimmedCharField(
        label=ugettext_lazy("API Key"),
    )
    project_id = TrimmedCharField(
        label=ugettext_lazy("Project ID"),
    )
    phone_id = TrimmedCharField(
        label=ugettext_lazy("Phone ID"),
    )
    webhook_secret = TrimmedCharField(
        label=ugettext_lazy("Webhook Secret"),
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Telerivet (Android) Settings"),
            'api_key',
            'project_id',
            'phone_id',
            'webhook_secret',
        )

    def clean_webhook_secret(self):
        # Circular import
        from corehq.messaging.smsbackends.telerivet.models import SQLTelerivetBackend
        value = self.cleaned_data['webhook_secret']
        backend = SQLTelerivetBackend.by_webhook_secret(value)
        if backend and backend.pk != self._cchq_backend_id:
            raise ValidationError(_("Already in use."))
        return value
Exemple #3
0
class TelerivetOutgoingSMSForm(Form):
    api_key = TrimmedCharField(label=ugettext_lazy("API Key"), required=True)
    project_id = TrimmedCharField(label=ugettext_lazy("Project ID"),
                                  required=True)
    phone_id = TrimmedCharField(label=ugettext_lazy("Phone ID"), required=True)

    def __init__(self, *args, **kwargs):
        super(TelerivetOutgoingSMSForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-2 col-md-1'
        self.helper.field_class = 'col-sm-4 col-md-3'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("API Key"),
                    Div(hqcrispy.MultiInlineField('api_key',
                                                  ng_model='apiKey')),
                    get_rmi_error_placeholder('apiKeyError'),
                    ng_class="{'has-error': apiKeyError}"),
                hqcrispy.B3MultiField(
                    _("Project ID"),
                    Div(
                        hqcrispy.MultiInlineField('project_id',
                                                  ng_model='projectId')),
                    get_rmi_error_placeholder('projectIdError'),
                    ng_class="{'has-error': projectIdError}"),
                hqcrispy.B3MultiField(
                    _("Phone ID"),
                    Div(
                        hqcrispy.MultiInlineField('phone_id',
                                                  ng_model='phoneId')),
                    get_rmi_error_placeholder('phoneIdError'),
                    ng_class="{'has-error': phoneIdError}")))
Exemple #4
0
class IvoryCoastMTNBackendForm(BackendForm):
    customer_id = TrimmedCharField(
        label=gettext_lazy("Customer ID"),
        required=True,
    )
    username = TrimmedCharField(
        label=gettext_lazy("Username"),
        required=True,
    )
    password = TrimmedCharField(
        label=gettext_lazy("Password"),
        required=True,
    )
    sender_id = TrimmedCharField(
        label=gettext_lazy("Sender ID"),
        required=True,
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Ivory Coast MTN Settings"),
            'customer_id',
            'username',
            'password',
            'sender_id',
        )
Exemple #5
0
class AppositBackendForm(BackendForm):
    application_id = TrimmedCharField(
        label=ugettext_lazy("Application Id"),
    )
    application_token = TrimmedCharField(
        label=ugettext_lazy("Application Token"),
    )
    from_number = TrimmedCharField(
        label=ugettext_lazy("From Number"),
    )
    host = TrimmedCharField(
        label=ugettext_lazy("Host"),
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Apposit Settings"),
            'application_id',
            'application_token',
            'from_number',
            'host',
        )

    def clean_host(self):
        value = self.cleaned_data.get("host")
        if is_url_or_host_banned(value):
            raise ValidationError(_("Invalid Host"))
        return value
Exemple #6
0
class HttpBackendForm(BackendForm):
    url = TrimmedCharField(label=ugettext_noop("URL"), )
    message_param = TrimmedCharField(
        label=ugettext_noop("Message Parameter"), )
    number_param = TrimmedCharField(
        label=ugettext_noop("Phone Number Parameter"), )
    include_plus = BooleanField(
        required=False,
        label=ugettext_noop("Include '+' in Phone Number"),
    )
    method = ChoiceField(
        label=ugettext_noop("HTTP Request Method"),
        choices=(("GET", "GET"), ("POST", "POST")),
    )
    additional_params = RecordListField(
        input_name="additional_params",
        label=ugettext_noop("Additional Parameters"),
    )

    def __init__(self, *args, **kwargs):
        if "initial" in kwargs and "additional_params" in kwargs["initial"]:
            additional_params_dict = kwargs["initial"]["additional_params"]
            kwargs["initial"]["additional_params"] = [{
                "name": key,
                "value": value
            } for key, value in additional_params_dict.items()]
        super(HttpBackendForm, self).__init__(*args, **kwargs)

    def clean_url(self):
        value = self.cleaned_data.get("url")
        if is_url_or_host_banned(value):
            raise ValidationError(_("Invalid URL"))
        return value

    def clean_additional_params(self):
        value = self.cleaned_data.get("additional_params")
        result = {}
        for pair in value:
            name = pair["name"].strip()
            value = pair["value"].strip()
            if name == "" or value == "":
                raise ValidationError("Please enter both name and value.")
            if name in result:
                raise ValidationError("Parameter name entered twice: %s" %
                                      name)
            result[name] = value
        return result

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("HTTP Settings"),
            'url',
            'method',
            'message_param',
            'number_param',
            'include_plus',
            'additional_params',
        )
class InfobipBackendForm(BackendForm):
    account_sid = TrimmedCharField(label=_("Account SID"), )
    auth_token = TrimmedCharField(label=_("Auth Token"), )

    scenario_key = TrimmedCharField(label=_("Scenario Key"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(_("Infobip Settings"), 'account_sid',
                               'auth_token', 'scenario_key')
Exemple #8
0
class TrumpiaBackendForm(BackendForm):
    username = TrimmedCharField(label=gettext_lazy("Username"), required=True)
    api_key = TrimmedCharField(label=gettext_lazy("API Key"), required=True)

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Trumpia Settings"),
            'username',
            'api_key',
        )
Exemple #9
0
class MegamobileBackendForm(BackendForm):
    api_account_name = TrimmedCharField(label=_("API Account Name"), )
    source_identifier = TrimmedCharField(label=_("Source Identifier"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Megamobile Settings"),
            'api_account_name',
            'source_identifier',
        )
Exemple #10
0
class GrapevineBackendForm(BackendForm):
    affiliate_code = TrimmedCharField(label=_("Affiliate Code"), )
    authentication_code = TrimmedCharField(label=_("Authentication Code"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Grapevine Settings"),
            'affiliate_code',
            'authentication_code',
        )
Exemple #11
0
class TwilioBackendForm(BackendForm, LoadBalancingBackendFormMixin):
    account_sid = TrimmedCharField(label=_("Account SID"), )
    auth_token = TrimmedCharField(label=_("Auth Token"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Twilio Settings"),
            'account_sid',
            'auth_token',
        )
Exemple #12
0
class TelerivetOutgoingSMSForm(Form):
    api_key = TrimmedCharField(label=ugettext_lazy("API Key"), required=True)
    project_id = TrimmedCharField(label=ugettext_lazy("Project ID"),
                                  required=True)
    phone_id = TrimmedCharField(label=ugettext_lazy("Phone ID"), required=True)

    def __init__(self, *args, **kwargs):
        super(TelerivetOutgoingSMSForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-2 col-md-1'
        self.helper.field_class = 'col-sm-4 col-md-3'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("API Key"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'api_key',
                            data_bind='value: apiKey',
                        )),
                    crispy.Div(
                        css_class="help-block",
                        data_bind="visible: apiKeyError, text: apiKeyError",
                    ),
                    data_bind="css: {'has-error': apiKeyError}",
                ),
                hqcrispy.B3MultiField(
                    _("Project ID"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'project_id',
                            data_bind='value: projectId',
                        )),
                    crispy.Div(
                        css_class="help-block",
                        data_bind=
                        "visible: projectIdError, text: projectIdError",
                    ),
                    data_bind="css: {'has-error': projectIdError}",
                ),
                hqcrispy.B3MultiField(
                    _("Phone ID"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'phone_id',
                            data_bind='value: phoneId',
                        )),
                    crispy.Div(
                        css_class="help-block",
                        data_bind="visible: phoneIdError, text: phoneIdError",
                    ),
                    data_bind="css: {'has-error': phoneIdError}",
                )))
Exemple #13
0
class UnicelBackendForm(BackendForm):
    username = TrimmedCharField(label=_("Username"), )
    password = TrimmedCharField(label=_("Password"), )
    sender = TrimmedCharField(label=_("Sender ID"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Unicel Settings"),
            'username',
            'password',
            'sender',
        )
Exemple #14
0
class PushBackendForm(BackendForm):
    channel = TrimmedCharField(label=ugettext_lazy("Channel"), )
    service = TrimmedCharField(label=ugettext_lazy("Service"), )
    password = TrimmedCharField(label=ugettext_lazy("Password"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Push Settings"),
            'channel',
            'service',
            'password',
        )
Exemple #15
0
class SMSGHBackendForm(BackendForm):
    from_number = TrimmedCharField(label=ugettext_lazy("From Number"), )
    client_id = TrimmedCharField(label=ugettext_lazy("Client Id"), )
    client_secret = TrimmedCharField(label=ugettext_lazy("Client Secret"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("SMSGH Settings"),
            'from_number',
            'client_id',
            'client_secret',
        )
Exemple #16
0
class ICDSBackendForm(BackendForm):
    username = TrimmedCharField(label=_('Username'), )
    pin = TrimmedCharField(label=_('PIN'), )
    sender_id = TrimmedCharField(label=_('Sender ID'), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("ICDS Settings"),
            'username',
            'pin',
            'sender_id',
        )
Exemple #17
0
class FinalizeGatewaySetupForm(Form):
    YES = 'Y'
    NO = 'N'

    YES_NO_CHOICES = (
        (YES, ugettext_lazy("Yes")),
        (NO, ugettext_lazy("No")),
    )

    name = TrimmedCharField(
        label=ugettext_lazy("Name"),
        required=True
    )
    set_as_default = ChoiceField(
        label=ugettext_lazy("Set as default gateway"),
        choices=YES_NO_CHOICES,
        required=True
    )

    def __init__(self, *args, **kwargs):
        super(FinalizeGatewaySetupForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-3 col-md-2'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("Name"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'name',
                            ng_model='name'
                        )
                    ),
                    get_rmi_error_placeholder('nameError'),
                    ng_class="{'has-error': nameError}"
                ),
                hqcrispy.B3MultiField(
                    _("Set as default gateway"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'set_as_default',
                            ng_model='setAsDefault',
                            style='margin-left: 0px;'
                        )
                    ),
                    get_rmi_error_placeholder('setAsDefaultError'),
                    ng_class="{'has-error': setAsDefaultError}"
                ),
                FormActions(
                    StrictButton(
                        _("Complete"),
                        id="id_create_backend",
                        css_class='btn-success',
                        ng_click='createBackend();'
                    )
                )
            )
        )
class TelerivetPhoneNumberForm(Form):
    test_phone_number = TrimmedCharField(
        required=True, label=ugettext_lazy("+ (Country Code) Phone Number"))

    def __init__(self, *args, **kwargs):
        super(TelerivetPhoneNumberForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-2 col-md-1'
        self.helper.field_class = 'col-sm-4 col-md-3'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("Test Phone Number"),
                    Div(
                        hqcrispy.MultiInlineField('test_phone_number',
                                                  ng_model='testPhoneNumber')),
                    get_rmi_error_placeholder('testPhoneNumberError'),
                    Div(
                        StrictButton(_("Send"),
                                     id='id_send_sms_button',
                                     css_class='btn btn-success',
                                     ng_click='sendTestSMS();')),
                    ng_class="{'has-error': testPhoneNumberError}")))

    def clean_test_phone_number(self):
        value = self.cleaned_data.get('test_phone_number')
        value = apply_leniency(value)
        validate_phone_number(
            value,
            error_message=
            _("Please enter digits only, in international format (country code and phone number)."
              ))
        return value
Exemple #19
0
class SelfRegistrationForm(forms.Form):
    def __init__(self, *args, **kwargs):
        if 'domain' not in kwargs:
            raise Exception('Expected kwargs: domain')
        self.domain = kwargs.pop('domain')
        require_email = kwargs.pop('require_email', False)

        super(SelfRegistrationForm, self).__init__(*args, **kwargs)

        if require_email:
            self.fields['email'].required = True

        self.helper = FormHelper()
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-xs-4'
        self.helper.field_class = 'col-xs-8'
        layout_fields = [
            crispy.Fieldset(
                _('Register'),
                crispy.Field('username'),
                crispy.Field('password'),
                crispy.Field('password2'),
                crispy.Field('email'),
            ),
            hqcrispy.FormActions(
                StrictButton(
                    _('Register'),
                    css_class='btn-primary',
                    type='submit',
                )),
        ]
        self.helper.layout = crispy.Layout(*layout_fields)

    username = TrimmedCharField(
        required=True,
        label=ugettext_lazy('Username (create a username)'),
    )
    password = forms.CharField(
        required=True,
        label=ugettext_lazy('Password (create a password)'),
        widget=PasswordInput(),
    )
    password2 = forms.CharField(
        required=True,
        label=ugettext_lazy('Re-enter Password'),
        widget=PasswordInput(),
    )
    email = forms.EmailField(
        required=False,
        label=ugettext_lazy('Email address'),
    )

    def clean_username(self):
        return clean_mobile_worker_username(self.domain,
                                            self.cleaned_data.get('username'))

    def clean_password2(self):
        if self.cleaned_data.get('password') != self.cleaned_data.get(
                'password2'):
            raise forms.ValidationError(_('Passwords do not match.'))
Exemple #20
0
class FinalizeGatewaySetupForm(Form):
    YES = 'Y'
    NO = 'N'

    YES_NO_CHOICES = (
        (YES, ugettext_lazy("Yes")),
        (NO, ugettext_lazy("No")),
    )

    name = TrimmedCharField(label=ugettext_lazy("Name"), required=True)
    set_as_default = ChoiceField(label=ugettext_lazy("Set as default gateway"),
                                 choices=YES_NO_CHOICES,
                                 required=True)

    def __init__(self, *args, **kwargs):
        super(FinalizeGatewaySetupForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-3 col-md-2'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("Name"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'name',
                            data_bind='value: name',
                        )),
                    crispy.Div(
                        css_class="help-block",
                        data_bind="visible: nameError, text: nameError",
                    ),
                    data_bind="css: {'has-error': nameError}",
                ),
                hqcrispy.B3MultiField(
                    _("Set as default gateway"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'set_as_default',
                            data_bind='value: setAsDefault',
                            style='margin-left: 0px;')),
                    crispy.Div(
                        css_class="help-block",
                        data_bind=
                        "visible: setAsDefaultError, text: setAsDefaultError",
                    ),
                    data_bind="css: {'has-error': setAsDefaultError}",
                ),
                FormActions(
                    StrictButton(
                        "",
                        id="id_create_backend",
                        css_class='btn-primary',
                        data_bind=
                        "text: backendButtonText, click: createBackend, disable: creatingBackend,"
                        "css: {'btn-primary': !backendButtonError(), "
                        "'btn-danger': backendButtonError()}",
                    ))))
Exemple #21
0
class TwilioBackendForm(BackendForm, LoadBalancingBackendFormMixin):
    account_sid = TrimmedCharField(label=_("Account SID"), )
    auth_token = TrimmedCharField(label=_("Auth Token"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Twilio Settings"),
            'account_sid',
            'auth_token',
        )

    def validate_phone_number(self, phone_number: str) -> None:
        from corehq.messaging.smsbackends.twilio.models import SQLTwilioBackend
        if not SQLTwilioBackend.phone_number_is_messaging_service_sid(
                phone_number):
            super().validate_phone_number(phone_number)
Exemple #22
0
class TropoBackendForm(BackendForm):
    messaging_token = TrimmedCharField(label=_("Messaging Token"))

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Tropo Settings"),
            'messaging_token',
        )
Exemple #23
0
class AppositBackendForm(BackendForm):
    application_id = TrimmedCharField(label=gettext_lazy("Application Id"), )
    application_token = TrimmedCharField(
        label=gettext_lazy("Application Token"), )
    from_number = TrimmedCharField(label=gettext_lazy("From Number"), )
    host = TrimmedCharField(label=gettext_lazy("Host"), )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Apposit Settings"),
            'application_id',
            'application_token',
            'from_number',
            'host',
        )

    def clean_host(self):
        host = self.cleaned_data.get("host")
        return form_clean_url(host)
Exemple #24
0
class VertexBackendForm(BackendForm):
    username = TrimmedCharField(
        label=ugettext_lazy("username"),
        required=True,
    )
    password = TrimmedCharField(
        label=ugettext_lazy("password"),
        required=True,
    )
    senderid = TrimmedCharField(
        label=ugettext_lazy("senderid"),
        required=True,
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Vertex Settings"),
            'username',
            'password',
            'senderid',
        )
Exemple #25
0
class StartEnterpriseBackendForm(BackendForm):
    username = TrimmedCharField(
        label=ugettext_lazy("Username"),
        required=True,
    )
    password = TrimmedCharField(
        label=ugettext_lazy("Password"),
        required=True,
    )
    sender_id = TrimmedCharField(
        label=ugettext_lazy("Sender Id"),
        required=True,
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Start Enterprise Settings"),
            'username',
            'password',
            'sender_id',
        )
Exemple #26
0
class InfobipBackendForm(BackendForm):
    account_sid = TrimmedCharField(label=_("Account SID"), required=True)
    auth_token = TrimmedCharField(label=_("Auth Token"), required=True)
    personalized_subdomain = TrimmedCharField(
        label=_("Personalized Subdomain"), required=True)
    scenario_key = TrimmedCharField(
        label=_("Scenario Key"),
        help_text=
        _("Enables sendimg messages via whatsapp, viber, line and voice channel with or "
          "without automatic failover to another channel according to the specific scenario."
          ),
        required=False)

    def clean_scenario_key(self):
        value = self.cleaned_data.get("scenario_key") or ""
        return value.strip() or None

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(_("Infobip Settings"), 'account_sid',
                               'auth_token', 'personalized_subdomain',
                               'scenario_key')
Exemple #27
0
class TelerivetPhoneNumberForm(Form):
    test_phone_number = TrimmedCharField(
        required=True, label=ugettext_lazy("+ (Country Code) Phone Number"))

    def __init__(self, *args, **kwargs):
        super(TelerivetPhoneNumberForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-2 col-md-1'
        self.helper.field_class = 'col-sm-4 col-md-3'
        self.helper.layout = Layout(
            Div(
                hqcrispy.B3MultiField(
                    _("Test Phone Number"),
                    Div(
                        hqcrispy.MultiInlineField(
                            'test_phone_number',
                            data_bind='value: testPhoneNumber',
                        )),
                    crispy.Div(
                        css_class="help-block",
                        data_bind=
                        "visible: testPhoneNumberError, text: testPhoneNumberError",
                    ),
                    Div(
                        StrictButton(
                            "",
                            id='id_send_sms_button',
                            css_class='btn',
                            data_bind=
                            "text: sendSmsButtonText, click: sendTestSMS, "
                            "css: {'btn-primary': !sendSmsButtonError(), "
                            "'btn-danger': sendSmsButtonError()}",
                        )),
                    data_bind="css: {'has-error': testPhoneNumberError}",
                )))

    def clean_test_phone_number(self):
        value = self.cleaned_data.get('test_phone_number')
        value = apply_leniency(value)
        validate_phone_number(
            value,
            error_message=
            _("Please enter digits only, in international format (country code and phone number)."
              ))
        return value
Exemple #28
0
class CaseUpdateRuleForm(forms.Form):
    # Prefix to avoid name collisions; this means all input
    # names in the HTML are prefixed with "rule-"
    prefix = "rule"

    name = TrimmedCharField(
        label=ugettext_lazy("Name"),
        required=True,
    )

    def compute_initial(self, rule):
        return {
            'name': rule.name,
        }

    def __init__(self, domain, *args, **kwargs):
        if 'initial' in kwargs:
            raise ValueError("Initial values are set by the form")

        self.is_system_admin = kwargs.pop('is_system_admin', False)

        rule = kwargs.pop('rule', None)
        if rule:
            kwargs['initial'] = self.compute_initial(rule)

        super(CaseUpdateRuleForm, self).__init__(*args, **kwargs)

        self.domain = domain
        self.helper = FormHelper()
        self.helper.label_class = 'col-xs-2 col-xs-offset-1'
        self.helper.field_class = 'col-xs-2'
        self.helper.form_tag = False

        self.helper.layout = Layout(
            Fieldset(
                _("Basic Information"),
                Field('name', data_bind='name'),
            ),
        )
Exemple #29
0
class AirtelTCLBackendForm(BackendForm):
    host_and_port = TrimmedCharField(
        label=gettext_lazy("Host:Port"),
        required=True,
    )
    user_name = TrimmedCharField(
        label=gettext_lazy("Username"),
        required=True,
    )
    password = TrimmedCharField(
        label=gettext_lazy("Password"),
        required=True,
    )
    sender_id = TrimmedCharField(
        label=gettext_lazy("Sender ID"),
        required=True,
    )
    circle_name = TrimmedCharField(
        label=gettext_lazy("Circle Name"),
        required=True,
    )
    campaign_name = TrimmedCharField(
        label=gettext_lazy("Campaign Name"),
        required=True,
    )

    @property
    def gateway_specific_fields(self):
        return crispy.Fieldset(
            _("Airtel (through TCL) Settings"),
            'host_and_port',
            'user_name',
            'password',
            'sender_id',
            'circle_name',
            'campaign_name',
        )

    def clean_host_and_port(self):
        host_and_port = self.cleaned_data.get('host_and_port')
        return form_clean_url(host_and_port)
Exemple #30
0
class SettingsForm(Form):
    # General Settings
    use_default_sms_response = ChoiceField(
        required=False,
        label=ugettext_noop("Default SMS Response"),
        choices=ENABLED_DISABLED_CHOICES,
    )
    default_sms_response = TrimmedCharField(
        required=False,
        label="",
    )
    use_restricted_sms_times = ChoiceField(
        required=False,
        label=ugettext_noop("Send SMS on..."),
        choices=(
            (DISABLED, ugettext_noop("any day, at any time")),
            (ENABLED, ugettext_noop("only specific days and times")),
        ),
    )
    restricted_sms_times_json = CharField(
        required=False,
        widget=forms.HiddenInput,
    )
    send_to_duplicated_case_numbers = ChoiceField(
        required=False,
        label=ugettext_noop("Send Messages to Non-Unique Phone Numbers"),
        choices=ENABLED_DISABLED_CHOICES,
    )

    # Chat Settings
    use_custom_case_username = ChoiceField(
        required=False,
        choices=DEFAULT_CUSTOM_CHOICES,
    )
    custom_case_username = TrimmedCharField(
        required=False,
        label=ugettext_noop("Enter a Case Property"),
    )
    use_custom_message_count_threshold = ChoiceField(
        required=False,
        choices=MESSAGE_COUNTER_CHOICES,
    )
    custom_message_count_threshold = IntegerField(
        required=False,
        label=ugettext_noop("Enter a Number"),
    )
    use_sms_conversation_times = ChoiceField(
        required=False,
        label=ugettext_noop("Delay Automated SMS"),
        choices=ENABLED_DISABLED_CHOICES,
    )
    sms_conversation_times_json = CharField(
        required=False,
        widget=forms.HiddenInput,
    )
    sms_conversation_length = ChoiceField(
        required=False,
        label=ugettext_noop("Conversation Duration"),
        choices=SMS_CONVERSATION_LENGTH_CHOICES,
    )
    survey_traffic_option = ChoiceField(
        required=False,
        label=ugettext_noop("Survey Traffic"),
        choices=(
            (SHOW_ALL, ugettext_noop("Show all survey traffic")),
            (SHOW_INVALID,
             ugettext_noop("Hide all survey traffic except "
                           "invalid responses")),
            (HIDE_ALL, ugettext_noop("Hide all survey traffic")),
        ),
    )
    count_messages_as_read_by_anyone = ChoiceField(
        required=False,
        label=ugettext_noop("A Message is Read..."),
        choices=(
            (ENABLED, ugettext_noop("when it is read by anyone")),
            (DISABLED, ugettext_noop("only for the user that reads it")),
        ),
    )
    use_custom_chat_template = ChoiceField(
        required=False,
        choices=DEFAULT_CUSTOM_CHOICES,
    )
    custom_chat_template = TrimmedCharField(
        required=False,
        label=ugettext_noop("Enter Chat Template Identifier"),
    )
    sms_case_registration_enabled = ChoiceField(
        required=False,
        choices=ENABLED_DISABLED_CHOICES,
        label=ugettext_noop("Case Self-Registration"),
    )
    sms_case_registration_type = TrimmedCharField(
        required=False,
        label=ugettext_noop("Default Case Type"),
    )
    sms_case_registration_owner_id = ChoiceField(
        required=False,
        label=ugettext_noop("Default Case Owner"),
    )
    sms_case_registration_user_id = ChoiceField(
        required=False,
        label=ugettext_noop("Registration Submitter"),
    )

    sms_mobile_worker_registration_enabled = ChoiceField(
        required=False,
        choices=ENABLED_DISABLED_CHOICES,
        label=ugettext_noop("SMS Mobile Worker Registration"),
    )

    @property
    def section_general(self):
        fields = [
            BootstrapMultiField(
                _("Default SMS Response"),
                InlineField(
                    "use_default_sms_response",
                    data_bind="value: use_default_sms_response",
                ),
                InlineField(
                    "default_sms_response",
                    css_class="input-xxlarge",
                    placeholder=_("Enter Default Response"),
                    data_bind="visible: showDefaultSMSResponse",
                ),
                help_bubble_text=_(
                    "Enable this option to provide a "
                    "default response when a user's incoming SMS does not "
                    "answer an open survey or match a known keyword."),
                css_id="default-sms-response-group",
            ),
            FieldWithHelpBubble(
                "use_restricted_sms_times",
                data_bind="value: use_restricted_sms_times",
                help_bubble_text=_(
                    "Use this option to limit the times "
                    "that SMS messages can be sent to users. Messages that "
                    "are sent outside these windows will remained queued "
                    "and will go out as soon as another window opens up."),
            ),
            BootstrapMultiField(
                "",
                HiddenFieldWithErrors(
                    "restricted_sms_times_json",
                    data_bind="value: restricted_sms_times_json"),
                crispy.Div(data_bind="template: {"
                           " name: 'ko-template-restricted-sms-times', "
                           " data: $data"
                           "}", ),
                data_bind="visible: showRestrictedSMSTimes",
            ),
            FieldWithHelpBubble(
                "send_to_duplicated_case_numbers",
                help_bubble_text=_(
                    "Enabling this option will send "
                    "outgoing-only messages to phone numbers registered "
                    "with more than one mobile worker or case. SMS surveys "
                    "and keywords will still only work for unique phone "
                    "numbers in your project."),
            ),
        ]
        return crispy.Fieldset(_("General Settings"), *fields)

    @property
    def section_registration(self):
        fields = [
            FieldWithHelpBubble(
                "sms_case_registration_enabled",
                help_bubble_text=_(
                    "When this option is enabled, a person "
                    "can send an SMS into the system saying 'join "
                    "[project]', where [project] is your project "
                    "space name, and the system will automatically "
                    "create a case tied to that person's phone number."),
                data_bind="value: sms_case_registration_enabled",
            ),
            crispy.Div(
                FieldWithHelpBubble(
                    "sms_case_registration_type",
                    placeholder=_("Enter a Case Type"),
                    help_bubble_text=_("Cases that self-register over SMS "
                                       "will be given this case type."),
                ),
                FieldWithHelpBubble(
                    "sms_case_registration_owner_id",
                    help_bubble_text=_(
                        "Cases that self-register over SMS "
                        "will be owned by this user or user group."),
                ),
                FieldWithHelpBubble(
                    "sms_case_registration_user_id",
                    help_bubble_text=_(
                        "The form submission for a "
                        "self-registration will belong to this user."),
                ),
                data_bind="visible: showRegistrationOptions",
            ),
            FieldWithHelpBubble(
                "sms_mobile_worker_registration_enabled",
                help_bubble_text=_(
                    "When this option is enabled, a person "
                    "can send an SMS into the system saying 'join "
                    "[project] worker [username]' (where [project] is your "
                    " project space and [username] is an optional username)"
                    ", and the system will add them as a mobile worker."),
            ),
        ]
        return crispy.Fieldset(_("Registration Settings"), *fields)

    @property
    def section_chat(self):
        fields = [
            BootstrapMultiField(
                _("Case Name Display"),
                InlineField(
                    "use_custom_case_username",
                    data_bind="value: use_custom_case_username",
                ),
                InlineField(
                    "custom_case_username",
                    css_class="input-large",
                    data_bind="visible: showCustomCaseUsername",
                ),
                help_bubble_text=_(
                    "By default, when chatting with a case, "
                    "the chat window will use the case's \"name\" case "
                    "property when displaying the case's name. To use a "
                    "different case property, specify it here."),
                css_id="custom-case-username-group",
            ),
            BootstrapMultiField(
                _("Message Counter"),
                InlineField(
                    "use_custom_message_count_threshold",
                    data_bind="value: use_custom_message_count_threshold",
                ),
                InlineField(
                    "custom_message_count_threshold",
                    css_class="input-large",
                    data_bind="visible: showCustomMessageCountThreshold",
                ),
                help_bubble_text=_(
                    "The chat window can use a counter to keep "
                    "track of how many messages are being sent and received "
                    "and highlight that number after a certain threshold is "
                    "reached. By default, the counter is disabled. To enable "
                    "it, enter the desired threshold here."),
                css_id="custom-message-count-threshold-group",
            ),
            FieldWithHelpBubble(
                "use_sms_conversation_times",
                data_bind="value: use_sms_conversation_times",
                help_bubble_text=_(
                    "When this option is enabled, the system "
                    "will not send automated SMS to chat recipients when "
                    "those recipients are in the middle of a conversation."),
            ),
            BootstrapMultiField(
                "",
                HiddenFieldWithErrors(
                    "sms_conversation_times_json",
                    data_bind="value: sms_conversation_times_json"),
                crispy.Div(data_bind="template: {"
                           " name: 'ko-template-sms-conversation-times', "
                           " data: $data"
                           "}", ),
                data_bind="visible: showSMSConversationTimes",
            ),
            crispy.Div(
                FieldWithHelpBubble(
                    "sms_conversation_length",
                    help_bubble_text=_(
                        "The number of minutes to wait "
                        "after receiving an incoming SMS from a chat "
                        "recipient before resuming automated SMS to that "
                        "recipient."),
                ),
                data_bind="visible: showSMSConversationTimes",
            ),
            FieldWithHelpBubble(
                "survey_traffic_option",
                help_bubble_text=_(
                    "This option allows you to hide a chat "
                    "recipient's survey questions and responses from chat "
                    "windows. There is also the option to show only invalid "
                    "responses to questions in the chat window, which could "
                    "be attempts to converse."),
            ),
            FieldWithHelpBubble(
                "count_messages_as_read_by_anyone",
                help_bubble_text=_(
                    "The chat window will mark unread "
                    "messages to the user viewing them. Use this option to "
                    "control whether a message counts as being read if it "
                    "is read by anyone, or if it counts as being read only "
                    "to the user who reads it."),
            ),
        ]
        if self._cchq_is_previewer:
            fields.append(
                BootstrapMultiField(
                    _("Chat Template"),
                    InlineField(
                        "use_custom_chat_template",
                        data_bind="value: use_custom_chat_template",
                    ),
                    InlineField(
                        "custom_chat_template",
                        data_bind="visible: showCustomChatTemplate",
                    ),
                    help_bubble_text=_(
                        "To use a custom template to render the "
                        "chat window, enter it here."),
                    css_id="custom-chat-template-group",
                ))
        attrs = {}
        if not self._cchq_is_previewer:
            attrs["style"] = "display: none;"
        return crispy.Fieldset(_("Chat Settings"), *fields, **attrs)

    def __init__(self,
                 data=None,
                 cchq_domain=None,
                 cchq_is_previewer=False,
                 *args,
                 **kwargs):
        self._cchq_domain = cchq_domain
        self._cchq_is_previewer = cchq_is_previewer
        super(SettingsForm, self).__init__(data, *args, **kwargs)
        self.populate_dynamic_choices()

        self.helper = FormHelper()
        self.helper.form_class = "form form-horizontal"
        self.helper.layout = crispy.Layout(
            self.section_general,
            self.section_registration,
            self.section_chat,
            FormActions(
                StrictButton(
                    _("Save"),
                    type="submit",
                    css_class="btn-primary",
                ), ),
        )
        self.restricted_sms_times_widget_context = {
            "template_name":
            "ko-template-restricted-sms-times",
            "explanation_text":
            _("SMS will only be sent when any of the following is true:"),
            "ko_array_name":
            "restricted_sms_times",
            "remove_window_method":
            "$parent.removeRestrictedSMSTime",
            "add_window_method":
            "addRestrictedSMSTime",
        }
        self.sms_conversation_times_widget_context = {
            "template_name":
            "ko-template-sms-conversation-times",
            "explanation_text":
            _("Automated SMS will be suppressed during "
              "chat conversations when any of the following "
              "is true:"),
            "ko_array_name":
            "sms_conversation_times",
            "remove_window_method":
            "$parent.removeSMSConversationTime",
            "add_window_method":
            "addSMSConversationTime",
        }

    @property
    def current_values(self):
        current_values = {}
        for field_name in self.fields.keys():
            value = self[field_name].value()
            if field_name in [
                    "restricted_sms_times_json", "sms_conversation_times_json"
            ]:
                if isinstance(value, basestring):
                    current_values[field_name] = json.loads(value)
                else:
                    current_values[field_name] = value
            else:
                current_values[field_name] = value
        return current_values

    def populate_dynamic_choices(self):
        groups = Group.get_case_sharing_groups(self._cchq_domain)
        users = CommCareUser.by_domain(self._cchq_domain)

        domain_group_choices = [(group._id, group.name) for group in groups]
        domain_user_choices = [(user._id, user.raw_username) for user in users]
        domain_owner_choices = domain_group_choices + domain_user_choices

        choose = [("", _("(Choose)"))]
        self.fields["sms_case_registration_owner_id"].choices = (
            choose + domain_owner_choices)
        self.fields["sms_case_registration_user_id"].choices = (
            choose + domain_user_choices)

    def _clean_dependent_field(self, bool_field, field):
        if self.cleaned_data.get(bool_field):
            value = self.cleaned_data.get(field, None)
            if not value:
                raise ValidationError(_("This field is required."))
            return value
        else:
            return None

    def clean_use_default_sms_response(self):
        return self.cleaned_data.get("use_default_sms_response") == ENABLED

    def clean_default_sms_response(self):
        return self._clean_dependent_field("use_default_sms_response",
                                           "default_sms_response")

    def clean_use_custom_case_username(self):
        return self.cleaned_data.get("use_custom_case_username") == CUSTOM

    def clean_custom_case_username(self):
        return self._clean_dependent_field("use_custom_case_username",
                                           "custom_case_username")

    def clean_use_custom_message_count_threshold(self):
        return (self.cleaned_data.get("use_custom_message_count_threshold") ==
                CUSTOM)

    def clean_custom_message_count_threshold(self):
        value = self._clean_dependent_field(
            "use_custom_message_count_threshold",
            "custom_message_count_threshold")
        if value is not None and value <= 0:
            raise ValidationError(_("Please enter a positive number"))
        return value

    def clean_use_custom_chat_template(self):
        if not self._cchq_is_previewer:
            return None
        return self.cleaned_data.get("use_custom_chat_template") == CUSTOM

    def clean_custom_chat_template(self):
        if not self._cchq_is_previewer:
            return None
        value = self._clean_dependent_field("use_custom_chat_template",
                                            "custom_chat_template")
        if value is not None and value not in settings.CUSTOM_CHAT_TEMPLATES:
            raise ValidationError(_("Unknown custom template identifier."))
        return value

    def _clean_time_window_json(self, field_name):
        try:
            time_window_json = json.loads(self.cleaned_data.get(field_name))
        except ValueError:
            raise ValidationError(
                _("An error has occurred. Please try again, "
                  "and if the problem persists, please report an issue."))
        result = []
        for window in time_window_json:
            day = window.get("day")
            start_time = window.get("start_time")
            end_time = window.get("end_time")
            time_input_relationship = window.get("time_input_relationship")

            try:
                day = int(day)
                assert day >= -1 and day <= 6
            except (ValueError, AssertionError):
                raise ValidationError(_("Invalid day chosen."))

            if time_input_relationship == TIME_BEFORE:
                end_time = validate_time(end_time)
                result.append(
                    DayTimeWindow(
                        day=day,
                        start_time=None,
                        end_time=end_time,
                    ))
            elif time_input_relationship == TIME_AFTER:
                start_time = validate_time(start_time)
                result.append(
                    DayTimeWindow(
                        day=day,
                        start_time=start_time,
                        end_time=None,
                    ))
            else:
                start_time = validate_time(start_time)
                end_time = validate_time(end_time)
                if start_time >= end_time:
                    raise ValidationError(
                        _("End time must come after start "
                          "time."))
                result.append(
                    DayTimeWindow(
                        day=day,
                        start_time=start_time,
                        end_time=end_time,
                    ))
        return result

    def clean_use_restricted_sms_times(self):
        return self.cleaned_data.get("use_restricted_sms_times") == ENABLED

    def clean_restricted_sms_times_json(self):
        if self.cleaned_data.get("use_restricted_sms_times"):
            return self._clean_time_window_json("restricted_sms_times_json")
        else:
            return []

    def clean_use_sms_conversation_times(self):
        return self.cleaned_data.get("use_sms_conversation_times") == ENABLED

    def clean_sms_conversation_times_json(self):
        if self.cleaned_data.get("use_sms_conversation_times"):
            return self._clean_time_window_json("sms_conversation_times_json")
        else:
            return []

    def clean_send_to_duplicated_case_numbers(self):
        return (self.cleaned_data.get("send_to_duplicated_case_numbers") ==
                ENABLED)

    def clean_count_messages_as_read_by_anyone(self):
        return (self.cleaned_data.get("count_messages_as_read_by_anyone") ==
                ENABLED)

    def clean_sms_case_registration_enabled(self):
        return (
            self.cleaned_data.get("sms_case_registration_enabled") == ENABLED)

    def clean_sms_case_registration_type(self):
        return self._clean_dependent_field("sms_case_registration_enabled",
                                           "sms_case_registration_type")

    def _clean_registration_id_field(self, field_name):
        if self.cleaned_data.get("sms_case_registration_enabled"):
            value = self.cleaned_data.get(field_name)
            if not value:
                raise ValidationError(_("This field is required."))
            # Otherwise, the ChoiceField automatically validates that it is
            # in the list that is dynamically populated in __init__
            return value
        else:
            return None

    def clean_sms_case_registration_owner_id(self):
        return self._clean_registration_id_field(
            "sms_case_registration_owner_id")

    def clean_sms_case_registration_user_id(self):
        return self._clean_registration_id_field(
            "sms_case_registration_user_id")

    def clean_sms_mobile_worker_registration_enabled(self):
        return (self.cleaned_data.get("sms_mobile_worker_registration_enabled")
                == ENABLED)

    def clean_sms_conversation_length(self):
        # Just cast to int, the ChoiceField will validate that it is an integer
        return int(self.cleaned_data.get("sms_conversation_length"))