<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    openslides.application.models
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Models for the application app.

    :copyright: 2011 by the OpenSlides team, see AUTHORS.
    :license: GNU GPL, see LICENSE for more details.
"""

from datetime import datetime

from django.db import models
from django.db.models import Max
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

from openslides.participant.models import Profile
from openslides.system.api import config_get

class Application(models.Model):
    STATUS = (
        ('pub', _('Published')),
        ('per', _('Permitted')),
        ('acc', _('Accepted')),
        ('rej', _('Rejected')),
        ('wit', _('Withdrawed')),
        ('adj', _('Adjourned')),
        ('noc', _('Not Concerned')),
        ('com', _('Commited a bill')),
        ('nop', _('Rejected (not permitted)')),
        #additional actions:
        # edit
        # delete
        # setnumber
        # support
        # unsupport
        # createitem
        # genpoll
    )

    submitter = models.ForeignKey(User, verbose_name=_("Submitter"))
    supporter = models.ManyToManyField(User, related_name='supporter', \
                                       null=True, blank=True, verbose_name=_("Supporters"))
    number = models.PositiveSmallIntegerField(blank=True, null=True,
                                        unique=True)
    status = models.CharField(max_length=3, choices=STATUS, default='pub')
    permitted = models.ForeignKey('AVersion', related_name='permitted', \
                                  null=True, blank=True)
    log = models.TextField(blank=True, null=True)

    @property
    def last_version(self):
        """
        Return last version of the application.
        """
        try:
            return AVersion.objects.filter(application=self).order_by('id') \
                                   .reverse()[0]
        except IndexError:
            return None

    @property
    def public_version(self):
        """
        Return permitted, if the application was permitted, else last_version
        """
        if self.permitted is not None:
            return self.permitted
        else:
            return self.last_version

    def accept_version(self, version):
        """
        accept a Version
        """
        self.permitted = version
        self.save(nonewversion=True)
        version.rejected = False
        version.save()

    def reject_version(self, version):
        if version.id > self.permitted.id:
            version.rejected = True
            version.save()
            return True
        return False

    @property
    def versions(self):
        """
        Return a list of all versions of the application.
        """
        return AVersion.objects.filter(application=self)

    @property
    def creation_time(self):
        """
        Return the time of the creation of the application.
        """
        try:
            return self.versions[0].time
        except IndexError:
            return None

    @property
    def notes(self):
        """
        Return some information of the application.
        """
        note = []
        if self.status == "pub" and not self.enough_supporters:
            note.append(_("Searching for supporters."))
        if self.status == "pub" and self.permitted is None:
            note.append(_("Not yet permitted."))
        elif self.unpermitted_changes and self.permitted:
            note.append(_("Not yet permitted changes."))
        return note

    @property
    def unpermitted_changes(self):
        """
        Return True if the application has unpermitted changes.

        The application has unpermitted changes, if the permitted-version
        is not the lastone and the lastone is not rejected.
        TODO: rename the property in unchecked__changes
        """
        if (self.last_version != self.permitted
        and not self.last_version.rejected):
            return True
        else:
            return False

    @property
    def enough_supporters(self):
        """
        Return True, if the application has enough supporters
        """
        min_supporters = int(config_get('application_min_supporters'))
        return self.supporter.count() >= min_supporters

    @property
    def missing_supporters(self):
        """
        Return number of missing supporters
        """
        min_supporters = int(config_get('application_min_supporters'))
        delta = min_supporters - self.supporter.count()
        if delta > 0:
            return delta
        else:
            return 0

    def save(self, user=None, nonewversion=False):
        """
        Save the Application, and create a new AVersion if necessary
        """
        super(Application, self).save()
        if nonewversion:
            return
        last_version = self.last_version
        if last_version is not None:
            if (last_version.text == self.text
            and last_version.title == self.title
            and last_version.reason == self.reason):
                return  # No changes
        try:
            if self.title != "":
                version = AVersion(title=getattr(self, 'title', ''),
                           text=getattr(self, 'text', ''),
                           reason=getattr(self, 'reason', ''),
                           application=self)
                version.save()
                self.writelog(_("Version %s created") % version.aid, user)
            is_manager = user.has_perm('application.can_manage_application')
        except AttributeError:
            is_manager = False

        if (self.status == "pub"
        and self.supporter.exists()
        and not is_manager):
            self.supporter.clear()
            self.writelog(_("Supporters removed"), user)

    def reset(self, user):
        """
        Reset the application.
        """
        self.status = "pub"
        self.permitted = None
        self.save()
        self.writelog(_("Status reseted to: %s") % (self.get_status_display()), user)

    def support(self, user):
        """
        Add a Supporter to the list of supporters of the application.
        """
        if user == self.submitter:
            raise NameError('Supporter can not be the submitter of a ' \
                            'application.')
        if self.permitted is not None:
            raise NameError('This application is already permitted.')
        if user not in self.supporter.all():
            self.supporter.add(user)
        self.writelog(_("Supporter: +%s") % (user))

    def unsupport(self, user):
        """
        remove a supporter from the list of supporters of the application
        """
        if self.permitted is not None:
            raise NameError('This application is already permitted.')
        if user in self.supporter.all():
            self.supporter.remove(user)
        self.writelog(_("Supporter: -%s") % (user))

    def set_number(self, number=None, user=None):
        """
        Set a number for ths application.
        """
        if self.number is not None:
            raise NameError('This application has already a number.')
        if number is None:
            try:
                number = Application.objects.aggregate(Max('number')) \
                            ['number__max'] + 1
            except TypeError:
                number = 1
        self.number = number
        self.save()
        self.writelog(_("Number set: %s") % (self.number), user)
        return self.number

    def permit(self, user=None):
        """
        Change the status of this application to permit.
        """
        self.set_status(user, "per")
        aversion = self.last_version
        if self.number is None:
            self.set_number()
        self.permitted = aversion
        self.save()
        self.writelog(_("Version %s permitted") % (aversion.aid), user)
        return self.permitted

    def notpermit(self, user=None):
        """
        Change the status of this application to 'not permitted (rejected)'.
        """
        self.set_status(user, "nop")
        #TODO: reject last version
        aversion = self.last_version
        #self.permitted = aversion
        if self.number is None:
            self.set_number()
        self.save()
        self.writelog(_("Version %s not permitted") % (self.last_version.aid), user)

    def set_status(self, user, status, force=False):
        """
        Set the status of the application.
        """
        error = True
        for a, b in Application.STATUS:
            if status == a:
                error = False
                break
        if error:
            raise NameError('%s is not a valid status.' % status)
        if self.status == status:
            raise NameError('The application status is already %s.' \
                            % self.status)

        actions = []
        actions = self.get_allowed_actions(user)
        if status not in actions and not force:
            raise NameError('The application status is: %s. You can not set' \
                            ' the status to %s.' % (self.status, status))

        oldstatus = self.get_status_display()
        self.status = status
        self.save()
        self.writelog(_("Status modified")+": %s -> %s" \
                      % (oldstatus, self.get_status_display()), user)

    def get_allowed_actions(self, user=None):
        """
        Return a list of all the allowed status.
        """
        actions = []

        # check if user allowed to withdraw an application
        if   (self.status == "pub"
          and self.number \
          and user == self.submitter) \
        or   (self.status == "pub" \
          and self.number \
          and user.has_perm("application.can_manage_application")) \
        or   (self.status == "per" \
          and user == self.submitter) \
        or (self.status == "per" \
          and user.has_perm("application.can_manage_application")):
            actions.append("wit")
        try:
        # Check if the user can support and unspoort the application
            if  self.status == "pub" \
            and user != self.submitter \
            and user not in self.supporter.all() \
            and user.profile:
                actions.append("support")
        except Profile.DoesNotExist:
            pass

        if self.status == "pub" and user in self.supporter.all():
            actions.append("unsupport")

        #Check if the user can edit the application
        if user == self.submitter \
        or user.has_perm("application.can_manage_application"):
            actions.append("edit")

        #Check if the user can delete the application
        if  self.number is None \
        and self.status == "pub" \
        and (self.submitter == user \
          or user.has_perm("application.can_manage_application")):
            actions.append("delete")

        #For the rest, all actions need the manage permission
        if not user.has_perm("application.can_manage_application"):
            return actions

        if self.status == "pub":
            actions.append("nop")
            actions.append("per")
            if self.number == None:
                actions.append("setnumber")

        if self.status == "per":
            actions.append("acc")
            actions.append("rej")
            actions.append("adj")
            actions.append("noc")
            actions.append("com")
            actions.append("genpoll")
            if self.unpermitted_changes:
                actions.append("permitversion")
                actions.append("rejectversion")

        if self.number and not self.itemapplication_set.all():
            actions.append("createitem")

        return actions

    def delete(self, force=False):
        """
        Delete the application. It is not possible, if the application has
        allready a number
        """
        if self.number and not force:
            raise NameError('The application has already a number. ' \
                            'You can not delete it.')
        super(Application, self).delete()

    def writelog(self, text, user=None):
        if not self.log:
            self.log = ""
        self.log += u"%s | %s" % (datetime.now().strftime("%d.%m.%Y %H:%M:%S"), text)
        if user is not None:
            self.log += u" (by %s)" % (user.username)
        self.log += "\n"
        self.save()

    def __getattr__(self, name):
        """
        if name is title, text, reason or time,
            Return this attribute from the newest version of the application
        """
        if name in ('title', 'text', 'reason', 'time', 'aid'):
            try:
                if name == 'aid':
                    return self.last_version.aid
                return self.last_version.__dict__[name]
            except TypeError:
                raise AttributeError(name)
            except AttributeError:
                raise AttributeError(name)
        raise AttributeError(name)

    def gen_poll(self, user=None):
        """
        Generates a poll object for the application
        """
        from poll.models import Poll
        poll = Poll(optiondecision=True, \
                    application=self)
        poll.save()
        poll.add_option(self)
        self.writelog(_("Poll created"), user)
        return poll

    @property
    def results(self):
        """
        Return a list of voting results
        """
        results = []
        for poll in self.poll_set.all():
            for option in poll.options:
                if poll.votesinvalid != None and poll.votescast != None:
                    results.append([option.yes, option.no, option.undesided, poll.votesinvalid, poll.votescast])
        return results

    @models.permalink
    def get_absolute_url(self, link='view'):
        if link == 'view':
            return ('application_view', [str(self.id)])
        if link == 'delete':
            return ('application_delete', [str(self.id)])

    def __unicode__(self):
        try:
            return self.last_version.title
        except AttributeError:
            return "no title jet"

    class Meta:
        permissions = (
            ('can_see_application', "Can see application"),
            ('can_create_application', "Can create application"),
            ('can_support_application', "Can support application"),
            ('can_manage_application', "Can manage application"),
        )

class AVersion(models.Model):
    title = models.CharField(max_length=100)
    text = models.TextField()
    reason = models.TextField(null=True, blank=True)
    rejected = models.BooleanField()
    time = models.DateTimeField(auto_now=True)
    application = models.ForeignKey(Application)

    def __unicode__(self):
        return "%s %s" % (self.id, self.title)

    @property
    def aid(self):
        try:
            return self._aid
        except AttributeError:
            self._aid = AVersion.objects \
                .filter(application=self.application) \
                .filter(id__lte=self.id).count()
            return self._aid
<commit_msg>Application: Check enough supports in status "pub" only.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    openslides.application.models
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Models for the application app.

    :copyright: 2011 by the OpenSlides team, see AUTHORS.
    :license: GNU GPL, see LICENSE for more details.
"""

from datetime import datetime

from django.db import models
from django.db.models import Max
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

from openslides.participant.models import Profile
from openslides.system.api import config_get

class Application(models.Model):
    STATUS = (
        ('pub', _('Published')),
        ('per', _('Permitted')),
        ('acc', _('Accepted')),
        ('rej', _('Rejected')),
        ('wit', _('Withdrawed')),
        ('adj', _('Adjourned')),
        ('noc', _('Not Concerned')),
        ('com', _('Commited a bill')),
        ('nop', _('Rejected (not permitted)')),
        #additional actions:
        # edit
        # delete
        # setnumber
        # support
        # unsupport
        # createitem
        # genpoll
    )

    submitter = models.ForeignKey(User, verbose_name=_("Submitter"))
    supporter = models.ManyToManyField(User, related_name='supporter', \
                                       null=True, blank=True, verbose_name=_("Supporters"))
    number = models.PositiveSmallIntegerField(blank=True, null=True,
                                        unique=True)
    status = models.CharField(max_length=3, choices=STATUS, default='pub')
    permitted = models.ForeignKey('AVersion', related_name='permitted', \
                                  null=True, blank=True)
    log = models.TextField(blank=True, null=True)

    @property
    def last_version(self):
        """
        Return last version of the application.
        """
        try:
            return AVersion.objects.filter(application=self).order_by('id') \
                                   .reverse()[0]
        except IndexError:
            return None

    @property
    def public_version(self):
        """
        Return permitted, if the application was permitted, else last_version
        """
        if self.permitted is not None:
            return self.permitted
        else:
            return self.last_version

    def accept_version(self, version):
        """
        accept a Version
        """
        self.permitted = version
        self.save(nonewversion=True)
        version.rejected = False
        version.save()

    def reject_version(self, version):
        if version.id > self.permitted.id:
            version.rejected = True
            version.save()
            return True
        return False

    @property
    def versions(self):
        """
        Return a list of all versions of the application.
        """
        return AVersion.objects.filter(application=self)

    @property
    def creation_time(self):
        """
        Return the time of the creation of the application.
        """
        try:
            return self.versions[0].time
        except IndexError:
            return None

    @property
    def notes(self):
        """
        Return some information of the application.
        """
        note = []
        if self.status == "pub" and not self.enough_supporters:
            note.append(_("Searching for supporters."))
        if self.status == "pub" and self.permitted is None:
            note.append(_("Not yet permitted."))
        elif self.unpermitted_changes and self.permitted:
            note.append(_("Not yet permitted changes."))
        return note

    @property
    def unpermitted_changes(self):
        """
        Return True if the application has unpermitted changes.

        The application has unpermitted changes, if the permitted-version
        is not the lastone and the lastone is not rejected.
        TODO: rename the property in unchecked__changes
        """
        if (self.last_version != self.permitted
        and not self.last_version.rejected):
            return True
        else:
            return False

    @property
    def enough_supporters(self):
        """
        Return True, if the application has enough supporters
        """
        min_supporters = int(config_get('application_min_supporters'))
        if self.status == "pub":
            return self.supporter.count() >= min_supporters
        else:
            return True

    @property
    def missing_supporters(self):
        """
        Return number of missing supporters
        """
        min_supporters = int(config_get('application_min_supporters'))
        delta = min_supporters - self.supporter.count()
        if delta > 0:
            return delta
        else:
            return 0

    def save(self, user=None, nonewversion=False):
        """
        Save the Application, and create a new AVersion if necessary
        """
        super(Application, self).save()
        if nonewversion:
            return
        last_version = self.last_version
        if last_version is not None:
            if (last_version.text == self.text
            and last_version.title == self.title
            and last_version.reason == self.reason):
                return  # No changes
        try:
            if self.title != "":
                version = AVersion(title=getattr(self, 'title', ''),
                           text=getattr(self, 'text', ''),
                           reason=getattr(self, 'reason', ''),
                           application=self)
                version.save()
                self.writelog(_("Version %s created") % version.aid, user)
            is_manager = user.has_perm('application.can_manage_application')
        except AttributeError:
            is_manager = False

        if (self.status == "pub"
        and self.supporter.exists()
        and not is_manager):
            self.supporter.clear()
            self.writelog(_("Supporters removed"), user)

    def reset(self, user):
        """
        Reset the application.
        """
        self.status = "pub"
        self.permitted = None
        self.save()
        self.writelog(_("Status reseted to: %s") % (self.get_status_display()), user)

    def support(self, user):
        """
        Add a Supporter to the list of supporters of the application.
        """
        if user == self.submitter:
            raise NameError('Supporter can not be the submitter of a ' \
                            'application.')
        if self.permitted is not None:
            raise NameError('This application is already permitted.')
        if user not in self.supporter.all():
            self.supporter.add(user)
        self.writelog(_("Supporter: +%s") % (user))

    def unsupport(self, user):
        """
        remove a supporter from the list of supporters of the application
        """
        if self.permitted is not None:
            raise NameError('This application is already permitted.')
        if user in self.supporter.all():
            self.supporter.remove(user)
        self.writelog(_("Supporter: -%s") % (user))

    def set_number(self, number=None, user=None):
        """
        Set a number for ths application.
        """
        if self.number is not None:
            raise NameError('This application has already a number.')
        if number is None:
            try:
                number = Application.objects.aggregate(Max('number')) \
                            ['number__max'] + 1
            except TypeError:
                number = 1
        self.number = number
        self.save()
        self.writelog(_("Number set: %s") % (self.number), user)
        return self.number

    def permit(self, user=None):
        """
        Change the status of this application to permit.
        """
        self.set_status(user, "per")
        aversion = self.last_version
        if self.number is None:
            self.set_number()
        self.permitted = aversion
        self.save()
        self.writelog(_("Version %s permitted") % (aversion.aid), user)
        return self.permitted

    def notpermit(self, user=None):
        """
        Change the status of this application to 'not permitted (rejected)'.
        """
        self.set_status(user, "nop")
        #TODO: reject last version
        aversion = self.last_version
        #self.permitted = aversion
        if self.number is None:
            self.set_number()
        self.save()
        self.writelog(_("Version %s not permitted") % (self.last_version.aid), user)

    def set_status(self, user, status, force=False):
        """
        Set the status of the application.
        """
        error = True
        for a, b in Application.STATUS:
            if status == a:
                error = False
                break
        if error:
            raise NameError('%s is not a valid status.' % status)
        if self.status == status:
            raise NameError('The application status is already %s.' \
                            % self.status)

        actions = []
        actions = self.get_allowed_actions(user)
        if status not in actions and not force:
            raise NameError('The application status is: %s. You can not set' \
                            ' the status to %s.' % (self.status, status))

        oldstatus = self.get_status_display()
        self.status = status
        self.save()
        self.writelog(_("Status modified")+": %s -> %s" \
                      % (oldstatus, self.get_status_display()), user)

    def get_allowed_actions(self, user=None):
        """
        Return a list of all the allowed status.
        """
        actions = []

        # check if user allowed to withdraw an application
        if   (self.status == "pub"
          and self.number \
          and user == self.submitter) \
        or   (self.status == "pub" \
          and self.number \
          and user.has_perm("application.can_manage_application")) \
        or   (self.status == "per" \
          and user == self.submitter) \
        or (self.status == "per" \
          and user.has_perm("application.can_manage_application")):
            actions.append("wit")
        try:
        # Check if the user can support and unspoort the application
            if  self.status == "pub" \
            and user != self.submitter \
            and user not in self.supporter.all() \
            and user.profile:
                actions.append("support")
        except Profile.DoesNotExist:
            pass

        if self.status == "pub" and user in self.supporter.all():
            actions.append("unsupport")

        #Check if the user can edit the application
        if user == self.submitter \
        or user.has_perm("application.can_manage_application"):
            actions.append("edit")

        #Check if the user can delete the application
        if  self.number is None \
        and self.status == "pub" \
        and (self.submitter == user \
          or user.has_perm("application.can_manage_application")):
            actions.append("delete")

        #For the rest, all actions need the manage permission
        if not user.has_perm("application.can_manage_application"):
            return actions

        if self.status == "pub":
            actions.append("nop")
            actions.append("per")
            if self.number == None:
                actions.append("setnumber")

        if self.status == "per":
            actions.append("acc")
            actions.append("rej")
            actions.append("adj")
            actions.append("noc")
            actions.append("com")
            actions.append("genpoll")
            if self.unpermitted_changes:
                actions.append("permitversion")
                actions.append("rejectversion")

        if self.number and not self.itemapplication_set.all():
            actions.append("createitem")

        return actions

    def delete(self, force=False):
        """
        Delete the application. It is not possible, if the application has
        allready a number
        """
        if self.number and not force:
            raise NameError('The application has already a number. ' \
                            'You can not delete it.')
        super(Application, self).delete()

    def writelog(self, text, user=None):
        if not self.log:
            self.log = ""
        self.log += u"%s | %s" % (datetime.now().strftime("%d.%m.%Y %H:%M:%S"), text)
        if user is not None:
            self.log += u" (by %s)" % (user.username)
        self.log += "\n"
        self.save()

    def __getattr__(self, name):
        """
        if name is title, text, reason or time,
            Return this attribute from the newest version of the application
        """
        if name in ('title', 'text', 'reason', 'time', 'aid'):
            try:
                if name == 'aid':
                    return self.last_version.aid
                return self.last_version.__dict__[name]
            except TypeError:
                raise AttributeError(name)
            except AttributeError:
                raise AttributeError(name)
        raise AttributeError(name)

    def gen_poll(self, user=None):
        """
        Generates a poll object for the application
        """
        from poll.models import Poll
        poll = Poll(optiondecision=True, \
                    application=self)
        poll.save()
        poll.add_option(self)
        self.writelog(_("Poll created"), user)
        return poll

    @property
    def results(self):
        """
        Return a list of voting results
        """
        results = []
        for poll in self.poll_set.all():
            for option in poll.options:
                if poll.votesinvalid != None and poll.votescast != None:
                    results.append([option.yes, option.no, option.undesided, poll.votesinvalid, poll.votescast])
        return results

    @models.permalink
    def get_absolute_url(self, link='view'):
        if link == 'view':
            return ('application_view', [str(self.id)])
        if link == 'delete':
            return ('application_delete', [str(self.id)])

    def __unicode__(self):
        try:
            return self.last_version.title
        except AttributeError:
            return "no title jet"

    class Meta:
        permissions = (
            ('can_see_application', "Can see application"),
            ('can_create_application', "Can create application"),
            ('can_support_application', "Can support application"),
            ('can_manage_application', "Can manage application"),
        )

class AVersion(models.Model):
    title = models.CharField(max_length=100)
    text = models.TextField()
    reason = models.TextField(null=True, blank=True)
    rejected = models.BooleanField()
    time = models.DateTimeField(auto_now=True)
    application = models.ForeignKey(Application)

    def __unicode__(self):
        return "%s %s" % (self.id, self.title)

    @property
    def aid(self):
        try:
            return self._aid
        except AttributeError:
            self._aid = AVersion.objects \
                .filter(application=self.application) \
                .filter(id__lte=self.id).count()
            return self._aid
<|endoftext|>


<commit_before># 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.

import alembic.command
import click.testing
import psycopg2
import pyramid.testing
import pytest

from pytest_dbfixtures.factories.postgresql import (
    init_postgresql_database, drop_postgresql_database,
)
from pytest_dbfixtures.utils import get_config
from sqlalchemy import event

from warehouse.config import configure
from warehouse.db import _Session

@pytest.fixture
def pyramid_request():
    return pyramid.testing.DummyRequest()

@pytest.yield_fixture
def pyramid_config(pyramid_request):
    with pyramid.testing.testConfig(request=pyramid_request) as config:
        yield config

@pytest.yield_fixture
def cli():
    runner = click.testing.CliRunner()
    with runner.isolated_filesystem():
        yield runner

@pytest.fixture(scope="session")
def database(request, postgresql_proc):
    config = get_config(request)
    pg_host = postgresql_proc.host
    pg_port = postgresql_proc.port
    pg_user = config.postgresql.user
    pg_db = config.postgresql.db
    db_url = "postgresql://{}@{}:{}/{}".format(
        pg_user, pg_host, pg_port, pg_db,
    )

    # Create our Database.
    init_postgresql_database(psycopg2, pg_user, pg_host, pg_port, pg_db)

    # Ensure our database gets deleted.
    @request.addfinalizer
    def drop_database():
        drop_postgresql_database(psycopg2, pg_user, pg_host, pg_port, pg_db)

    # Create enough of a configuration to run the migrations.
    config = configure(
        settings={
            "env": "production",
            "database.url": db_url,
            "sessions.secret": "123456",
            "sessions.url": "redis://localhost:0/",
        },
    )

    # Actually run our migrations
    alembic.command.upgrade(config.alembic_config(), "head")

    # Give back our database url for other things to use.
    return db_url

@pytest.fixture
def app_config(database):
    # Create our configuration
    config = configure(
        settings={
            "env": "production",
            "database.url": database,
            "sessions.secret": "123456",
            "sessions.url": "redis://localhost:0/",
        },
    )

    return config

@pytest.yield_fixture
def db_session(app_config):
    engine = app_config.registry["sqlalchemy.engine"]
    conn = engine.connect()
    trans = conn.begin()
    session = _Session(bind=conn)

    # Start the session in a SAVEPOINT
    session.begin_nested()

    # Then each time that SAVEPOINT ends, reopen it
    @event.listens_for(session, "after_transaction_end")
    def restart_savepoint(session, transaction):
        if transaction.nested and not transaction._parent.nested:
            session.begin_nested()

    try:
        yield session
    finally:
        session.close()
        trans.rollback()
        conn.close()
        engine.dispose()

@pytest.fixture
def db_request(pyramid_request, db_session):
    pyramid_request.db = db_session
    return pyramid_request
<commit_msg>Refactor the pytest fixtures to remove duplication<commit_after># 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.

import alembic.command
import click.testing
import psycopg2
import pyramid.testing
import pytest

from pytest_dbfixtures.factories.postgresql import (
    init_postgresql_database, drop_postgresql_database,
)
from pytest_dbfixtures.utils import get_config
from sqlalchemy import event

from warehouse.config import configure
from warehouse.db import _Session

@pytest.fixture
def pyramid_request():
    return pyramid.testing.DummyRequest()

@pytest.yield_fixture
def pyramid_config(pyramid_request):
    with pyramid.testing.testConfig(request=pyramid_request) as config:
        yield config

@pytest.yield_fixture
def cli():
    runner = click.testing.CliRunner()
    with runner.isolated_filesystem():
        yield runner

@pytest.fixture(scope="session")
def database(request, postgresql_proc):
    config = get_config(request)
    pg_host = postgresql_proc.host
    pg_port = postgresql_proc.port
    pg_user = config.postgresql.user
    pg_db = config.postgresql.db

    # Create our Database.
    init_postgresql_database(psycopg2, pg_user, pg_host, pg_port, pg_db)

    # Ensure our database gets deleted.
    @request.addfinalizer
    def drop_database():
        drop_postgresql_database(psycopg2, pg_user, pg_host, pg_port, pg_db)

    return "postgresql://{}@{}:{}/{}".format(pg_user, pg_host, pg_port, pg_db)

@pytest.fixture
def app_config(database):
    config = configure(
        settings={
            "env": "production",
            "database.url": database,
            "sessions.secret": "123456",
            "sessions.url": "redis://localhost:0/",
        },
    )

    # Ensure our migrations have been ran.
    alembic.command.upgrade(config.alembic_config(), "head")

    return config

@pytest.yield_fixture
def db_session(app_config):
    engine = app_config.registry["sqlalchemy.engine"]
    conn = engine.connect()
    trans = conn.begin()
    session = _Session(bind=conn)

    # Start the session in a SAVEPOINT
    session.begin_nested()

    # Then each time that SAVEPOINT ends, reopen it
    @event.listens_for(session, "after_transaction_end")
    def restart_savepoint(session, transaction):
        if transaction.nested and not transaction._parent.nested:
            session.begin_nested()

    try:
        yield session
    finally:
        session.close()
        trans.rollback()
        conn.close()
        engine.dispose()

@pytest.fixture
def db_request(pyramid_request, db_session):
    pyramid_request.db = db_session
    return pyramid_request
<|endoftext|>


<commit_before># Copyright (c) 2013 OpenStack Foundation
# 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.

"""
Helpers for comparing version strings.
"""

import functools
import pkg_resources

from openstack.common.gettextutils import _
from openstack.common import log as logging

LOG = logging.getLogger(__name__)

class deprecated(object):
    """A decorator to mark callables as deprecated.

    deprecated logs a deprecation message when the callable it decorates
    is used. The message will include the release where the callable was
    deprecated, the release where is may be removed and possibly an
    optional replacement.

    Examples:

    1. Specifing the required deprecated release

    >>> @deprecated(as_of=deprecated.ICEHOUSE)
    ... def a(): pass

    2. Specifing a replacement:

    >>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()')
    ... def b(): pass

    3. Specifying the release where the functionality may be removed:

    >>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=+1)
    ... def c(): pass

    """

    FOLSOM = 'F'
    GRIZZLY = 'G'
    HAVANA = 'H'
    ICEHOUSE = 'I'

    _RELEASES = {
        'F': 'Folsom',
        'G': 'Grizzly',
        'H': 'Havana',
        'I': 'Icehouse',
    }

    _deprecated_msg_with_alternative = _(
        '%(what)s is deprecated as of %(as_of)s in favor of '
        '%(in_favor_of)s and may be removed in %(remove_in)s.')

    _deprecated_msg_no_alternative = _(
        '%(what)s is deprecated as of %(as_of)s and may be '
        'removed in %(remove_in)s. It will not be superseded.')

    def __init__(self, as_of, in_favor_of=None, remove_in=2, what=None):
        """Initialize decorator

        :param as_of: the release deprecating the callable. Constants
            are define in this class for convenience.
        :param in_favor_of: the replacement for the callable (optional)
        :param remove_in: an integer specifying how many releases to wait
            before removing (default: 2)
        :param what: name of the thing being deprecated (default: the
            callable's name)

        """
        self.as_of = as_of
        self.in_favor_of = in_favor_of
        self.remove_in = remove_in
        self.what = what

    def __call__(self, func):
        if not self.what:
            self.what = func.__name__ + '()'

        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            msg, details = self._build_message()
            LOG.deprecated(msg, details)
            return func(*args, **kwargs)
        return wrapped

    def _get_safe_to_remove_release(self, release):
        # TODO(dstanek): this method will have to be reimplemented once
        #    when we get to the X release because once we get to the Y
        #    release, what is Y+2?
        new_release = chr(ord(release) + self.remove_in)
        if new_release in self._RELEASES:
            return self._RELEASES[new_release]
        else:
            return new_release

    def _build_message(self):
        details = dict(what=self.what,
                       as_of=self._RELEASES[self.as_of],
                       remove_in=self._get_safe_to_remove_release(self.as_of))

        if self.in_favor_of:
            details['in_favor_of'] = self.in_favor_of
            msg = self._deprecated_msg_with_alternative
        else:
            msg = self._deprecated_msg_no_alternative
        return msg, details

def is_compatible(requested_version, current_version, same_major=True):
    """Determine whether `requested_version` is satisfied by
    `current_version`; in other words, `current_version` is >=
    `requested_version`.

    :param requested_version: version to check for compatibility
    :param current_version: version to check against
    :param same_major: if True, the major version must be identical between
        `requested_version` and `current_version`. This is used when a
        major-version difference indicates incompatibility between the two
        versions. Since this is the common-case in practice, the default is
        True.
    :returns: True if compatible, False if not
    """
    requested_parts = pkg_resources.parse_version(requested_version)
    current_parts = pkg_resources.parse_version(current_version)

    if same_major and (requested_parts[0] != current_parts[0]):
        return False

    return current_parts >= requested_parts
<commit_msg>Fix violations of H302:import only modules<commit_after># Copyright (c) 2013 OpenStack Foundation
# 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.

"""
Helpers for comparing version strings.
"""

import functools
import pkg_resources

from openstack.common.gettextutils import _  # noqa
from openstack.common import log as logging

LOG = logging.getLogger(__name__)

class deprecated(object):
    """A decorator to mark callables as deprecated.

    deprecated logs a deprecation message when the callable it decorates
    is used. The message will include the release where the callable was
    deprecated, the release where is may be removed and possibly an
    optional replacement.

    Examples:

    1. Specifing the required deprecated release

    >>> @deprecated(as_of=deprecated.ICEHOUSE)
    ... def a(): pass

    2. Specifing a replacement:

    >>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()')
    ... def b(): pass

    3. Specifying the release where the functionality may be removed:

    >>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=+1)
    ... def c(): pass

    """

    FOLSOM = 'F'
    GRIZZLY = 'G'
    HAVANA = 'H'
    ICEHOUSE = 'I'

    _RELEASES = {
        'F': 'Folsom',
        'G': 'Grizzly',
        'H': 'Havana',
        'I': 'Icehouse',
    }

    _deprecated_msg_with_alternative = _(
        '%(what)s is deprecated as of %(as_of)s in favor of '
        '%(in_favor_of)s and may be removed in %(remove_in)s.')

    _deprecated_msg_no_alternative = _(
        '%(what)s is deprecated as of %(as_of)s and may be '
        'removed in %(remove_in)s. It will not be superseded.')

    def __init__(self, as_of, in_favor_of=None, remove_in=2, what=None):
        """Initialize decorator

        :param as_of: the release deprecating the callable. Constants
            are define in this class for convenience.
        :param in_favor_of: the replacement for the callable (optional)
        :param remove_in: an integer specifying how many releases to wait
            before removing (default: 2)
        :param what: name of the thing being deprecated (default: the
            callable's name)

        """
        self.as_of = as_of
        self.in_favor_of = in_favor_of
        self.remove_in = remove_in
        self.what = what

    def __call__(self, func):
        if not self.what:
            self.what = func.__name__ + '()'

        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            msg, details = self._build_message()
            LOG.deprecated(msg, details)
            return func(*args, **kwargs)
        return wrapped

    def _get_safe_to_remove_release(self, release):
        # TODO(dstanek): this method will have to be reimplemented once
        #    when we get to the X release because once we get to the Y
        #    release, what is Y+2?
        new_release = chr(ord(release) + self.remove_in)
        if new_release in self._RELEASES:
            return self._RELEASES[new_release]
        else:
            return new_release

    def _build_message(self):
        details = dict(what=self.what,
                       as_of=self._RELEASES[self.as_of],
                       remove_in=self._get_safe_to_remove_release(self.as_of))

        if self.in_favor_of:
            details['in_favor_of'] = self.in_favor_of
            msg = self._deprecated_msg_with_alternative
        else:
            msg = self._deprecated_msg_no_alternative
        return msg, details

def is_compatible(requested_version, current_version, same_major=True):
    """Determine whether `requested_version` is satisfied by
    `current_version`; in other words, `current_version` is >=
    `requested_version`.

    :param requested_version: version to check for compatibility
    :param current_version: version to check against
    :param same_major: if True, the major version must be identical between
        `requested_version` and `current_version`. This is used when a
        major-version difference indicates incompatibility between the two
        versions. Since this is the common-case in practice, the default is
        True.
    :returns: True if compatible, False if not
    """
    requested_parts = pkg_resources.parse_version(requested_version)
    current_parts = pkg_resources.parse_version(current_version)

    if same_major and (requested_parts[0] != current_parts[0]):
        return False

    return current_parts >= requested_parts
<|endoftext|>


<commit_before>#!/usr/bin/env python
# add_dose_time_to_mtz.py
#
#   Copyright (C) 2009 Diamond Light Source, Graeme Winter
#
#   This code is distributed under the BSD license, a copy of which is
#   included in the root directory of this package.
#
# A replacement for the FORTRAN program DOSER, which adds two columns DOSE
# and TIME to unmerged MTZ files, so that they can be analysed dose-wise
# by CHEF. In reality, the functionality of both could be mapped to a
# single program now...
#

import os
import sys

from iotbx import mtz
from cctbx.array_family import flex

def add_dose_time_to_mtz(hklin, hklout, doses, times = None):
    '''Add doses and times from dictionaries doses, times (optional)
    to hklin to produce hklout. The dictionaries are indexed by the
    BATCH column in hklin. Will raise exception if no BATCH column.'''

    # instantiate the MTZ object representation

    mtz_obj = mtz.object(file_name = hklin)

    # construct a list of columns in the file

    cnames = []
    ctypes = []

    batch_column = None
    batch_dataset = None

    for crystal in mtz_obj.crystals():
        for dataset in crystal.datasets():
            for column in dataset.columns():
                if column.label() == 'BATCH':
                    batch_column = column
                    batch_dataset = dataset

    if not batch_column:
        raise RuntimeError, 'no BATCH column found in %s' % hklin

    # right, so get the values out from the batch column, create a flex
    # array of the same size and assign DOSE, TIME, then add these to the
    # same dataset.

    batch_column_values = batch_column.extract_values(
        not_a_number_substitute = -1)

    dose_column = batch_dataset.add_column(label = 'DOSE', type = 'F')
    dose_column_values = flex.float()

    if times:
        time_column = batch_dataset.add_column(label = 'TIME', type = 'F')
        time_column_values = flex.float()

    valid = flex.bool()

    for b in batch_column_values:

        valid.append(True)
        dose_column_values.append(doses.get(b, -1.0))

        if times:
            time_column_values.append(times.get(b, -1.0))

    # add the columns back to the MTZ file structure

    dose_column.set_values(values = dose_column_values,
                           selection_valid = valid)

    if times:
        time_column.set_values(values = time_column_values,
                               selection_valid = valid)

    # and write this lot out as hklout

    mtz_obj.write(file_name = hklout)

if (__name__ == "__main__"):

    doses = { }
    times = { }

    for record in open('doser.in', 'r').readlines():
        values = record.split()
        if not values:
            continue
        batch = int(values[1])
        dose = float(values[3])
        time = float(values[5])

        doses[batch] = dose
        times[batch] = time

    add_dose_time_to_mtz(hklin = 'TS03_12287_chef_INFL.mtz',
                         hklout = 'hklout.mtz',
                         doses = doses,
                         times = times)
<commit_msg>Fixed the column type<commit_after>#!/usr/bin/env python
# add_dose_time_to_mtz.py
#
#   Copyright (C) 2009 Diamond Light Source, Graeme Winter
#
#   This code is distributed under the BSD license, a copy of which is
#   included in the root directory of this package.
#
# A replacement for the FORTRAN program DOSER, which adds two columns DOSE
# and TIME to unmerged MTZ files, so that they can be analysed dose-wise
# by CHEF. In reality, the functionality of both could be mapped to a
# single program now...
#

import os
import sys

from iotbx import mtz
from cctbx.array_family import flex

def add_dose_time_to_mtz(hklin, hklout, doses, times = None):
    '''Add doses and times from dictionaries doses, times (optional)
    to hklin to produce hklout. The dictionaries are indexed by the
    BATCH column in hklin. Will raise exception if no BATCH column.'''

    # instantiate the MTZ object representation

    mtz_obj = mtz.object(file_name = hklin)

    # construct a list of columns in the file

    cnames = []
    ctypes = []

    batch_column = None
    batch_dataset = None

    for crystal in mtz_obj.crystals():
        for dataset in crystal.datasets():
            for column in dataset.columns():
                if column.label() == 'BATCH':
                    batch_column = column
                    batch_dataset = dataset

    if not batch_column:
        raise RuntimeError, 'no BATCH column found in %s' % hklin

    # right, so get the values out from the batch column, create a flex
    # array of the same size and assign DOSE, TIME, then add these to the
    # same dataset.

    batch_column_values = batch_column.extract_values(
        not_a_number_substitute = -1)

    dose_column = batch_dataset.add_column(label = 'DOSE', type = 'R')
    dose_column_values = flex.float()

    if times:
        time_column = batch_dataset.add_column(label = 'TIME', type = 'R')
        time_column_values = flex.float()

    valid = flex.bool()

    for b in batch_column_values:

        valid.append(True)
        dose_column_values.append(doses.get(b, -1.0))

        if times:
            time_column_values.append(times.get(b, -1.0))

    # add the columns back to the MTZ file structure

    dose_column.set_values(values = dose_column_values,
                           selection_valid = valid)

    if times:
        time_column.set_values(values = time_column_values,
                               selection_valid = valid)

    # and write this lot out as hklout

    mtz_obj.write(file_name = hklout)

if (__name__ == "__main__"):

    doses = { }
    times = { }

    for record in open('doser.in', 'r').readlines():
        values = record.split()
        if not values:
            continue
        batch = int(values[1])
        dose = float(values[3])
        time = float(values[5])

        doses[batch] = dose
        times[batch] = time

    add_dose_time_to_mtz(hklin = 'TS03_12287_chef_INFL.mtz',
                         hklout = 'hklout.mtz',
                         doses = doses,
                         times = times)
<|endoftext|>


<commit_before>#    Copyright 2013, Big Switch Networks, Inc.
#
#    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.

from __future__ import absolute_import

from django.utils.datastructures import SortedDict

from openstack_dashboard.api import neutron

neutronclient = neutron.neutronclient

class Vip(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer vip."""

    def __init__(self, apiresource):
        super(Vip, self).__init__(apiresource)

class Pool(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool."""

    def __init__(self, apiresource):
        if 'provider' not in apiresource:
            apiresource['provider'] = None
        super(Pool, self).__init__(apiresource)

class Member(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer member."""

    def __init__(self, apiresource):
        super(Member, self).__init__(apiresource)

class PoolStats(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool stats."""

    def __init__(self, apiresource):
        super(PoolStats, self).__init__(apiresource)

class PoolMonitor(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool health monitor."""

    def __init__(self, apiresource):
        super(PoolMonitor, self).__init__(apiresource)

def vip_create(request, **kwargs):
    """Create a vip for a specified pool.

    :param request: request context
    :param address: virtual IP address
    :param name: name for vip
    :param description: description for vip
    :param subnet_id: subnet_id for subnet of vip
    :param protocol_port: transport layer port number for vip
    :returns: Vip object
    """
    body = {'vip': {'name': kwargs['name'],
                    'description': kwargs['description'],
                    'subnet_id': kwargs['subnet_id'],
                    'protocol_port': kwargs['protocol_port'],
                    'protocol': kwargs['protocol'],
                    'pool_id': kwargs['pool_id'],
                    'session_persistence': kwargs['session_persistence'],
                    'admin_state_up': kwargs['admin_state_up']
                    }}
    if kwargs.get('connection_limit'):
        body['vip']['connection_limit'] = kwargs['connection_limit']

    if kwargs.get('address'):
        body['vip']['address'] = kwargs['address']

    vip = neutronclient(request).create_vip(body).get('vip')
    return Vip(vip)

def vip_list(request, **kwargs):
    vips = neutronclient(request).list_vips(**kwargs).get('vips')
    return [Vip(v) for v in vips]

def vip_get(request, vip_id):
    return _vip_get(request, vip_id, expand_resource=True)

def _vip_get(request, vip_id, expand_resource=False):
    vip = neutronclient(request).show_vip(vip_id).get('vip')
    if expand_resource:
        vip['subnet'] = neutron.subnet_get(request, vip['subnet_id'])
        vip['port'] = neutron.port_get(request, vip['port_id'])
        vip['pool'] = _pool_get(request, vip['pool_id'])
    return Vip(vip)

def vip_update(request, vip_id, **kwargs):
    vip = neutronclient(request).update_vip(vip_id, kwargs).get('vip')
    return Vip(vip)

def vip_delete(request, vip_id):
    neutronclient(request).delete_vip(vip_id)

def pool_create(request, **kwargs):
    """Create a pool for specified protocol

    :param request: request context
    :param name: name for pool
    :param description: description for pool
    :param subnet_id: subnet_id for subnet of pool
    :param protocol: load balanced protocol
    :param lb_method: load balancer method
    :param admin_state_up: admin state (default on)
    """
    body = {'pool': {'name': kwargs['name'],
                     'description': kwargs['description'],
                     'subnet_id': kwargs['subnet_id'],
                     'protocol': kwargs['protocol'],
                     'lb_method': kwargs['lb_method'],
                     'admin_state_up': kwargs['admin_state_up'],
                     'provider': kwargs['provider'],
                     }}
    pool = neutronclient(request).create_pool(body).get('pool')
    return Pool(pool)

def _get_vip(request, pool, vip_dict, expand_name_only=False):
    if pool['vip_id'] is not None:
        try:
            if vip_dict:
                vip = vip_dict.get(pool['vip_id'])
            else:
                vip = _vip_get(request, pool['vip_id'])
        except Exception:
            vip = Vip({'id': pool['vip_id'], 'name': ''})
        if expand_name_only:
            vip = vip.name_or_id
        return vip
    else:
        return None

def pool_list(request, **kwargs):
    return _pool_list(request, expand_subnet=True, expand_vip=True, **kwargs)

def _pool_list(request, expand_subnet=False, expand_vip=False, **kwargs):
    pools = neutronclient(request).list_pools(**kwargs).get('pools')
    if expand_subnet:
        subnets = neutron.subnet_list(request)
        subnet_dict = SortedDict((s.id, s) for s in subnets)
        for p in pools:
            subnet = subnet_dict.get(p['subnet_id'])
            p['subnet_name'] = subnet.cidr if subnet else None
    if expand_vip:
        vips = vip_list(request)
        vip_dict = SortedDict((v.id, v) for v in vips)
        for p in pools:
            p['vip_name'] = _get_vip(request, p, vip_dict,
                                     expand_name_only=True)
    return [Pool(p) for p in pools]

def pool_get(request, pool_id):
    return _pool_get(request, pool_id, expand_resource=True)

def _pool_get(request, pool_id, expand_resource=False):
    pool = neutronclient(request).show_pool(pool_id).get('pool')
    if expand_resource:
        pool['subnet'] = neutron.subnet_get(request, pool['subnet_id'])
        pool['vip'] = _get_vip(request, pool, vip_dict=None,
                               expand_name_only=False)
        pool['members'] = _member_list(request, expand_pool=False,
                                       pool_id=pool_id)
        pool['health_monitors'] = pool_health_monitor_list(
            request, id=pool['health_monitors'])
    return Pool(pool)

def pool_update(request, pool_id, **kwargs):
    pool = neutronclient(request).update_pool(pool_id, kwargs).get('pool')
    return Pool(pool)

def pool_delete(request, pool):
    neutronclient(request).delete_pool(pool)

# not linked to UI yet
def pool_stats(request, pool_id, **kwargs):
    stats = neutronclient(request).retrieve_pool_stats(pool_id, **kwargs)
    return PoolStats(stats)

def pool_health_monitor_create(request, **kwargs):
    """Create a health monitor

    :param request: request context
    :param type: type of monitor
    :param delay: delay of monitor
    :param timeout: timeout of monitor
    :param max_retries: max retries [1..10]
    :param http_method: http method
    :param url_path: url path
    :param expected_codes: http return code
    :param admin_state_up: admin state
    """
    monitor_type = kwargs['type'].upper()
    body = {'health_monitor': {'type': monitor_type,
                               'delay': kwargs['delay'],
                               'timeout': kwargs['timeout'],
                               'max_retries': kwargs['max_retries'],
                               'admin_state_up': kwargs['admin_state_up']
                               }}
    if monitor_type in ['HTTP', 'HTTPS']:
        body['health_monitor']['http_method'] = kwargs['http_method']
        body['health_monitor']['url_path'] = kwargs['url_path']
        body['health_monitor']['expected_codes'] = kwargs['expected_codes']
    mon = neutronclient(request).create_health_monitor(body).get(
        'health_monitor')

    return PoolMonitor(mon)

def pool_health_monitor_list(request, **kwargs):
    monitors = neutronclient(request).list_health_monitors(
        **kwargs).get('health_monitors')
    return [PoolMonitor(m) for m in monitors]

def pool_health_monitor_get(request, monitor_id):
    return _pool_health_monitor_get(request, monitor_id, expand_resource=True)

def _pool_health_monitor_get(request, monitor_id, expand_resource=False):
    monitor = neutronclient(request
                            ).show_health_monitor(monitor_id
                                                  ).get('health_monitor')
    if expand_resource:
        pool_ids = [p['pool_id'] for p in monitor['pools']]
        monitor['pools'] = _pool_list(request, id=pool_ids)
    return PoolMonitor(monitor)

def pool_health_monitor_update(request, monitor_id, **kwargs):
    monitor = neutronclient(request).update_health_monitor(monitor_id, kwargs)
    return PoolMonitor(monitor)

def pool_health_monitor_delete(request, mon_id):
    neutronclient(request).delete_health_monitor(mon_id)

def member_create(request, **kwargs):
    """Create a load balance member

    :param request: request context
    :param pool_id: pool_id of pool for member
    :param address: IP address
    :param protocol_port: transport layer port number
    :param weight: weight for member
    :param admin_state_up: admin_state
    """
    body = {'member': {'pool_id': kwargs['pool_id'],
                       'address': kwargs['address'],
                       'protocol_port': kwargs['protocol_port'],
                       'admin_state_up': kwargs['admin_state_up']
                       }}
    if kwargs.get('weight'):
        body['member']['weight'] = kwargs['weight']
    member = neutronclient(request).create_member(body).get('member')
    return Member(member)

def member_list(request, **kwargs):
    return _member_list(request, expand_pool=True, **kwargs)

def _member_list(request, expand_pool, **kwargs):
    members = neutronclient(request).list_members(**kwargs).get('members')
    if expand_pool:
        pools = _pool_list(request)
        pool_dict = SortedDict((p.id, p) for p in pools)
        for m in members:
            m['pool_name'] = pool_dict.get(m['pool_id']).name_or_id
    return [Member(m) for m in members]

def member_get(request, member_id):
    return _member_get(request, member_id, expand_pool=True)

def _member_get(request, member_id, expand_pool):
    member = neutronclient(request).show_member(member_id).get('member')
    if expand_pool:
        member['pool'] = _pool_get(request, member['pool_id'])
    return Member(member)

def member_update(request, member_id, **kwargs):
    member = neutronclient(request).update_member(member_id, kwargs)
    return Member(member)

def member_delete(request, mem_id):
    neutronclient(request).delete_member(mem_id)

def pool_monitor_association_create(request, **kwargs):
    """Associate a health monitor with pool

    :param request: request context
    :param monitor_id: id of monitor
    :param pool_id: id of pool
    """

    body = {'health_monitor': {'id': kwargs['monitor_id'], }}

    neutronclient(request).associate_health_monitor(
        kwargs['pool_id'], body)

def pool_monitor_association_delete(request, **kwargs):
    """Disassociate a health monitor from pool

    :param request: request context
    :param monitor_id: id of monitor
    :param pool_id: id of pool
    """

    neutronclient(request).disassociate_health_monitor(
        kwargs['pool_id'], kwargs['monitor_id'])
<commit_msg>Throw a warning message when failed to get pool detail<commit_after>#    Copyright 2013, Big Switch Networks, Inc.
#
#    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.

from __future__ import absolute_import

from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy as _

from horizon import messages

from openstack_dashboard.api import neutron

neutronclient = neutron.neutronclient

class Vip(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer vip."""

    def __init__(self, apiresource):
        super(Vip, self).__init__(apiresource)

class Pool(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool."""

    def __init__(self, apiresource):
        if 'provider' not in apiresource:
            apiresource['provider'] = None
        super(Pool, self).__init__(apiresource)

class Member(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer member."""

    def __init__(self, apiresource):
        super(Member, self).__init__(apiresource)

class PoolStats(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool stats."""

    def __init__(self, apiresource):
        super(PoolStats, self).__init__(apiresource)

class PoolMonitor(neutron.NeutronAPIDictWrapper):
    """Wrapper for neutron load balancer pool health monitor."""

    def __init__(self, apiresource):
        super(PoolMonitor, self).__init__(apiresource)

def vip_create(request, **kwargs):
    """Create a vip for a specified pool.

    :param request: request context
    :param address: virtual IP address
    :param name: name for vip
    :param description: description for vip
    :param subnet_id: subnet_id for subnet of vip
    :param protocol_port: transport layer port number for vip
    :returns: Vip object
    """
    body = {'vip': {'name': kwargs['name'],
                    'description': kwargs['description'],
                    'subnet_id': kwargs['subnet_id'],
                    'protocol_port': kwargs['protocol_port'],
                    'protocol': kwargs['protocol'],
                    'pool_id': kwargs['pool_id'],
                    'session_persistence': kwargs['session_persistence'],
                    'admin_state_up': kwargs['admin_state_up']
                    }}
    if kwargs.get('connection_limit'):
        body['vip']['connection_limit'] = kwargs['connection_limit']

    if kwargs.get('address'):
        body['vip']['address'] = kwargs['address']

    vip = neutronclient(request).create_vip(body).get('vip')
    return Vip(vip)

def vip_list(request, **kwargs):
    vips = neutronclient(request).list_vips(**kwargs).get('vips')
    return [Vip(v) for v in vips]

def vip_get(request, vip_id):
    return _vip_get(request, vip_id, expand_resource=True)

def _vip_get(request, vip_id, expand_resource=False):
    vip = neutronclient(request).show_vip(vip_id).get('vip')
    if expand_resource:
        vip['subnet'] = neutron.subnet_get(request, vip['subnet_id'])
        vip['port'] = neutron.port_get(request, vip['port_id'])
        vip['pool'] = _pool_get(request, vip['pool_id'])
    return Vip(vip)

def vip_update(request, vip_id, **kwargs):
    vip = neutronclient(request).update_vip(vip_id, kwargs).get('vip')
    return Vip(vip)

def vip_delete(request, vip_id):
    neutronclient(request).delete_vip(vip_id)

def pool_create(request, **kwargs):
    """Create a pool for specified protocol

    :param request: request context
    :param name: name for pool
    :param description: description for pool
    :param subnet_id: subnet_id for subnet of pool
    :param protocol: load balanced protocol
    :param lb_method: load balancer method
    :param admin_state_up: admin state (default on)
    """
    body = {'pool': {'name': kwargs['name'],
                     'description': kwargs['description'],
                     'subnet_id': kwargs['subnet_id'],
                     'protocol': kwargs['protocol'],
                     'lb_method': kwargs['lb_method'],
                     'admin_state_up': kwargs['admin_state_up'],
                     'provider': kwargs['provider'],
                     }}
    pool = neutronclient(request).create_pool(body).get('pool')
    return Pool(pool)

def _get_vip(request, pool, vip_dict, expand_name_only=False):
    if pool['vip_id'] is not None:
        try:
            if vip_dict:
                vip = vip_dict.get(pool['vip_id'])
            else:
                vip = _vip_get(request, pool['vip_id'])
        except Exception:
            messages.warning(request, _("Unable to get VIP for pool "
                                        "%(pool)s.") % {"pool": pool["id"]})
            vip = Vip({'id': pool['vip_id'], 'name': ''})
        if expand_name_only:
            vip = vip.name_or_id
        return vip
    else:
        return None

def pool_list(request, **kwargs):
    return _pool_list(request, expand_subnet=True, expand_vip=True, **kwargs)

def _pool_list(request, expand_subnet=False, expand_vip=False, **kwargs):
    pools = neutronclient(request).list_pools(**kwargs).get('pools')
    if expand_subnet:
        subnets = neutron.subnet_list(request)
        subnet_dict = SortedDict((s.id, s) for s in subnets)
        for p in pools:
            subnet = subnet_dict.get(p['subnet_id'])
            p['subnet_name'] = subnet.cidr if subnet else None
    if expand_vip:
        vips = vip_list(request)
        vip_dict = SortedDict((v.id, v) for v in vips)
        for p in pools:
            p['vip_name'] = _get_vip(request, p, vip_dict,
                                     expand_name_only=True)
    return [Pool(p) for p in pools]

def pool_get(request, pool_id):
    return _pool_get(request, pool_id, expand_resource=True)

def _pool_get(request, pool_id, expand_resource=False):
    try:
        pool = neutronclient(request).show_pool(pool_id).get('pool')
    except Exception:
        messages.warning(request, _("Unable to get pool detail."))
        return None
    if expand_resource:
        # TODO(lyj): The expand resource(subnet, member etc.) attached
        # to a pool could be deleted without cleanup pool related database,
        # this will cause exceptions if we trying to get the deleted resources.
        # so we need to handle the situation by showing a warning message here.
        # we can safely remove the try/except once the neutron bug is fixed
        # https://bugs.launchpad.net/neutron/+bug/1406854
        try:
            pool['subnet'] = neutron.subnet_get(request, pool['subnet_id'])
        except Exception:
            messages.warning(request, _("Unable to get subnet for pool "
                                        "%(pool)s.") % {"pool": pool_id})
        pool['vip'] = _get_vip(request, pool, vip_dict=None,
                               expand_name_only=False)
        try:
            pool['members'] = _member_list(request, expand_pool=False,
                                           pool_id=pool_id)
        except Exception:
            messages.warning(request, _("Unable to get members for pool "
                                        "%(pool)s.") % {"pool": pool_id})
        try:
            pool['health_monitors'] = pool_health_monitor_list(
                request, id=pool['health_monitors'])
        except Exception:
            messages.warning(request,
                             _("Unable to get health monitors "
                               "for pool %(pool)s.") % {"pool": pool_id})
    return Pool(pool)

def pool_update(request, pool_id, **kwargs):
    pool = neutronclient(request).update_pool(pool_id, kwargs).get('pool')
    return Pool(pool)

def pool_delete(request, pool):
    neutronclient(request).delete_pool(pool)

# not linked to UI yet
def pool_stats(request, pool_id, **kwargs):
    stats = neutronclient(request).retrieve_pool_stats(pool_id, **kwargs)
    return PoolStats(stats)

def pool_health_monitor_create(request, **kwargs):
    """Create a health monitor

    :param request: request context
    :param type: type of monitor
    :param delay: delay of monitor
    :param timeout: timeout of monitor
    :param max_retries: max retries [1..10]
    :param http_method: http method
    :param url_path: url path
    :param expected_codes: http return code
    :param admin_state_up: admin state
    """
    monitor_type = kwargs['type'].upper()
    body = {'health_monitor': {'type': monitor_type,
                               'delay': kwargs['delay'],
                               'timeout': kwargs['timeout'],
                               'max_retries': kwargs['max_retries'],
                               'admin_state_up': kwargs['admin_state_up']
                               }}
    if monitor_type in ['HTTP', 'HTTPS']:
        body['health_monitor']['http_method'] = kwargs['http_method']
        body['health_monitor']['url_path'] = kwargs['url_path']
        body['health_monitor']['expected_codes'] = kwargs['expected_codes']
    mon = neutronclient(request).create_health_monitor(body).get(
        'health_monitor')

    return PoolMonitor(mon)

def pool_health_monitor_list(request, **kwargs):
    monitors = neutronclient(request).list_health_monitors(
        **kwargs).get('health_monitors')
    return [PoolMonitor(m) for m in monitors]

def pool_health_monitor_get(request, monitor_id):
    return _pool_health_monitor_get(request, monitor_id, expand_resource=True)

def _pool_health_monitor_get(request, monitor_id, expand_resource=False):
    monitor = neutronclient(request
                            ).show_health_monitor(monitor_id
                                                  ).get('health_monitor')
    if expand_resource:
        pool_ids = [p['pool_id'] for p in monitor['pools']]
        monitor['pools'] = _pool_list(request, id=pool_ids)
    return PoolMonitor(monitor)

def pool_health_monitor_update(request, monitor_id, **kwargs):
    monitor = neutronclient(request).update_health_monitor(monitor_id, kwargs)
    return PoolMonitor(monitor)

def pool_health_monitor_delete(request, mon_id):
    neutronclient(request).delete_health_monitor(mon_id)

def member_create(request, **kwargs):
    """Create a load balance member

    :param request: request context
    :param pool_id: pool_id of pool for member
    :param address: IP address
    :param protocol_port: transport layer port number
    :param weight: weight for member
    :param admin_state_up: admin_state
    """
    body = {'member': {'pool_id': kwargs['pool_id'],
                       'address': kwargs['address'],
                       'protocol_port': kwargs['protocol_port'],
                       'admin_state_up': kwargs['admin_state_up']
                       }}
    if kwargs.get('weight'):
        body['member']['weight'] = kwargs['weight']
    member = neutronclient(request).create_member(body).get('member')
    return Member(member)

def member_list(request, **kwargs):
    return _member_list(request, expand_pool=True, **kwargs)

def _member_list(request, expand_pool, **kwargs):
    members = neutronclient(request).list_members(**kwargs).get('members')
    if expand_pool:
        pools = _pool_list(request)
        pool_dict = SortedDict((p.id, p) for p in pools)
        for m in members:
            m['pool_name'] = pool_dict.get(m['pool_id']).name_or_id
    return [Member(m) for m in members]

def member_get(request, member_id):
    return _member_get(request, member_id, expand_pool=True)

def _member_get(request, member_id, expand_pool):
    member = neutronclient(request).show_member(member_id).get('member')
    if expand_pool:
        member['pool'] = _pool_get(request, member['pool_id'])
    return Member(member)

def member_update(request, member_id, **kwargs):
    member = neutronclient(request).update_member(member_id, kwargs)
    return Member(member)

def member_delete(request, mem_id):
    neutronclient(request).delete_member(mem_id)

def pool_monitor_association_create(request, **kwargs):
    """Associate a health monitor with pool

    :param request: request context
    :param monitor_id: id of monitor
    :param pool_id: id of pool
    """

    body = {'health_monitor': {'id': kwargs['monitor_id'], }}

    neutronclient(request).associate_health_monitor(
        kwargs['pool_id'], body)

def pool_monitor_association_delete(request, **kwargs):
    """Disassociate a health monitor from pool

    :param request: request context
    :param monitor_id: id of monitor
    :param pool_id: id of pool
    """

    neutronclient(request).disassociate_health_monitor(
        kwargs['pool_id'], kwargs['monitor_id'])
<|endoftext|>