<commit_before># -*- coding: utf-8 -*-
"""
Spyder Editor

Sandbox for better understanding of the application's structure. In further
commits, this file should not exist and its parts should become auxiliary
modules for the application.

Author: Luiz Felipe Machado Votto
"""

from abc import ABC, abstractmethod
from scipy import special
import numpy as np

class Field(ABC):
    """ This is representative of a Field in tridimensional space.
    """
    functions = {}

    def __init__(self, **kwargs):
        self.functions = kwargs

    def evaluate(self, **kwargs):
        """ Evaluates the value of a field given a point.
        """
        result = []
        for key in kwargs:
            result.append(self.functions[key](kwargs[key]))
        return np.array(result)

    @abstractmethod
    def abs(self, coordinate1, coordinate2, coordinate3):
        """ Evaluates magnitude of field in a given point.
        """
        pass

class SphericalField(Field):
    """ Represents a tridimensional field in spherical coordinates
    """
    def __init__(self, r=None, theta=None, phi=None):
        kwargs = {'r' : r, 'theta' : theta, 'phi' : phi}
        super(SphericalField, self).__init__(**kwargs)

    def abs(self, radial, theta, phi):
        return self.functions['r'](radial, theta, phi)

class CartesianField(Field):
    """ Represents a tridimensional field in cartesian coordinates
    """
    def __init__(self, x=None, y=None, z=None):
        kwargs = {'x' : x, 'y' : y, 'z' : z}
        super(CartesianField, self).__init__(**kwargs)

    def abs(self, x_value, y_value, z_value):
        return np.linalg.norm(
            self.evaluate(x=x_value, y=y_value, z=z_value))

def riccati_bessel_j(degree, argument):
    """ Riccati-Bessel function of first kind
    """
    return special.riccati_jn(degree, argument)[0]

def d_riccati_bessel_j(degree, argument):
    """ Derivative of Riccati-Bessel function of first kind
    """
    return special.riccati_jn(degree, argument)[1]

def d2_riccati_bessel_j(degree, argument):
    """ Second order derivative of Riccati-Bessel function of first kind

    This was made based on relations 10.51.2 from: http://dlmf.nist.gov/10.51
    """
    return riccati_bessel_j(degree - 2, argument) \
           - (degree + 1) * degree \
             * riccati_bessel_j(degree, argument) / (argument * argument) \
           - 2 * (degree + 1) * d_riccati_bessel_j(degree, argument) / argument

def legendre_p(degree, order, argument):
    """ Associated Legendre function of integer order
    """
    return special.lpmv(degree, order, argument)

def legendre_tau(degree, order, argument):
    """ Returns generalized Legendre function tau

    Derivative is calculated based on relation 14.10.5:
    http://dlmf.nist.gov/14.10
    """
    return ((degree - order - 1) * legendre_p(degree - 1, order, argument) \
            - degree * argument * legendre_p(degree, order, argument)) \
            / (1 - argument*argument)

def legendre_pi(degree, order, argument):
    """ Generalized associated Legendre function pi
    """
    return legendre_p(degree, order, argument) / (1 - argument * argument)

EPSILON = 1E-5
AXICON = 0.349066  # 20 degrees
MAX_IT = 1E4

def bromwich_scalar_g_exa(degree, axicon=AXICON):
    """ Computes exact BSC

    From eq. 5 in AMBROSIO, Leonardo et al. !!! NEED REFERENCE
    """
    # FIXME
    return (1 + np.cos(axicon)) / (2 * degree * (degree + 1)) \
            * (legendre_tau(degree, 1, np.cos(axicon)) \
               + legendre_pi(degree, 1, np.cos(axicon)))

def bromwich_scalar_g(degree, order, axicon=AXICON, mode='TM'):
    """ Computes BSC in terms of degree and order
    """
    if mode == 'TM':
        return bromwich_scalar_g_exa(degree, axicon=axicon) / 2
    if mode == 'TE':
        retval = np.complex(0, 1) \
                     * bromwich_scalar_g_exa(degree, axicon=axicon) / 2
        if order > 0:
            return retval
        else:
            return -retval

def plane_wave_coefficient(degree, wave_number_k):
    """ Computes plane wave coefficient c_{n}^{pw}

    From eq. (III.3) in GOUESBET, Gerárd !!! NEED REFERENCE
    """
    # FIXME
    return (1 / (np.complex(0, 1) * wave_number_k)) \
            * pow(-np.complex(0, 1), degree) \
            * (2 * degree + 1) / (degree * (degree + 1))

def radial_electric_i_tm(radial, theta, phi, wave_number_k):
    """ Computes the radial component of inciding electric field in TM mode.
    """
    error = float('inf')
    result = 0
    last_result = 0
    n = 0
    m = 0

    while error > EPSILON and n < MAX_IT:
        for m in [-1, 1]:
            result += plane_wave_coefficient(n, wave_number_k) \
                      * bromwich_scalar_g(n, m) \
                      * (d2_riccati_bessel_j(n, wave_number_k * radial)[n] \
                       - riccati_bessel_j(n, wave_number_k * radial)[n]) \
                      * legendre_p(n, m, np.cos(theta)) \
                      * np.exp(np.imag * m * phi)
        error = np.abs(last_result - result).sum()
        last_result = result[:]
        n += 1
<commit_msg>Fix spherical Bessel computing<commit_after># -*- coding: utf-8 -*-
"""
Sandbox for better understanding of the application's structure. In further
commits, this file should not exist and its parts should become auxiliary
modules for the application.

Author: Luiz Felipe Machado Votto
"""

from abc import ABC, abstractmethod
from scipy import special
import numpy as np

EPSILON = 1E-5
AXICON = 0.349066  # 20 degrees
MAX_IT = 1E4

class Field(ABC):
    """ This is representative of a Field in tridimensional space.
    """
    functions = {}

    def __init__(self, **kwargs):
        self.functions = kwargs

    def evaluate(self, *args, **kwargs):
        """ Evaluates the value of the field given a point.
        """
        result = []
        for key in kwargs:
            result.append(self.functions[key](*args, **kwargs) or 0)
        return np.array(result)

    @abstractmethod
    def abs(self, coordinate1, coordinate2, coordinate3):
        """ Evaluates magnitude of field in a given point.
        """
        pass

class SphericalField(Field):
    """ Represents a tridimensional field in spherical coordinates
    """
    def __init__(self, r=None, theta=None, phi=None):
        kwargs = {'r' : r, 'theta' : theta, 'phi' : phi}
        super(SphericalField, self).__init__(**kwargs)

    def abs(self, radial, theta, phi):
        return np.abs(self.functions['r'](radial, theta, phi))

class CartesianField(Field):
    """ Represents a tridimensional field in cartesian coordinates
    """
    def __init__(self, x=None, y=None, z=None):
        kwargs = {'x' : x, 'y' : y, 'z' : z}
        super(CartesianField, self).__init__(**kwargs)

    def abs(self, x_value, y_value, z_value):
        return np.linalg.norm(
            self.evaluate(x=x_value, y=y_value, z=z_value))

def _riccati_bessel_j(degree, argument):
    """ Riccati-Bessel function of first kind and derivative
    """
    return special.riccati_jn(degree, argument)

def riccati_bessel_j(degree, argument):
    """ Riccati-Bessel function of first kind
    """
    return special.riccati_jn(degree, argument)[0]

def d_riccati_bessel_j(degree, argument):
    """ Derivative of Riccati-Bessel function of first kind
    """
    return special.riccati_jn(degree, argument)[1]

def d2_riccati_bessel_j(degree, argument):
    """ Second order derivative of Riccati-Bessel function of first kind

    This was made based on relations 10.51.2 from: http://dlmf.nist.gov/10.51
    """
    values = _riccati_bessel_j(degree, argument)
    values_2 = np.roll(values[0], 2)
    values_2[0] = values_2[1] = 0
    print('VALUES = ', values)
    print('VALUES 0 = ', values[0])
    print('VALUES 1 = ', values[1])
    print('VALUES 2 = ', values_2)

    return values_2 \
           - (degree + 1) * degree \
             * values[0] / (argument * argument) \
           - 2 * (degree + 1) * values[1] / argument

def legendre_p(degree, order, argument):
    """ Associated Legendre function of integer order
    """
    return special.lpmv(degree, order, argument)

def legendre_tau(degree, order, argument):
    """ Returns generalized Legendre function tau

    Derivative is calculated based on relation 14.10.5:
    http://dlmf.nist.gov/14.10
    """
    return ((degree - order - 1) * legendre_p(degree - 1, order, argument) \
            - degree * argument * legendre_p(degree, order, argument)) \
            / (1 - argument*argument)

def legendre_pi(degree, order, argument):
    """ Generalized associated Legendre function pi
    """
    return legendre_p(degree, order, argument) / (1 - argument * argument)

def bromwich_scalar_g_exa(degree, axicon=AXICON):
    """ Computes exact BSC from equations referenced by the article
    """
    return (1 + np.cos(axicon)) / (2 * degree * (degree + 1)) \
            * (legendre_tau(degree, 1, np.cos(axicon)) \
               + legendre_pi(degree, 1, np.cos(axicon)))

def bromwich_scalar_g(degree, order, axicon=AXICON, mode='TM'):
    """ Computes BSC in terms of degree and order
    """
    if mode == 'TM':
        return bromwich_scalar_g_exa(degree, axicon=axicon) / 2
    if mode == 'TE':
        retval = np.complex(0, 1) \
                     * bromwich_scalar_g_exa(degree, axicon=axicon) / 2
        if order > 0:
            return retval
        else:
            return -retval

def plane_wave_coefficient(degree, wave_number_k):
    """ Computes plane wave coefficient c_{n}^{pw}
    """
    return (1 / (np.complex(0, 1) * wave_number_k)) \
            * pow(-np.complex(0, 1), degree) \
            * (2 * degree + 1) / (degree * (degree + 1))

def radial_electric_i_tm(radial, theta, phi, wave_number_k):
    """ Computes the radial component of inciding electric field in TM mode.
    """
    error = float('inf')
    result = 0
    last_result = 0
    n = 0
    m = 0

    riccati_bessel_list = _riccati_bessel_j(MAX_IT, wave_number_k * radial)
    riccati_bessel = riccati_bessel_list[0]
    d2_riccati_bessel = d2_riccati_bessel_j(MAX_IT, wave_number_k * radial)

    while error > EPSILON and n < MAX_IT:
        for m in [-1, 1]:
            result += plane_wave_coefficient(n, wave_number_k) \
                      * bromwich_scalar_g(n, m, mode='TM') \
                      * (d2_riccati_bessel[n] - riccati_bessel[n]) \
                      * legendre_p(n, m, np.cos(theta)) \
                      * np.exp(np.imag * m * phi)
        error = np.abs(last_result - result).sum()
        last_result = result[:]
        n += 1

    return result
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from django.core.exceptions import ValidationError, PermissionDenied
from django.utils.decorators import method_decorator
from django.conf import settings
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.utils import DatabaseError
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse

from mapentity.helpers import api_bbox
from mapentity import views as mapentity_views
from mapentity.settings import app_settings

from geotrek.common.utils import sql_extent
from geotrek import __version__

#async data imports
import os
import json
from zipfile import ZipFile
from geotrek.common.parsers import AttachmentParserMixin
from geotrek.celery import app
from djcelery.models import TaskMeta
from datetime import datetime, timedelta

from .tasks import import_datas
from .forms import ImportDatasetForm
from pip.cmdoptions import no_cache

class FormsetMixin(object):
    context_name = None
    formset_class = None

    def form_valid(self, form):
        context = self.get_context_data()
        formset_form = context[self.context_name]

        if formset_form.is_valid():
            response = super(FormsetMixin, self).form_valid(form)
            formset_form.instance = self.object
            formset_form.save()
        else:
            response = self.form_invalid(form)
        return response

    def get_context_data(self, **kwargs):
        context = super(FormsetMixin, self).get_context_data(**kwargs)
        if self.request.POST:
            try:
                context[self.context_name] = self.formset_class(self.request.POST, instance=self.object)
            except ValidationError:
                pass
        else:
            context[self.context_name] = self.formset_class(instance=self.object)
        return context

class PublicOrReadPermMixin(object):
    def get_object(self, queryset=None):
        obj = super(PublicOrReadPermMixin, self).get_object(queryset)
        if not obj.is_public():
            if not self.request.user.is_authenticated():
                raise PermissionDenied
            if not self.request.user.has_perm('%s.read_%s' % (obj._meta.app_label, obj._meta.model_name)):
                raise PermissionDenied
        return obj

class DocumentPublicPDF(PublicOrReadPermMixin, mapentity_views.DocumentConvert):
    # Override login_required
    def dispatch(self, *args, **kwargs):
        return super(mapentity_views.Convert, self).dispatch(*args, **kwargs)

    def source_url(self):
        return self.get_object().get_document_public_url()

class DocumentPublicBase(PublicOrReadPermMixin, mapentity_views.MapEntityDocument):
    template_name_suffix = "_public"

    # Override view_permission_required
    def dispatch(self, *args, **kwargs):
        return super(mapentity_views.MapEntityDocumentBase, self).dispatch(*args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(DocumentPublicBase, self).get_context_data(**kwargs)
        modelname = self.get_model()._meta.object_name.lower()
        context['mapimage_ratio'] = settings.EXPORT_MAP_IMAGE_SIZE[modelname]
        return context

class DocumentPublicOdt(DocumentPublicBase):
    with_html_attributes = False

    def render_to_response(self, context, **response_kwargs):
        # Use attachment that overrides document print, if any.
        # And return it as response
        try:
            overriden = self.object.get_attachment_print()
            response = HttpResponse(mimetype='application/vnd.oasis.opendocument.text')
            with open(overriden, 'rb') as f:
                response.write(f.read())
            return response
        except ObjectDoesNotExist:
            pass
        return super(DocumentPublicOdt, self).render_to_response(context, **response_kwargs)

if app_settings['MAPENTITY_WEASYPRINT']:
    DocumentPublic = DocumentPublicBase
else:
    DocumentPublic = DocumentPublicOdt

#
# Concrete views
# ..............................

class JSSettings(mapentity_views.JSSettings):
    """ Override mapentity base settings in order to provide
    Geotrek necessary stuff.
    """
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(JSSettings, self).dispatch(*args, **kwargs)

    def get_context_data(self):
        dictsettings = super(JSSettings, self).get_context_data()
        # Add geotrek map styles
        base_styles = dictsettings['map']['styles']
        for name, override in settings.MAP_STYLES.items():
            merged = base_styles.get(name, {})
            merged.update(override)
            base_styles[name] = merged
        # Add extra stuff (edition, labelling)
        dictsettings['map'].update(
            snap_distance=settings.SNAP_DISTANCE,
            paths_line_marker=settings.PATHS_LINE_MARKER,
            colorspool=settings.COLORS_POOL,
        )
        dictsettings['version'] = __version__
        return dictsettings

@login_required
@user_passes_test(lambda u: u.is_superuser)
def admin_check_extents(request):
    """
    This view allows administrators to visualize data and configured extents.

    Since it's the first, we implemented this in a very rough way. If there is
    to be more admin tools like this one. Move this to a separate Django app and
    style HTML properly.
    """
    path_extent_native = sql_extent("SELECT ST_Extent(geom) FROM l_t_troncon;")
    path_extent = api_bbox(path_extent_native)
    try:
        dem_extent_native = sql_extent("SELECT ST_Extent(rast::geometry) FROM mnt;")
        dem_extent = api_bbox(dem_extent_native)
    except DatabaseError:  # mnt table missing
        dem_extent_native = None
        dem_extent = None
    tiles_extent_native = settings.SPATIAL_EXTENT
    tiles_extent = api_bbox(tiles_extent_native)
    viewport_native = settings.LEAFLET_CONFIG['SPATIAL_EXTENT']
    viewport = api_bbox(viewport_native, srid=settings.API_SRID)

    def leafletbounds(bbox):
        return [[bbox[1], bbox[0]], [bbox[3], bbox[2]]]

    context = dict(
        path_extent=leafletbounds(path_extent),
        path_extent_native=path_extent_native,
        dem_extent=leafletbounds(dem_extent) if dem_extent else None,
        dem_extent_native=dem_extent_native,
        tiles_extent=leafletbounds(tiles_extent),
        tiles_extent_native=tiles_extent_native,
        viewport=leafletbounds(viewport),
        viewport_native=viewport_native,
        SRID=settings.SRID,
        API_SRID=settings.API_SRID,
    )
    return render(request, 'common/check_extents.html', context)

class UserArgMixin(object):
    def get_form_kwargs(self):
        kwargs = super(UserArgMixin, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

def get_all_subclasses(cls):
    all_subclasses = []

    for subclass in cls.__subclasses__():
        all_subclasses.append(subclass)
        all_subclasses.extend(get_all_subclasses(subclass))

    return all_subclasses

@login_required
@user_passes_test(lambda u: u.is_superuser)
def import_view(request):
    """
    Gets the existing declared parsers for the current project.
    This view handles only the file based import parsers.
    """
    choices = []
    try:
        from bulkimport.parsers import *
    except ImportError:
        pass

    classes = get_all_subclasses(AttachmentParserMixin)
    for index, cls in enumerate(classes):
        choices.append((index, cls.__name__))

    choices = sorted(choices, key=lambda x: x[1])

    if request.method == 'POST':
        form = ImportDatasetForm(choices, request.POST, request.FILES)

        if form.is_valid():
            uploaded = request.FILES['file']
            if uploaded.content_type == u'application/zip':

                save_dir = '/tmp/geotrek/{}'.format(uploaded.name)
                if not os.path.exists('/tmp/geotrek'):
                    os.mkdir('/tmp/geotrek')
                if not os.path.exists(save_dir):
                    os.mkdir(save_dir)
                with open(save_dir+'/{}'.format(uploaded.name), 'w+') as f:
                    f.write(uploaded.file.read())

                    zfile = ZipFile(f)
                    for name in zfile.namelist():
                        zfile.extract(name, save_dir)
                        if name.endswith('shp'):
                            try:
                                parser = classes[int(form['parser'].value())]
                                async_job = import_datas.delay('/'.join((save_dir, name)), parser.__name__, parser.__module__)
                            except Exception as e:
                                raise e
    else:
        form = ImportDatasetForm(choices)

    return render(request, 'common/import_dataset.html', {
        'form': form
    })

@login_required
@user_passes_test(lambda u: u.is_superuser)
def import_update_json(request):
    results = []
    threshold = datetime.now() - timedelta(seconds=30)
    for task in TaskMeta.objects.filter(date_done__gte=threshold):
        results.append(
           {
            'id': task.task_id,
            'result': task.result or {'current': 0, 'total': 0},
            'status': task.status
           }
        )

    return HttpResponse(json.dumps(results), content_type="application/json")

<commit_msg>fix typo<commit_after># -*- coding: utf-8 -*-
from django.core.exceptions import ValidationError, PermissionDenied
from django.utils.decorators import method_decorator
from django.conf import settings
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.utils import DatabaseError
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse

from mapentity.helpers import api_bbox
from mapentity import views as mapentity_views
from mapentity.settings import app_settings

from geotrek.common.utils import sql_extent
from geotrek import __version__

#async data imports
import os
import json
from zipfile import ZipFile
from geotrek.common.parsers import AttachmentParserMixin
from geotrek.celery import app
from djcelery.models import TaskMeta
from datetime import datetime, timedelta

from .tasks import import_datas
from .forms import ImportDatasetForm

class FormsetMixin(object):
    context_name = None
    formset_class = None

    def form_valid(self, form):
        context = self.get_context_data()
        formset_form = context[self.context_name]

        if formset_form.is_valid():
            response = super(FormsetMixin, self).form_valid(form)
            formset_form.instance = self.object
            formset_form.save()
        else:
            response = self.form_invalid(form)
        return response

    def get_context_data(self, **kwargs):
        context = super(FormsetMixin, self).get_context_data(**kwargs)
        if self.request.POST:
            try:
                context[self.context_name] = self.formset_class(self.request.POST, instance=self.object)
            except ValidationError:
                pass
        else:
            context[self.context_name] = self.formset_class(instance=self.object)
        return context

class PublicOrReadPermMixin(object):
    def get_object(self, queryset=None):
        obj = super(PublicOrReadPermMixin, self).get_object(queryset)
        if not obj.is_public():
            if not self.request.user.is_authenticated():
                raise PermissionDenied
            if not self.request.user.has_perm('%s.read_%s' % (obj._meta.app_label, obj._meta.model_name)):
                raise PermissionDenied
        return obj

class DocumentPublicPDF(PublicOrReadPermMixin, mapentity_views.DocumentConvert):
    # Override login_required
    def dispatch(self, *args, **kwargs):
        return super(mapentity_views.Convert, self).dispatch(*args, **kwargs)

    def source_url(self):
        return self.get_object().get_document_public_url()

class DocumentPublicBase(PublicOrReadPermMixin, mapentity_views.MapEntityDocument):
    template_name_suffix = "_public"

    # Override view_permission_required
    def dispatch(self, *args, **kwargs):
        return super(mapentity_views.MapEntityDocumentBase, self).dispatch(*args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(DocumentPublicBase, self).get_context_data(**kwargs)
        modelname = self.get_model()._meta.object_name.lower()
        context['mapimage_ratio'] = settings.EXPORT_MAP_IMAGE_SIZE[modelname]
        return context

class DocumentPublicOdt(DocumentPublicBase):
    with_html_attributes = False

    def render_to_response(self, context, **response_kwargs):
        # Use attachment that overrides document print, if any.
        # And return it as response
        try:
            overriden = self.object.get_attachment_print()
            response = HttpResponse(mimetype='application/vnd.oasis.opendocument.text')
            with open(overriden, 'rb') as f:
                response.write(f.read())
            return response
        except ObjectDoesNotExist:
            pass
        return super(DocumentPublicOdt, self).render_to_response(context, **response_kwargs)

if app_settings['MAPENTITY_WEASYPRINT']:
    DocumentPublic = DocumentPublicBase
else:
    DocumentPublic = DocumentPublicOdt

#
# Concrete views
# ..............................

class JSSettings(mapentity_views.JSSettings):
    """ Override mapentity base settings in order to provide
    Geotrek necessary stuff.
    """
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(JSSettings, self).dispatch(*args, **kwargs)

    def get_context_data(self):
        dictsettings = super(JSSettings, self).get_context_data()
        # Add geotrek map styles
        base_styles = dictsettings['map']['styles']
        for name, override in settings.MAP_STYLES.items():
            merged = base_styles.get(name, {})
            merged.update(override)
            base_styles[name] = merged
        # Add extra stuff (edition, labelling)
        dictsettings['map'].update(
            snap_distance=settings.SNAP_DISTANCE,
            paths_line_marker=settings.PATHS_LINE_MARKER,
            colorspool=settings.COLORS_POOL,
        )
        dictsettings['version'] = __version__
        return dictsettings

@login_required
@user_passes_test(lambda u: u.is_superuser)
def admin_check_extents(request):
    """
    This view allows administrators to visualize data and configured extents.

    Since it's the first, we implemented this in a very rough way. If there is
    to be more admin tools like this one. Move this to a separate Django app and
    style HTML properly.
    """
    path_extent_native = sql_extent("SELECT ST_Extent(geom) FROM l_t_troncon;")
    path_extent = api_bbox(path_extent_native)
    try:
        dem_extent_native = sql_extent("SELECT ST_Extent(rast::geometry) FROM mnt;")
        dem_extent = api_bbox(dem_extent_native)
    except DatabaseError:  # mnt table missing
        dem_extent_native = None
        dem_extent = None
    tiles_extent_native = settings.SPATIAL_EXTENT
    tiles_extent = api_bbox(tiles_extent_native)
    viewport_native = settings.LEAFLET_CONFIG['SPATIAL_EXTENT']
    viewport = api_bbox(viewport_native, srid=settings.API_SRID)

    def leafletbounds(bbox):
        return [[bbox[1], bbox[0]], [bbox[3], bbox[2]]]

    context = dict(
        path_extent=leafletbounds(path_extent),
        path_extent_native=path_extent_native,
        dem_extent=leafletbounds(dem_extent) if dem_extent else None,
        dem_extent_native=dem_extent_native,
        tiles_extent=leafletbounds(tiles_extent),
        tiles_extent_native=tiles_extent_native,
        viewport=leafletbounds(viewport),
        viewport_native=viewport_native,
        SRID=settings.SRID,
        API_SRID=settings.API_SRID,
    )
    return render(request, 'common/check_extents.html', context)

class UserArgMixin(object):
    def get_form_kwargs(self):
        kwargs = super(UserArgMixin, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

def get_all_subclasses(cls):
    all_subclasses = []

    for subclass in cls.__subclasses__():
        all_subclasses.append(subclass)
        all_subclasses.extend(get_all_subclasses(subclass))

    return all_subclasses

@login_required
@user_passes_test(lambda u: u.is_superuser)
def import_view(request):
    """
    Gets the existing declared parsers for the current project.
    This view handles only the file based import parsers.
    """
    choices = []
    try:
        from bulkimport.parsers import *
    except ImportError:
        pass

    classes = get_all_subclasses(AttachmentParserMixin)
    for index, cls in enumerate(classes):
        choices.append((index, cls.__name__))

    choices = sorted(choices, key=lambda x: x[1])

    if request.method == 'POST':
        form = ImportDatasetForm(choices, request.POST, request.FILES)

        if form.is_valid():
            uploaded = request.FILES['file']
            if uploaded.content_type == u'application/zip':

                save_dir = '/tmp/geotrek/{}'.format(uploaded.name)
                if not os.path.exists('/tmp/geotrek'):
                    os.mkdir('/tmp/geotrek')
                if not os.path.exists(save_dir):
                    os.mkdir(save_dir)
                with open(save_dir+'/{}'.format(uploaded.name), 'w+') as f:
                    f.write(uploaded.file.read())

                    zfile = ZipFile(f)
                    for name in zfile.namelist():
                        zfile.extract(name, save_dir)
                        if name.endswith('shp'):
                            try:
                                parser = classes[int(form['parser'].value())]
                                async_job = import_datas.delay('/'.join((save_dir, name)), parser.__name__, parser.__module__)
                            except Exception as e:
                                raise e
    else:
        form = ImportDatasetForm(choices)

    return render(request, 'common/import_dataset.html', {
        'form': form
    })

@login_required
@user_passes_test(lambda u: u.is_superuser)
def import_update_json(request):
    results = []
    threshold = datetime.now() - timedelta(seconds=30)
    for task in TaskMeta.objects.filter(date_done__gte=threshold):
        results.append(
           {
            'id': task.task_id,
            'result': task.result or {'current': 0, 'total': 0},
            'status': task.status
           }
        )

    return HttpResponse(json.dumps(results), content_type="application/json")

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-20 09:55
from __future__ import unicode_literals

import json
import six

from django.conf import settings
from django.db import migrations
from django.urls import reverse
from twilio.rest import TwilioRestClient

def migrate_twilio_app(channel):
    """
    Migrates a single Twilio channel to use a channel specific TwiML app with new channel-specific endpoints
    """
    org_config = json.loads(channel.org.config)
    client = TwilioRestClient(org_config['ACCOUNT_SID'], org_config['ACCOUNT_TOKEN'])

    number_sid = channel.bod
    is_short_code = len(channel.address) <= 6

    new_receive_url = "https://" + settings.TEMBA_HOST + reverse('handlers.twilio_handler', args=['receive', channel.uuid])
    new_status_url = "https://" + settings.TEMBA_HOST + reverse('handlers.twilio_handler', args=['status', channel.uuid])
    new_voice_url = "https://" + settings.TEMBA_HOST + reverse('handlers.twilio_handler', args=['voice', channel.uuid])

    new_app = client.applications.create(
        friendly_name="%s/%s" % (settings.TEMBA_HOST.lower(), channel.uuid),
        sms_url=new_receive_url,
        sms_method="POST",
        voice_url=new_voice_url,
        voice_fallback_url="https://" + settings.AWS_BUCKET_DOMAIN + "/voice_unavailable.xml",
        voice_fallback_method='GET',
        status_callback=new_status_url,
        status_callback_method='POST'
    )

    # store new app sid on the channel and clear bod as number sid is now in the channel config
    channel.config = json.dumps({'application_sid': new_app.sid, 'number_sid': number_sid})
    channel.bod = None
    channel.save(update_fields=('config', 'bod'))

    # associate the Twilio number with the new app
    if is_short_code:
        client.sms.short_codes.update(number_sid, sms_url=new_receive_url, sms_method='POST')
    else:
        client.phone_numbers.update(number_sid, sms_application_sid=new_app.sid, voice_application_sid=new_app.sid)

    # cleanup old org-level app
    old_app_sid = org_config.get('APPLICATION_SID')

    if old_app_sid:
        # remove app sid from org config
        del org_config['APPLICATION_SID']
        channel.org.config = json.dumps(org_config)
        channel.org.save(update_fields=('config',))

        # delete the old org-level app
        client.applications.delete(sid=old_app_sid)

def migrate_all_twilio_apps(Channel):
    """
    Migrates all active Twilio channels to use channel specific TwiML apps with new channel-specific endpoints
    """
    twilio_channels = list(Channel.objects.filter(channel_type='T', is_active=True).exclude(org=None).select_related('org'))

    if twilio_channels:
        print("Fetched %d Twilio channels to migrate apps for..." % len(twilio_channels))

    if not settings.IS_PROD:
        if twilio_channels:
            print("Skipping Twilio app migration on non-prod instance")
        return

    for c, channel in enumerate(twilio_channels):
        try:
            channel_config = json.loads(channel.config)

            if 'APPLICATION_SID' in channel_config:
                print(" > Skipping channel %s as it appears to be already migrated" % channel.uuid)

            migrate_twilio_app(channel)

            print(" > Migrated channel %s for org '%s' (%d/%d)" % (channel.uuid, channel.org.name, (c + 1), len(twilio_channels)))
        except Exception as e:
            print(" ! Error occurred migrating app for channel %s: %s" % (channel.uuid, six.text_type(e)))

def apply_as_migration(apps, schema_editor):
    Channel = apps.get_model('channels', 'Channel')
    migrate_all_twilio_apps(Channel)

def apply_manual():
    from temba.channels.models import Channel
    migrate_all_twilio_apps(Channel)

class Migration(migrations.Migration):

    dependencies = [
        ('channels', '0071_auto_20170614_0915'),
    ]

    operations = [
        migrations.RunPython(apply_as_migration)
    ]
<commit_msg>Move migration to its own pr<commit_after><|endoftext|>


<commit_before>from datetime import date

import icalendar
from django.conf import settings
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.template import TemplateDoesNotExist

from patreonmanager.models import FundraisingStatus

from .models import Event, User
from story.models import Story
from sponsor.models import Donor
from .quotes import DONOR_QUOTES

def index(request):

    return render(request, 'core/index.html', {
        'future_events': Event.objects.future(),
        'stories': Story.objects.filter(is_story=True).order_by('-created')[:2],
        'blogposts': Story.objects.filter(is_story=False).order_by('-created')[:3],
        'patreon_stats': FundraisingStatus.objects.all().first(),
        'organizers_count': User.objects.all().count(),
        'cities_count': Event.objects.values('city').distinct().count(),
        'country_count': Event.objects.values('country').distinct().count(),
    })

def events(request):

    return render(request, 'core/events.html', {
        'future_events': Event.objects.future(),
        'past_events': Event.objects.past(),
    })

def events_map(request):

    return render(request, 'core/events_map.html', {
        'events': Event.objects.public().order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def resources(request):
    return render(request, 'core/resources.html', {})

def event(request, city):
    now_approx = date.today()
    event = get_object_or_404(Event, page_url=city.lower())

    if event.page_url != city:
        return redirect('core:event', city=event.page_url, permanent=True)

    user = request.user
    user_is_organizer = user.is_authenticated and event.has_organizer(user)
    is_preview = 'preview' in request.GET
    previewable = user.is_superuser or user_is_organizer or is_preview

    if not (event.is_page_live or previewable):
        return render(
            request,
            'applications/event_not_live.html',
            {'city': city, 'past': date(event.date.year, event.date.month, event.date.day) <= now_approx}
        )

    return render(request, "core/event.html", {
        'event': event,
        'menu': event.menu.all(),
        'content': event.content.prefetch_related('coaches', 'sponsors').filter(is_public=True),
    })

def events_ical(request):
    events = Event.objects.public().order_by('-date')
    calendar = icalendar.Calendar()
    calendar['summary'] = "List of Django Girls events around the world"
    for event in events:
        ical_event = event.as_ical()
        if ical_event is None:
            continue  # Skip events with an approximate date
        calendar.add_component(ical_event)

    return HttpResponse(calendar.to_ical(),
                        content_type='text/calendar; charset=UTF-8')

def newsletter(request):
    return render(request, 'core/newsletter.html', {})

def faq(request):
    return render(request, 'core/faq.html', {})

def foundation(request):
    return render(request, 'core/foundation.html', {})

def governing_document(request):
    return render(request, 'core/governing_document.html', {})

def contribute(request):
    return render(request, 'core/contribute.html', {})

def donate(request):
    return render(request, 'core/donate.html', {
        'patreon_stats': FundraisingStatus.objects.all().first(),
    })

def year_2015(request):
    return render(request, 'core/2015.html', {
        'events': Event.objects.public().filter(date__lt='2016-01-01').order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def year_2016_2017(request):
    return render(request, 'core/2016-2017.html', {
        'events_2015': Event.objects.public().filter(date__lt='2016-01-01').order_by('date'),
        'events_20162017': Event.objects.public().filter(date__lt='2017-08-01', date__gte='2016-01-01').order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def terms_conditions(request):
    return render(request, 'core/terms_conditions.html', {})

def privacy_cookies(request):
    return render(request, 'core/privacy_cookies.html', {})

def workshop_box(request):
    return render(request, 'core/workshop_box.html', {})

def server_error(request):
    return HttpResponse(status=500)

def coc(request, lang=None):
    if lang is None:
        lang = 'en'
    template_name = "core/coc/{}.html".format(lang)
    try:
        return render(request, template_name)
    except TemplateDoesNotExist:
        raise Http404("No translation for language {}".format(lang))

def crowdfunding_donors(request):
    donor_list = Donor.objects.filter(visible=True).order_by('-amount')
    return render(request, 'core/crowdfunding_donors.html', {
        'donor_list': donor_list,
        'quotes': DONOR_QUOTES,
    })
<commit_msg>Fix past date issue that's causing server error<commit_after>from datetime import date

import icalendar
from django.conf import settings
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.template import TemplateDoesNotExist

from patreonmanager.models import FundraisingStatus

from .models import Event, User
from story.models import Story
from sponsor.models import Donor
from .quotes import DONOR_QUOTES

def index(request):

    return render(request, 'core/index.html', {
        'future_events': Event.objects.future(),
        'stories': Story.objects.filter(is_story=True).order_by('-created')[:2],
        'blogposts': Story.objects.filter(is_story=False).order_by('-created')[:3],
        'patreon_stats': FundraisingStatus.objects.all().first(),
        'organizers_count': User.objects.all().count(),
        'cities_count': Event.objects.values('city').distinct().count(),
        'country_count': Event.objects.values('country').distinct().count(),
    })

def events(request):

    return render(request, 'core/events.html', {
        'future_events': Event.objects.future(),
        'past_events': Event.objects.past(),
    })

def events_map(request):

    return render(request, 'core/events_map.html', {
        'events': Event.objects.public().order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def resources(request):
    return render(request, 'core/resources.html', {})

def event(request, city):
    now_approx = date.today()
    event = get_object_or_404(Event, page_url=city.lower())

    if event.page_url != city:
        return redirect('core:event', city=event.page_url, permanent=True)

    user = request.user
    user_is_organizer = user.is_authenticated and event.has_organizer(user)
    is_preview = 'preview' in request.GET
    previewable = user.is_superuser or user_is_organizer or is_preview

    if not (event.is_page_live or previewable):
        return render(
            request,
            'applications/event_not_live.html',
            {'city': city, 'past': date(event.date.year, event.date.month, event.date.day) < now_approx}
        )

    return render(request, "core/event.html", {
        'event': event,
        'menu': event.menu.all(),
        'content': event.content.prefetch_related('coaches', 'sponsors').filter(is_public=True),
    })

def events_ical(request):
    events = Event.objects.public().order_by('-date')
    calendar = icalendar.Calendar()
    calendar['summary'] = "List of Django Girls events around the world"
    for event in events:
        ical_event = event.as_ical()
        if ical_event is None:
            continue  # Skip events with an approximate date
        calendar.add_component(ical_event)

    return HttpResponse(calendar.to_ical(),
                        content_type='text/calendar; charset=UTF-8')

def newsletter(request):
    return render(request, 'core/newsletter.html', {})

def faq(request):
    return render(request, 'core/faq.html', {})

def foundation(request):
    return render(request, 'core/foundation.html', {})

def governing_document(request):
    return render(request, 'core/governing_document.html', {})

def contribute(request):
    return render(request, 'core/contribute.html', {})

def donate(request):
    return render(request, 'core/donate.html', {
        'patreon_stats': FundraisingStatus.objects.all().first(),
    })

def year_2015(request):
    return render(request, 'core/2015.html', {
        'events': Event.objects.public().filter(date__lt='2016-01-01').order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def year_2016_2017(request):
    return render(request, 'core/2016-2017.html', {
        'events_2015': Event.objects.public().filter(date__lt='2016-01-01').order_by('date'),
        'events_20162017': Event.objects.public().filter(date__lt='2017-08-01', date__gte='2016-01-01').order_by('date'),
        'mapbox_map_id': settings.MAPBOX_MAP_ID,
    })

def terms_conditions(request):
    return render(request, 'core/terms_conditions.html', {})

def privacy_cookies(request):
    return render(request, 'core/privacy_cookies.html', {})

def workshop_box(request):
    return render(request, 'core/workshop_box.html', {})

def server_error(request):
    return HttpResponse(status=500)

def coc(request, lang=None):
    if lang is None:
        lang = 'en'
    template_name = "core/coc/{}.html".format(lang)
    try:
        return render(request, template_name)
    except TemplateDoesNotExist:
        raise Http404("No translation for language {}".format(lang))

def crowdfunding_donors(request):
    donor_list = Donor.objects.filter(visible=True).order_by('-amount')
    return render(request, 'core/crowdfunding_donors.html', {
        'donor_list': donor_list,
        'quotes': DONOR_QUOTES,
    })
<|endoftext|>


<commit_before>import param
import numpy as np
from cartopy import crs as ccrs
from cartopy.feature import Feature as cFeature
from cartopy.io.img_tiles import GoogleTiles as cGoogleTiles
from cartopy.io.shapereader import Reader
from holoviews.core import Element2D, Dimension, Dataset as HvDataset, NdOverlay
from holoviews.core.util import basestring, pd, max_extents, dimension_range
from holoviews.element import (Text as HvText, Path as HvPath,
                               Polygons as HvPolygons, Image as HvImage,
                               RGB as HvRGB, Contours as HvContours)

from shapely.geometry.base import BaseGeometry

try:
    from iris.cube import Cube
except ImportError:
    Cube = None

try:
    from bokeh.models import WMTSTileSource
except:
    WMTSTileSource = None

try:
    from owslib.wmts import WebMapTileService
except:
    WebMapTileService = None

from ..util import path_to_geom, polygon_to_geom

geographic_types = (cGoogleTiles, cFeature, BaseGeometry)

def is_geographic(element, kdims=None):
    """
    Utility to determine whether the supplied element optionally
    a subset of its key dimensions represent a geographic coordinate
    system.
    """
    if isinstance(element, NdOverlay):
        element = element.last

    if kdims:
        kdims = [element.get_dimension(d) for d in kdims]
    else:
        kdims = element.kdims

    if len(kdims) != 2:
        return False
    if isinstance(element.data, geographic_types) or isinstance(element, (WMTS, Feature)):
        return True
    elif isinstance(element, _Element):
        return kdims == element.kdims and element.crs
    else:
        return False

class _Element(Element2D):
    """
    Baseclass for Element2D types with associated cartopy
    coordinate reference system.
    """

    _abstract = True

    crs = param.ClassSelector(default=ccrs.PlateCarree(), class_=ccrs.CRS, doc="""
        Cartopy coordinate-reference-system specifying the
        coordinate system of the data. Inferred automatically
        when _Element wraps cartopy Feature object.""")

    kdims = param.List(default=[Dimension('Longitude'), Dimension('Latitude')],
                       bounds=(2, 2), constant=True)

    def __init__(self, data, kdims=None, vdims=None, **kwargs):
        crs = None
        crs_data = data.data if isinstance(data, HvDataset) else data
        if Cube and isinstance(crs_data, Cube):
            coord_sys = crs_data.coord_system()
            if hasattr(coord_sys, 'as_cartopy_projection'):
                crs = coord_sys.as_cartopy_projection()
        elif isinstance(crs_data, (cFeature, cGoogleTiles)):
            crs = crs_data.crs

        supplied_crs = kwargs.get('crs', None)
        if supplied_crs and crs and crs != supplied_crs:
            raise ValueError('Supplied coordinate reference '
                             'system must match crs of the data.')
        elif crs:
            kwargs['crs'] = crs
        super(_Element, self).__init__(data, kdims=kdims, vdims=vdims, **kwargs)

    def clone(self, data=None, shared_data=True, new_type=None,
              *args, **overrides):
        if 'crs' not in overrides and (not new_type or isinstance(new_type, _Element)):
            overrides['crs'] = self.crs
        return super(_Element, self).clone(data, shared_data, new_type,
                                           *args, **overrides)

class _GeoFeature(_Element):
    """
    Baseclass for geographic types without their own data.
    """

    _auxiliary_component = True

    def dimension_values(self, dim):
        """
        _GeoFeature types do not contain actual data.
        """
        return []

class Feature(_GeoFeature):
    """
    A Feature represents a geographical feature
    specified as a cartopy Feature type.
    """

    group = param.String(default='Feature')

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, cFeature):
            raise TypeError('%s data has to be an cartopy Feature type'
                            % type(data).__name__)
        super(Feature, self).__init__(data, kdims=kdims, vdims=vdims, **params)

    def range(self, dim, data_range=True):
        didx = self.get_dimension_index(dim)
        if didx in [0, 1] and data_range:
            dim = self.get_dimension(dim)
            l, b, r, t = max_extents([geom.bounds for geom in self.data.geometries()])
            lower, upper = (b, t) if didx else (l, r)
            return dimension_range(lower, upper, dim)
        return super(Feature, self).range(dim, data_range)

class WMTS(_GeoFeature):
    """
    The WMTS Element represents a Web Map Tile Service
    specified as a tuple of the API URL and
    """

    crs = param.ClassSelector(default=ccrs.GOOGLE_MERCATOR, class_=ccrs.CRS, doc="""
        Cartopy coordinate-reference-system specifying the
        coordinate system of the data. Inferred automatically
        when _Element wraps cartopy Feature object.""")

    group = param.String(default='WMTS')

    layer = param.String(doc="The layer on the tile service")

    def __init__(self, data, kdims=None, vdims=None, **params):
        if isinstance(data, tuple):
            data = data
        else:
            data = (data,)

        for d in data:
            if WMTSTileSource and isinstance(d, WMTSTileSource):
                pass
            elif WebMapTileService and isinstance(d, WebMapTileService):
                if 'crs' not in params and not self.crs:
                    raise Exception('Must supply coordinate reference '
                                    'system with cartopy WMTS URL.')
            elif not isinstance(d, basestring):
                raise TypeError('%s data has to be a tile service URL'
                                % type(d).__name__)
        super(WMTS, self).__init__(data, kdims=kdims, vdims=vdims, **params)

class Tiles(_GeoFeature):
    """
    Tiles represents an image tile source to dynamically
    load data from depending on the zoom level.
    """

    group = param.String(default='Tiles')

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, cGoogleTiles):
            raise TypeError('%s data has to be a cartopy GoogleTiles type'
                            % type(data).__name__)
        super(Tiles, self).__init__(data, kdims=kdims, vdims=vdims, **params)

class Dataset(_Element, HvDataset):
    """
    Coordinate system aware version of a HoloViews dataset.
    """

class Points(Dataset):
    """
    Points represent a collection of points with
    an associated cartopy coordinate-reference system.
    """

    group = param.String(default='Points')

class LineContours(_Element, HvImage):
    """
    Contours represents a 2D array of some quantity with
    some associated coordinates, which may be discretized
    into one or more line contours.
    """

    vdims = param.List(default=[Dimension('z')], bounds=(1, 1))

    group = param.String(default='LineContours')

class FilledContours(LineContours):
    """
    Contours represents a 2D array of some quantity with
    some associated coordinates, which may be discretized
    into one or more filled contours.
    """

    group = param.String(default='FilledContours')

class Image(_Element, HvImage):
    """
    Image represents a 2D array of some quantity with
    some associated coordinates.
    """

    vdims = param.List(default=[Dimension('z')], bounds=(1, 1))

    group = param.String(default='Image')

class RGB(_Element, HvRGB):
    """
    An RGB element is a Image containing channel data for the the
    red, green, blue and (optionally) the alpha channels. The values
    of each channel must be in the range 0.0 to 1.0.

    In input array may have a shape of NxMx4 or NxMx3. In the latter
    case, the defined alpha dimension parameter is appended to the
    list of value dimensions.
    """

    group = param.String(default='RGB', constant=True)

    vdims = param.List(
        default=[Dimension('R', range=(0,1)), Dimension('G',range=(0,1)),
                 Dimension('B', range=(0,1))], bounds=(3, 4), doc="""
        The dimension description of the data held in the matrix.

        If an alpha channel is supplied, the defined alpha_dimension
        is automatically appended to this list.""")

class Text(HvText, _Element):
    """
    An annotation containing some text at an x, y coordinate
    along with a coordinate reference system.
    """

class Path(_Element, HvPath):
    """
    The Path Element contains a list of Paths stored as Nx2 numpy
    arrays along with a coordinate reference system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return path_to_geom(self)

class Contours(_Element, HvContours):
    """
    Contours is a Path Element type that may contain any number of
    closed paths with an associated value and a coordinate reference
    system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return path_to_geom(self)

class Polygons(_Element, HvPolygons):
    """
    Polygons is a Path Element type that may contain any number of
    closed paths with an associated value and a coordinate reference
    system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return polygon_to_geom(self)

class Shape(_Element):
    """
    Shape wraps any shapely geometry type.
    """

    group = param.String(default='Shape')

    level = param.Number(default=None, doc="""
        Optional level associated with the set of Contours.""")

    vdims = param.List(default=[Dimension('Level')], doc="""
        Contours optionally accept a value dimension, corresponding
        to the supplied values.""", bounds=(1,1))

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, BaseGeometry):
            raise TypeError('%s data has to be a shapely geometry type.'
                            % type(data).__name__)
        super(Shape, self).__init__(data, kdims=kdims, vdims=vdims, **params)

    @classmethod
    def from_shapefile(cls, shapefile, *args, **kwargs):
        """
        Loads a shapefile from disk and optionally merges
        it with a dataset. See ``from_records`` for full
        signature.
        """
        reader = Reader(shapefile)
        return cls.from_records(reader.records(), *args, **kwargs)

    @classmethod
    def from_records(cls, records, dataset=None, on=None,
                     value=None, index=[], drop_missing=False, **kwargs):
        """
        Load data from a collection of
        ``cartopy.io.shapereader.Record`` objects and optionally merge
        it with a dataset to assign values to each polygon and form a
        chloropleth. Supplying just records will return an NdOverlay
        of Shape Elements with a numeric index. If a dataset is
        supplied, a mapping between the attribute names in the records
        and the dimension names in the dataset must be supplied. The
        values assigned to each shape file can then be drawn from the
        dataset by supplying a ``value`` and keys the Shapes are
        indexed by specifying one or index dimensions.

        * records - An iterator of cartopy.io.shapereader.Record
                    objects.
        * dataset - Any HoloViews Dataset type.
        * on      - A mapping between the attribute names in
                    the records and the dimensions in the dataset.
        * value   - The value dimension in the dataset the
                    values will be drawn from.
        * index   - One or more dimensions in the dataset
                    the Shapes will be indexed by.
        * drop_missing - Whether to drop shapes which are missing from
                         the provided dataset.

        Returns an NdOverlay of Shapes.
        """
        if dataset is not None and not on:
            raise ValueError('To merge dataset with shapes mapping '
                             'must define attribute(s) to merge on.')

        if pd and isinstance(dataset, pd.DataFrame):
            dataset = Dataset(dataset)

        if not isinstance(on, (dict, list)):
            on = [on]
        if on and not isinstance(on, dict):
            on = {o: o for o in on}
        if not isinstance(index, list):
            index = [index]

        kdims = []
        for ind in (index if index else ['Index']):
            if dataset and dataset.get_dimension(ind):
                dim = dataset.get_dimension(ind)
            else:
                dim = Dimension(ind)
            kdims.append(dim)

        ddims = []
        if dataset:
            vdim = dataset.get_dimension(value)
            kwargs['vdims'] = [vdim]
            if not vdim:
                raise ValueError('Value dimension not found '
                                 'in dataset: {}'.format(vdim))
            ddims = dataset.dimensions()

        data = []
        notfound = False
        for i, rec in enumerate(records):
            if dataset:
                selection = {dim: rec.attributes.get(attr, None)
                             for attr, dim in on.items()}
                row = dataset.select(**selection)
                if len(row):
                    value = row[vdim.name][0]
                elif drop_missing:
                    continue
                else:
                    value = np.NaN
                kwargs['level'] = value
            if index:
                key = []
                for kdim in kdims:
                    if kdim in ddims and len(row):
                        k = row[kdim.name][0]
                    elif kdim.name in rec.attributes:
                        k = rec.attributes[kdim.name]
                    else:
                        k = None
                        notfound = True
                    key.append(k)
                key = tuple(key)
            else:
                key = (i,)
            data.append((key, Shape(rec.geometry, **kwargs)))
        if notfound:
            kdims = ['Index']+kdims
            data = [((i,)+subk, v) for i, (subk, v) in enumerate(data)]
        return NdOverlay(data, kdims=kdims)

    def dimension_values(self, dimension):
        """
        Shapes do not support convert to array values.
        """
        dim = self.get_dimension(dimension)
        if dim in self.vdims:
            return [self.level]
        else:
            return []

    def range(self, dim, data_range=True):
        dim = self.get_dimension(dim)
        if dim.range != (None, None):
            return dim.range

        idx = self.get_dimension_index(dim)
        if idx == 2 and data_range:
            return self.level, self.level
        if idx in [0, 1] and data_range:
            l, b, r, t = self.data.bounds
            lower, upper = (b, t) if idx else (l, r)
            return dimension_range(lower, upper, dim)
        else:
            return super(Shape, self).range(dim, data_range)

    def geom(self):
        """
        Returns Shape as a shapely geometry
        """
        return self.data

    def __len__(self):
        return len(self.data)
<commit_msg>Allowed any number of dimensions on gv.Dataset<commit_after>import param
import numpy as np
from cartopy import crs as ccrs
from cartopy.feature import Feature as cFeature
from cartopy.io.img_tiles import GoogleTiles as cGoogleTiles
from cartopy.io.shapereader import Reader
from holoviews.core import Element2D, Dimension, Dataset as HvDataset, NdOverlay
from holoviews.core.util import basestring, pd, max_extents, dimension_range
from holoviews.element import (Text as HvText, Path as HvPath,
                               Polygons as HvPolygons, Image as HvImage,
                               RGB as HvRGB, Contours as HvContours)

from shapely.geometry.base import BaseGeometry

try:
    from iris.cube import Cube
except ImportError:
    Cube = None

try:
    from bokeh.models import WMTSTileSource
except:
    WMTSTileSource = None

try:
    from owslib.wmts import WebMapTileService
except:
    WebMapTileService = None

from ..util import path_to_geom, polygon_to_geom

geographic_types = (cGoogleTiles, cFeature, BaseGeometry)

def is_geographic(element, kdims=None):
    """
    Utility to determine whether the supplied element optionally
    a subset of its key dimensions represent a geographic coordinate
    system.
    """
    if isinstance(element, NdOverlay):
        element = element.last

    if kdims:
        kdims = [element.get_dimension(d) for d in kdims]
    else:
        kdims = element.kdims

    if len(kdims) != 2:
        return False
    if isinstance(element.data, geographic_types) or isinstance(element, (WMTS, Feature)):
        return True
    elif isinstance(element, _Element):
        return kdims == element.kdims and element.crs
    else:
        return False

class _Element(Element2D):
    """
    Baseclass for Element2D types with associated cartopy
    coordinate reference system.
    """

    _abstract = True

    crs = param.ClassSelector(default=ccrs.PlateCarree(), class_=ccrs.CRS, doc="""
        Cartopy coordinate-reference-system specifying the
        coordinate system of the data. Inferred automatically
        when _Element wraps cartopy Feature object.""")

    kdims = param.List(default=[Dimension('Longitude'), Dimension('Latitude')],
                       bounds=(2, 2), constant=True)

    def __init__(self, data, kdims=None, vdims=None, **kwargs):
        crs = None
        crs_data = data.data if isinstance(data, HvDataset) else data
        if Cube and isinstance(crs_data, Cube):
            coord_sys = crs_data.coord_system()
            if hasattr(coord_sys, 'as_cartopy_projection'):
                crs = coord_sys.as_cartopy_projection()
        elif isinstance(crs_data, (cFeature, cGoogleTiles)):
            crs = crs_data.crs

        supplied_crs = kwargs.get('crs', None)
        if supplied_crs and crs and crs != supplied_crs:
            raise ValueError('Supplied coordinate reference '
                             'system must match crs of the data.')
        elif crs:
            kwargs['crs'] = crs
        super(_Element, self).__init__(data, kdims=kdims, vdims=vdims, **kwargs)

    def clone(self, data=None, shared_data=True, new_type=None,
              *args, **overrides):
        if 'crs' not in overrides and (not new_type or isinstance(new_type, _Element)):
            overrides['crs'] = self.crs
        return super(_Element, self).clone(data, shared_data, new_type,
                                           *args, **overrides)

class _GeoFeature(_Element):
    """
    Baseclass for geographic types without their own data.
    """

    _auxiliary_component = True

    def dimension_values(self, dim):
        """
        _GeoFeature types do not contain actual data.
        """
        return []

class Feature(_GeoFeature):
    """
    A Feature represents a geographical feature
    specified as a cartopy Feature type.
    """

    group = param.String(default='Feature')

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, cFeature):
            raise TypeError('%s data has to be an cartopy Feature type'
                            % type(data).__name__)
        super(Feature, self).__init__(data, kdims=kdims, vdims=vdims, **params)

    def range(self, dim, data_range=True):
        didx = self.get_dimension_index(dim)
        if didx in [0, 1] and data_range:
            dim = self.get_dimension(dim)
            l, b, r, t = max_extents([geom.bounds for geom in self.data.geometries()])
            lower, upper = (b, t) if didx else (l, r)
            return dimension_range(lower, upper, dim)
        return super(Feature, self).range(dim, data_range)

class WMTS(_GeoFeature):
    """
    The WMTS Element represents a Web Map Tile Service
    specified as a tuple of the API URL and
    """

    crs = param.ClassSelector(default=ccrs.GOOGLE_MERCATOR, class_=ccrs.CRS, doc="""
        Cartopy coordinate-reference-system specifying the
        coordinate system of the data. Inferred automatically
        when _Element wraps cartopy Feature object.""")

    group = param.String(default='WMTS')

    layer = param.String(doc="The layer on the tile service")

    def __init__(self, data, kdims=None, vdims=None, **params):
        if isinstance(data, tuple):
            data = data
        else:
            data = (data,)

        for d in data:
            if WMTSTileSource and isinstance(d, WMTSTileSource):
                pass
            elif WebMapTileService and isinstance(d, WebMapTileService):
                if 'crs' not in params and not self.crs:
                    raise Exception('Must supply coordinate reference '
                                    'system with cartopy WMTS URL.')
            elif not isinstance(d, basestring):
                raise TypeError('%s data has to be a tile service URL'
                                % type(d).__name__)
        super(WMTS, self).__init__(data, kdims=kdims, vdims=vdims, **params)

class Tiles(_GeoFeature):
    """
    Tiles represents an image tile source to dynamically
    load data from depending on the zoom level.
    """

    group = param.String(default='Tiles')

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, cGoogleTiles):
            raise TypeError('%s data has to be a cartopy GoogleTiles type'
                            % type(data).__name__)
        super(Tiles, self).__init__(data, kdims=kdims, vdims=vdims, **params)

class Dataset(_Element, HvDataset):
    """
    Coordinate system aware version of a HoloViews dataset.
    """

    kdims = param.List(default=[Dimension('Longitude'), Dimension('Latitude')],
                       constant=True)

    group = param.String(default='Dataset')

class Points(Dataset):
    """
    Points represent a collection of points with
    an associated cartopy coordinate-reference system.
    """

    group = param.String(default='Points')

class LineContours(_Element, HvImage):
    """
    Contours represents a 2D array of some quantity with
    some associated coordinates, which may be discretized
    into one or more line contours.
    """

    vdims = param.List(default=[Dimension('z')], bounds=(1, 1))

    group = param.String(default='LineContours')

class FilledContours(LineContours):
    """
    Contours represents a 2D array of some quantity with
    some associated coordinates, which may be discretized
    into one or more filled contours.
    """

    group = param.String(default='FilledContours')

class Image(_Element, HvImage):
    """
    Image represents a 2D array of some quantity with
    some associated coordinates.
    """

    vdims = param.List(default=[Dimension('z')], bounds=(1, 1))

    group = param.String(default='Image')

class RGB(_Element, HvRGB):
    """
    An RGB element is a Image containing channel data for the the
    red, green, blue and (optionally) the alpha channels. The values
    of each channel must be in the range 0.0 to 1.0.

    In input array may have a shape of NxMx4 or NxMx3. In the latter
    case, the defined alpha dimension parameter is appended to the
    list of value dimensions.
    """

    group = param.String(default='RGB', constant=True)

    vdims = param.List(
        default=[Dimension('R', range=(0,1)), Dimension('G',range=(0,1)),
                 Dimension('B', range=(0,1))], bounds=(3, 4), doc="""
        The dimension description of the data held in the matrix.

        If an alpha channel is supplied, the defined alpha_dimension
        is automatically appended to this list.""")

class Text(HvText, _Element):
    """
    An annotation containing some text at an x, y coordinate
    along with a coordinate reference system.
    """

class Path(_Element, HvPath):
    """
    The Path Element contains a list of Paths stored as Nx2 numpy
    arrays along with a coordinate reference system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return path_to_geom(self)

class Contours(_Element, HvContours):
    """
    Contours is a Path Element type that may contain any number of
    closed paths with an associated value and a coordinate reference
    system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return path_to_geom(self)

class Polygons(_Element, HvPolygons):
    """
    Polygons is a Path Element type that may contain any number of
    closed paths with an associated value and a coordinate reference
    system.
    """

    def geom(self):
        """
        Returns Path as a shapely geometry.
        """
        return polygon_to_geom(self)

class Shape(_Element):
    """
    Shape wraps any shapely geometry type.
    """

    group = param.String(default='Shape')

    level = param.Number(default=None, doc="""
        Optional level associated with the set of Contours.""")

    vdims = param.List(default=[Dimension('Level')], doc="""
        Contours optionally accept a value dimension, corresponding
        to the supplied values.""", bounds=(1,1))

    def __init__(self, data, kdims=None, vdims=None, **params):
        if not isinstance(data, BaseGeometry):
            raise TypeError('%s data has to be a shapely geometry type.'
                            % type(data).__name__)
        super(Shape, self).__init__(data, kdims=kdims, vdims=vdims, **params)

    @classmethod
    def from_shapefile(cls, shapefile, *args, **kwargs):
        """
        Loads a shapefile from disk and optionally merges
        it with a dataset. See ``from_records`` for full
        signature.
        """
        reader = Reader(shapefile)
        return cls.from_records(reader.records(), *args, **kwargs)

    @classmethod
    def from_records(cls, records, dataset=None, on=None,
                     value=None, index=[], drop_missing=False, **kwargs):
        """
        Load data from a collection of
        ``cartopy.io.shapereader.Record`` objects and optionally merge
        it with a dataset to assign values to each polygon and form a
        chloropleth. Supplying just records will return an NdOverlay
        of Shape Elements with a numeric index. If a dataset is
        supplied, a mapping between the attribute names in the records
        and the dimension names in the dataset must be supplied. The
        values assigned to each shape file can then be drawn from the
        dataset by supplying a ``value`` and keys the Shapes are
        indexed by specifying one or index dimensions.

        * records - An iterator of cartopy.io.shapereader.Record
                    objects.
        * dataset - Any HoloViews Dataset type.
        * on      - A mapping between the attribute names in
                    the records and the dimensions in the dataset.
        * value   - The value dimension in the dataset the
                    values will be drawn from.
        * index   - One or more dimensions in the dataset
                    the Shapes will be indexed by.
        * drop_missing - Whether to drop shapes which are missing from
                         the provided dataset.

        Returns an NdOverlay of Shapes.
        """
        if dataset is not None and not on:
            raise ValueError('To merge dataset with shapes mapping '
                             'must define attribute(s) to merge on.')

        if pd and isinstance(dataset, pd.DataFrame):
            dataset = Dataset(dataset)

        if not isinstance(on, (dict, list)):
            on = [on]
        if on and not isinstance(on, dict):
            on = {o: o for o in on}
        if not isinstance(index, list):
            index = [index]

        kdims = []
        for ind in (index if index else ['Index']):
            if dataset and dataset.get_dimension(ind):
                dim = dataset.get_dimension(ind)
            else:
                dim = Dimension(ind)
            kdims.append(dim)

        ddims = []
        if dataset:
            vdim = dataset.get_dimension(value)
            kwargs['vdims'] = [vdim]
            if not vdim:
                raise ValueError('Value dimension not found '
                                 'in dataset: {}'.format(vdim))
            ddims = dataset.dimensions()

        data = []
        notfound = False
        for i, rec in enumerate(records):
            if dataset:
                selection = {dim: rec.attributes.get(attr, None)
                             for attr, dim in on.items()}
                row = dataset.select(**selection)
                if len(row):
                    value = row[vdim.name][0]
                elif drop_missing:
                    continue
                else:
                    value = np.NaN
                kwargs['level'] = value
            if index:
                key = []
                for kdim in kdims:
                    if kdim in ddims and len(row):
                        k = row[kdim.name][0]
                    elif kdim.name in rec.attributes:
                        k = rec.attributes[kdim.name]
                    else:
                        k = None
                        notfound = True
                    key.append(k)
                key = tuple(key)
            else:
                key = (i,)
            data.append((key, Shape(rec.geometry, **kwargs)))
        if notfound:
            kdims = ['Index']+kdims
            data = [((i,)+subk, v) for i, (subk, v) in enumerate(data)]
        return NdOverlay(data, kdims=kdims)

    def dimension_values(self, dimension):
        """
        Shapes do not support convert to array values.
        """
        dim = self.get_dimension(dimension)
        if dim in self.vdims:
            return [self.level]
        else:
            return []

    def range(self, dim, data_range=True):
        dim = self.get_dimension(dim)
        if dim.range != (None, None):
            return dim.range

        idx = self.get_dimension_index(dim)
        if idx == 2 and data_range:
            return self.level, self.level
        if idx in [0, 1] and data_range:
            l, b, r, t = self.data.bounds
            lower, upper = (b, t) if idx else (l, r)
            return dimension_range(lower, upper, dim)
        else:
            return super(Shape, self).range(dim, data_range)

    def geom(self):
        """
        Returns Shape as a shapely geometry
        """
        return self.data

    def __len__(self):
        return len(self.data)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 OpenERP S.A. (<http://www.openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
Module to handle publisher warranty contracts as well as notifications from
OpenERP.
"""

import datetime
import logging
import sys
import urllib
import urllib2

import pooler
import release
from osv import osv, fields
from tools.translate import _
from tools.safe_eval import safe_eval
from tools.config import config
from tools import misc

_logger = logging.getLogger(__name__)

"""
Time interval that will be used to determine up to which date we will
check the logs to see if a message we just received was already logged.
@type: datetime.timedelta
"""
_PREVIOUS_LOG_CHECK = datetime.timedelta(days=365)

class publisher_warranty_contract(osv.osv):
    """
    Osv representing a publisher warranty contract.
    """
    _name = "publisher_warranty.contract"

    def _get_valid_contracts(self, cr, uid):
        """
        Return the list of the valid contracts encoded in the system.

        @return: A list of contracts
        @rtype: list of publisher_warranty.contract browse records
        """
        return [contract for contract in self.browse(cr, uid, self.search(cr, uid, []))
                if contract.state == 'valid']

    def status(self, cr, uid):
        """ Method called by the client to check availability of publisher warranty contract. """

        contracts = self._get_valid_contracts(cr, uid)
        return {
            'status': "full" if contracts else "none" ,
            'uncovered_modules': list(),
        }

    def send(self, cr, uid, tb, explanations, remarks=None, issue_name=None, email=None):
        """ Method called by the client to send a problem to the publisher warranty server. """

        if not remarks:
            remarks = ""

        valid_contracts = self._get_valid_contracts(cr, uid)
        valid_contract = valid_contracts[0]

        try:
            origin = 'client'
            dbuuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
            db_create_date = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')

            msg = {'contract_name': valid_contract.name,
                'tb': tb,
                'explanations': explanations,
                'remarks': remarks,
                'origin': origin,
                'dbname': cr.dbname,
                'dbuuid': dbuuid,
                'db_create_date': db_create_date,
                'issue_name': issue_name,
                'email': email,
            }

            add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}
            uo = urllib2.urlopen(config.get("publisher_warranty_url"),
                                    urllib.urlencode({'arg0': msg, "action": "send",}),**add_arg)
            try:
                submit_result = uo.read()
            finally:
                uo.close()

            result = safe_eval(submit_result)

            crm_case_id = result

            if not crm_case_id:
                return False

        except osv.except_osv:
            raise
        except Exception:
            _logger.warning("Error sending problem report", exc_info=1)
            raise osv.except_osv("Connection error", "An error occured during the connection " +
                                 "with the publisher warranty server.")

        return True

    def check_validity(self, cr, uid, ids, context=None):
        """
        Check the validity of a publisher warranty contract. This method just call get_logs() but checks
        some more things, so it can be called from a user interface.
        """
        contract_id = ids[0]
        contract = self.browse(cr, uid, contract_id)
        state = contract.state
        validated = state != "unvalidated"

        self.get_logs(cr, uid, ids, cron_mode=False, context=context)

        contract = self.browse(cr, uid, contract_id)
        validated2 = contract.state != "unvalidated"
        if not validated and not validated2:
            raise osv.except_osv(_("Contract validation error"),
                                 _("Please check your publisher warranty contract name and validity."))
        return True

    def get_logs(self, cr, uid, ids, cron_mode=True, context=None):
        """
        Send a message to OpenERP's publisher warranty server to check the validity of
        the contracts, get notifications, etc...

        @param cron_mode: If true, catch all exceptions (appropriate for usage in a cron).
        @type cron_mode: boolean
        """
        try:
            try:
                result = get_sys_logs(cr, uid)
            except Exception:
                if cron_mode: # we don't want to see any stack trace in cron
                    return False
                _logger.debug("Exception while sending a get logs messages", exc_info=1)
                raise osv.except_osv(_("Error"), _("Error during communication with the publisher warranty server."))

            contracts = result["contracts"]
            for contract in contracts:
                c_id = self.search(cr, uid, [("name","=",contract)])[0]
                date_from = contracts[contract][0]
                date_to = contracts[contract][1]
                state = contracts[contract][2]
                self.write(cr, uid, c_id, {
                    "date_start": date_from,
                    "date_stop": date_to,
                    "state": state,
                })

            limit_date = (datetime.datetime.now() - _PREVIOUS_LOG_CHECK).strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT)
            for message in result["messages"]:
                ids = self.pool.get("res.log").search(cr, uid, [("res_model", "=", "publisher_warranty.contract"),
                                                          ("create_date", ">=", limit_date),
                                                          ("name", "=", message)])
                if ids:
                    continue
                self.pool.get('res.log').create(cr, uid,
                        {
                            'name': message,
                            'res_model': "publisher_warranty.contract",
                            "read": True,
                            "user_id": False,
                        },
                        context=context
                )
        except Exception:
            if cron_mode:
                return False # we don't want to see any stack trace in cron
            else:
                raise
        return True

    def get_last_user_messages(self, cr, uid, limit, context=None):
        """
        Get the messages to be written in the web client.
        @return: A list of html messages with ids, can be False or empty.
        @rtype: list of tuples(int,string)
        """
        ids = self.pool.get('res.log').search(cr, uid, [("res_model", "=", "publisher_warranty.contract")]
                                        , order="create_date desc", limit=limit)
        if not ids:
            return []
        messages = [(x.id, x.name) for x in self.pool.get('res.log').browse(cr, uid, ids)]

        return messages

    def del_user_message(self, cr, uid, id, context=None):
        """
        Delete a message.
        """
        self.pool.get('res.log').unlink(cr, uid, [id])

        return True

    _columns = {
        'name' : fields.char('Serial Key', size=384, required=True),
        'date_start' : fields.date('Starting Date', readonly=True),
        'date_stop' : fields.date('Ending Date', readonly=True),
        'state' : fields.selection([('unvalidated', 'Unvalidated'), ('valid', 'Valid')
                            , ('terminated', 'Terminated'), ('canceled', 'Canceled')], string="State", readonly=True),
        'kind' : fields.char('Kind', size=64, readonly=True),
    }

    _defaults = {
        'state': 'unvalidated',
    }

    _sql_constraints = [
        ('uniq_name', 'unique(name)', "Your publisher warranty contract is already subscribed in the system !")
    ]

publisher_warranty_contract()

class maintenance_contract(osv.osv_memory):
    """ Old osv we only keep for compatibility with the clients. """

    _name = "maintenance.contract"

    def status(self, cr, uid):
        return self.pool.get("publisher_warranty.contract").status(cr, uid)

    def send(self, cr, uid, tb, explanations, remarks=None, issue_name=None, email=None):
        return self.pool.get("publisher_warranty.contract").send(cr, uid, tb,
                        explanations, remarks, issue_name, email)

maintenance_contract()

class publisher_warranty_contract_wizard(osv.osv_memory):
    """
    A wizard osv to help people entering a publisher warranty contract.
    """
    _name = 'publisher_warranty.contract.wizard'
    _inherit = "ir.wizard.screen"

    _columns = {
        'name' : fields.char('Serial Key', size=256, required=True ),
        'state' : fields.selection([("draft", "Draft"), ("finished", "Finished")])
    }

    _defaults = {
        "state": "draft",
    }

    def action_validate(self, cr, uid, ids, context=None):
        if not ids:
            return False

        wiz = self.browse(cr, uid, ids[0])
        c_name = wiz.name

        contract_osv = self.pool.get("publisher_warranty.contract")
        contracts = contract_osv.search(cr, uid, [("name","=",c_name)])
        if contracts:
            raise osv.except_osv(_("Error"), _("That contract is already registered in the system."))

        contract_id = contract_osv.create(cr, uid, {
            "name": c_name,
            "state": "unvalidated",
        })

        contract_osv.check_validity(cr, uid, [contract_id])

        self.write(cr, uid, ids, {"state": "finished"})

        return True

publisher_warranty_contract_wizard()

def get_sys_logs(cr, uid):
    """
    Utility method to send a publisher warranty get logs messages.
    """
    pool = pooler.get_pool(cr.dbname)

    dbuuid = pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
    db_create_date = pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
    nbr_users = pool.get("res.users").search(cr, uid, [], count=True)
    contractosv = pool.get('publisher_warranty.contract')
    contracts = contractosv.browse(cr, uid, contractosv.search(cr, uid, []))
    user = pool.get("res.users").browse(cr, uid, uid)
    msg = {
        "dbuuid": dbuuid,
        "nbr_users": nbr_users,
        "dbname": cr.dbname,
        "db_create_date": db_create_date,
        "version": release.version,
        "contracts": [c.name for c in contracts],
        "language": user.context_lang,
    }

    add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}
    uo = urllib2.urlopen(config.get("publisher_warranty_url"),
                        urllib.urlencode({'arg0': msg, "action": "update",}), **add_arg)
    try:
        submit_result = uo.read()
    finally:
        uo.close()

    result = safe_eval(submit_result)

    return result

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<commit_msg>[IMP] Improved email and username handling when sending an publisher warranty issue report.<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 OpenERP S.A. (<http://www.openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
Module to handle publisher warranty contracts as well as notifications from
OpenERP.
"""

import datetime
import logging
import sys
import urllib
import urllib2

import pooler
import release
from osv import osv, fields
from tools.translate import _
from tools.safe_eval import safe_eval
from tools.config import config
from tools import misc

_logger = logging.getLogger(__name__)

"""
Time interval that will be used to determine up to which date we will
check the logs to see if a message we just received was already logged.
@type: datetime.timedelta
"""
_PREVIOUS_LOG_CHECK = datetime.timedelta(days=365)

class publisher_warranty_contract(osv.osv):
    """
    Osv representing a publisher warranty contract.
    """
    _name = "publisher_warranty.contract"

    def _get_valid_contracts(self, cr, uid):
        """
        Return the list of the valid contracts encoded in the system.

        @return: A list of contracts
        @rtype: list of publisher_warranty.contract browse records
        """
        return [contract for contract in self.browse(cr, uid, self.search(cr, uid, []))
                if contract.state == 'valid']

    def status(self, cr, uid):
        """ Method called by the client to check availability of publisher warranty contract. """

        contracts = self._get_valid_contracts(cr, uid)
        return {
            'status': "full" if contracts else "none" ,
            'uncovered_modules': list(),
        }

    def send(self, cr, uid, tb, explanations, remarks=None, issue_name=None):
        """ Method called by the client to send a problem to the publisher warranty server. """

        if not remarks:
            remarks = ""

        valid_contracts = self._get_valid_contracts(cr, uid)
        valid_contract = valid_contracts[0]

        try:
            origin = 'client'
            dbuuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
            db_create_date = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
            user = self.pool.get("res.users").browse(cr, uid, uid)
            user_name = user.name
            email = user.email

            msg = {'contract_name': valid_contract.name,
                'tb': tb,
                'explanations': explanations,
                'remarks': remarks,
                'origin': origin,
                'dbname': cr.dbname,
                'dbuuid': dbuuid,
                'db_create_date': db_create_date,
                'issue_name': issue_name,
                'email': email,
                'user_name': user_name,
            }

            add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}
            uo = urllib2.urlopen(config.get("publisher_warranty_url"),
                                    urllib.urlencode({'arg0': msg, "action": "send",}),**add_arg)
            try:
                submit_result = uo.read()
            finally:
                uo.close()

            result = safe_eval(submit_result)

            crm_case_id = result

            if not crm_case_id:
                return False

        except osv.except_osv:
            raise
        except Exception:
            _logger.warning("Error sending problem report", exc_info=1)
            raise osv.except_osv("Connection error", "An error occured during the connection " +
                                 "with the publisher warranty server.")

        return True

    def check_validity(self, cr, uid, ids, context=None):
        """
        Check the validity of a publisher warranty contract. This method just call get_logs() but checks
        some more things, so it can be called from a user interface.
        """
        contract_id = ids[0]
        contract = self.browse(cr, uid, contract_id)
        state = contract.state
        validated = state != "unvalidated"

        self.get_logs(cr, uid, ids, cron_mode=False, context=context)

        contract = self.browse(cr, uid, contract_id)
        validated2 = contract.state != "unvalidated"
        if not validated and not validated2:
            raise osv.except_osv(_("Contract validation error"),
                                 _("Please check your publisher warranty contract name and validity."))
        return True

    def get_logs(self, cr, uid, ids, cron_mode=True, context=None):
        """
        Send a message to OpenERP's publisher warranty server to check the validity of
        the contracts, get notifications, etc...

        @param cron_mode: If true, catch all exceptions (appropriate for usage in a cron).
        @type cron_mode: boolean
        """
        try:
            try:
                result = get_sys_logs(cr, uid)
            except Exception:
                if cron_mode: # we don't want to see any stack trace in cron
                    return False
                _logger.debug("Exception while sending a get logs messages", exc_info=1)
                raise osv.except_osv(_("Error"), _("Error during communication with the publisher warranty server."))

            contracts = result["contracts"]
            for contract in contracts:
                c_id = self.search(cr, uid, [("name","=",contract)])[0]
                date_from = contracts[contract][0]
                date_to = contracts[contract][1]
                state = contracts[contract][2]
                self.write(cr, uid, c_id, {
                    "date_start": date_from,
                    "date_stop": date_to,
                    "state": state,
                })

            limit_date = (datetime.datetime.now() - _PREVIOUS_LOG_CHECK).strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT)
            for message in result["messages"]:
                ids = self.pool.get("res.log").search(cr, uid, [("res_model", "=", "publisher_warranty.contract"),
                                                          ("create_date", ">=", limit_date),
                                                          ("name", "=", message)])
                if ids:
                    continue
                self.pool.get('res.log').create(cr, uid,
                        {
                            'name': message,
                            'res_model': "publisher_warranty.contract",
                            "read": True,
                            "user_id": False,
                        },
                        context=context
                )
        except Exception:
            if cron_mode:
                return False # we don't want to see any stack trace in cron
            else:
                raise
        return True

    def get_last_user_messages(self, cr, uid, limit, context=None):
        """
        Get the messages to be written in the web client.
        @return: A list of html messages with ids, can be False or empty.
        @rtype: list of tuples(int,string)
        """
        ids = self.pool.get('res.log').search(cr, uid, [("res_model", "=", "publisher_warranty.contract")]
                                        , order="create_date desc", limit=limit)
        if not ids:
            return []
        messages = [(x.id, x.name) for x in self.pool.get('res.log').browse(cr, uid, ids)]

        return messages

    def del_user_message(self, cr, uid, id, context=None):
        """
        Delete a message.
        """
        self.pool.get('res.log').unlink(cr, uid, [id])

        return True

    _columns = {
        'name' : fields.char('Serial Key', size=384, required=True),
        'date_start' : fields.date('Starting Date', readonly=True),
        'date_stop' : fields.date('Ending Date', readonly=True),
        'state' : fields.selection([('unvalidated', 'Unvalidated'), ('valid', 'Valid')
                            , ('terminated', 'Terminated'), ('canceled', 'Canceled')], string="State", readonly=True),
        'kind' : fields.char('Kind', size=64, readonly=True),
    }

    _defaults = {
        'state': 'unvalidated',
    }

    _sql_constraints = [
        ('uniq_name', 'unique(name)', "Your publisher warranty contract is already subscribed in the system !")
    ]

publisher_warranty_contract()

class maintenance_contract(osv.osv_memory):
    """ Old osv we only keep for compatibility with the clients. """

    _name = "maintenance.contract"

    def status(self, cr, uid):
        return self.pool.get("publisher_warranty.contract").status(cr, uid)

    def send(self, cr, uid, tb, explanations, remarks=None, issue_name=None):
        return self.pool.get("publisher_warranty.contract").send(cr, uid, tb,
                        explanations, remarks, issue_name)

maintenance_contract()

class publisher_warranty_contract_wizard(osv.osv_memory):
    """
    A wizard osv to help people entering a publisher warranty contract.
    """
    _name = 'publisher_warranty.contract.wizard'
    _inherit = "ir.wizard.screen"

    _columns = {
        'name' : fields.char('Serial Key', size=256, required=True ),
        'state' : fields.selection([("draft", "Draft"), ("finished", "Finished")])
    }

    _defaults = {
        "state": "draft",
    }

    def action_validate(self, cr, uid, ids, context=None):
        if not ids:
            return False

        wiz = self.browse(cr, uid, ids[0])
        c_name = wiz.name

        contract_osv = self.pool.get("publisher_warranty.contract")
        contracts = contract_osv.search(cr, uid, [("name","=",c_name)])
        if contracts:
            raise osv.except_osv(_("Error"), _("That contract is already registered in the system."))

        contract_id = contract_osv.create(cr, uid, {
            "name": c_name,
            "state": "unvalidated",
        })

        contract_osv.check_validity(cr, uid, [contract_id])

        self.write(cr, uid, ids, {"state": "finished"})

        return True

publisher_warranty_contract_wizard()

def get_sys_logs(cr, uid):
    """
    Utility method to send a publisher warranty get logs messages.
    """
    pool = pooler.get_pool(cr.dbname)

    dbuuid = pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
    db_create_date = pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
    nbr_users = pool.get("res.users").search(cr, uid, [], count=True)
    contractosv = pool.get('publisher_warranty.contract')
    contracts = contractosv.browse(cr, uid, contractosv.search(cr, uid, []))
    user = pool.get("res.users").browse(cr, uid, uid)
    msg = {
        "dbuuid": dbuuid,
        "nbr_users": nbr_users,
        "dbname": cr.dbname,
        "db_create_date": db_create_date,
        "version": release.version,
        "contracts": [c.name for c in contracts],
        "language": user.context_lang,
    }

    add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}
    uo = urllib2.urlopen(config.get("publisher_warranty_url"),
                        urllib.urlencode({'arg0': msg, "action": "update",}), **add_arg)
    try:
        submit_result = uo.read()
    finally:
        uo.close()

    result = safe_eval(submit_result)

    return result

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<|endoftext|>


<commit_before>
from AppKit import *
from mojo.UI import *
from mojo.roboFont import CurrentFont, CurrentGlyph, AllFonts, OpenWindow

def getDesignSpaceDocuments():
    """ Try to find designspace windows."""
    designSpaces = []
    windows = [w for w in NSApp().orderedWindows() if w.isVisible()]
    for window in windows:
        delegate = window.delegate()
        if not hasattr(delegate, "vanillaWrapper"):
            continue
        vanillaWrapper = delegate.vanillaWrapper()
        if vanillaWrapper.__class__.__name__ == "DesignSpaceEditor":
            designSpaces.append(vanillaWrapper)
    return designSpaces

# see if we can find a designspace for the current UFO
def CurrentDesignSpace():
    docs = getDesignSpaceDocuments()
    # can we find the designspace that belongs to the currentfont?
    f = CurrentFont()
    if f is not None:
        for doc in docs:
            for sourceDescriptor in doc.doc.sources:
                if sourceDescriptor.path == f.path:
                    return doc.doc
    # if we have no currentfont, can we find the designspace that is the first?
    if docs:
        return docs[0].doc
    # we have no open fonts, no open docs
    return None

if __name__ == "__main__":
    result = CurrentDesignSpace()
    if result is not None:
        for font, location in result.getFonts():
            print location, font

        <commit_msg>Cleanup.<commit_after><|endoftext|>