<commit_before>from bs4 import BeautifulSoup
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
from django.utils import simplejson as json
from geoforms.models import Geoform
from geoforms.models import Questionnaire
from django.template import RequestContext
from django.views.decorators.csrf import ensure_csrf_cookie
from datetime import date
from geonition_utils.http import HttpResponse
from django.utils.translation import ugettext as _

@ensure_csrf_cookie
def questionnaire(request, questionnaire_slug, template=''):
    """
    This view creates the whole questionnaire html.
    """

    quest = Questionnaire.on_site.select_related().get(slug = questionnaire_slug)

    form_list = quest.geoforms.all().order_by('questionnaireform__order')
    elements = {}
    popup_set = set(Geoform.objects.filter(page_type = 'popup').values_list('slug', flat=True))
    bigcontent_forms = set()
    for form in form_list:
        popup_elements = form.elements.filter(element_type = 'drawbutton').values_list('html', flat=True)

        if len(popup_elements) == 0:
            bigcontent_forms.add(form.name)

        for e in popup_elements:
            soup = BeautifulSoup(e)
            popup_set.add(soup.button['data-popup'])

        elements[form.slug] = form.elements.order_by('formelement__order', '?')

    popup_list = Geoform.objects.filter(page_type = 'popup').filter(slug__in = popup_set)

    #add the popup elements to elements
    for popupform in popup_list:
        elements[popupform.slug] = popupform.elements.order_by('formelement__order', '?')

    form_list = form_list.filter(page_type = 'form')
    if not template:
        template = 'questionnaire.html'
    return render_to_response(template,
                             {'form_list': form_list,
                              'popup_list': popup_list,
                              'bigcontent_forms': bigcontent_forms,
                              'elements': elements,
                              'questionnaire': quest,
                              'map_slug': 'questionnaire-map'},
                             context_instance = RequestContext(request))

def get_active_questionnaires(request):
    today = date.today()
    active_quests = Questionnaire.on_site.filter(start_date__lte=today).filter(end_date__gte=today)
    questionnaires = []
    for quest in active_quests:
        cur_quest = {}
        cur_feature = {"type": "Feature",
                       "id": quest.id,
                       "geometry": json.loads(quest.area.json),
                       "crs": {"type": "name",
                              "properties": {
                                  "code": "EPSG:" + str(quest.area.srid)
                             }}
                       }
        cur_quest['name'] = quest.name
        cur_quest['description'] = quest.description
        cur_quest['area'] = cur_feature
        cur_quest['url'] = reverse('questionnaire', kwargs={'questionnaire_slug': quest.slug})
        cur_quest['link_text'] = _('Go to the application..')
        questionnaires.append(cur_quest)

#    return HttpResponse(json.dumps({'questionnaires': questionnaires}))
    return HttpResponse(json.dumps(questionnaires))

def feedback(request, questionnaire_slug):
    return questionnaire(request, questionnaire_slug, 'questionnaire_feedback.html')
<commit_msg>updated active questionnaire json<commit_after>from bs4 import BeautifulSoup
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
from django.utils import simplejson as json
from geoforms.models import Geoform
from geoforms.models import Questionnaire
from django.template import RequestContext
from django.views.decorators.csrf import ensure_csrf_cookie
from datetime import date
from geonition_utils.http import HttpResponse
from django.utils.translation import ugettext as _

@ensure_csrf_cookie
def questionnaire(request, questionnaire_slug, template=''):
    """
    This view creates the whole questionnaire html.
    """

    quest = Questionnaire.on_site.select_related().get(slug = questionnaire_slug)

    form_list = quest.geoforms.all().order_by('questionnaireform__order')
    elements = {}
    popup_set = set(Geoform.objects.filter(page_type = 'popup').values_list('slug', flat=True))
    bigcontent_forms = set()
    for form in form_list:
        popup_elements = form.elements.filter(element_type = 'drawbutton').values_list('html', flat=True)

        if len(popup_elements) == 0:
            bigcontent_forms.add(form.name)

        for e in popup_elements:
            soup = BeautifulSoup(e)
            popup_set.add(soup.button['data-popup'])

        elements[form.slug] = form.elements.order_by('formelement__order', '?')

    popup_list = Geoform.objects.filter(page_type = 'popup').filter(slug__in = popup_set)

    #add the popup elements to elements
    for popupform in popup_list:
        elements[popupform.slug] = popupform.elements.order_by('formelement__order', '?')

    form_list = form_list.filter(page_type = 'form')
    if not template:
        template = 'questionnaire.html'
    return render_to_response(template,
                             {'form_list': form_list,
                              'popup_list': popup_list,
                              'bigcontent_forms': bigcontent_forms,
                              'elements': elements,
                              'questionnaire': quest,
                              'map_slug': 'questionnaire-map'},
                             context_instance = RequestContext(request))

def get_active_questionnaires(request):
    today = date.today()
    active_quests = Questionnaire.on_site.filter(start_date__lte=today).filter(end_date__gte=today)
    questionnaires = []
    for quest in active_quests:
        cur_quest = {}
        cur_feature = {"type": "Feature",
                       "id": quest.id,
                       "geometry": json.loads(quest.area.json),
                       "crs": {"type": "name",
                              "properties": {
                                  "code": "EPSG:" + str(quest.area.srid)
                             }}
                       }
        cur_quest['name'] = quest.name
        cur_quest['description'] = quest.description
        cur_quest['area'] = cur_feature
        cur_quest['project_url'] = reverse('questionnaire', kwargs={'questionnaire_slug': quest.slug})
#        cur_quest['link_text'] = _('Go to the application..')
        questionnaires.append(cur_quest)

    return HttpResponse(json.dumps({'projectType': 'questionnaires',
                                    'content': questionnaires}))
#    return HttpResponse(json.dumps(questionnaires))

def feedback(request, questionnaire_slug):
    return questionnaire(request, questionnaire_slug, 'questionnaire_feedback.html')
<|endoftext|>


<commit_before># Copyright (c) 2014 AnsibleWorks, Inc.
# All Rights Reserved.

# Python
import json
import shlex

# PyYAML
import yaml

# Django
import django
from django.conf import settings
from django.db import models
from django.db.models import signals
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now

# Django-JSONField
from jsonfield import JSONField

# Django-Polymorphic
from polymorphic import PolymorphicModel

# Django-Taggit
from taggit.managers import TaggableManager

# Django-Celery
from djcelery.models import TaskMeta

# Django-CRUM
from crum import get_current_user

# Ansible Tower
from awx.main.utils import encrypt_field

__all__ = ['VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
           'PasswordFieldsModel', 'PrimordialModel', 'CommonModel',
           'CommonModelNameNotUnique',
           'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
           'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY',
           'PERM_INVENTORY_CHECK', 'JOB_TYPE_CHOICES',
           'PERMISSION_TYPE_CHOICES', 'CLOUD_INVENTORY_SOURCES']

PERM_INVENTORY_ADMIN  = 'admin'
PERM_INVENTORY_READ   = 'read'
PERM_INVENTORY_WRITE  = 'write'
PERM_INVENTORY_DEPLOY = 'run'
PERM_INVENTORY_CHECK  = 'check'

JOB_TYPE_CHOICES = [
    (PERM_INVENTORY_DEPLOY, _('Run')),
    (PERM_INVENTORY_CHECK, _('Check')),
]

PERMISSION_TYPE_CHOICES = [
    (PERM_INVENTORY_READ, _('Read Inventory')),
    (PERM_INVENTORY_WRITE, _('Edit Inventory')),
    (PERM_INVENTORY_ADMIN, _('Administrate Inventory')),
    (PERM_INVENTORY_DEPLOY, _('Deploy To Inventory')),
    (PERM_INVENTORY_CHECK, _('Deploy To Inventory (Dry Run)')),
]

CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure']

class VarsDictProperty(object):
    '''
    Retrieve a string of variables in YAML or JSON as a dictionary.
    '''

    def __init__(self, field='variables', key_value=False):
        self.field = field
        self.key_value = key_value

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        v = getattr(obj, self.field).encode('utf-8')
        d = None
        try:
            d = json.loads(v.strip() or '{}')
        except ValueError:
            pass
        if d is None:
            try:
                d = yaml.safe_load(v)
            except yaml.YAMLError:
                pass
        if d is None and self.key_value:
            d = {}
            for kv in [x.decode('utf-8') for x in shlex.split(v, posix=True)]:
                if '=' in kv:
                    k, v = kv.split('=', 1)
                    d[k] = v
        return d if hasattr(d, 'items') else {}

    def __set__(self, obj, value):
        raise AttributeError('readonly property')

class BaseModel(models.Model):
    '''
    Base model class with common methods for all models.
    '''

    class Meta:
        abstract = True

    def __unicode__(self):
        if hasattr(self, 'name'):
            return u'%s-%s' % (self.name, self.id)
        else:
            return u'%s-%s' % (self._meta.verbose_name, self.id)

    def clean_fields(self, exclude=None):
        '''
        Override default clean_fields to support methods for cleaning
        individual model fields.
        '''
        exclude = exclude or []
        errors = {}
        try:
            super(BaseModel, self).clean_fields(exclude)
        except ValidationError, e:
            errors = e.update_error_dict(errors)
        for f in self._meta.fields:
            if f.name in exclude:
                continue
            if hasattr(self, 'clean_%s' % f.name):
                try:
                    setattr(self, f.name, getattr(self, 'clean_%s' % f.name)())
                except ValidationError, e:
                    errors[f.name] = e.messages
        if errors:
             raise ValidationError(errors)

    def update_fields(self, **kwargs):
        save = kwargs.pop('save', True)
        update_fields = []
        for field, value in kwargs.items():
            if getattr(self, field) != value:
                setattr(self, field, value)
                update_fields.append(field)
        if save and update_fields:
            self.save(update_fields=update_fields)
        return update_fields

    def save(self, *args, **kwargs):
        """Save the model instance to the database.

        Additionally, if `update_fields` is present but we are on a version
        of Django that doesn't yet support it, handle support for it
        ourselves.
        """
        # If we're trying to use update_fields and Django doesn't yet support
        # it, then we need to do the save using the manager's update method,
        # which is the only way to save only individual fields on earlier
        # versions of Django.
        update_fields = kwargs.get('update_fields', None)
        if update_fields is not None and django.VERSION < (1, 5):
            # Sanity check: If update_fields is empty, do nothing.
            if len(update_fields) == 0:
                return

            # We need to manually send the pre_save signal; Django won't do it
            # using a manager update.
            #
            # This code is copied from Django itself.
            # See: django/db/models/base.py
            #
            # Django's copyright and license are found here:
            # https://github.com/django/django/blob/master/LICENSE
            cls = origin = self.__class__
            if cls._meta.proxy:
                cls = cls._meta.concrete_model
            meta = cls._meta
            if not meta.auto_created:
                # It's safe to send `update_fields` here since signal listeners
                # are required to take **kwargs.
                signals.pre_save.send(sender=origin, instance=self,
                                      created=False,
                                      raw=kwargs.get('raw', False),
                                      using=kwargs.get('using', None),
                                      update_fields=update_fields)
            # (end copied code)

            # Actually update the record. We do this with an update off of
            # the manager. Also, since update_fields in 1.5+ requires the
            # record already exist, I do not need to check for that here.
            to_update = {}
            for field in update_fields:
                to_update[field] = getattr(self, field)
            cls.objects.filter(pk=self.pk).update(**to_update)

            # Send the post-save signal.
            if not meta.auto_created:
                signals.post_save.send(sender=origin, instance=self,
                                       created=False,
                                       raw=kwargs.get('raw', False),
                                       using=kwargs.get('using', None),
                                       update_fields=update_fields)

            # Now we're done; return None.
            return

        # This is either Django 1.5+, or not using update_fields.
        # Either way, we're in good shape.
        if 'update_fields' in kwargs and kwargs['update_fields'] is None:
            kwargs.pop('update_fields')
        return super(BaseModel, self).save(*args, **kwargs)

class CreatedModifiedModel(BaseModel):
    '''
    Common model with created/modified timestamp fields.  Allows explicitly
    specifying created/modified timestamps in certain cases (migrations, job
    events), calculates automatically if not specified.
    '''

    class Meta:
        abstract = True

    created = models.DateTimeField(
        default=None,
        editable=False,
    )
    modified = models.DateTimeField(
        default=None,
        editable=False,
    )

    def save(self, *args, **kwargs):
        update_fields = kwargs.get('update_fields', [])
        # Manually perform auto_now_add and auto_now logic.
        if not self.pk and not self.created:
            self.created = now()
            if 'created' not in update_fields:
                update_fields.append('created')
        if 'modified' not in update_fields or not self.modified:
            self.modified = now()
            update_fields.append('modified')
        super(CreatedModifiedModel, self).save(*args, **kwargs)

class PasswordFieldsModel(BaseModel):
    '''
    Abstract base class for a model with password fields that should be stored
    as encrypted values.
    '''

    PASSWORD_FIELDS = ()

    class Meta:
        abstract = True

    def _password_field_allows_ask(self, field):
        return False # Override in subclasses if needed.

    def mark_inactive(self, save=True):
        '''
        When marking a password model inactive we'll clear sensitive fields
        '''
        for sensitive_field in self.PASSWORD_FIELDS:
            setattr(self, sensitive_field, "")
        self.save()
        super(PasswordFieldsModel, self).mark_inactive(save=save)

    def save(self, *args, **kwargs):
        new_instance = not bool(self.pk)
        # If update_fields has been specified, add our field names to it,
        # if it hasn't been specified, then we're just doing a normal save.
        update_fields = kwargs.get('update_fields', [])
        # When first saving to the database, don't store any password field
        # values, but instead save them until after the instance is created.
        # Otherwise, store encrypted values to the database.
        for field in self.PASSWORD_FIELDS:
            if new_instance:
                value = getattr(self, field, '')
                setattr(self, '_saved_%s' % field, value)
                setattr(self, field, '')
            else:
                ask = self._password_field_allows_ask(field)
                encrypted = encrypt_field(self, field, ask)
                setattr(self, field, encrypted)
                if field not in update_fields:
                    update_fields.append(field)
        super(PasswordFieldsModel, self).save(*args, **kwargs)
        # After saving a new instance for the first time, set the password
        # fields and save again.
        if new_instance:
            update_fields = []
            for field in self.PASSWORD_FIELDS:
                saved_value = getattr(self, '_saved_%s' % field, '')
                setattr(self, field, saved_value)
                update_fields.append(field)
            self.save(update_fields=update_fields)

class PrimordialModel(CreatedModifiedModel):
    '''
    Common model for all object types that have these standard fields
    must use a subclass CommonModel or CommonModelNameNotUnique though
    as this lacks a name field.
    '''

    class Meta:
        abstract = True

    description = models.TextField(
        blank=True,
        default='',
    )
    created_by = models.ForeignKey(
        'auth.User',
        related_name='%s(class)s_created+',
        default=None,
        null=True,
        editable=False,
        on_delete=models.SET_NULL,
    )
    modified_by = models.ForeignKey(
        'auth.User',
        related_name='%s(class)s_modified+',
        default=None,
        null=True,
        editable=False,
        on_delete=models.SET_NULL,
    )
    active = models.BooleanField(
        default=True,
        editable=False,
    )

    tags = TaggableManager(blank=True)

    def mark_inactive(self, save=True, update_fields=None, skip_active_check=False):
        '''Use instead of delete to rename and mark inactive.'''
        update_fields = update_fields or []
        if skip_active_check or self.active:
            dtnow = now()
            if 'name' in self._meta.get_all_field_names():
                self.name   = "_deleted_%s_%s" % (dtnow.isoformat(), self.name)
                if 'name' not in update_fields:
                    update_fields.append('name')
            self.active = False
            if 'active' not in update_fields:
                update_fields.append('active')
            if save:
                self.save(update_fields=update_fields)
        return update_fields

    def save(self, *args, **kwargs):
        update_fields = kwargs.get('update_fields', [])
        user = get_current_user()
        if user and not user.id:
            user = None
        if not self.pk and not self.created_by:
            self.created_by = user
            if 'created_by' not in update_fields:
                update_fields.append('created_by')
        self.modified_by = user
        if 'modified_by' not in update_fields:
            update_fields.append('modified_by')
        super(PrimordialModel, self).save(*args, **kwargs)

    def clean_description(self):
        # Description should always be empty string, never null.
        return self.description or ''

class CommonModel(PrimordialModel):
    ''' a base model where the name is unique '''

    class Meta:
        abstract = True

    name = models.CharField(
        max_length=512,
        unique=True,
    )

class CommonModelNameNotUnique(PrimordialModel):
    ''' a base model where the name is not unique '''

    class Meta:
        abstract = True

    name = models.CharField(
        max_length=512,
        unique=False,
    )
<commit_msg>Revert "Alter save mechanism on Django 1.4"<commit_after># Copyright (c) 2014 AnsibleWorks, Inc.
# All Rights Reserved.

# Python
import json
import shlex

# PyYAML
import yaml

# Django
from django.conf import settings
from django.db import models
from django.db.models import signals
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now

# Django-JSONField
from jsonfield import JSONField

# Django-Polymorphic
from polymorphic import PolymorphicModel

# Django-Taggit
from taggit.managers import TaggableManager

# Django-Celery
from djcelery.models import TaskMeta

# Django-CRUM
from crum import get_current_user

# Ansible Tower
from awx.main.utils import encrypt_field

__all__ = ['VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
           'PasswordFieldsModel', 'PrimordialModel', 'CommonModel',
           'CommonModelNameNotUnique',
           'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
           'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY',
           'PERM_INVENTORY_CHECK', 'JOB_TYPE_CHOICES',
           'PERMISSION_TYPE_CHOICES', 'CLOUD_INVENTORY_SOURCES']

PERM_INVENTORY_ADMIN  = 'admin'
PERM_INVENTORY_READ   = 'read'
PERM_INVENTORY_WRITE  = 'write'
PERM_INVENTORY_DEPLOY = 'run'
PERM_INVENTORY_CHECK  = 'check'

JOB_TYPE_CHOICES = [
    (PERM_INVENTORY_DEPLOY, _('Run')),
    (PERM_INVENTORY_CHECK, _('Check')),
]

PERMISSION_TYPE_CHOICES = [
    (PERM_INVENTORY_READ, _('Read Inventory')),
    (PERM_INVENTORY_WRITE, _('Edit Inventory')),
    (PERM_INVENTORY_ADMIN, _('Administrate Inventory')),
    (PERM_INVENTORY_DEPLOY, _('Deploy To Inventory')),
    (PERM_INVENTORY_CHECK, _('Deploy To Inventory (Dry Run)')),
]

CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure']

class VarsDictProperty(object):
    '''
    Retrieve a string of variables in YAML or JSON as a dictionary.
    '''

    def __init__(self, field='variables', key_value=False):
        self.field = field
        self.key_value = key_value

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        v = getattr(obj, self.field).encode('utf-8')
        d = None
        try:
            d = json.loads(v.strip() or '{}')
        except ValueError:
            pass
        if d is None:
            try:
                d = yaml.safe_load(v)
            except yaml.YAMLError:
                pass
        if d is None and self.key_value:
            d = {}
            for kv in [x.decode('utf-8') for x in shlex.split(v, posix=True)]:
                if '=' in kv:
                    k, v = kv.split('=', 1)
                    d[k] = v
        return d if hasattr(d, 'items') else {}

    def __set__(self, obj, value):
        raise AttributeError('readonly property')

class BaseModel(models.Model):
    '''
    Base model class with common methods for all models.
    '''

    class Meta:
        abstract = True

    def __unicode__(self):
        if hasattr(self, 'name'):
            return u'%s-%s' % (self.name, self.id)
        else:
            return u'%s-%s' % (self._meta.verbose_name, self.id)

    def clean_fields(self, exclude=None):
        '''
        Override default clean_fields to support methods for cleaning
        individual model fields.
        '''
        exclude = exclude or []
        errors = {}
        try:
            super(BaseModel, self).clean_fields(exclude)
        except ValidationError, e:
            errors = e.update_error_dict(errors)
        for f in self._meta.fields:
            if f.name in exclude:
                continue
            if hasattr(self, 'clean_%s' % f.name):
                try:
                    setattr(self, f.name, getattr(self, 'clean_%s' % f.name)())
                except ValidationError, e:
                    errors[f.name] = e.messages
        if errors:
             raise ValidationError(errors)

    def update_fields(self, **kwargs):
        save = kwargs.pop('save', True)
        update_fields = []
        for field, value in kwargs.items():
            if getattr(self, field) != value:
                setattr(self, field, value)
                update_fields.append(field)
        if save and update_fields:
            self.save(update_fields=update_fields)
        return update_fields

    def save(self, *args, **kwargs):
        # For compatibility with Django 1.4.x, attempt to handle any calls to
        # save that pass update_fields.
        try:
            super(BaseModel, self).save(*args, **kwargs)
        except TypeError:
            if 'update_fields' not in kwargs:
                raise
            kwargs.pop('update_fields')
            super(BaseModel, self).save(*args, **kwargs)

class CreatedModifiedModel(BaseModel):
    '''
    Common model with created/modified timestamp fields.  Allows explicitly
    specifying created/modified timestamps in certain cases (migrations, job
    events), calculates automatically if not specified.
    '''

    class Meta:
        abstract = True

    created = models.DateTimeField(
        default=None,
        editable=False,
    )
    modified = models.DateTimeField(
        default=None,
        editable=False,
    )

    def save(self, *args, **kwargs):
        update_fields = kwargs.get('update_fields', [])
        # Manually perform auto_now_add and auto_now logic.
        if not self.pk and not self.created:
            self.created = now()
            if 'created' not in update_fields:
                update_fields.append('created')
        if 'modified' not in update_fields or not self.modified:
            self.modified = now()
            update_fields.append('modified')
        super(CreatedModifiedModel, self).save(*args, **kwargs)

class PasswordFieldsModel(BaseModel):
    '''
    Abstract base class for a model with password fields that should be stored
    as encrypted values.
    '''

    PASSWORD_FIELDS = ()

    class Meta:
        abstract = True

    def _password_field_allows_ask(self, field):
        return False # Override in subclasses if needed.

    def mark_inactive(self, save=True):
        '''
        When marking a password model inactive we'll clear sensitive fields
        '''
        for sensitive_field in self.PASSWORD_FIELDS:
            setattr(self, sensitive_field, "")
        self.save()
        super(PasswordFieldsModel, self).mark_inactive(save=save)

    def save(self, *args, **kwargs):
        new_instance = not bool(self.pk)
        # If update_fields has been specified, add our field names to it,
        # if it hasn't been specified, then we're just doing a normal save.
        update_fields = kwargs.get('update_fields', [])
        # When first saving to the database, don't store any password field
        # values, but instead save them until after the instance is created.
        # Otherwise, store encrypted values to the database.
        for field in self.PASSWORD_FIELDS:
            if new_instance:
                value = getattr(self, field, '')
                setattr(self, '_saved_%s' % field, value)
                setattr(self, field, '')
            else:
                ask = self._password_field_allows_ask(field)
                encrypted = encrypt_field(self, field, ask)
                setattr(self, field, encrypted)
                if field not in update_fields:
                    update_fields.append(field)
        super(PasswordFieldsModel, self).save(*args, **kwargs)
        # After saving a new instance for the first time, set the password
        # fields and save again.
        if new_instance:
            update_fields = []
            for field in self.PASSWORD_FIELDS:
                saved_value = getattr(self, '_saved_%s' % field, '')
                setattr(self, field, saved_value)
                update_fields.append(field)
            self.save(update_fields=update_fields)

class PrimordialModel(CreatedModifiedModel):
    '''
    Common model for all object types that have these standard fields
    must use a subclass CommonModel or CommonModelNameNotUnique though
    as this lacks a name field.
    '''

    class Meta:
        abstract = True

    description = models.TextField(
        blank=True,
        default='',
    )
    created_by = models.ForeignKey(
        'auth.User',
        related_name='%s(class)s_created+',
        default=None,
        null=True,
        editable=False,
        on_delete=models.SET_NULL,
    )
    modified_by = models.ForeignKey(
        'auth.User',
        related_name='%s(class)s_modified+',
        default=None,
        null=True,
        editable=False,
        on_delete=models.SET_NULL,
    )
    active = models.BooleanField(
        default=True,
        editable=False,
    )

    tags = TaggableManager(blank=True)

    def mark_inactive(self, save=True, update_fields=None, skip_active_check=False):
        '''Use instead of delete to rename and mark inactive.'''
        update_fields = update_fields or []
        if skip_active_check or self.active:
            dtnow = now()
            if 'name' in self._meta.get_all_field_names():
                self.name   = "_deleted_%s_%s" % (dtnow.isoformat(), self.name)
                if 'name' not in update_fields:
                    update_fields.append('name')
            self.active = False
            if 'active' not in update_fields:
                update_fields.append('active')
            if save:
                self.save(update_fields=update_fields)
        return update_fields

    def save(self, *args, **kwargs):
        update_fields = kwargs.get('update_fields', [])
        user = get_current_user()
        if user and not user.id:
            user = None
        if not self.pk and not self.created_by:
            self.created_by = user
            if 'created_by' not in update_fields:
                update_fields.append('created_by')
        self.modified_by = user
        if 'modified_by' not in update_fields:
            update_fields.append('modified_by')
        super(PrimordialModel, self).save(*args, **kwargs)

    def clean_description(self):
        # Description should always be empty string, never null.
        return self.description or ''

class CommonModel(PrimordialModel):
    ''' a base model where the name is unique '''

    class Meta:
        abstract = True

    name = models.CharField(
        max_length=512,
        unique=True,
    )

class CommonModelNameNotUnique(PrimordialModel):
    ''' a base model where the name is not unique '''

    class Meta:
        abstract = True

    name = models.CharField(
        max_length=512,
        unique=False,
    )
<|endoftext|>


<commit_before>#!/usr/bin/env python
#-*- coding: utf-8 -*-

from subprocess import call
from logLib import *
def msgSend(phonenum_list,msg_content):
    for phonenum in phonenum_list:
        cmd = "gsmsend -s emp01.baidu.com:15003 "+phonenum+"@"+msg_content
        Ret=call(cmd, shell=True)
        if(Ret != 0):
            logging.error("msgSend failed!")<commit_msg>update<commit_after>#!/usr/bin/env python
#-*- coding: utf-8 -*-

from subprocess import call
from logLib import *
def msgSend(phonenum_list,msg_content):
    for phonenum in phonenum_list:
        cmd = "gsmsend -s emp01.baidu.com:15003 "+phonenum+"@"+"\""+msg_content+"\""
	print cmd
        Ret=call(cmd, shell=True)
        if(Ret != 0):
            logging.error("msgSend failed!")

if __name__ == '__main__':
    msgSend(['18665817689'],'userPreference:getResponse failed 3 times.')
<|endoftext|>


<commit_before>########
# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
#    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    * See the License for the specific language governing permissions and
#    * limitations under the License.

# Built-in Imports
import requests
from requests import Request,Session,Response
import json
import constants
import sys
import auth
import utils
import os
from cloudify.exceptions import NonRecoverableError
from cloudify import ctx
from cloudify.decorators import operation

#virtualmachine:

@operation
def creation_validation(**_):
    for property_key in constants.VM_REQUIRED_PROPERTIES:
        _validate_node_properties(property_key, ctx.node.properties)

@operation
def create_vm(**_):
    RANDOM_SUFFIX_VALUE = utils.random_suffix_generator()
    vm_name = ctx.node.properties['vm_name']+RANDOM_SUFFIX_VALUE
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    storage_account_name = ctx.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY]
    location = ctx.node.properties['location']
    vnet_name = ctx.instance.runtime_properties[constants.VNET_KEY]
    nic_name = ctx.instance.runtime_properties[constants.NIC_KEY]
    public_ip_name= ctx.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    credentials='Bearer '+auth.get_token_from_client_credentials()
    subscription_id = ctx.node.properties['subscription_id']
    headers = {"Content-Type": "application/json", "Authorization": credentials}

    ctx.logger.info("Checking availability of virtual network: " + vnet_name)
    if 1:
        try:
            ctx.logger.info("Creating new virtual machine: " + vm_name)
            virtual_machine_params=json.dumps(
            {
                "id":"/subscriptions/"+subscription_id+"/resourceGroups/"+resource_group_name+"/providers/Microsoft.Compute/virtualMachines/"+vm_name,
                "name":vm_name,
                "type":"Microsoft.Compute/virtualMachines",
                "location":location,
                "properties": {
                    "hardwareProfile": {
                        "vmSize": ctx.node.properties['vm_size']
                    },
                    "osProfile": {
                        "computername": vm_name,
                        "adminUsername": ctx.node.properties['ssh_username'],
                        "linuxConfiguration": {
                            "disablePasswordAuthentication": "true",
                            "ssh": {
                                "publicKeys": [
                                    {
                                        "path": "/home/"+ctx.node.properties['ssh_username']+"/.ssh/authorized_keys",
                                        "keyData": ctx.node.properties['key_data']}
                                ]
                            }
                        }
                    },
                    "storageProfile": {
                        "imageReference": {
                            "publisher": ctx.node.properties['image_reference_publisher'],
                            "offer": ctx.node.properties['image_reference_offer'],
                            "sku" : ctx.node.properties['image_reference_sku'],
                            "version":constants.vm_version
                        },
                        "osDisk" : {
                            "name": constants.os_disk_name,
                            "vhd": {
                                "uri": "http://"+storage_account_name+".blob.core.windows.net/vhds/osdisk.vhd"
                            },
                            "caching": "ReadWrite",
                            "createOption": "FromImage"
                        }
                    },
                    "networkProfile": {
                        "networkInterfaces": [
                            {
                                "id": "/subscriptions/"+subscription_id+"/resourceGroups/"+resource_group_name+"/providers/Microsoft.Network/networkInterfaces/"+nic_name
                            }
                        ]                        }
                    }
                })
            virtual_machine_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'?validating=true&api-version='+constants.api_version
            response_vm = requests.put(url=virtual_machine_url, data=virtual_machine_params, headers=headers)
            print(response_vm.text)
            ctx.instance.runtime_properties[constants.VM_KEY]=vm_name
        except:
          ctx.logger.info("Virtual Machine " + vm_name + "could not be created.")
          sys.exit(1)
    else:
     ctx.logger.info("Virtual Machine" + vm_name + "has already been provisioned by another user.")

#start_vm
@operation
def start_vm(**_):
    credentials='Bearer '+auth.get_token_from_client_credentials()
    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    subscription_id = ctx.node.properties['subscription_id']
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    public_ip_name= ctx.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    get_pip_info_url= constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/microsoft.network/publicIPAddresses/'+public_ip_name+'?api-version='+constants.api_version
    raw_response = requests.get(url=get_pip_info_url, headers=headers)
    ctx.logger.info("raw_response : " + str(raw_response))
    response_get_info = raw_response.json()
    ctx.logger.info("response_get_info : " + str(response_get_info))
    currProperties = response_get_info[u'properties']
    ctx.logger.info("currProperties : " + str(currProperties))
    currIpAddress = currProperties[u'ipAddress']
    ctx.logger.info("Current public IP address is " + str(currIpAddress))
    ctx.instance.runtime_properties['vm_public_ip']= currIpAddress
    resource_group_name = resourcegroup.resource_group_name
    start_vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'/start?api-version='+constants.api_version
    response_start_vm=requests.post(start_vm_url,headers=headers)
    print (response_start_vm.text)

#stop_vm
@operation
def stop_vm(**_):
    subscription_id = ctx.node.properties['subscription_id']

    credentials='Bearer '+auth.get_token_from_client_credentials()

    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    stop_vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'/start?api-version='+constants.api_version
    response_stop_vm=requests.post(stop_vm_url,headers=headers)
    print (response_stop_vm.text)

@operation
def delete_virtual_machine(**_):
    resource_group_name = ctx.runtime_properties[constants.RESOURCE_GROUP_KEY]
    subscription_id = ctx.node.properties['subscription_id']
    vnet_name = ctx.instance.runtime_properties[constants.VNET_KEY]
    credentials='Bearer '+auth.get_token_from_client_credentials()
    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    ctx.logger.info("Checking availability of virtual network: " + vnet_name)
    if 1:
        try:
            ctx.logger.info("Deleting the virtual machine: " + vm_name)
            vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'?validating=true&api-version='+constants.api_version
            response_vm = requests.delete(url=vm_url,headers=headers)
            print(response_vm.text)

        except:
            ctx.logger.info("Virtual Machine " + vm_name + " could not be deleted.")
        sys.exit(1)
    else:
        ctx.logger.info("Virtual Machine " + vm_name + " does not exist.")

@operation
def set_dependent_resources_names(azure_config,**kwargs):
    ctx.logger.info("Setting set_private_ip")
    vm_private_ip = ctx.target.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    ctx.logger.info("vm_private_ip is " + vm_private_ip)
    ctx.source.instance.runtime_properties['ip'] = vm_private_ip
    ctx.source.instance.runtime_properties[constants.RESOURCE_GROUP_KEY] = ctx.target.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    ctx.source.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY] = ctx.target.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY]
    ctx.source.instance.runtime_properties[constants.VNET_KEY] = ctx.target.instance.runtime_properties[constants.VNET_KEY]
    ctx.source.instance.runtime_properties[constants.PUBLIC_IP_KEY] = ctx.target.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    ctx.source.instance.runtime_properties[constants..NIC_KEY] = ctx.target.instance.runtime_properties[constants.NIC_KEY]

def _validate_node_properties(key, ctx_node_properties):
    if key not in ctx_node_properties:
        raise NonRecoverableError('{0} is a required input. Unable to create.'.format(key))
<commit_msg>Update server.py<commit_after>########
# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
#    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    * See the License for the specific language governing permissions and
#    * limitations under the License.

# Built-in Imports
import requests
from requests import Request,Session,Response
import json
import constants
import sys
import auth
import utils
import os
from cloudify.exceptions import NonRecoverableError
from cloudify import ctx
from cloudify.decorators import operation

#virtualmachine:

@operation
def creation_validation(**_):
    for property_key in constants.VM_REQUIRED_PROPERTIES:
        _validate_node_properties(property_key, ctx.node.properties)

@operation
def create_vm(**_):
    RANDOM_SUFFIX_VALUE = utils.random_suffix_generator()
    vm_name = ctx.node.properties['vm_name']+RANDOM_SUFFIX_VALUE
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    storage_account_name = ctx.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY]
    location = ctx.node.properties['location']
    vnet_name = ctx.instance.runtime_properties[constants.VNET_KEY]
    nic_name = ctx.instance.runtime_properties[constants.NIC_KEY]
    public_ip_name= ctx.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    credentials='Bearer '+auth.get_token_from_client_credentials()
    subscription_id = ctx.node.properties['subscription_id']
    headers = {"Content-Type": "application/json", "Authorization": credentials}

    ctx.logger.info("Checking availability of virtual network: " + vnet_name)
    if 1:
        try:
            ctx.logger.info("Creating new virtual machine: " + vm_name)
            virtual_machine_params=json.dumps(
            {
                "id":"/subscriptions/"+subscription_id+"/resourceGroups/"+resource_group_name+"/providers/Microsoft.Compute/virtualMachines/"+vm_name,
                "name":vm_name,
                "type":"Microsoft.Compute/virtualMachines",
                "location":location,
                "properties": {
                    "hardwareProfile": {
                        "vmSize": ctx.node.properties['vm_size']
                    },
                    "osProfile": {
                        "computername": vm_name,
                        "adminUsername": ctx.node.properties['ssh_username'],
                        "linuxConfiguration": {
                            "disablePasswordAuthentication": "true",
                            "ssh": {
                                "publicKeys": [
                                    {
                                        "path": "/home/"+ctx.node.properties['ssh_username']+"/.ssh/authorized_keys",
                                        "keyData": ctx.node.properties['key_data']}
                                ]
                            }
                        }
                    },
                    "storageProfile": {
                        "imageReference": {
                            "publisher": ctx.node.properties['image_reference_publisher'],
                            "offer": ctx.node.properties['image_reference_offer'],
                            "sku" : ctx.node.properties['image_reference_sku'],
                            "version":constants.vm_version
                        },
                        "osDisk" : {
                            "name": constants.os_disk_name,
                            "vhd": {
                                "uri": "http://"+storage_account_name+".blob.core.windows.net/vhds/osdisk.vhd"
                            },
                            "caching": "ReadWrite",
                            "createOption": "FromImage"
                        }
                    },
                    "networkProfile": {
                        "networkInterfaces": [
                            {
                                "id": "/subscriptions/"+subscription_id+"/resourceGroups/"+resource_group_name+"/providers/Microsoft.Network/networkInterfaces/"+nic_name
                            }
                        ]                        }
                    }
                })
            virtual_machine_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'?validating=true&api-version='+constants.api_version
            response_vm = requests.put(url=virtual_machine_url, data=virtual_machine_params, headers=headers)
            print(response_vm.text)
            ctx.instance.runtime_properties[constants.VM_KEY]=vm_name
        except:
          ctx.logger.info("Virtual Machine " + vm_name + "could not be created.")
          sys.exit(1)
    else:
     ctx.logger.info("Virtual Machine" + vm_name + "has already been provisioned by another user.")

#start_vm
@operation
def start_vm(**_):
    credentials='Bearer '+auth.get_token_from_client_credentials()
    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    subscription_id = ctx.node.properties['subscription_id']
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    public_ip_name= ctx.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    get_pip_info_url= constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/microsoft.network/publicIPAddresses/'+public_ip_name+'?api-version='+constants.api_version
    raw_response = requests.get(url=get_pip_info_url, headers=headers)
    ctx.logger.info("raw_response : " + str(raw_response))
    response_get_info = raw_response.json()
    ctx.logger.info("response_get_info : " + str(response_get_info))
    currProperties = response_get_info[u'properties']
    ctx.logger.info("currProperties : " + str(currProperties))
    currIpAddress = currProperties[u'ipAddress']
    ctx.logger.info("Current public IP address is " + str(currIpAddress))
    ctx.instance.runtime_properties['vm_public_ip']= currIpAddress
    resource_group_name = resourcegroup.resource_group_name
    start_vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'/start?api-version='+constants.api_version
    response_start_vm=requests.post(start_vm_url,headers=headers)
    print (response_start_vm.text)

#stop_vm
@operation
def stop_vm(**_):
    subscription_id = ctx.node.properties['subscription_id']

    credentials='Bearer '+auth.get_token_from_client_credentials()

    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    resource_group_name = ctx.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    stop_vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'/start?api-version='+constants.api_version
    response_stop_vm=requests.post(stop_vm_url,headers=headers)
    print (response_stop_vm.text)

@operation
def delete_virtual_machine(**_):
    resource_group_name = ctx.runtime_properties[constants.RESOURCE_GROUP_KEY]
    subscription_id = ctx.node.properties['subscription_id']
    vnet_name = ctx.instance.runtime_properties[constants.VNET_KEY]
    credentials='Bearer '+auth.get_token_from_client_credentials()
    headers = {"Content-Type": "application/json", "Authorization": credentials}
    vm_name = ctx.instance.runtime_properties[constants.VM_KEY]
    ctx.logger.info("Checking availability of virtual network: " + vnet_name)
    if 1:
        try:
            ctx.logger.info("Deleting the virtual machine: " + vm_name)
            vm_url=constants.azure_url+'/subscriptions/'+subscription_id+'/resourceGroups/'+resource_group_name+'/providers/Microsoft.Compute/virtualMachines/'+vm_name+'?validating=true&api-version='+constants.api_version
            response_vm = requests.delete(url=vm_url,headers=headers)
            print(response_vm.text)

        except:
            ctx.logger.info("Virtual Machine " + vm_name + " could not be deleted.")
        sys.exit(1)
    else:
        ctx.logger.info("Virtual Machine " + vm_name + " does not exist.")

@operation
def set_dependent_resources_names(azure_config,**kwargs):
    ctx.logger.info("Setting set_private_ip")
    vm_private_ip = ctx.target.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    ctx.logger.info("vm_private_ip is " + vm_private_ip)
    ctx.source.instance.runtime_properties['ip'] = vm_private_ip
    ctx.source.instance.runtime_properties[constants.RESOURCE_GROUP_KEY] = ctx.target.instance.runtime_properties[constants.RESOURCE_GROUP_KEY]
    ctx.source.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY] = ctx.target.instance.runtime_properties[constants.STORAGE_ACCOUNT_KEY]
    ctx.source.instance.runtime_properties[constants.VNET_KEY] = ctx.target.instance.runtime_properties[constants.VNET_KEY]
    ctx.source.instance.runtime_properties[constants.PUBLIC_IP_KEY] = ctx.target.instance.runtime_properties[constants.PUBLIC_IP_KEY]
    ctx.source.instance.runtime_properties[constants.NIC_KEY] = ctx.target.instance.runtime_properties[constants.NIC_KEY]

def _validate_node_properties(key, ctx_node_properties):
    if key not in ctx_node_properties:
        raise NonRecoverableError('{0} is a required input. Unable to create.'.format(key))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# --------------------------------------------------------------------
# The MIT License (MIT)
#
# Copyright (c) 2015 Jonathan Labéjof <jonathan.labejof@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# --------------------------------------------------------------------

"""Annotations dedicated to object oriented programming.
"""

from b3j0f.utils.version import PY2
from b3j0f.annotation import Annotation
from b3j0f.annotation.interception import Interceptor, PrivateInterceptor

from types import MethodType

from inspect import getmembers, isfunction, ismethod, isclass

from warnings import warn_explicit

__all__ = ['Transform', 'Mixin', 'Deprecated', 'Singleton', 'MethodMixin']

class Transform(Annotation):
    """Transform a class into an annotation or something else if parameters are
    different.
    """

    NAME = 'name'
    BASES = 'bases'
    DICT = 'dict'
    UPDATE = 'update'

    DEFAULT_BASES = (Annotation,)
    DEFAULT_DICT = {}

    __slots__ = (NAME, BASES, DICT, UPDATE) + Annotation.__slots__

    def __init__(
        self, name=None, bases=DEFAULT_BASES, dict=DEFAULT_DICT, update=True
    ):
        """
        According to type constructor parameters, you can specifiy name, bases
        and dict.

        :param str name: new class name.
        :param tuple bases: new class bases.
        :param dict dict: class __dict__.
        :param bool update: if True, update new properties on the new class.
        Else replace old ones.
        """

        self.name = name
        self.bases = bases
        self.dict = dict
        self.update = update

    def _bind_target(self, target, *args, **kwargs):

        result = target
        # do something only for class objects
        if isclass(target):

            name = target.__name__ if self.name is None else self.name
            # if update is True, update target properties
            if self.update:
                bases = tuple(set(target.__bases__ + self.bases))
                dict = target.__dict__.copy()
                dict.update(self.dict)
            else:  # else use new properties
                bases = self.bases
                dict = self.dict
            # get the new type related to name, bases and dict
            result = type(name, bases, dict)
        else:
            raise TypeError(
                'Wrong annotated element type {0}, class expected.'.format(
                    target
                )
            )

        return result

class Mixin(Annotation):
    """Annotation which enrichs a target with Mixin.

    For every defined mixin, a private couple of (name, array of mixed items)
    is created into the target in order to go back in a no mixin state.
    """

    class MixInError(Exception):
        """
        Raised for any Mixin error.
        """

        pass

    #: key to organize a dictionary of mixed elements by name in targets.
    __MIXEDIN_KEY__ = '__MIXEDIN__'

    #: Key to identify if a mixin add or replace a content.
    __NEW_CONTENT_KEY__ = '__NEW_CONTENT__'

    def __init__(self, classes=tuple(), *attributes, **named_attributes):

        super(Mixin, self).__init__()

        self.classes = classes if isinstance(classes, tuple) else (classes,)
        self.attributes = attributes
        self.named_attributes = named_attributes

    def on_bind_target(self, target, ctx, *args, **kwargs):

        super(Mixin, self).on_bind_target(target)

        for cls in self.classes:
            Mixin.mixin(target, cls)

        for attribute in self.attributes:
            Mixin.mixin(target, attribute)

        for name in self.named_attributes:
            attribute = self.named_attributes[name]
            Mixin.mixin(target, attribute, name)

    @staticmethod
    def mixin_class(target, cls):
        """Mix cls content in target.
        """

        for name, field in getmembers(cls):
            Mixin.mixin(target, field, name)

    @staticmethod
    def mixin_function_or_method(
        target, fm, name=None, bound_method=False
    ):
        """Mixin a function or a method into the target.

        If name is not given, then the fm name is used.
        If bound method is True (False by default), the mixin result is a bound
        method to target.
        """

        function = None

        if isfunction(fm):
            function = fm
        elif ismethod(fm):
            function = fm.__func__
        else:
            raise Mixin.MixInError(
                "{0} must be a function or a method.".format(fm))

        if name is None:
            name = fm.__name__

        if not isclass(target) or bound_method:
            _type = type(target)
            _type = Interceptor.get_source_target(_type)
            method_args = [function, target]
            if PY2:
                method_args += _type
            result = MethodType(*method_args)
        else:
            if PY2:
                result = MethodType(function, None, target)
            else:
                result = function

        Mixin.set_mixin(target, result, name)

        return result

    @staticmethod
    def mixin(target, resource, name=None):
        """Do the correct mixin depending on the type of input resource.

        - Method or Function: mixin_function_or_method.
        - class: mixin_class.
        - other: set_mixin.

        And returns the result of the choosen method (one or a list of mixins).
        """

        result = None

        if ismethod(resource) or isfunction(resource):
            result = Mixin.mixin_function_or_method(target, resource, name)
        elif isclass(resource):
            result = list()
            for name, content in getmembers(resource):
                if isclass(content):
                    mixin = Mixin.set_mixin(target, content, name)
                else:
                    mixin = Mixin.mixin(target, content, name)
                result.append(mixin)
        else:
            result = Mixin.set_mixin(target, resource, name)

        return result

    @staticmethod
    def get_mixedins_by_name(target):
        """Get a set of couple (name, field) of target mixedin.
        """

        result = getattr(target, Mixin.__MIXEDIN_KEY__, None)

        if result is None:
            result = dict()
            setattr(target, Mixin.__MIXEDIN_KEY__, result)

        return result

    @staticmethod
    def set_mixin(target, resource, name=None, override=True):
        """Set a resource and returns the mixed one in target content or
        Mixin.__NEW_CONTENT_KEY__ if resource name didn't exist in target.

        The optional input property name designates the target content item
        to mix with the resource.
        The override parameter (True by default) permits to replace an old
        resource by the new one.
        """

        if name is None and not hasattr(resource, '__name__'):
            raise Mixin.MixInError(
                "name must be given or resource {0} can't be anonymous"
                .format(resource))

        result = None

        name = resource.__name__ if name is None else name

        mixedins_by_name = Mixin.get_mixedins_by_name(target)

        result = getattr(target, name, Mixin.__NEW_CONTENT_KEY__)

        if override or result == Mixin.__NEW_CONTENT_KEY__:

            if name not in mixedins_by_name:
                mixedins_by_name[name] = (result,)
            else:
                mixedins_by_name[name] += (result,)

            try:
                setattr(target, name, resource)
            except Exception:
                if len(mixedins_by_name[name]) == 1:
                    del mixedins_by_name[name]
                    if len(mixedins_by_name) == 0:
                        delattr(target, Mixin.__MIXEDIN_KEY__)
                else:
                    mixedins_by_name[name] = mixedins_by_name[name][:-2]
                result = None
        else:
            result = None

        return result

    @staticmethod
    def remove_mixin(target, name, mixedin=None, set=True):
        """Remove a mixin with name (and reference) from targetand returns the
        replaced one or None.

        The mixedin parameter designates a mixedin value or the last defined
        mixedin if is None (default).
        If set is True (default), the removed mixedin replaces
        the current mixin.
        """

        try:
            result = getattr(target, name)
        except AttributeError:
            raise Mixin.MixInError(
                "No mixin {0} exists in {1}".format(name, target))

        mixedins_by_name = Mixin.get_mixedins_by_name(target)

        mixedins = mixedins_by_name.get(name)
        if mixedins:

            if mixedin is None:
                mixedin = mixedins[-1]
                mixedins = mixedins[:-2]
            else:
                try:
                    index = mixedins.index(mixedin)
                except ValueError:
                    raise Mixin.MixInError(
                        "Mixedin {0} with name {1} does not exist \
                        in target {2}"
                        .format(mixedin, name, target))
                mixedins = mixedins[0:index] + mixedins[index + 1:]

            if len(mixedins) == 0:
                # force to replace/delete the mixin even if set is False
                # in order to stay in a consistent state
                if mixedin != Mixin.__NEW_CONTENT_KEY__:
                    setattr(target, name, mixedin)
                else:
                    delattr(target, name)
                del mixedins_by_name[name]
            else:
                if set:
                    setattr(target, name, mixedin)
                mixedins_by_name[name] = mixedins

        else:
            # shouldn't be raised except if removing has been done
            # manually
            raise Mixin.MixInError(
                "No mixin {0} exists in {1}".format(name, target))

        # clean mixedins if no one exists
        if len(mixedins_by_name) == 0:
            delattr(target, Mixin.__MIXEDIN_KEY__)

        return result

    @staticmethod
    def remove_all_mixins(target, name=None):
        """Tries to get back target in a no mixin consistent state.
        If name is given, then all mixin related to input name may be removed.
        """

        mixedins_by_name = Mixin.get_mixedins_by_name(target).copy()

        for _name in mixedins_by_name:
            if name is None or name == _name:
                try:
                    while True:
                        Mixin.remove_mixin(target, _name)
                except Mixin.MixInError:
                    pass

class MethodMixin(Annotation):
    """Apply a mixin on a method.
    """

    def __init__(self, function, *args, **kwargs):

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

        self.function = function

    def _bind_target(self, target, *args, **kwargs):

        result = super(MethodMixin, self)._bind_target(target, *args, **kwargs)

        if ismethod(result):
            cls = target.im_class
            name = target.__name__
            Mixin.mixin_function_or_method(cls, self.function, name)

            return target

        else:
            return self.function

class Deprecated(PrivateInterceptor):
    """Decorator which can be used to mark functions as deprecated. It will
    result in a warning being emitted when the function is used.
    """

    def _interception(self, joinpoint, *args, **kwargs):

        target = joinpoint.target
        warn_explicit(
            "Call to deprecated function {0}.".format(target.__name__),
            category=DeprecationWarning,
            filename=target.__code__.co_filename,
            lineno=target.__code__.co_firstlineno + 1
        )
        result = joinpoint.proceed()
        return result

class Singleton(Annotation):
    """Transforms cls into a singleton.

    Reference to cls, or to any instance is the same reference.
    """

    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__()
        self.args = args
        self.kwargs = kwargs

    def _bind_target(self, target, ctx, *args, **kwargs):

        target = super(Singleton, self)._bind_target(
            target, ctx=ctx, *args, **kwargs
        )

        instance = target(*self.args, **self.kwargs)
        instance.__call__ = lambda x=None: instance
        target.__call__ = lambda x=None: instance

        return instance
<commit_msg>:fix: oop UT<commit_after># -*- coding: utf-8 -*-

# --------------------------------------------------------------------
# The MIT License (MIT)
#
# Copyright (c) 2015 Jonathan Labéjof <jonathan.labejof@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# --------------------------------------------------------------------

"""Annotations dedicated to object oriented programming.
"""

from b3j0f.utils.version import PY2
from b3j0f.annotation import Annotation
from b3j0f.annotation.interception import Interceptor, PrivateInterceptor

from types import MethodType

from inspect import getmembers, isfunction, ismethod, isclass

from warnings import warn_explicit

__all__ = ['Transform', 'Mixin', 'Deprecated', 'Singleton', 'MethodMixin']

class Transform(Annotation):
    """Transform a class into an annotation or something else if parameters are
    different.
    """

    NAME = 'name'
    BASES = 'bases'
    DICT = 'dict'
    UPDATE = 'update'

    DEFAULT_BASES = (Annotation,)
    DEFAULT_DICT = {}

    __slots__ = (NAME, BASES, DICT, UPDATE) + Annotation.__slots__

    def __init__(
        self, name=None, bases=DEFAULT_BASES, dict=DEFAULT_DICT, update=True
    ):
        """
        According to type constructor parameters, you can specifiy name, bases
        and dict.

        :param str name: new class name.
        :param tuple bases: new class bases.
        :param dict dict: class __dict__.
        :param bool update: if True, update new properties on the new class.
        Else replace old ones.
        """

        self.name = name
        self.bases = bases
        self.dict = dict
        self.update = update

    def _bind_target(self, target, *args, **kwargs):

        result = target
        # do something only for class objects
        if isclass(target):

            name = target.__name__ if self.name is None else self.name
            # if update is True, update target properties
            bases = tuple(set((target,) + self.bases))
            if self.update:
                dict = target.__dict__.copy()
                dict.update(self.dict)
            else:  # else use new properties
                dict = self.dict
            # get the new type related to name, bases and dict
            result = type(name, bases, dict)
        else:
            raise TypeError(
                'Wrong annotated element type {0}, class expected.'.format(
                    target
                )
            )

        return result

class Mixin(Annotation):
    """Annotation which enrichs a target with Mixin.

    For every defined mixin, a private couple of (name, array of mixed items)
    is created into the target in order to go back in a no mixin state.
    """

    class MixInError(Exception):
        """
        Raised for any Mixin error.
        """

        pass

    #: key to organize a dictionary of mixed elements by name in targets.
    __MIXEDIN_KEY__ = '__MIXEDIN__'

    #: Key to identify if a mixin add or replace a content.
    __NEW_CONTENT_KEY__ = '__NEW_CONTENT__'

    def __init__(self, classes=tuple(), *attributes, **named_attributes):

        super(Mixin, self).__init__()

        self.classes = classes if isinstance(classes, tuple) else (classes,)
        self.attributes = attributes
        self.named_attributes = named_attributes

    def on_bind_target(self, target, ctx, *args, **kwargs):

        super(Mixin, self).on_bind_target(target)

        for cls in self.classes:
            Mixin.mixin(target, cls)

        for attribute in self.attributes:
            Mixin.mixin(target, attribute)

        for name in self.named_attributes:
            attribute = self.named_attributes[name]
            Mixin.mixin(target, attribute, name)

    @staticmethod
    def mixin_class(target, cls):
        """Mix cls content in target.
        """

        for name, field in getmembers(cls):
            Mixin.mixin(target, field, name)

    @staticmethod
    def mixin_function_or_method(
        target, fm, name=None, bound_method=False
    ):
        """Mixin a function or a method into the target.

        If name is not given, then the fm name is used.
        If bound method is True (False by default), the mixin result is a bound
        method to target.
        """

        function = None

        if isfunction(fm):
            function = fm
        elif ismethod(fm):
            function = fm.__func__
        else:
            raise Mixin.MixInError(
                "{0} must be a function or a method.".format(fm))

        if name is None:
            name = fm.__name__

        if not isclass(target) or bound_method:
            _type = type(target)
            _type = Interceptor.get_source_target(_type)
            method_args = [function, target]
            if PY2:
                method_args += _type
            result = MethodType(*method_args)
        else:
            if PY2:
                result = MethodType(function, None, target)
            else:
                result = function

        Mixin.set_mixin(target, result, name)

        return result

    @staticmethod
    def mixin(target, resource, name=None):
        """Do the correct mixin depending on the type of input resource.

        - Method or Function: mixin_function_or_method.
        - class: mixin_class.
        - other: set_mixin.

        And returns the result of the choosen method (one or a list of mixins).
        """

        result = None

        if ismethod(resource) or isfunction(resource):
            result = Mixin.mixin_function_or_method(target, resource, name)
        elif isclass(resource):
            result = list()
            for name, content in getmembers(resource):
                if isclass(content):
                    mixin = Mixin.set_mixin(target, content, name)
                else:
                    mixin = Mixin.mixin(target, content, name)
                result.append(mixin)
        else:
            result = Mixin.set_mixin(target, resource, name)

        return result

    @staticmethod
    def get_mixedins_by_name(target):
        """Get a set of couple (name, field) of target mixedin.
        """

        result = getattr(target, Mixin.__MIXEDIN_KEY__, None)

        if result is None:
            result = dict()
            setattr(target, Mixin.__MIXEDIN_KEY__, result)

        return result

    @staticmethod
    def set_mixin(target, resource, name=None, override=True):
        """Set a resource and returns the mixed one in target content or
        Mixin.__NEW_CONTENT_KEY__ if resource name didn't exist in target.

        The optional input property name designates the target content item
        to mix with the resource.
        The override parameter (True by default) permits to replace an old
        resource by the new one.
        """

        if name is None and not hasattr(resource, '__name__'):
            raise Mixin.MixInError(
                "name must be given or resource {0} can't be anonymous"
                .format(resource))

        result = None

        name = resource.__name__ if name is None else name

        mixedins_by_name = Mixin.get_mixedins_by_name(target)

        result = getattr(target, name, Mixin.__NEW_CONTENT_KEY__)

        if override or result == Mixin.__NEW_CONTENT_KEY__:

            if name not in mixedins_by_name:
                mixedins_by_name[name] = (result,)
            else:
                mixedins_by_name[name] += (result,)

            try:
                setattr(target, name, resource)
            except Exception:
                if len(mixedins_by_name[name]) == 1:
                    del mixedins_by_name[name]
                    if len(mixedins_by_name) == 0:
                        delattr(target, Mixin.__MIXEDIN_KEY__)
                else:
                    mixedins_by_name[name] = mixedins_by_name[name][:-2]
                result = None
        else:
            result = None

        return result

    @staticmethod
    def remove_mixin(target, name, mixedin=None, set=True):
        """Remove a mixin with name (and reference) from targetand returns the
        replaced one or None.

        The mixedin parameter designates a mixedin value or the last defined
        mixedin if is None (default).
        If set is True (default), the removed mixedin replaces
        the current mixin.
        """

        try:
            result = getattr(target, name)
        except AttributeError:
            raise Mixin.MixInError(
                "No mixin {0} exists in {1}".format(name, target))

        mixedins_by_name = Mixin.get_mixedins_by_name(target)

        mixedins = mixedins_by_name.get(name)
        if mixedins:

            if mixedin is None:
                mixedin = mixedins[-1]
                mixedins = mixedins[:-2]
            else:
                try:
                    index = mixedins.index(mixedin)
                except ValueError:
                    raise Mixin.MixInError(
                        "Mixedin {0} with name {1} does not exist \
                        in target {2}"
                        .format(mixedin, name, target))
                mixedins = mixedins[0:index] + mixedins[index + 1:]

            if len(mixedins) == 0:
                # force to replace/delete the mixin even if set is False
                # in order to stay in a consistent state
                if mixedin != Mixin.__NEW_CONTENT_KEY__:
                    setattr(target, name, mixedin)
                else:
                    delattr(target, name)
                del mixedins_by_name[name]
            else:
                if set:
                    setattr(target, name, mixedin)
                mixedins_by_name[name] = mixedins

        else:
            # shouldn't be raised except if removing has been done
            # manually
            raise Mixin.MixInError(
                "No mixin {0} exists in {1}".format(name, target))

        # clean mixedins if no one exists
        if len(mixedins_by_name) == 0:
            delattr(target, Mixin.__MIXEDIN_KEY__)

        return result

    @staticmethod
    def remove_all_mixins(target, name=None):
        """Tries to get back target in a no mixin consistent state.
        If name is given, then all mixin related to input name may be removed.
        """

        mixedins_by_name = Mixin.get_mixedins_by_name(target).copy()

        for _name in mixedins_by_name:
            if name is None or name == _name:
                try:
                    while True:
                        Mixin.remove_mixin(target, _name)
                except Mixin.MixInError:
                    pass

class MethodMixin(Annotation):
    """Apply a mixin on a method.
    """

    def __init__(self, function, *args, **kwargs):

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

        self.function = function

    def _bind_target(self, target, ctx, *args, **kwargs):

        result = super(MethodMixin, self)._bind_target(
            target=target, ctx=ctx, *args, **kwargs
        )

        if ismethod(result):
            cls = target.im_class
            name = target.__name__
            Mixin.mixin_function_or_method(cls, self.function, name)
            result = target

        else:
            if ctx is not None:
                cls = ctx
                name = target.__name__
                Mixin.mixin_function_or_method(cls, self.function, name)
            result = self.function

        return result

class Deprecated(PrivateInterceptor):
    """Decorator which can be used to mark functions as deprecated. It will
    result in a warning being emitted when the function is used.
    """

    def _interception(self, joinpoint, *args, **kwargs):

        target = joinpoint.target
        warn_explicit(
            "Call to deprecated function {0}.".format(target.__name__),
            category=DeprecationWarning,
            filename=target.__code__.co_filename,
            lineno=target.__code__.co_firstlineno + 1
        )
        result = joinpoint.proceed()
        return result

class Singleton(Annotation):
    """Transforms cls into a singleton.

    Reference to cls, or to any instance is the same reference.
    """

    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__()
        self.args = args
        self.kwargs = kwargs

    def _bind_target(self, target, ctx, *args, **kwargs):

        target = super(Singleton, self)._bind_target(
            target, ctx=ctx, *args, **kwargs
        )

        instance = target(*self.args, **self.kwargs)
        instance.__call__ = lambda x=None: instance
        target.__call__ = lambda x=None: instance

        return instance
<|endoftext|>