Source code for ussd.screens.menu_screen

from ussd.core import UssdHandlerAbstract, UssdResponse
from .serializers import UssdContentBaseSerializer, \
    MenuOptionSerializer, NextUssdScreenSerializer, UssdTextSerializer
from rest_framework.serializers import ListField, ValidationError, \
    CharField
from django.core.paginator import Paginator
import textwrap
from django.conf import settings
from ussd import defaults


class WithItemField(CharField):
    def to_internal_value(self, data):
        if isinstance(data, list):
            return data
        return super(WithItemField, self).to_internal_value(data)


class WithDictField(CharField):
    def to_internal_value(self, data):
        if isinstance(data, dict):
            return data
        return super(WithDictField, self).to_internal_value(data)


class ItemsSerializer(UssdTextSerializer, NextUssdScreenSerializer):
    value = CharField()
    session_key = CharField()
    with_items = WithItemField(required=False, default=None)
    with_dict = WithDictField(required=False, default=None)

    def to_internal_value(self, data):
        # set data in instance to access later
        self.custom_data = data
        return super(ItemsSerializer, self).to_internal_value(data)

    def validate_with_items(self, value, loop_value='with_dict'):
        if value is None and self.custom_data.get(loop_value, None) is None:
            raise ValidationError(
                "with_items or with_dict field is required"
            )
        return value

    def validate_with_dict(self, value):
        return self.validate_with_items(value, 'with_items')


class MenuScreenSerializer(UssdContentBaseSerializer):
    """
    - text:
        .. autoclass:: UssdContentBaseSerializer

    - options:
        This is a list of options to display to the user
        each option is
            .. autoclass:: MenuOptionSerializer

    - items:
        Sometimes you what to display a list of items and not
        menu options. Item is used for this
            .. autoclass:: ItemsSerializer

    - error_message: This is an optional message to display if the
                     user enters invalid input

    - option and items are mutual exclusive.

    Examples of menu screen:

        .. literalinclude:: .././ussd/tests/sample_screen_definition/valid_menu_screen_conf.yml
    """
    options = ListField(
        child=MenuOptionSerializer(),
        required=False
    )
    items = ItemsSerializer(required=False)

    def validate(self, data):
        if 'options' not in data and 'items' not in data:
            raise ValidationError(
                'options field is required or items is required'
            )
        return super(MenuScreenSerializer, self).validate(data)


class ListItem(object):
    def __init__(self, text, value):
        self.text = text
        self.value = value


class MenuOption(object):
    def __init__(self, text, next_screen, index_display=None,
                 index_value=None):
        self.text = text
        self.next_screen = next_screen
        self.index_display = index_display or index_value
        self.index_value = index_value or self.index_display