<commit_before>"""
Utils.
"""
import inflection
from django.core import urlresolvers
from django.conf import settings
from django.utils import six, encoding
from django.utils.translation import ugettext_lazy as _
from rest_framework.serializers import BaseSerializer, ListSerializer, ModelSerializer
from rest_framework.relations import RelatedField, HyperlinkedRelatedField, PrimaryKeyRelatedField
from rest_framework.settings import api_settings
from rest_framework.exceptions import APIException

from django.utils.six.moves.urllib.parse import urlparse

try:
    from rest_framework.compat import OrderedDict
except ImportError:
    OrderedDict = dict

try:
    from rest_framework.serializers import ManyRelatedField
except ImportError:
    ManyRelatedField = type(None)

try:
    from rest_framework_nested.relations import HyperlinkedRouterField
except ImportError:
    HyperlinkedRouterField = type(None)

def get_resource_name(context):
    """
    Return the name of a resource.
    """
    view = context.get('view')

    # Sanity check to make sure we have a view.
    if not view:
        raise APIException(_('Could not find view.'))

    # Check to see if there is a status code and return early
    # with the resource_name value of `errors`.
    try:
        code = str(view.response.status_code)
    except (AttributeError, ValueError):
        pass
    else:
        if code.startswith('4') or code.startswith('5'):
            return 'errors'

    try:
        resource_name = getattr(view, 'resource_name')
    except AttributeError:
        try:
            # Check the meta class
            resource_name = (getattr(view, 'serializer_class').Meta.resource_name)
        except AttributeError:
            # Use the model
            try:
                resource_name = (getattr(view, 'serializer_class').Meta.model.__name__)
            except AttributeError:
                try:
                    resource_name = view.model.__name__
                except AttributeError:
                    resource_name = view.__class__.__name__

            # if the name was calculated automatically then pluralize and format
            if not isinstance(resource_name, six.string_types):
                return resource_name

            resource_name = inflection.pluralize(resource_name.lower())

            resource_name = format_value(resource_name)

    return resource_name

def get_serializer_fields(serializer):
    if hasattr(serializer, 'child'):
        return getattr(serializer.child, 'fields')
    if hasattr(serializer, 'fields'):
        return getattr(serializer, 'fields')

def format_keys(obj, format_type=None):
    """
    Takes either a dict or list and returns it with camelized keys only if
    JSON_API_FORMAT_KEYS is set.

    :format_type: Either 'dasherize', 'camelize' or 'underscore'
    """
    if format_type is None:
        format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)

    if format_type in ('dasherize', 'camelize', 'underscore'):

        if isinstance(obj, dict):
            formatted = OrderedDict()
            for key, value in obj.items():
                if format_type == 'dasherize':
                    formatted[inflection.dasherize(key)] \
                        = format_keys(value, format_type)
                elif format_type == 'camelize':
                    formatted[inflection.camelize(key, False)] \
                        = format_keys(value, format_type)
                elif format_type == 'underscore':
                    formatted[inflection.underscore(key)] \
                        = format_keys(value, format_type)
            return formatted
        if isinstance(obj, list):
            return [format_keys(item, format_type) for item in obj]
        else:
            return obj
    else:
        return obj

def format_value(value, format_type=None):
    format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)
    if format_type == 'dasherize':
        value = inflection.dasherize(value)
    elif format_type == 'camelize':
        value = inflection.camelize(value)
    elif format_type == 'underscore':
        value = inflection.underscore(value)
    return value

def build_json_resource_obj(fields, resource, resource_instance, resource_name):
    resource_data = [
        ('type', resource_name),
        ('id', extract_id(fields, resource)),
        ('attributes', extract_attributes(fields, resource)),
    ]
    relationships = extract_relationships(fields, resource, resource_instance)
    if relationships:
        resource_data.append(('relationships', relationships))
    # Add 'self' link if field is present and valid
    if api_settings.URL_FIELD_NAME in resource and \
            isinstance(fields[api_settings.URL_FIELD_NAME], RelatedField):
        resource_data.append(('links', {'self': resource[api_settings.URL_FIELD_NAME]}))
    return OrderedDict(resource_data)

def get_related_resource_type(relation):
    if hasattr(relation, 'get_queryset') and relation.get_queryset() is not None:
        relation_model = relation.get_queryset().model
    else:
        parent_serializer = relation.parent
        if hasattr(parent_serializer, 'Meta'):
            parent_model = parent_serializer.Meta.model
        else:
            parent_model = parent_serializer.parent.Meta.model
        parent_model_relation = getattr(
            parent_model,
            (relation.source if relation.source else parent_serializer.field_name)
        )
        if hasattr(parent_model_relation, 'related'):
            relation_model = parent_model_relation.related.model
        elif hasattr(parent_model_relation, 'field'):
            relation_model = parent_model_relation.field.related.model
        else:
            raise APIException('Unable to find related model for relation {relation}'.format(relation=relation))
    return inflection.pluralize(relation_model.__name__).lower()

def extract_id_from_url(url):
    http_prefix = url.startswith(('http:', 'https:'))
    if http_prefix:
        # If needed convert absolute URLs to relative path
        data = urlparse(url).path
        prefix = urlresolvers.get_script_prefix()
        if data.startswith(prefix):
            url = '/' + data[len(prefix):]

    match = urlresolvers.resolve(url)
    return encoding.force_text(match.kwargs['pk'])

def extract_id(fields, resource):
    for field_name, field in six.iteritems(fields):
        if field_name == 'id':
            return encoding.force_text(resource.get(field_name))
        if field_name == api_settings.URL_FIELD_NAME:
            return extract_id_from_url(resource.get(field_name))

def extract_attributes(fields, resource):
    data = OrderedDict()
    for field_name, field in six.iteritems(fields):
        # ID is always provided in the root of JSON API so remove it from attrs
        if field_name == 'id':
            continue
        # Skip fields with relations
        if isinstance(field, (RelatedField, BaseSerializer, ManyRelatedField)):
            continue
        data.update({
            field_name: resource.get(field_name)
        })

    return format_keys(data)

def extract_relationships(fields, resource, resource_instance):
    data = OrderedDict()
    for field_name, field in six.iteritems(fields):
        # Skip URL field
        if field_name == api_settings.URL_FIELD_NAME:
            continue

        # Skip fields without relations
        if not isinstance(field, (RelatedField, ManyRelatedField, BaseSerializer)):
            continue

        if isinstance(field, HyperlinkedRouterField):
            # special case for HyperlinkedRouterField
            relation_data = list()
            relation_type = get_related_resource_type(field)
            related = getattr(resource_instance, field_name).all()
            for relation in related:
                relation_data.append(OrderedDict([('type', relation_type), ('id', relation.pk)]))

            data.update({field_name: {
                'links': {
                    "related": resource.get(field_name)},
                'data': relation_data,
                'meta': {
                    'count': len(relation_data)
                }
            }})
            continue

        if isinstance(field, (PrimaryKeyRelatedField, HyperlinkedRelatedField)):
            relation_type = get_related_resource_type(field)

            if resource.get(field_name) is not None:
                if isinstance(field, PrimaryKeyRelatedField):
                    relation_id = encoding.force_text(resource.get(field_name))
                elif isinstance(field, HyperlinkedRelatedField):
                    relation_id = extract_id_from_url(resource.get(field_name))
            else:
                relation_id = None

            data.update(
                {
                    field_name: {
                        'data': (OrderedDict([
                            ('type', relation_type), ('id', relation_id)
                        ]) if relation_id is not None else None)
                    }
                }
            )
            continue

        if isinstance(field, ManyRelatedField):
            relation_data = list()

            relation = field.child_relation

            relation_type = get_related_resource_type(relation)

            if isinstance(relation, HyperlinkedRelatedField):
                for link in resource.get(field_name, list()):
                    relation_data.append(OrderedDict([('type', relation_type), ('id', extract_id_from_url(link))]))

                data.update({field_name: {'data': relation_data}})
                continue

            if isinstance(relation, PrimaryKeyRelatedField):
                for pk in resource.get(field_name, list()):
                    relation_data.append(OrderedDict([('type', relation_type), ('id', encoding.force_text(pk))]))

                data.update({field_name: {'data': relation_data}})
                continue

        if isinstance(field, ListSerializer):
            relation_data = list()

            serializer = field.child
            relation_model = serializer.Meta.model
            relation_type = inflection.pluralize(relation_model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(serializer)
            serializer_data = resource.get(field_name)
            if isinstance(serializer_data, list):
                for serializer_resource in serializer_data:
                    relation_data.append(
                        OrderedDict([
                            ('type', relation_type), ('id', extract_id(serializer_fields, serializer_resource))
                        ]))

                data.update({field_name: {'data': relation_data}})
                continue

        if isinstance(field, ModelSerializer):
            relation_model = field.Meta.model
            relation_type = inflection.pluralize(relation_model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(field)
            serializer_data = resource.get(field_name)
            data.update({
                field_name: {
                    'data': (
                        OrderedDict([
                            ('type', relation_type),
                            ('id', extract_id(serializer_fields, serializer_data))
                        ]) if resource.get(field_name) else None)
                }
            })
            continue

    return format_keys(data)

def extract_included(fields, resource):
    included_data = list()
    for field_name, field in six.iteritems(fields):
        # Skip URL field
        if field_name == api_settings.URL_FIELD_NAME:
            continue

        # Skip fields without serialized data
        if not isinstance(field, BaseSerializer):
            continue

        if isinstance(field, ListSerializer):

            serializer = field.child
            model = serializer.Meta.model
            relation_type = inflection.pluralize(model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(serializer)
            serializer_data = resource.get(field_name)
            if isinstance(serializer_data, list):
                for serializer_resource in serializer_data:
                    included_data.append(build_json_resource_obj(serializer_fields, serializer_resource, relation_type))

        if isinstance(field, ModelSerializer):

            model = field.Meta.model
            relation_type = inflection.pluralize(model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(field)
            serializer_data = resource.get(field_name)
            if serializer_data:
                included_data.append(build_json_resource_obj(serializer_fields, serializer_data, relation_type))

    return format_keys(included_data)
<commit_msg>Removed extract_id as we now have access to the resource instance<commit_after>"""
Utils.
"""
import inflection
from django.core import urlresolvers
from django.conf import settings
from django.utils import six, encoding
from django.utils.translation import ugettext_lazy as _
from rest_framework.serializers import BaseSerializer, ListSerializer, ModelSerializer
from rest_framework.relations import RelatedField, HyperlinkedRelatedField, PrimaryKeyRelatedField
from rest_framework.settings import api_settings
from rest_framework.exceptions import APIException

from django.utils.six.moves.urllib.parse import urlparse

try:
    from rest_framework.compat import OrderedDict
except ImportError:
    OrderedDict = dict

try:
    from rest_framework.serializers import ManyRelatedField
except ImportError:
    ManyRelatedField = type(None)

try:
    from rest_framework_nested.relations import HyperlinkedRouterField
except ImportError:
    HyperlinkedRouterField = type(None)

def get_resource_name(context):
    """
    Return the name of a resource.
    """
    view = context.get('view')

    # Sanity check to make sure we have a view.
    if not view:
        raise APIException(_('Could not find view.'))

    # Check to see if there is a status code and return early
    # with the resource_name value of `errors`.
    try:
        code = str(view.response.status_code)
    except (AttributeError, ValueError):
        pass
    else:
        if code.startswith('4') or code.startswith('5'):
            return 'errors'

    try:
        resource_name = getattr(view, 'resource_name')
    except AttributeError:
        try:
            # Check the meta class
            resource_name = (getattr(view, 'serializer_class').Meta.resource_name)
        except AttributeError:
            # Use the model
            try:
                resource_name = (getattr(view, 'serializer_class').Meta.model.__name__)
            except AttributeError:
                try:
                    resource_name = view.model.__name__
                except AttributeError:
                    resource_name = view.__class__.__name__

            # if the name was calculated automatically then pluralize and format
            if not isinstance(resource_name, six.string_types):
                return resource_name

            resource_name = inflection.pluralize(resource_name.lower())

            resource_name = format_value(resource_name)

    return resource_name

def get_serializer_fields(serializer):
    if hasattr(serializer, 'child'):
        return getattr(serializer.child, 'fields')
    if hasattr(serializer, 'fields'):
        return getattr(serializer, 'fields')

def format_keys(obj, format_type=None):
    """
    Takes either a dict or list and returns it with camelized keys only if
    JSON_API_FORMAT_KEYS is set.

    :format_type: Either 'dasherize', 'camelize' or 'underscore'
    """
    if format_type is None:
        format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)

    if format_type in ('dasherize', 'camelize', 'underscore'):

        if isinstance(obj, dict):
            formatted = OrderedDict()
            for key, value in obj.items():
                if format_type == 'dasherize':
                    formatted[inflection.dasherize(key)] \
                        = format_keys(value, format_type)
                elif format_type == 'camelize':
                    formatted[inflection.camelize(key, False)] \
                        = format_keys(value, format_type)
                elif format_type == 'underscore':
                    formatted[inflection.underscore(key)] \
                        = format_keys(value, format_type)
            return formatted
        if isinstance(obj, list):
            return [format_keys(item, format_type) for item in obj]
        else:
            return obj
    else:
        return obj

def format_value(value, format_type=None):
    format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)
    if format_type == 'dasherize':
        value = inflection.dasherize(value)
    elif format_type == 'camelize':
        value = inflection.camelize(value)
    elif format_type == 'underscore':
        value = inflection.underscore(value)
    return value

def build_json_resource_obj(fields, resource, resource_instance, resource_name):
    resource_data = [
        ('type', resource_name),
        ('id', resource_instance.pk),
        ('attributes', extract_attributes(fields, resource)),
    ]
    relationships = extract_relationships(fields, resource, resource_instance)
    if relationships:
        resource_data.append(('relationships', relationships))
    # Add 'self' link if field is present and valid
    if api_settings.URL_FIELD_NAME in resource and \
            isinstance(fields[api_settings.URL_FIELD_NAME], RelatedField):
        resource_data.append(('links', {'self': resource[api_settings.URL_FIELD_NAME]}))
    return OrderedDict(resource_data)

def get_related_resource_type(relation):
    if hasattr(relation, 'get_queryset') and relation.get_queryset() is not None:
        relation_model = relation.get_queryset().model
    else:
        parent_serializer = relation.parent
        if hasattr(parent_serializer, 'Meta'):
            parent_model = parent_serializer.Meta.model
        else:
            parent_model = parent_serializer.parent.Meta.model
        parent_model_relation = getattr(
            parent_model,
            (relation.source if relation.source else parent_serializer.field_name)
        )
        if hasattr(parent_model_relation, 'related'):
            relation_model = parent_model_relation.related.model
        elif hasattr(parent_model_relation, 'field'):
            relation_model = parent_model_relation.field.related.model
        else:
            raise APIException('Unable to find related model for relation {relation}'.format(relation=relation))
    return inflection.pluralize(relation_model.__name__).lower()

def extract_id_from_url(url):
    http_prefix = url.startswith(('http:', 'https:'))
    if http_prefix:
        # If needed convert absolute URLs to relative path
        data = urlparse(url).path
        prefix = urlresolvers.get_script_prefix()
        if data.startswith(prefix):
            url = '/' + data[len(prefix):]

    match = urlresolvers.resolve(url)
    return encoding.force_text(match.kwargs['pk'])

def extract_attributes(fields, resource):
    data = OrderedDict()
    for field_name, field in six.iteritems(fields):
        # ID is always provided in the root of JSON API so remove it from attributes
        if field_name == 'id':
            continue
        # Skip fields with relations
        if isinstance(field, (RelatedField, BaseSerializer, ManyRelatedField)):
            continue
        data.update({
            field_name: resource.get(field_name)
        })

    return format_keys(data)

def extract_relationships(fields, resource, resource_instance):
    data = OrderedDict()
    for field_name, field in six.iteritems(fields):
        # Skip URL field
        if field_name == api_settings.URL_FIELD_NAME:
            continue

        # Skip fields without relations
        if not isinstance(field, (RelatedField, ManyRelatedField, BaseSerializer)):
            continue

        if isinstance(field, HyperlinkedRouterField):
            # special case for HyperlinkedRouterField
            relation_data = list()
            relation_type = get_related_resource_type(field)
            related = getattr(resource_instance, field_name).all()
            for relation in related:
                relation_data.append(OrderedDict([('type', relation_type), ('id', relation.pk)]))

            data.update({field_name: {
                'links': {
                    "related": resource.get(field_name)},
                'data': relation_data,
                'meta': {
                    'count': len(relation_data)
                }
            }})
            continue

        if isinstance(field, (PrimaryKeyRelatedField, HyperlinkedRelatedField)):
            relation_type = get_related_resource_type(field)

            if resource.get(field_name) is not None:
                if isinstance(field, PrimaryKeyRelatedField):
                    relation_id = encoding.force_text(resource.get(field_name))
                elif isinstance(field, HyperlinkedRelatedField):
                    relation_id = extract_id_from_url(resource.get(field_name))
            else:
                relation_id = None

            data.update(
                {
                    field_name: {
                        'data': (OrderedDict([
                            ('type', relation_type), ('id', relation_id)
                        ]) if relation_id is not None else None)
                    }
                }
            )
            continue

        if isinstance(field, ManyRelatedField):
            relation_data = list()

            relation = field.child_relation

            relation_type = get_related_resource_type(relation)

            if isinstance(relation, HyperlinkedRelatedField):
                for link in resource.get(field_name, list()):
                    relation_data.append(OrderedDict([('type', relation_type), ('id', extract_id_from_url(link))]))

                data.update({field_name: {'data': relation_data}})
                continue

            if isinstance(relation, PrimaryKeyRelatedField):
                for pk in resource.get(field_name, list()):
                    relation_data.append(OrderedDict([('type', relation_type), ('id', encoding.force_text(pk))]))

                data.update({field_name: {'data': relation_data}})
                continue

        if isinstance(field, ListSerializer):
            relation_data = list()

            serializer = field.child
            relation_model = serializer.Meta.model
            relation_type = inflection.pluralize(relation_model.__name__).lower()

            serializer_data = resource.get(field_name)
            if isinstance(serializer_data, list):
                for position in range(len(serializer_data)):
                    resource_instance_manager = getattr(resource_instance, field_name).all()
                    nested_resource_instance = resource_instance_manager[position]
                    relation_data.append(
                        OrderedDict([
                            ('type', relation_type), ('id', nested_resource_instance.pk)
                        ]))

                data.update({field_name: {'data': relation_data}})
                continue

        if isinstance(field, ModelSerializer):
            relation_model = field.Meta.model
            relation_type = inflection.pluralize(relation_model.__name__).lower()

            data.update({
                field_name: {
                    'data': (
                        OrderedDict([
                            ('type', relation_type),
                            ('id', getattr(resource_instance, field_name).pk)
                        ]) if resource.get(field_name) else None)
                }
            })
            continue

    return format_keys(data)

def extract_included(fields, resource):
    included_data = list()
    for field_name, field in six.iteritems(fields):
        # Skip URL field
        if field_name == api_settings.URL_FIELD_NAME:
            continue

        # Skip fields without serialized data
        if not isinstance(field, BaseSerializer):
            continue

        if isinstance(field, ListSerializer):

            serializer = field.child
            model = serializer.Meta.model
            relation_type = inflection.pluralize(model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(serializer)
            serializer_data = resource.get(field_name)
            if isinstance(serializer_data, list):
                for serializer_resource in serializer_data:
                    included_data.append(build_json_resource_obj(serializer_fields, serializer_resource, relation_type))

        if isinstance(field, ModelSerializer):

            model = field.Meta.model
            relation_type = inflection.pluralize(model.__name__).lower()

            # Get the serializer fields
            serializer_fields = get_serializer_fields(field)
            serializer_data = resource.get(field_name)
            if serializer_data:
                included_data.append(build_json_resource_obj(serializer_fields, serializer_data, relation_type))

    return format_keys(included_data)
<|endoftext|>


<commit_before># encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <gogogo.vm@gmail.com>
"""

from __future__ import absolute_import

from collections import namedtuple
import ipaddress
import platform

import typepy
from typepy.type import Integer

DEFAULT_WAITTIME = 1

class PingResult(namedtuple("PingResult", "stdout stderr returncode")):
    """
    Data class to store ``ping`` command execution result.

    .. py:attribute:: stdout

        Standard output of ``ping`` command execution result.

    .. py:attribute:: stderr

        Standard error of ``ping`` command execution result.

    .. py:attribute:: returncode

        Return code of ``ping`` command execution result.
    """

class PingTransmitter(object):
    """
    Transmitter class to send ICMP packets by using the OS built-in ``ping``
    command.

    .. py:attribute:: destination_host

        Hostname or IP-address (IPv4/IPf6) to sending ICMP packets.

    .. py:attribute:: waittime

        Time ``[sec]`` of sending ICMP packets. This will be ignored if
        the value is ``None``. If both :py:attr:`~.waittime` and
        :py:attr:`~.count` are ``None``, :py:attr:`~.waittime` will be set to
        ``1``.
        Defaults to ``None``.

    .. py:attribute:: count

        Number of sending ICMP packets. This will be ignored if the value is
        ``None``. Defaults to ``None``.

    .. py:attribute:: ping_option

        Additional ``ping`` command option.

    .. py:attribute:: interface

        Interface name or zone-id. This will be required when
        :py:attr:`~.destination_host` is IPv6 link-local scope address.
        Defaults to ``None``.

    .. py:attribute:: auto_codepage

        [Only for windows environment] Automatically change code page if
        ``True``. Defaults to ``True``.
    """

    def __init__(self):
        self.destination_host = ""
        self.waittime = None
        self.count = None
        self.ping_option = ""
        self.interface = None
        self.auto_codepage = True

    def ping(self):
        """
        Sending ICMP packets.

        :return: ``ping`` command execution result.
        :rtype: :py:class:`.PingResult`
        :raises ValueError: If parameters not valid.
        """

        import subprocess

        self.__validate_ping_param()

        command_list = self.__get_base_ping_command_list()

        if typepy.is_not_null_string(self.ping_option):
            command_list.append(self.ping_option)

        command_list.extend([
            self.__get_waittime_option(),
            self.__get_count_option(),
        ])

        ping_proc = subprocess.Popen(
            " ".join(command_list), shell=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = ping_proc.communicate()

        return PingResult(stdout, stderr, ping_proc.returncode)

    def __is_windows(self):
        return platform.system() == "Windows"

    def __is_ipv6(self):
        try:
            network = ipaddress.ip_network(self.destination_host)
        except ValueError:
            return False

        return network.version == 6

    def __validate_ping_param(self):
        if typepy.is_null_string(self.destination_host):
            raise ValueError("required destination_host")

        self.__validate_waittime()
        self.__validate_count()
        self.__validate_interface()

    def __validate_waittime(self):
        if self.waittime is None:
            return

        try:
            waittime = Integer(self.waittime).convert()
        except typepy.TypeConversionError:
            raise ValueError("wait time must be an integer: actual={}".format(
                self.waittime))

        if waittime <= 0:
            raise ValueError("wait time must be greater than zero")

    def __validate_count(self):
        if self.count is None:
            return

        try:
            count = Integer(self.count).convert()
        except typepy.TypeConversionError:
            raise ValueError("count must be an integer: actual={}".format(
                self.count))

        if count <= 0:
            raise ValueError("count must be greater than zero")

    def __validate_interface(self):
        if not self.__is_ipv6():
            return

        if not ipaddress.ip_network(self.destination_host).is_link_local:
            return

        if typepy.is_null_string(self.interface):
            raise ValueError(
                "interface required to ping to IPv6 link local address")

    def __get_base_ping_command_list(self):
        command_list = []

        if self.__is_windows() and self.auto_codepage:
            command_list.append("chcp 437 &")

        command_list.extend([
            self.__get_ping_command(),
            self.__get_destination_host(),
        ])

        return command_list

    def __get_destination_host(self):
        if self.__is_windows() and self.__is_ipv6():
            return "{:s}%{}".format(self.destination_host, self.interface)

        return self.destination_host

    def __get_ping_command(self):
        if self.__is_windows():
            return "ping"

        if self.__is_ipv6():
            return "ping6"

        return "ping"

    def __get_waittime_option(self):
        try:
            waittime = Integer(self.waittime).convert()
        except typepy.TypeConversionError:
            if self.count:
                return ""

            waittime = DEFAULT_WAITTIME

        if self.__is_windows():
            return "-n {:d}".format(waittime)
        else:
            return "-q -w {:d}".format(waittime)

    def __get_count_option(self):
        try:
            count = Integer(self.count).convert()
        except typepy.TypeConversionError:
            return ""

        if self.__is_windows():
            return "-n {:d}".format(count)
        else:
            return "-c {:d}".format(count)
<commit_msg>Improve Python 2 compatibility<commit_after># encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <gogogo.vm@gmail.com>
"""

from __future__ import absolute_import

from collections import namedtuple
import ipaddress
import platform

import six
import typepy
from typepy.type import Integer

DEFAULT_WAITTIME = 1

class PingResult(namedtuple("PingResult", "stdout stderr returncode")):
    """
    Data class to store ``ping`` command execution result.

    .. py:attribute:: stdout

        Standard output of ``ping`` command execution result.

    .. py:attribute:: stderr

        Standard error of ``ping`` command execution result.

    .. py:attribute:: returncode

        Return code of ``ping`` command execution result.
    """

class PingTransmitter(object):
    """
    Transmitter class to send ICMP packets by using the OS built-in ``ping``
    command.

    .. py:attribute:: destination_host

        Hostname or IP-address (IPv4/IPf6) to sending ICMP packets.

    .. py:attribute:: waittime

        Time ``[sec]`` of sending ICMP packets. This will be ignored if
        the value is ``None``. If both :py:attr:`~.waittime` and
        :py:attr:`~.count` are ``None``, :py:attr:`~.waittime` will be set to
        ``1``.
        Defaults to ``None``.

    .. py:attribute:: count

        Number of sending ICMP packets. This will be ignored if the value is
        ``None``. Defaults to ``None``.

    .. py:attribute:: ping_option

        Additional ``ping`` command option.

    .. py:attribute:: interface

        Interface name or zone-id. This will be required when
        :py:attr:`~.destination_host` is IPv6 link-local scope address.
        Defaults to ``None``.

    .. py:attribute:: auto_codepage

        [Only for windows environment] Automatically change code page if
        ``True``. Defaults to ``True``.
    """

    def __init__(self):
        self.destination_host = ""
        self.waittime = None
        self.count = None
        self.ping_option = ""
        self.interface = None
        self.auto_codepage = True

    def ping(self):
        """
        Sending ICMP packets.

        :return: ``ping`` command execution result.
        :rtype: :py:class:`.PingResult`
        :raises ValueError: If parameters not valid.
        """

        import subprocess

        self.__validate_ping_param()

        command_list = self.__get_base_ping_command_list()

        if typepy.is_not_null_string(self.ping_option):
            command_list.append(self.ping_option)

        command_list.extend([
            self.__get_waittime_option(),
            self.__get_count_option(),
        ])

        ping_proc = subprocess.Popen(
            " ".join(command_list), shell=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = ping_proc.communicate()

        return PingResult(stdout, stderr, ping_proc.returncode)

    def __is_windows(self):
        return platform.system() == "Windows"

    def __is_ipv6(self):
        try:
        except ValueError:
            network = ipaddress.ip_address(
                six.text_type(self.destination_host))
            return False

        return network.version == 6

    def __validate_ping_param(self):
        if typepy.is_null_string(self.destination_host):
            raise ValueError("required destination_host")

        self.__validate_waittime()
        self.__validate_count()
        self.__validate_interface()

    def __validate_waittime(self):
        if self.waittime is None:
            return

        try:
            waittime = Integer(self.waittime).convert()
        except typepy.TypeConversionError:
            raise ValueError("wait time must be an integer: actual={}".format(
                self.waittime))

        if waittime <= 0:
            raise ValueError("wait time must be greater than zero")

    def __validate_count(self):
        if self.count is None:
            return

        try:
            count = Integer(self.count).convert()
        except typepy.TypeConversionError:
            raise ValueError("count must be an integer: actual={}".format(
                self.count))

        if count <= 0:
            raise ValueError("count must be greater than zero")

    def __validate_interface(self):
        if not self.__is_ipv6():
            return

        if not ipaddress.ip_network(
                six.text_type(self.destination_host)).is_link_local:
            return

        if typepy.is_null_string(self.interface):
            raise ValueError(
                "interface required to ping to IPv6 link local address")

    def __get_base_ping_command_list(self):
        command_list = []

        if self.__is_windows() and self.auto_codepage:
            command_list.append("chcp 437 &")

        command_list.extend([
            self.__get_ping_command(),
            self.__get_destination_host(),
        ])

        return command_list

    def __get_destination_host(self):
        if self.__is_windows() and self.__is_ipv6():
            return "{:s}%{}".format(self.destination_host, self.interface)

        return self.destination_host

    def __get_ping_command(self):
        if self.__is_windows():
            return "ping"

        if self.__is_ipv6():
            return "ping6"

        return "ping"

    def __get_waittime_option(self):
        try:
            waittime = Integer(self.waittime).convert()
        except typepy.TypeConversionError:
            if self.count:
                return ""

            waittime = DEFAULT_WAITTIME

        if self.__is_windows():
            return "-n {:d}".format(waittime)
        else:
            return "-q -w {:d}".format(waittime)

    def __get_count_option(self):
        try:
            count = Integer(self.count).convert()
        except typepy.TypeConversionError:
            return ""

        if self.__is_windows():
            return "-n {:d}".format(count)
        else:
            return "-c {:d}".format(count)
<|endoftext|>


<commit_before>from datetime import date

from braces.views import LoginRequiredMixin, StaffuserRequiredMixin
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.forms import Form
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.views.generic import DetailView, FormView

from reunition.apps.alumni import models as alumni_m

from . import forms as f
from . import models as m

def redirect_to_latest(request):
    # TODO: don't assume only a single graduating class
    today = date.today()
    reunion = m.Reunion.objects.filter(starts_on__gte=today).order_by('starts_on')[0]
    return redirect(
        'reunions:detail',
        pk=reunion.pk,
    )

# ------------------------------------------

class ReunionDetailView(DetailView):

    model = m.Reunion
    context_object_name = 'reunion'

detail_view = ReunionDetailView.as_view()

# ------------------------------------------

class ReunionReportsView(LoginRequiredMixin, StaffuserRequiredMixin, DetailView):

    model = m.Reunion
    context_object_name = 'reunion'
    template_name_suffix = '_reports'

reports_view =  ReunionReportsView.as_view()

# ------------------------------------------

class GetRsvpMixin(object):

    def get_reunion(self):
        return m.Reunion.objects.get(pk=self.kwargs['pk'])

    def get_rsvp(self):
        reunion = self.get_reunion()
        return reunion.rsvp_set.get(created_by=self.request.user)

class GetAttendeeMixin(object):

    attendee_class = None

    def get_attendee(self):
        attendee = self.attendee_class.objects.get(
            pk=self.kwargs['attendee_pk'],
            rsvp=self.get_rsvp(),
        )
        return attendee

class RedirectToRsvpOnSuccessMixin(object):

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

class RsvpView(LoginRequiredMixin, DetailView):

    model = m.Reunion
    context_object_name = 'reunion'
    template_name_suffix = '_rsvp'

    def get_context_data(self, **kwargs):
        context = super(RsvpView, self).get_context_data(**kwargs)
        rsvp = self.request.user.rsvp_set.filter(reunion=self.object).first()
        if rsvp:
            context.update(
                rsvp=rsvp,
                update_form=f.UpdateForm(initial=dict(
                    attending=rsvp.attending,
                    current_city=rsvp.current_city,
                    contact_method=rsvp.contact_method,
                    phone=rsvp.phone,
                ))
            )
        else:
            context.update(self._initial_form_context_data())
        return context

    def _initial_form_context_data(self):
        form_data = {}
        fb_account = self.request.user.socialaccount_set.filter(provider='facebook').first()
        if fb_account:
            fb_data = fb_account.extra_data
            first_name = fb_data.get('first_name')
            last_name = fb_data.get('last_name')
            alumnus = alumni_m.Person.objects.matching_any_name_in_class(
                self.object.graduating_class, first_name, last_name)
            if alumnus:
                message = """
                    We matched your Facebook contact information with our alumni roster.
                    Please complete the following and change your current name if necessary.
                """
                messages.add_message(self.request, messages.INFO, message)
                form_data.update(
                    graduation_first_name=alumnus.graduation_first_name,
                    graduation_last_name=alumnus.graduation_last_name,
                    current_first_name=alumnus.current_first_name,
                    current_last_name=alumnus.current_last_name,
                )
            else:
                message = 'Is this information correct? Please change your current or graduation names as needed.'
                messages.add_message(self.request, messages.INFO, message)
                form_data.update(
                    graduation_first_name=first_name,
                    graduation_last_name=last_name,
                )
        initial_form = f.InitialForm(initial=form_data)
        return dict(
            initial_form=initial_form,
        )

class RsvpInitialFormView(LoginRequiredMixin, FormView):

    form_class = f.InitialForm
    template_name = 'reunions/reunion_rsvp_initial_form.html'

    def get_reunion(self):
        return m.Reunion.objects.get(pk=self.kwargs['pk'])

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

    def get_context_data(self, **kwargs):
        data = super(RsvpInitialFormView, self).get_context_data(**kwargs)
        data.update(
            reunion=self.get_reunion(),
        )
        return data

    def form_invalid(self, form):
        message = 'Please fill in the required fields to continue.'
        messages.add_message(self.request, messages.WARNING, message)
        return super(RsvpInitialFormView, self).form_invalid(form)

    def form_valid(self, form):
        data = form.cleaned_data
        reunion = self.get_reunion()
        if not m.Rsvp.objects.filter(created_by=self.request.user, reunion=reunion).exists():
            rsvp = m.Rsvp.objects.create(
                created_by=self.request.user,
                reunion=reunion,
                attending=data['attending'],
                current_city=data['current_city'],
                contact_method=data['contact_method'],
                phone=data['phone'],
            )
            rsvp.add_alumni_attendee_by_name(
                graduation_first_name=data['graduation_first_name'],
                graduation_last_name=data['graduation_last_name'],
                current_first_name=data['current_first_name'],
                current_last_name=data['current_last_name'],
                request=self.request,
            )
        return super(RsvpInitialFormView, self).form_valid(form)

class RsvpUpdateView(GetRsvpMixin, LoginRequiredMixin, FormView):

    form_class = f.UpdateForm
    template_name = 'reunions/reunion_rsvp_update.html'

    def form_valid(self, form):
        rsvp = self.get_rsvp()
        for k, v in form.cleaned_data.items():
            setattr(rsvp, k, v)
        rsvp.save()
        return super(RsvpUpdateView, self).form_valid(form)

    def get(self, request, *args, **kwargs):
        # Don't allow GET for this form.
        return HttpResponseRedirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        data = super(RsvpUpdateView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        data.update(
            reunion=rsvp.reunion,
            rsvp=rsvp,
        )
        return data

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

class RsvpAlumniAddView(GetRsvpMixin,
                        LoginRequiredMixin,
                        RedirectToRsvpOnSuccessMixin,
                        FormView):

    form_class = f.AlumniAddForm
    template_name = 'reunions/reunion_rsvp_alumni_add.html'

    def form_valid(self, form):
        data = form.cleaned_data
        self.get_rsvp().add_alumni_attendee_by_name(
            graduation_first_name=data['graduation_first_name'],
            graduation_last_name=data['graduation_last_name'],
            current_first_name=data['current_first_name'],
            current_last_name=data['current_last_name'],
            request=self.request,
            always_update_current_name=False,
        )
        return super(RsvpAlumniAddView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniAddView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
        )
        return data

class RsvpAlumniEditView(GetRsvpMixin,
                         GetAttendeeMixin,
                         LoginRequiredMixin,
                         RedirectToRsvpOnSuccessMixin,
                         FormView):

    attendee_class = m.RsvpAlumniAttendee
    form_class = f.AlumniUpdateForm
    template_name = 'reunions/reunion_rsvp_alumni_edit.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        person = attendee.person
        person.current_first_name = data['current_first_name']
        person.current_last_name = data['current_last_name']
        person.save()
        return super(RsvpAlumniEditView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniEditView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

    def get_initial(self):
        attendee = self.get_attendee()
        return dict(
            current_first_name=attendee.person.current_first_name,
            current_last_name=attendee.person.current_last_name,
        )

class RsvpAlumniRemoveView(GetRsvpMixin,
                           GetAttendeeMixin,
                           LoginRequiredMixin,
                           RedirectToRsvpOnSuccessMixin,
                           FormView):

    attendee_class = m.RsvpAlumniAttendee
    form_class = Form  # empty form
    template_name = 'reunions/reunion_rsvp_alumni_remove.html'

    def dispatch(self, request, *args, **kwargs):
        if self.get_rsvp().rsvpalumniattendee_set.count() == 1:
            return HttpResponseRedirect(self.get_success_url())

        return super(RsvpAlumniRemoveView, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.delete()
        message = '{} removed from alumni list.'.format(attendee)
        messages.add_message(self.request, messages.SUCCESS, message)
        return super(RsvpAlumniRemoveView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniRemoveView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

class RsvpGuestAddView(GetRsvpMixin,
                       LoginRequiredMixin,
                       RedirectToRsvpOnSuccessMixin,
                       FormView):

    form_class = f.GuestForm
    template_name = 'reunions/reunion_rsvp_guest_add.html'

    def form_valid(self, form):
        data = form.cleaned_data
        self.get_rsvp().rsvpguestattendee_set.create(
            first_name=data['first_name'],
            last_name=data['last_name'],
            relationship=data['relationship'],
        )
        return super(RsvpGuestAddView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestAddView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
        )
        return data

class RsvpGuestEditView(GetRsvpMixin,
                        GetAttendeeMixin,
                        LoginRequiredMixin,
                        RedirectToRsvpOnSuccessMixin,
                        FormView):

    attendee_class = m.RsvpGuestAttendee
    form_class = f.GuestForm
    template_name = 'reunions/reunion_rsvp_guest_edit.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.first_name = data['first_name']
        attendee.last_name = data['last_name']
        attendee.relationship = data['relationship']
        attendee.save()
        return super(RsvpGuestEditView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestEditView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

    def get_initial(self):
        attendee = self.get_attendee()
        return dict(
            first_name=attendee.first_name,
            last_name=attendee.last_name,
            relationship=attendee.relationship,
        )

class RsvpGuestRemoveView(GetRsvpMixin,
                          GetAttendeeMixin,
                          LoginRequiredMixin,
                          RedirectToRsvpOnSuccessMixin,
                          FormView):

    attendee_class = m.RsvpGuestAttendee
    form_class = Form  # empty form
    template_name = 'reunions/reunion_rsvp_guest_remove.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.delete()
        message = '{} removed from guest list.'.format(attendee)
        messages.add_message(self.request, messages.SUCCESS, message)
        return super(RsvpGuestRemoveView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestRemoveView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

rsvp_view = RsvpView.as_view()
rsvp_initial_form_view = RsvpInitialFormView.as_view()
rsvp_update_view = RsvpUpdateView.as_view()
rsvp_alumni_add_view = RsvpAlumniAddView.as_view()
rsvp_alumni_edit_view = RsvpAlumniEditView.as_view()
rsvp_alumni_remove_view = RsvpAlumniRemoveView.as_view()
rsvp_guest_add_view = RsvpGuestAddView.as_view()
rsvp_guest_edit_view = RsvpGuestEditView.as_view()
rsvp_guest_remove_view = RsvpGuestRemoveView.as_view()
<commit_msg>Show "403 permission denied" when not staff<commit_after>from datetime import date

from braces.views import LoginRequiredMixin, StaffuserRequiredMixin
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.forms import Form
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.views.generic import DetailView, FormView

from reunition.apps.alumni import models as alumni_m

from . import forms as f
from . import models as m

def redirect_to_latest(request):
    # TODO: don't assume only a single graduating class
    today = date.today()
    reunion = m.Reunion.objects.filter(starts_on__gte=today).order_by('starts_on')[0]
    return redirect(
        'reunions:detail',
        pk=reunion.pk,
    )

# ------------------------------------------

class ReunionDetailView(DetailView):

    model = m.Reunion
    context_object_name = 'reunion'

detail_view = ReunionDetailView.as_view()

# ------------------------------------------

class ReunionReportsView(LoginRequiredMixin, StaffuserRequiredMixin, DetailView):

    model = m.Reunion
    context_object_name = 'reunion'
    template_name_suffix = '_reports'

    raise_exception = True

reports_view =  ReunionReportsView.as_view()

# ------------------------------------------

class GetRsvpMixin(object):

    def get_reunion(self):
        return m.Reunion.objects.get(pk=self.kwargs['pk'])

    def get_rsvp(self):
        reunion = self.get_reunion()
        return reunion.rsvp_set.get(created_by=self.request.user)

class GetAttendeeMixin(object):

    attendee_class = None

    def get_attendee(self):
        attendee = self.attendee_class.objects.get(
            pk=self.kwargs['attendee_pk'],
            rsvp=self.get_rsvp(),
        )
        return attendee

class RedirectToRsvpOnSuccessMixin(object):

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

class RsvpView(LoginRequiredMixin, DetailView):

    model = m.Reunion
    context_object_name = 'reunion'
    template_name_suffix = '_rsvp'

    def get_context_data(self, **kwargs):
        context = super(RsvpView, self).get_context_data(**kwargs)
        rsvp = self.request.user.rsvp_set.filter(reunion=self.object).first()
        if rsvp:
            context.update(
                rsvp=rsvp,
                update_form=f.UpdateForm(initial=dict(
                    attending=rsvp.attending,
                    current_city=rsvp.current_city,
                    contact_method=rsvp.contact_method,
                    phone=rsvp.phone,
                ))
            )
        else:
            context.update(self._initial_form_context_data())
        return context

    def _initial_form_context_data(self):
        form_data = {}
        fb_account = self.request.user.socialaccount_set.filter(provider='facebook').first()
        if fb_account:
            fb_data = fb_account.extra_data
            first_name = fb_data.get('first_name')
            last_name = fb_data.get('last_name')
            alumnus = alumni_m.Person.objects.matching_any_name_in_class(
                self.object.graduating_class, first_name, last_name)
            if alumnus:
                message = """
                    We matched your Facebook contact information with our alumni roster.
                    Please complete the following and change your current name if necessary.
                """
                messages.add_message(self.request, messages.INFO, message)
                form_data.update(
                    graduation_first_name=alumnus.graduation_first_name,
                    graduation_last_name=alumnus.graduation_last_name,
                    current_first_name=alumnus.current_first_name,
                    current_last_name=alumnus.current_last_name,
                )
            else:
                message = 'Is this information correct? Please change your current or graduation names as needed.'
                messages.add_message(self.request, messages.INFO, message)
                form_data.update(
                    graduation_first_name=first_name,
                    graduation_last_name=last_name,
                )
        initial_form = f.InitialForm(initial=form_data)
        return dict(
            initial_form=initial_form,
        )

class RsvpInitialFormView(LoginRequiredMixin, FormView):

    form_class = f.InitialForm
    template_name = 'reunions/reunion_rsvp_initial_form.html'

    def get_reunion(self):
        return m.Reunion.objects.get(pk=self.kwargs['pk'])

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

    def get_context_data(self, **kwargs):
        data = super(RsvpInitialFormView, self).get_context_data(**kwargs)
        data.update(
            reunion=self.get_reunion(),
        )
        return data

    def form_invalid(self, form):
        message = 'Please fill in the required fields to continue.'
        messages.add_message(self.request, messages.WARNING, message)
        return super(RsvpInitialFormView, self).form_invalid(form)

    def form_valid(self, form):
        data = form.cleaned_data
        reunion = self.get_reunion()
        if not m.Rsvp.objects.filter(created_by=self.request.user, reunion=reunion).exists():
            rsvp = m.Rsvp.objects.create(
                created_by=self.request.user,
                reunion=reunion,
                attending=data['attending'],
                current_city=data['current_city'],
                contact_method=data['contact_method'],
                phone=data['phone'],
            )
            rsvp.add_alumni_attendee_by_name(
                graduation_first_name=data['graduation_first_name'],
                graduation_last_name=data['graduation_last_name'],
                current_first_name=data['current_first_name'],
                current_last_name=data['current_last_name'],
                request=self.request,
            )
        return super(RsvpInitialFormView, self).form_valid(form)

class RsvpUpdateView(GetRsvpMixin, LoginRequiredMixin, FormView):

    form_class = f.UpdateForm
    template_name = 'reunions/reunion_rsvp_update.html'

    def form_valid(self, form):
        rsvp = self.get_rsvp()
        for k, v in form.cleaned_data.items():
            setattr(rsvp, k, v)
        rsvp.save()
        return super(RsvpUpdateView, self).form_valid(form)

    def get(self, request, *args, **kwargs):
        # Don't allow GET for this form.
        return HttpResponseRedirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        data = super(RsvpUpdateView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        data.update(
            reunion=rsvp.reunion,
            rsvp=rsvp,
        )
        return data

    def get_success_url(self):
        return reverse('reunions:rsvp', kwargs=dict(pk=self.kwargs['pk']))

class RsvpAlumniAddView(GetRsvpMixin,
                        LoginRequiredMixin,
                        RedirectToRsvpOnSuccessMixin,
                        FormView):

    form_class = f.AlumniAddForm
    template_name = 'reunions/reunion_rsvp_alumni_add.html'

    def form_valid(self, form):
        data = form.cleaned_data
        self.get_rsvp().add_alumni_attendee_by_name(
            graduation_first_name=data['graduation_first_name'],
            graduation_last_name=data['graduation_last_name'],
            current_first_name=data['current_first_name'],
            current_last_name=data['current_last_name'],
            request=self.request,
            always_update_current_name=False,
        )
        return super(RsvpAlumniAddView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniAddView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
        )
        return data

class RsvpAlumniEditView(GetRsvpMixin,
                         GetAttendeeMixin,
                         LoginRequiredMixin,
                         RedirectToRsvpOnSuccessMixin,
                         FormView):

    attendee_class = m.RsvpAlumniAttendee
    form_class = f.AlumniUpdateForm
    template_name = 'reunions/reunion_rsvp_alumni_edit.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        person = attendee.person
        person.current_first_name = data['current_first_name']
        person.current_last_name = data['current_last_name']
        person.save()
        return super(RsvpAlumniEditView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniEditView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

    def get_initial(self):
        attendee = self.get_attendee()
        return dict(
            current_first_name=attendee.person.current_first_name,
            current_last_name=attendee.person.current_last_name,
        )

class RsvpAlumniRemoveView(GetRsvpMixin,
                           GetAttendeeMixin,
                           LoginRequiredMixin,
                           RedirectToRsvpOnSuccessMixin,
                           FormView):

    attendee_class = m.RsvpAlumniAttendee
    form_class = Form  # empty form
    template_name = 'reunions/reunion_rsvp_alumni_remove.html'

    def dispatch(self, request, *args, **kwargs):
        if self.get_rsvp().rsvpalumniattendee_set.count() == 1:
            return HttpResponseRedirect(self.get_success_url())

        return super(RsvpAlumniRemoveView, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.delete()
        message = '{} removed from alumni list.'.format(attendee)
        messages.add_message(self.request, messages.SUCCESS, message)
        return super(RsvpAlumniRemoveView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpAlumniRemoveView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

class RsvpGuestAddView(GetRsvpMixin,
                       LoginRequiredMixin,
                       RedirectToRsvpOnSuccessMixin,
                       FormView):

    form_class = f.GuestForm
    template_name = 'reunions/reunion_rsvp_guest_add.html'

    def form_valid(self, form):
        data = form.cleaned_data
        self.get_rsvp().rsvpguestattendee_set.create(
            first_name=data['first_name'],
            last_name=data['last_name'],
            relationship=data['relationship'],
        )
        return super(RsvpGuestAddView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestAddView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
        )
        return data

class RsvpGuestEditView(GetRsvpMixin,
                        GetAttendeeMixin,
                        LoginRequiredMixin,
                        RedirectToRsvpOnSuccessMixin,
                        FormView):

    attendee_class = m.RsvpGuestAttendee
    form_class = f.GuestForm
    template_name = 'reunions/reunion_rsvp_guest_edit.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.first_name = data['first_name']
        attendee.last_name = data['last_name']
        attendee.relationship = data['relationship']
        attendee.save()
        return super(RsvpGuestEditView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestEditView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

    def get_initial(self):
        attendee = self.get_attendee()
        return dict(
            first_name=attendee.first_name,
            last_name=attendee.last_name,
            relationship=attendee.relationship,
        )

class RsvpGuestRemoveView(GetRsvpMixin,
                          GetAttendeeMixin,
                          LoginRequiredMixin,
                          RedirectToRsvpOnSuccessMixin,
                          FormView):

    attendee_class = m.RsvpGuestAttendee
    form_class = Form  # empty form
    template_name = 'reunions/reunion_rsvp_guest_remove.html'

    def form_valid(self, form):
        data = form.cleaned_data
        attendee = self.get_attendee()
        attendee.delete()
        message = '{} removed from guest list.'.format(attendee)
        messages.add_message(self.request, messages.SUCCESS, message)
        return super(RsvpGuestRemoveView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        data = super(RsvpGuestRemoveView, self).get_context_data(**kwargs)
        rsvp = self.get_rsvp()
        reunion = rsvp.reunion
        data.update(
            rsvp=rsvp,
            reunion=reunion,
            attendee=self.get_attendee(),
        )
        return data

rsvp_view = RsvpView.as_view()
rsvp_initial_form_view = RsvpInitialFormView.as_view()
rsvp_update_view = RsvpUpdateView.as_view()
rsvp_alumni_add_view = RsvpAlumniAddView.as_view()
rsvp_alumni_edit_view = RsvpAlumniEditView.as_view()
rsvp_alumni_remove_view = RsvpAlumniRemoveView.as_view()
rsvp_guest_add_view = RsvpGuestAddView.as_view()
rsvp_guest_edit_view = RsvpGuestEditView.as_view()
rsvp_guest_remove_view = RsvpGuestRemoveView.as_view()
<|endoftext|>


<commit_before># Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from ducktape.mark import parametrize
from ducktape.mark.resource import cluster
from ducktape.tests.test import Test
from ducktape.utils.util import wait_until
from kafkatest.services.kafka import KafkaService
from kafkatest.services.streams import StreamsBrokerCompatibilityService
from kafkatest.services.verifiable_consumer import VerifiableConsumer
from kafkatest.services.zookeeper import ZookeeperService
from kafkatest.version import LATEST_0_11_0, LATEST_0_10_2, LATEST_0_10_1, LATEST_0_10_0, LATEST_1_0, LATEST_1_1, \
    LATEST_2_0, LATEST_2_1, LATEST_2_2, LATEST_2_3, LATEST_2_4, LATEST_2_5, LATEST_2_6, KafkaVersion

class StreamsBrokerCompatibility(Test):
    """
    These tests validates that
    - Streams works for older brokers 0.11 (or newer)
    - Streams w/ EOS-alpha works for older brokers 0.11 (or newer)
    - Streams w/ EOS-beta works for older brokers 2.5 (or newer)
    - Streams fails fast for older brokers 0.10.0, 0.10.2, and 0.10.1
    - Streams w/ EOS-beta fails fast for older brokers 2.4 or older
    """

    input = "brokerCompatibilitySourceTopic"
    output = "brokerCompatibilitySinkTopic"

    def __init__(self, test_context):
        super(StreamsBrokerCompatibility, self).__init__(test_context=test_context)
        self.zk = ZookeeperService(test_context, num_nodes=1)
        self.kafka = KafkaService(test_context,
                                  num_nodes=1,
                                  zk=self.zk,
                                  topics={
                                      self.input: {'partitions': 1, 'replication-factor': 1},
                                      self.output: {'partitions': 1, 'replication-factor': 1}
                                  },
                                  server_prop_overrides=[
                                      ["transaction.state.log.replication.factor", "1"],
                                      ["transaction.state.log.min.isr", "1"]
                                  ])
        self.consumer = VerifiableConsumer(test_context,
                                           1,
                                           self.kafka,
                                           self.output,
                                           "stream-broker-compatibility-verify-consumer")

    def setUp(self):
        self.zk.start()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_compatible_brokers_eos_disabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "at_least_once")
        processor.start()

        self.consumer.start()

        processor.wait()

        wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")

        self.consumer.stop()
        self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_6))
    @parametrize(broker_version=str(LATEST_2_5))
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_compatible_brokers_eos_alpha_enabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once")
        processor.start()

        self.consumer.start()

        processor.wait()

        wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")

        self.consumer.stop()
        self.kafka.stop()

    # TODO enable after 2.5 is released
    # @parametrize(broker_version=str(LATEST_2_5))
    # def test_compatible_brokers_eos_beta_enabled(self, broker_version):
    #     self.kafka.set_version(KafkaVersion(broker_version))
    #     self.kafka.start()
    #
    #     processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once_beta")
    #     processor.start()
    #
    #     self.consumer.start()
    #
    #     processor.wait()
    #
    #     wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")
    #
    #     self.consumer.stop()
    #     self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_0_10_2))
    @parametrize(broker_version=str(LATEST_0_10_1))
    @parametrize(broker_version=str(LATEST_0_10_0))
    def test_fail_fast_on_incompatible_brokers(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "at_least_once")

        with processor.node.account.monitor_log(processor.STDERR_FILE) as monitor:
            processor.start()
            monitor.wait_until('FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException',
                        timeout_sec=60,
                        err_msg="Never saw 'FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException " + str(processor.node.account))

        self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_fail_fast_on_incompatible_brokers_if_eos_beta_enabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once_beta")

        with processor.node.account.monitor_log(processor.STDERR_FILE) as monitor:
            with processor.node.account.monitor_log(processor.LOG_FILE) as log:
                processor.start()
                log.wait_until('Shutting down because the Kafka cluster seems to be on a too old version. Setting processing\.guarantee="exactly_once_beta" requires broker version 2\.5 or higher\.',
                               timeout_sec=60,
                               err_msg="Never saw 'Shutting down, because the Kafka cluster seems to be on a too old version. Setting `processing.guarantee=\"exaclty_once_beta\"` requires broker version 2.5 or higher.' log message " + str(processor.node.account))
                monitor.wait_until('FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException',
                                   timeout_sec=60,
                                   err_msg="Never saw 'FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException' error message " + str(processor.node.account))

        self.kafka.stop()
<commit_msg>MINOR: fix streams_broker_compatibility_test.py (#10632)<commit_after># Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from ducktape.mark import parametrize
from ducktape.mark.resource import cluster
from ducktape.tests.test import Test
from ducktape.utils.util import wait_until
from kafkatest.services.kafka import KafkaService
from kafkatest.services.streams import StreamsBrokerCompatibilityService
from kafkatest.services.verifiable_consumer import VerifiableConsumer
from kafkatest.services.zookeeper import ZookeeperService
from kafkatest.version import LATEST_0_11_0, LATEST_0_10_2, LATEST_0_10_1, LATEST_0_10_0, LATEST_1_0, LATEST_1_1, \
    LATEST_2_0, LATEST_2_1, LATEST_2_2, LATEST_2_3, LATEST_2_4, LATEST_2_5, LATEST_2_6, KafkaVersion

class StreamsBrokerCompatibility(Test):
    """
    These tests validates that
    - Streams works for older brokers 0.11 (or newer)
    - Streams w/ EOS-alpha works for older brokers 0.11 (or newer)
    - Streams w/ EOS-beta works for older brokers 2.5 (or newer)
    - Streams fails fast for older brokers 0.10.0, 0.10.2, and 0.10.1
    - Streams w/ EOS-beta fails fast for older brokers 2.4 or older
    """

    input = "brokerCompatibilitySourceTopic"
    output = "brokerCompatibilitySinkTopic"

    def __init__(self, test_context):
        super(StreamsBrokerCompatibility, self).__init__(test_context=test_context)
        self.zk = ZookeeperService(test_context, num_nodes=1)
        self.kafka = KafkaService(test_context,
                                  num_nodes=1,
                                  zk=self.zk,
                                  topics={
                                      self.input: {'partitions': 1, 'replication-factor': 1},
                                      self.output: {'partitions': 1, 'replication-factor': 1}
                                  },
                                  server_prop_overrides=[
                                      ["transaction.state.log.replication.factor", "1"],
                                      ["transaction.state.log.min.isr", "1"]
                                  ])
        self.consumer = VerifiableConsumer(test_context,
                                           1,
                                           self.kafka,
                                           self.output,
                                           "stream-broker-compatibility-verify-consumer")

    def setUp(self):
        self.zk.start()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_compatible_brokers_eos_disabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "at_least_once")
        processor.start()

        self.consumer.start()

        processor.wait()

        wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")

        self.consumer.stop()
        self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_6))
    @parametrize(broker_version=str(LATEST_2_5))
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_compatible_brokers_eos_alpha_enabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once")
        processor.start()

        self.consumer.start()

        processor.wait()

        wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")

        self.consumer.stop()
        self.kafka.stop()

    # TODO enable after 2.5 is released
    # @parametrize(broker_version=str(LATEST_2_5))
    # def test_compatible_brokers_eos_beta_enabled(self, broker_version):
    #     self.kafka.set_version(KafkaVersion(broker_version))
    #     self.kafka.start()
    #
    #     processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once_beta")
    #     processor.start()
    #
    #     self.consumer.start()
    #
    #     processor.wait()
    #
    #     wait_until(lambda: self.consumer.total_consumed() > 0, timeout_sec=30, err_msg="Did expect to read a message but got none within 30 seconds.")
    #
    #     self.consumer.stop()
    #     self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_0_10_2))
    @parametrize(broker_version=str(LATEST_0_10_1))
    @parametrize(broker_version=str(LATEST_0_10_0))
    def test_fail_fast_on_incompatible_brokers(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "at_least_once")

        with processor.node.account.monitor_log(processor.STDERR_FILE) as monitor:
            processor.start()
            monitor.wait_until('FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException',
                        timeout_sec=60,
                        err_msg="Never saw 'FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException " + str(processor.node.account))

        self.kafka.stop()

    @cluster(num_nodes=4)
    @parametrize(broker_version=str(LATEST_2_4))
    @parametrize(broker_version=str(LATEST_2_3))
    @parametrize(broker_version=str(LATEST_2_2))
    @parametrize(broker_version=str(LATEST_2_1))
    @parametrize(broker_version=str(LATEST_2_0))
    @parametrize(broker_version=str(LATEST_1_1))
    @parametrize(broker_version=str(LATEST_1_0))
    @parametrize(broker_version=str(LATEST_0_11_0))
    def test_fail_fast_on_incompatible_brokers_if_eos_beta_enabled(self, broker_version):
        self.kafka.set_version(KafkaVersion(broker_version))
        self.kafka.start()

        processor = StreamsBrokerCompatibilityService(self.test_context, self.kafka, "exactly_once_beta")

        with processor.node.account.monitor_log(processor.STDERR_FILE) as monitor:
            with processor.node.account.monitor_log(processor.LOG_FILE) as log:
                processor.start()
                log.wait_until('Shutting down because the Kafka cluster seems to be on a too old version. Setting processing\.guarantee="exactly_once_v2"/"exactly_once_beta" requires broker version 2\.5 or higher\.',
                               timeout_sec=60,
                               err_msg="Never saw 'Shutting down because the Kafka cluster seems to be on a too old version. Setting `processing.guarantee=\"exactly_once_v2\"/\"exaclty_once_beta\"` requires broker version 2.5 or higher.' log message " + str(processor.node.account))
                monitor.wait_until('FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException',
                                   timeout_sec=60,
                                   err_msg="Never saw 'FATAL: An unexpected exception org.apache.kafka.common.errors.UnsupportedVersionException' error message " + str(processor.node.account))

        self.kafka.stop()
<|endoftext|>