<commit_before>from __future__ import unicode_literals

import json
import csv
from modularodm import Q

from django.views.generic import ListView, DetailView, FormView, UpdateView
from django.views.defaults import permission_denied, bad_request
from django.core.urlresolvers import reverse
from django.http import JsonResponse, Http404, HttpResponse
from django.shortcuts import redirect

from admin.common_auth.logs import (
    update_admin_log,
    ACCEPT_PREREG,
    REJECT_PREREG,
    COMMENT_PREREG,
)
from admin.pre_reg import serializers
from admin.pre_reg.forms import DraftRegistrationForm
from admin.pre_reg.utils import sort_drafts, SORT_BY
from framework.exceptions import PermissionsError
from website.exceptions import NodeStateError
from website.files.models import FileNode
from website.project.model import DraftRegistration, Node
from website.prereg.utils import get_prereg_schema
from website.project.metadata.schemas import from_json

from admin.base.utils import PreregAdmin

class DraftListView(PreregAdmin, ListView):
    template_name = 'pre_reg/draft_list.html'
    ordering = '-date'
    context_object_name = 'draft'

    def get_queryset(self):
        query = (
            Q('registration_schema', 'eq', get_prereg_schema()) &
            Q('approval', 'ne', None)
        )
        ordering = self.get_ordering()
        if 'initiator' in ordering:
            return DraftRegistration.find(query).sort(ordering)
        if ordering == SORT_BY['title']:
            return DraftRegistration.find(query).sort(
                'registration_metadata.q1.value')
        if ordering == SORT_BY['n_title']:
            return DraftRegistration.find(query).sort(
                '-registration_metadata.q1.value')
        return sort_drafts(DraftRegistration.find(query), ordering)

    def get_context_data(self, **kwargs):
        query_set = kwargs.pop('object_list', self.object_list)
        page_size = self.get_paginate_by(query_set)
        paginator, page, query_set, is_paginated = self.paginate_queryset(
            query_set, page_size)
        return {
            'drafts': [
                serializers.serialize_draft_registration(d, json_safe=False)
                for d in query_set
            ],
            'page': page,
            'p': self.get_paginate_by(query_set),
            'SORT_BY': SORT_BY,
            'order': self.get_ordering(),
            'status': self.request.GET.get('status', 'all'),
        }

    def get_paginate_by(self, queryset):
        return int(self.request.GET.get('p', 10))

    def get_paginate_orphans(self):
        return int(self.get_paginate_by(None) / 11.0) + 1

    def get_ordering(self):
        return self.request.GET.get('order_by', self.ordering)

class DraftDownloadListView(DraftListView):
    def get(self, request, *args, **kwargs):
        try:
            queryset = map(serializers.serialize_draft_registration,
                           self.get_queryset())
        except AttributeError:
            raise Http404('A draft was malformed.')
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename=prereg.csv;'
        response['Cache-Control'] = 'no-cache'
        keys = queryset[0].keys()
        keys.remove('registration_schema')
        writer = csv.DictWriter(response, fieldnames=keys)
        writer.writeheader()
        for draft in queryset:
            draft.pop('registration_schema')
            draft.update({'initiator': draft['initiator']['username']})
            writer.writerow(
                {k: v.encode('utf8') if isinstance(v, unicode) else v
                 for k, v in draft.items()}
            )
        return response

class DraftDetailView(PreregAdmin, DetailView):
    template_name = 'pre_reg/draft_detail.html'
    context_object_name = 'draft'

    def get_object(self, queryset=None):
        draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
        self.checkout_files(draft)
        try:
            return serializers.serialize_draft_registration(draft)
        except AttributeError:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))

    def checkout_files(self, draft):
        prereg_user = self.request.user.osf_user
        for item in get_metadata_files(draft):
            item.checkout = prereg_user
            item.save()

class DraftFormView(PreregAdmin, FormView):
    template_name = 'pre_reg/draft_form.html'
    form_class = DraftRegistrationForm
    context_object_name = 'draft'

    def dispatch(self, request, *args, **kwargs):
        self.draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
        if self.draft is None:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))
        return super(DraftFormView, self).dispatch(request, *args, **kwargs)

    def get_initial(self):
        flags = self.draft.flags
        self.initial = {
            'notes': self.draft.notes,
            'assignee': flags.get('assignee'),
            'payment_sent': flags.get('payment_sent'),
            'proof_of_publication': flags.get('proof_of_publication'),
        }
        return super(DraftFormView, self).get_initial()

    def get_context_data(self, **kwargs):
        kwargs.setdefault('draft', serializers.serialize_draft_registration(
            self.draft,
            json_safe=False
        ))
        kwargs.setdefault('IMMEDIATE', serializers.IMMEDIATE)
        return super(DraftFormView, self).get_context_data(**kwargs)

    def form_valid(self, form):
        if 'approve_reject' in form.changed_data:
            osf_user = self.request.user.osf_user
            try:
                if form.cleaned_data.get('approve_reject') == 'approve':
                    flag = ACCEPT_PREREG
                    message = 'Approved'
                    self.draft.approve(osf_user)
                else:
                    flag = REJECT_PREREG
                    message = 'Rejected'
                    self.draft.reject(osf_user)
            except PermissionsError as e:
                return permission_denied(self.request, e)
            self.checkin_files(self.draft)
            update_admin_log(self.request.user.id, self.kwargs.get('draft_pk'),
                             'Draft Registration', message, flag)
        admin_settings = form.cleaned_data
        self.draft.notes = admin_settings.get('notes', self.draft.notes)
        del admin_settings['approve_reject']
        del admin_settings['notes']
        self.draft.flags = admin_settings
        self.draft.save()
        return super(DraftFormView, self).form_valid(form)

    def checkin_files(self, draft):
        for item in get_metadata_files(draft):
            item.checkout = None
            item.save()

    def get_success_url(self):
        return '{}?page={}'.format(reverse('pre_reg:prereg'),
                                   self.request.POST.get('page', 1))

class CommentUpdateView(PreregAdmin, UpdateView):
    context_object_name = 'draft'

    def post(self, request, *args, **kwargs):
        try:
            data = json.loads(request.body).get('schema_data', {})
            draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
            draft.update_metadata(data)
            draft.save()
            log_message = list()
            for key, value in data.iteritems():
                comments = data.get(key, {}).get('comments', [])
                for comment in comments:
                    log_message.append('{}: {}'.format(key, comment['value']))
            update_admin_log(
                user_id=request.user.id,
                object_id=draft._id,
                object_repr='Draft Registration',
                message='Comments:
{}
'.format('

'.join(log_message)),
                action_flag=COMMENT_PREREG
            )
            return JsonResponse(serializers.serialize_draft_registration(draft))
        except AttributeError:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))
        except NodeStateError as e:
            return bad_request(request, e)

def view_file(request, node_id, provider, file_id):
    fp = FileNode.load(file_id)
    wb_url = fp.generate_waterbutler_url()
    return redirect(wb_url)

def get_metadata_files(draft):
    data = draft.registration_metadata
    for q, question in get_file_questions('prereg-prize.json'):
        if not isinstance(data[q]['value'], dict):
            for i, file_info in enumerate(data[q]['extra']):
                provider = file_info['data']['provider']
                if provider != 'osfstorage':
                    raise Http404(
                        'File does not exist in OSFStorage ({}: {})'.format(
                            q, question
                        ))
                file_guid = file_info.get('fileId')
                if file_guid is None:
                    node = Node.load(file_info.get('nodeId'))
                    path = file_info['data'].get('path')
                    item = FileNode.resolve_class(
                        provider,
                        FileNode.FILE
                    ).get_or_create(node, path)
                    file_guid = item.get_guid(create=True)._id
                    data[q]['extra'][i]['fileId'] = file_guid
                    draft.update_metadata(data)
                else:
                    item = FileNode.load(file_guid)
                if item is None:
                    raise Http404(
                        'File with guid "{}" in "{}" does not exist'.format(
                            file_guid, question
                        ))
                yield item
            continue
        for i, file_info in enumerate(data[q]['value']['uploader']['extra']):
            provider = file_info['data']['provider']
            if provider != 'osfstorage':
                raise Http404(
                    'File does not exist in OSFStorage ({}: {})'.format(
                        q, question
                    ))
            file_guid = file_info.get('fileId')
            if file_guid is None:
                node = Node.load(file_info.get('nodeId'))
                path = file_info['data'].get('path')
                item = FileNode.resolve_class(
                    provider,
                    FileNode.FILE
                ).get_or_create(node, path)
                file_guid = item.get_guid(create=True)._id
                data[q]['value']['uploader']['extra'][i]['fileId'] = file_guid
                draft.update_metadata(data)
            else:
                item = FileNode.load(file_guid)
            if item is None:
                raise Http404(
                    'File with guid "{}" in "{}" does not exist'.format(
                        file_guid, question
                    ))
            yield item

def get_file_questions(json_file):
    uploader = {
        'id': 'uploader',
        'type': 'osf-upload',
        'format': 'osf-upload-toggle'
    }
    questions = []
    schema = from_json(json_file)
    for item in schema['pages']:
        for question in item['questions']:
            if question['type'] == 'osf-upload':
                questions.append((question['qid'], question['title']))
                continue
            properties = question.get('properties')
            if properties is None:
                continue
            if uploader in properties:
                questions.append((question['qid'], question['title']))
    return questions
<commit_msg>Actually get guid object<commit_after>from __future__ import unicode_literals

import json
import csv
from modularodm import Q

from django.views.generic import ListView, DetailView, FormView, UpdateView
from django.views.defaults import permission_denied, bad_request
from django.core.urlresolvers import reverse
from django.http import JsonResponse, Http404, HttpResponse
from django.shortcuts import redirect

from admin.common_auth.logs import (
    update_admin_log,
    ACCEPT_PREREG,
    REJECT_PREREG,
    COMMENT_PREREG,
)
from admin.pre_reg import serializers
from admin.pre_reg.forms import DraftRegistrationForm
from admin.pre_reg.utils import sort_drafts, SORT_BY
from framework.exceptions import PermissionsError
from framework.guid.model import Guid
from website.exceptions import NodeStateError
from website.files.models import FileNode
from website.project.model import DraftRegistration, Node
from website.prereg.utils import get_prereg_schema
from website.project.metadata.schemas import from_json

from admin.base.utils import PreregAdmin

class DraftListView(PreregAdmin, ListView):
    template_name = 'pre_reg/draft_list.html'
    ordering = '-date'
    context_object_name = 'draft'

    def get_queryset(self):
        query = (
            Q('registration_schema', 'eq', get_prereg_schema()) &
            Q('approval', 'ne', None)
        )
        ordering = self.get_ordering()
        if 'initiator' in ordering:
            return DraftRegistration.find(query).sort(ordering)
        if ordering == SORT_BY['title']:
            return DraftRegistration.find(query).sort(
                'registration_metadata.q1.value')
        if ordering == SORT_BY['n_title']:
            return DraftRegistration.find(query).sort(
                '-registration_metadata.q1.value')
        return sort_drafts(DraftRegistration.find(query), ordering)

    def get_context_data(self, **kwargs):
        query_set = kwargs.pop('object_list', self.object_list)
        page_size = self.get_paginate_by(query_set)
        paginator, page, query_set, is_paginated = self.paginate_queryset(
            query_set, page_size)
        return {
            'drafts': [
                serializers.serialize_draft_registration(d, json_safe=False)
                for d in query_set
            ],
            'page': page,
            'p': self.get_paginate_by(query_set),
            'SORT_BY': SORT_BY,
            'order': self.get_ordering(),
            'status': self.request.GET.get('status', 'all'),
        }

    def get_paginate_by(self, queryset):
        return int(self.request.GET.get('p', 10))

    def get_paginate_orphans(self):
        return int(self.get_paginate_by(None) / 11.0) + 1

    def get_ordering(self):
        return self.request.GET.get('order_by', self.ordering)

class DraftDownloadListView(DraftListView):
    def get(self, request, *args, **kwargs):
        try:
            queryset = map(serializers.serialize_draft_registration,
                           self.get_queryset())
        except AttributeError:
            raise Http404('A draft was malformed.')
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename=prereg.csv;'
        response['Cache-Control'] = 'no-cache'
        keys = queryset[0].keys()
        keys.remove('registration_schema')
        writer = csv.DictWriter(response, fieldnames=keys)
        writer.writeheader()
        for draft in queryset:
            draft.pop('registration_schema')
            draft.update({'initiator': draft['initiator']['username']})
            writer.writerow(
                {k: v.encode('utf8') if isinstance(v, unicode) else v
                 for k, v in draft.items()}
            )
        return response

class DraftDetailView(PreregAdmin, DetailView):
    template_name = 'pre_reg/draft_detail.html'
    context_object_name = 'draft'

    def get_object(self, queryset=None):
        draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
        self.checkout_files(draft)
        try:
            return serializers.serialize_draft_registration(draft)
        except AttributeError:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))

    def checkout_files(self, draft):
        prereg_user = self.request.user.osf_user
        for item in get_metadata_files(draft):
            item.checkout = prereg_user
            item.save()

class DraftFormView(PreregAdmin, FormView):
    template_name = 'pre_reg/draft_form.html'
    form_class = DraftRegistrationForm
    context_object_name = 'draft'

    def dispatch(self, request, *args, **kwargs):
        self.draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
        if self.draft is None:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))
        return super(DraftFormView, self).dispatch(request, *args, **kwargs)

    def get_initial(self):
        flags = self.draft.flags
        self.initial = {
            'notes': self.draft.notes,
            'assignee': flags.get('assignee'),
            'payment_sent': flags.get('payment_sent'),
            'proof_of_publication': flags.get('proof_of_publication'),
        }
        return super(DraftFormView, self).get_initial()

    def get_context_data(self, **kwargs):
        kwargs.setdefault('draft', serializers.serialize_draft_registration(
            self.draft,
            json_safe=False
        ))
        kwargs.setdefault('IMMEDIATE', serializers.IMMEDIATE)
        return super(DraftFormView, self).get_context_data(**kwargs)

    def form_valid(self, form):
        if 'approve_reject' in form.changed_data:
            osf_user = self.request.user.osf_user
            try:
                if form.cleaned_data.get('approve_reject') == 'approve':
                    flag = ACCEPT_PREREG
                    message = 'Approved'
                    self.draft.approve(osf_user)
                else:
                    flag = REJECT_PREREG
                    message = 'Rejected'
                    self.draft.reject(osf_user)
            except PermissionsError as e:
                return permission_denied(self.request, e)
            self.checkin_files(self.draft)
            update_admin_log(self.request.user.id, self.kwargs.get('draft_pk'),
                             'Draft Registration', message, flag)
        admin_settings = form.cleaned_data
        self.draft.notes = admin_settings.get('notes', self.draft.notes)
        del admin_settings['approve_reject']
        del admin_settings['notes']
        self.draft.flags = admin_settings
        self.draft.save()
        return super(DraftFormView, self).form_valid(form)

    def checkin_files(self, draft):
        for item in get_metadata_files(draft):
            item.checkout = None
            item.save()

    def get_success_url(self):
        return '{}?page={}'.format(reverse('pre_reg:prereg'),
                                   self.request.POST.get('page', 1))

class CommentUpdateView(PreregAdmin, UpdateView):
    context_object_name = 'draft'

    def post(self, request, *args, **kwargs):
        try:
            data = json.loads(request.body).get('schema_data', {})
            draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
            draft.update_metadata(data)
            draft.save()
            log_message = list()
            for key, value in data.iteritems():
                comments = data.get(key, {}).get('comments', [])
                for comment in comments:
                    log_message.append('{}: {}'.format(key, comment['value']))
            update_admin_log(
                user_id=request.user.id,
                object_id=draft._id,
                object_repr='Draft Registration',
                message='Comments:
{}
'.format('

'.join(log_message)),
                action_flag=COMMENT_PREREG
            )
            return JsonResponse(serializers.serialize_draft_registration(draft))
        except AttributeError:
            raise Http404('{} with id "{}" not found.'.format(
                self.context_object_name.title(),
                self.kwargs.get('draft_pk')
            ))
        except NodeStateError as e:
            return bad_request(request, e)

def view_file(request, node_id, provider, file_id):
    fp = FileNode.load(file_id)
    wb_url = fp.generate_waterbutler_url()
    return redirect(wb_url)

def get_metadata_files(draft):
    data = draft.registration_metadata
    for q, question in get_file_questions('prereg-prize.json'):
        if not isinstance(data[q]['value'], dict):
            for i, file_info in enumerate(data[q]['extra']):
                provider = file_info['data']['provider']
                if provider != 'osfstorage':
                    raise Http404(
                        'File does not exist in OSFStorage ({}: {})'.format(
                            q, question
                        ))
                file_guid = file_info.get('fileId')
                if file_guid is None:
                    node = Node.load(file_info.get('nodeId'))
                    path = file_info['data'].get('path')
                    item = FileNode.resolve_class(
                        provider,
                        FileNode.FILE
                    ).get_or_create(node, path)
                    file_guid = item.get_guid(create=True)._id
                    data[q]['extra'][i]['fileId'] = file_guid
                    draft.update_metadata(data)
                    draft.save()
                else:
                    guid = Guid.load(file_guid)
                    item = guid.referent
                if item is None:
                    raise Http404(
                        'File with guid "{}" in "{}" does not exist'.format(
                            file_guid, question
                        ))
                yield item
            continue
        for i, file_info in enumerate(data[q]['value']['uploader']['extra']):
            provider = file_info['data']['provider']
            if provider != 'osfstorage':
                raise Http404(
                    'File does not exist in OSFStorage ({}: {})'.format(
                        q, question
                    ))
            file_guid = file_info.get('fileId')
            if file_guid is None:
                node = Node.load(file_info.get('nodeId'))
                path = file_info['data'].get('path')
                item = FileNode.resolve_class(
                    provider,
                    FileNode.FILE
                ).get_or_create(node, path)
                file_guid = item.get_guid(create=True)._id
                data[q]['value']['uploader']['extra'][i]['fileId'] = file_guid
                draft.update_metadata(data)
                draft.save()
            else:
                guid = Guid.load(file_guid)
                item = guid.referent
            if item is None:
                raise Http404(
                    'File with guid "{}" in "{}" does not exist'.format(
                        file_guid, question
                    ))
            yield item

def get_file_questions(json_file):
    uploader = {
        'id': 'uploader',
        'type': 'osf-upload',
        'format': 'osf-upload-toggle'
    }
    questions = []
    schema = from_json(json_file)
    for item in schema['pages']:
        for question in item['questions']:
            if question['type'] == 'osf-upload':
                questions.append((question['qid'], question['title']))
                continue
            properties = question.get('properties')
            if properties is None:
                continue
            if uploader in properties:
                questions.append((question['qid'], question['title']))
    return questions
<|endoftext|>


<commit_before>from __future__ import unicode_literals

from django import forms
from django.conf.urls import url
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as Admin
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import Group
from django.core import urlresolvers
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _

from .filters import ChoiceDropdownFilter
from administrator.models import DishCategory
from administrator.models import User
from restaurant.models import Dish
from restaurant.models import Restaurant
from restaurant.models import RestaurantType

class RegistrationForm(UserCreationForm):

    """A form for users creation.

    Email, name, password and role are given.
    """

    email = forms.EmailField(required=True)

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = User
        fields = ("role",)

    def save(self, commit=True):
        """Save a new user.

        Return a User object.
        """
        user = super(RegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data["email"]
        user.role = self.cleaned_data["role"]
        user.set_is_staff(user.role)
        user.save()
        user.set_permissions(user.role)
        if commit:
            user.save()
        return user

class UserChangeForm(forms.ModelForm):

    """A form for users modification."""

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = User
        fields = ("name", "email", "phone", "role", "status", "parent")

    def save(self, commit=True):
        """Save the provided password in a hashed format and put
        is_active into an appropriate value (according to the
        user's status)

        Return a User object.
        """
        user = super(UserChangeForm, self).save(commit=False)
        user.set_is_active(user.status)
        user.set_is_staff(user.role)
        user.set_permissions(user.role)
        if commit:
            user.save()
        return user

def delete_selected_users(modeladmin, request, queryset):
    """Block selected users instead of dropping them."""
    for obj in queryset:
        obj.delete()

delete_selected_users.short_description = "Delete selested users"

class UserAdmin(Admin):

    """Represent a model in the admin interface."""

    form = UserChangeForm
    add_form = RegistrationForm

    search_fields = ("name", "email", "phone")
    list_display = ("name", "email", "phone", "role", "status", "parent")
    ordering = ["name"]
    list_per_page = 10
    list_filter = [
        ("status", ChoiceDropdownFilter),
        ("role", ChoiceDropdownFilter)
    ]

    fieldsets = (
        (None, {"fields": ("name", "email",)}),
        (_("Personal info"), {"fields": ("phone",)}),
        (_("Status"), {"fields": ("status",)}),
        (_("Permissions"), {"fields": ("role", "parent",)}),
    )

    def get_queryset(self, request):
        """ Represent the objects.

        Return a QuerySet of all model instances that can be edited
        by the admin site.
        """
        qs = super(UserAdmin, self).get_queryset(request)
        if request.user.role == User.ROLE_ADMIN:
            return qs
        return qs.filter(parent=request.user.id)

    def formfield_for_choice_field(self, db_field, request, **kwargs):
        """Shows only Sub-manager roles when Manager adds Sub-manager."""
        if db_field.name == "role":
            if request.user.role == User.ROLE_MANAGER:
                kwargs['choices'] = (
                    (User.ROLE_SUB_MANAGER, "Sub-manager"),
                )
        return super(UserAdmin, self).formfield_for_choice_field(
            db_field, request, **kwargs)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Shows only current manager in parent field when
        Manager adds Sub-manager.
        """
        if db_field.name == "parent":
            if request.user.role == User.ROLE_MANAGER:
                kwargs['queryset'] = User.objects.filter(id=request.user.id)
            if request.user.role == User.ROLE_ADMIN:
                kwargs['queryset'] = User.objects.exclude(role=User.ROLE_ADMIN)
        return super(UserAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs)

    def get_form(self, request, *args, **kwargs):
        """Return a ModelForm class with current user id for using in the
        admin"""
        form = super(UserAdmin, self).get_form(request, *args, **kwargs)
        form.current_user = request.user
        return form

    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (
            None, {"fields": ("email", "name", "password1", "password2",
                              "role", "parent")}
        ),
    )

    actions = [delete_selected_users]

def soft_delete(modeladmin, request, queryset):
    """Soft delete function for QuerySet list."""
    for obj in queryset:
        obj.delete()

soft_delete.short_description = "Delete selected items"

def clone(modeladmin, queryset):
    """Clone instance"""
    for object in queryset:
        object.id = None
        object.save()

clone.short_description = "Clone"

class RestaurantTypeAdmin(admin.ModelAdmin):

    list_display = ("restaurant_type", )

    def has_add_permission(self, request):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_change_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_delete_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

class RestaurantForm(forms.ModelForm):

    """A form for restaurants modifications."""

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = Restaurant
        fields = ("name", "logo", "location", "restaurant_type",
                  "tables_count", "description", "status",
                  "manager", "sub_manager")

    def __init__(self, *args, **kwargs):
        super(RestaurantForm, self).__init__(*args, **kwargs)
        users = User.objects.all()

        manager_choices = [(None, "---------")]

        if self.current_user.role == User.ROLE_MANAGER:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        user.id == self.current_user.id):
                    manager_choices.append((user.pk, user.get_full_name()))
        elif self.current_user.role == User.ROLE_ADMIN:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        user.role == User.ROLE_MANAGER):
                    manager_choices.append((user.pk, user.get_full_name()))

        self.fields["manager"].choices = manager_choices

        sub_manager_choices = [(None, "---------")]

        if self.current_user.role == User.ROLE_MANAGER:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        (user.id == self.current_user.id or
                         user.parent == self.current_user)):
                    sub_manager_choices.append((user.pk, user.get_full_name()))
        elif self.current_user.role == User.ROLE_ADMIN:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        (user.role == User.ROLE_MANAGER or
                         user.role == User.ROLE_SUB_MANAGER)):
                    sub_manager_choices.append((user.pk, user.get_full_name()))

        self.fields["sub_manager"].choices = sub_manager_choices

    def save(self, commit=True):
        """Save the restaurant.

        Return a Restaurant object.
        """
        restaurant = super(RestaurantForm, self).save(commit=False)

        if restaurant.manager:
            restaurant.set_manager(restaurant.manager)

        if restaurant.sub_manager:
            restaurant.set_sub_manager(restaurant.sub_manager)

        if commit:
            restaurant.save()
        return restaurant

class RestaurantAdmin(admin.ModelAdmin):

    """Custom display in restaurant's list."""

    def get_queryset(self, request):
        """ Represent the objects.

        Return a QuerySet of all model instances that can be edited
        by the admin site.
        """
        qs = super(RestaurantAdmin, self).get_queryset(request)
        if request.user.role == User.ROLE_ADMIN:
            return qs
        return qs.filter(manager=request.user.id)

    def get_form(self, request, *args, **kwargs):
        """Return a ModelForm class with current user id for using in the
        admin"""
        form = super(RestaurantAdmin, self).get_form(request, *args, **kwargs)
        form.current_user = request.user
        return form

    form = RestaurantForm
    list_display = ("name", "restaurant_type", "status",
                    "tables_count", "manager", "sub_manager",
                    "list_of_dishes")
    list_per_page = 15
    actions = [soft_delete, clone]
    admin.site.disable_action('delete_selected')
    list_filter = [('status', ChoiceDropdownFilter)]

    def list_of_dishes(self, obj):
        """Forms link to list of dishes of each restaurant."""
        url = urlresolvers.reverse("admin:restaurant_dish_changelist")
        return u'%s' % (url, "restaurant__id__exact",
                                               obj.pk, "View dish")

    list_of_dishes.short_description = "Dish"
    list_of_dishes.allow_tags = True

    def change_view(self, request, object_id, form_url='', extra_context=None):
        """View for the model instance editing page."""
        extra_context = {
            "clone_url": request.path.replace("change/", "clone/")
        }

        return super(RestaurantAdmin, self).change_view(
            request,
            object_id,
            form_url,
            extra_context=extra_context,
        )

    def get_urls(self):
        """Return the URLs to be used for that ModelAdmin."""
        urls = super(RestaurantAdmin, self).get_urls()

        custom_urls = [
            url(
                r'^(?P<restaurant>.+)/clone/$',
                self.admin_site.admin_view(self.clone_view),
                name='clone',
            )
        ]

        return custom_urls + urls

    def clone_view(self, request, *args, **kwargs):
        """View for cloning instance."""
        new_restaurant = Restaurant.objects.get(id=kwargs["restaurant"])
        new_restaurant.id = None
        new_restaurant.save()

        return HttpResponseRedirect("/admin/restaurant/restaurant/")

    def _type_id(self, obj):
        return obj.type_id
    _type_id.short_description = "restaurant type"

class DishCategoryAdmin(admin.ModelAdmin):

    """Custom display dishes categories list."""

    list_display = ("name", "id", "is_visible")
    list_per_page = 20
    ordering = ["name"]

    def has_add_permission(self, request):
        return request.user.role == User.ROLE_ADMIN

    def has_change_permission(self, request, obj=None):
        return request.user.role == User.ROLE_ADMIN

    def has_delete_permission(self, request, obj=None):
        return request.user.role == User.ROLE_ADMIN

class DishAdmin(admin.ModelAdmin):

    """Custom display dishes list."""

    list_display = ("name", "category", "price", "weight", "available")
    ordering = ["name"]

    def has_add_permission(self, request):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_change_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_delete_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def get_model_perms(self, request):
        """Return empty perms dict thus hiding the model from admin index."""
        return {}

    def parse_filter_in_request(self, request):
        """Get id of restaurant"""
        filters = request.GET.get('_changelist_filters')
        var, value = filters.split('=')
        return value

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Shows only parent restaurant in field "restaurant" when Admin or
        Manager adds Dish.
        """
        if db_field.name == "restaurant":
            restaurant_id = self.parse_filter_in_request(request)
            kwargs['queryset'] = Restaurant.objects.filter(
                id__exact=restaurant_id)
        return super(DishAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs)

admin.site.register(User, UserAdmin)
admin.site.register(Restaurant, RestaurantAdmin)
admin.site.register(RestaurantType, RestaurantTypeAdmin)
admin.site.register(DishCategory, DishCategoryAdmin)
admin.site.register(Dish, DishAdmin)
admin.site.unregister(Group)
<commit_msg>Sub-manager can view/change only his restaurants.<commit_after>from __future__ import unicode_literals

from django import forms
from django.conf.urls import url
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as Admin
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import Group
from django.core import urlresolvers
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _

from .filters import ChoiceDropdownFilter
from administrator.models import DishCategory
from administrator.models import User
from restaurant.models import Dish
from restaurant.models import Restaurant
from restaurant.models import RestaurantType

class RegistrationForm(UserCreationForm):

    """A form for users creation.

    Email, name, password and role are given.
    """

    email = forms.EmailField(required=True)

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = User
        fields = ("role",)

    def save(self, commit=True):
        """Save a new user.

        Return a User object.
        """
        user = super(RegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data["email"]
        user.role = self.cleaned_data["role"]
        user.set_is_staff(user.role)
        user.save()
        user.set_permissions(user.role)
        if commit:
            user.save()
        return user

class UserChangeForm(forms.ModelForm):

    """A form for users modification."""

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = User
        fields = ("name", "email", "phone", "role", "status", "parent")

    def save(self, commit=True):
        """Save the provided password in a hashed format and put
        is_active into an appropriate value (according to the
        user's status)

        Return a User object.
        """
        user = super(UserChangeForm, self).save(commit=False)
        user.set_is_active(user.status)
        user.set_is_staff(user.role)
        user.set_permissions(user.role)
        if commit:
            user.save()
        return user

def delete_selected_users(modeladmin, request, queryset):
    """Block selected users instead of dropping them."""
    for obj in queryset:
        obj.delete()

delete_selected_users.short_description = "Delete selested users"

class UserAdmin(Admin):

    """Represent a model in the admin interface."""

    form = UserChangeForm
    add_form = RegistrationForm

    search_fields = ("name", "email", "phone")
    list_display = ("name", "email", "phone", "role", "status", "parent")
    ordering = ["name"]
    list_per_page = 10
    list_filter = [
        ("status", ChoiceDropdownFilter),
        ("role", ChoiceDropdownFilter)
    ]

    fieldsets = (
        (None, {"fields": ("name", "email",)}),
        (_("Personal info"), {"fields": ("phone",)}),
        (_("Status"), {"fields": ("status",)}),
        (_("Permissions"), {"fields": ("role", "parent",)}),
    )

    def get_queryset(self, request):
        """ Represent the objects.

        Return a QuerySet of all model instances that can be edited
        by the admin site.
        """
        qs = super(UserAdmin, self).get_queryset(request)
        if request.user.role == User.ROLE_ADMIN:
            return qs
        return qs.filter(parent=request.user.id)

    def formfield_for_choice_field(self, db_field, request, **kwargs):
        """Shows only Sub-manager roles when Manager adds Sub-manager."""
        if db_field.name == "role":
            if request.user.role == User.ROLE_MANAGER:
                kwargs['choices'] = (
                    (User.ROLE_SUB_MANAGER, "Sub-manager"),
                )
        return super(UserAdmin, self).formfield_for_choice_field(
            db_field, request, **kwargs)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Shows only current manager in parent field when
        Manager adds Sub-manager.
        """
        if db_field.name == "parent":
            if request.user.role == User.ROLE_MANAGER:
                kwargs['queryset'] = User.objects.filter(id=request.user.id)
            if request.user.role == User.ROLE_ADMIN:
                kwargs['queryset'] = User.objects.exclude(role=User.ROLE_ADMIN)
        return super(UserAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs)

    def get_form(self, request, *args, **kwargs):
        """Return a ModelForm class with current user id for using in the
        admin"""
        form = super(UserAdmin, self).get_form(request, *args, **kwargs)
        form.current_user = request.user
        return form

    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (
            None, {"fields": ("email", "name", "password1", "password2",
                              "role", "parent")}
        ),
    )

    actions = [delete_selected_users]

def soft_delete(modeladmin, request, queryset):
    """Soft delete function for QuerySet list."""
    for obj in queryset:
        obj.delete()

soft_delete.short_description = "Delete selected items"

def clone(modeladmin, queryset):
    """Clone instance"""
    for object in queryset:
        object.id = None
        object.save()

clone.short_description = "Clone"

class RestaurantTypeAdmin(admin.ModelAdmin):

    list_display = ("restaurant_type", )

    def has_add_permission(self, request):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_change_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_delete_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

class RestaurantForm(forms.ModelForm):

    """A form for restaurants modifications."""

    class Meta:

        """Give some options (metadata) attached to the form."""

        model = Restaurant
        fields = ("name", "logo", "location", "restaurant_type",
                  "tables_count", "description", "status",
                  "manager", "sub_manager")

    def __init__(self, *args, **kwargs):
        super(RestaurantForm, self).__init__(*args, **kwargs)
        users = User.objects.all()

        manager_choices = [(None, "---------")]

        if self.current_user.role == User.ROLE_MANAGER:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        user.id == self.current_user.id):
                    manager_choices.append((user.pk, user.get_full_name()))
        elif self.current_user.role == User.ROLE_ADMIN:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        user.role == User.ROLE_MANAGER):
                    manager_choices.append((user.pk, user.get_full_name()))

        self.fields["manager"].choices = manager_choices

        sub_manager_choices = [(None, "---------")]

        if self.current_user.role == User.ROLE_MANAGER:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        (user.id == self.current_user.id or
                         user.parent == self.current_user)):
                    sub_manager_choices.append((user.pk, user.get_full_name()))
        elif self.current_user.role == User.ROLE_ADMIN:
            for user in users:
                if (user.status != User.STATUS_DELETED and
                        (user.role == User.ROLE_MANAGER or
                         user.role == User.ROLE_SUB_MANAGER)):
                    sub_manager_choices.append((user.pk, user.get_full_name()))

        self.fields["sub_manager"].choices = sub_manager_choices

    def save(self, commit=True):
        """Save the restaurant.

        Return a Restaurant object.
        """
        restaurant = super(RestaurantForm, self).save(commit=False)

        if restaurant.manager:
            restaurant.set_manager(restaurant.manager)

        if restaurant.sub_manager:
            restaurant.set_sub_manager(restaurant.sub_manager)

        if commit:
            restaurant.save()
        return restaurant

class RestaurantAdmin(admin.ModelAdmin):

    """Custom display in restaurant's list."""

    def get_queryset(self, request):
        """ Represent the objects.

        Return a QuerySet of all model instances that can be edited
        by the admin site.
        """
        qs = super(RestaurantAdmin, self).get_queryset(request)
        if request.user.role == User.ROLE_ADMIN:
            return qs
        elif request.user.role == User.ROLE_SUB_MANAGER:
            return qs.filter(sub_manager=request.user.id)
        return qs.filter(manager=request.user.id)

    def get_form(self, request, *args, **kwargs):
        """Return a ModelForm class with current user id for using in the
        admin"""
        form = super(RestaurantAdmin, self).get_form(request, *args, **kwargs)
        form.current_user = request.user
        return form

    def has_change_permission(self, request, obj=None):
        if request.user.has_perm('restaurant.read_restaurant'):
            return True

    form = RestaurantForm
    list_display = ("name", "restaurant_type", "status",
                    "tables_count", "manager", "sub_manager",
                    "list_of_dishes")
    list_per_page = 15
    actions = [soft_delete, clone]
    admin.site.disable_action('delete_selected')
    list_filter = [('status', ChoiceDropdownFilter)]

    def list_of_dishes(self, obj):
        """Forms link to list of dishes of each restaurant."""
        url = urlresolvers.reverse("admin:restaurant_dish_changelist")
        return u'%s' % (url, "restaurant__id__exact",
                                               obj.pk, "View dish")

    list_of_dishes.short_description = "Dish"
    list_of_dishes.allow_tags = True

    def change_view(self, request, object_id, form_url='', extra_context=None):
        """View for the model instance editing page."""
        extra_context = {
            "clone_url": request.path.replace("change/", "clone/")
        }

        return super(RestaurantAdmin, self).change_view(
            request,
            object_id,
            form_url,
            extra_context=extra_context,
        )

    def get_urls(self):
        """Return the URLs to be used for that ModelAdmin."""
        urls = super(RestaurantAdmin, self).get_urls()

        custom_urls = [
            url(
                r'^(?P<restaurant>.+)/clone/$',
                self.admin_site.admin_view(self.clone_view),
                name='clone',
            )
        ]

        return custom_urls + urls

    def clone_view(self, request, *args, **kwargs):
        """View for cloning instance."""
        new_restaurant = Restaurant.objects.get(id=kwargs["restaurant"])
        new_restaurant.id = None
        new_restaurant.save()

        return HttpResponseRedirect("/admin/restaurant/restaurant/")

    def _type_id(self, obj):
        return obj.type_id
    _type_id.short_description = "restaurant type"

class DishCategoryAdmin(admin.ModelAdmin):

    """Custom display dishes categories list."""

    list_display = ("name", "id", "is_visible")
    list_per_page = 20
    ordering = ["name"]

    def has_add_permission(self, request):
        return request.user.role == User.ROLE_ADMIN

    def has_change_permission(self, request, obj=None):
        return request.user.role == User.ROLE_ADMIN

    def has_delete_permission(self, request, obj=None):
        return request.user.role == User.ROLE_ADMIN

class DishAdmin(admin.ModelAdmin):

    """Custom display dishes list."""

    list_display = ("name", "category", "price", "weight", "available")
    ordering = ["name"]

    def has_add_permission(self, request):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def has_change_permission(self, request, obj=None):
        return request.user.role != User.ROLE_USER

    def has_delete_permission(self, request, obj=None):
        return (request.user.role == User.ROLE_ADMIN or
                request.user.role == User.ROLE_MANAGER)

    def get_model_perms(self, request):
        """Return empty perms dict thus hiding the model from admin index."""
        return {}

    def parse_filter_in_request(self, request):
        """Get id of restaurant"""
        filters = request.GET.get('_changelist_filters')
        var, value = filters.split('=')
        return value

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Shows only parent restaurant in field "restaurant" when Admin or
        Manager adds Dish.
        """
        if db_field.name == "restaurant":
            restaurant_id = self.parse_filter_in_request(request)
            kwargs['queryset'] = Restaurant.objects.filter(
                id__exact=restaurant_id)
        return super(DishAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs)

admin.site.register(User, UserAdmin)
admin.site.register(Restaurant, RestaurantAdmin)
admin.site.register(RestaurantType, RestaurantTypeAdmin)
admin.site.register(DishCategory, DishCategoryAdmin)
admin.site.register(Dish, DishAdmin)
admin.site.unregister(Group)
<|endoftext|>


<commit_before>"""
This package contains functions for post-processing labeled segmentation
masks produced by segmentation algorithms.
"""

# make functions available at the package level using shadow imports
# since we mostly have one function per file
from .CompactLabel import CompactLabel
from .ComputeNeighborhoodMask import ComputeNeighborhoodMask
from .CondenseLabel import CondenseLabel
from .DeleteLabel import DeleteLabel
from .LabelPerimeter import LabelPerimeter
from .ShuffleLabel import ShuffleLabel
from .trace_object_boundary import trace_object_boundary

# must be imported after CondenseLabel
from .AreaOpenLabel import AreaOpenLabel
from .SplitLabel import SplitLabel
from .WidthOpenLabel import WidthOpenLabel

# list out things that are available for public use
__all__ = (

    # functions and classes of this package
    'AreaOpenLabel',
    'CompactLabel',
    'ComputeNeighborhoodMask',
    'CondenseLabel',
    'DeleteLabel',
    'LabelPerimeter',
    'ShuffleLabel',
    'SplitLabel',
    'trace_object_boundary',
    'WidthOpenLabel',
)
<commit_msg>Modified __init__.py<commit_after>"""
This package contains functions for post-processing labeled segmentation
masks produced by segmentation algorithms.
"""

# make functions available at the package level using shadow imports
# since we mostly have one function per file
from .CompactLabel import CompactLabel
from .ComputeNeighborhoodMask import ComputeNeighborhoodMask
from .CondenseLabel import CondenseLabel
from .DeleteLabel import DeleteLabel
from .LabelPerimeter import LabelPerimeter
from .ShuffleLabel import ShuffleLabel
from .trace_boundaries import trace_boundaries

# must be imported after CondenseLabel
from .AreaOpenLabel import AreaOpenLabel
from .SplitLabel import SplitLabel
from .WidthOpenLabel import WidthOpenLabel

# list out things that are available for public use
__all__ = (

    # functions and classes of this package
    'AreaOpenLabel',
    'CompactLabel',
    'ComputeNeighborhoodMask',
    'CondenseLabel',
    'DeleteLabel',
    'LabelPerimeter',
    'ShuffleLabel',
    'SplitLabel',
    'trace_boundaries',
    'WidthOpenLabel',
)
<|endoftext|>


<commit_before>"""
Support for Flux lights.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.flux_led/
"""
import logging
import socket
import random

import voluptuous as vol

from homeassistant.const import CONF_DEVICES, CONF_NAME
from homeassistant.components.light import (
    ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_EFFECT, EFFECT_RANDOM,
    SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, SUPPORT_RGB_COLOR, Light,
    PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['https://github.com/Danielhiversen/flux_led/archive/0.8.zip'
                '#flux_led==0.8']

_LOGGER = logging.getLogger(__name__)

CONF_AUTOMATIC_ADD = 'automatic_add'

DOMAIN = 'flux_led'

SUPPORT_FLUX_LED = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT |
                    SUPPORT_RGB_COLOR)

DEVICE_SCHEMA = vol.Schema({
    vol.Optional(CONF_NAME): cv.string,
})

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA},
    vol.Optional(CONF_AUTOMATIC_ADD, default=False):  cv.boolean,
})

def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Flux lights."""
    import flux_led
    lights = []
    light_ips = []
    for ipaddr, device_config in config[CONF_DEVICES].items():
        device = {}
        device['name'] = device_config[CONF_NAME]
        device['ipaddr'] = ipaddr
        light = FluxLight(device)
        if light.is_valid:
            lights.append(light)
            light_ips.append(ipaddr)

    if not config[CONF_AUTOMATIC_ADD]:
        add_devices(lights)
        return

    # Find the bulbs on the LAN
    scanner = flux_led.BulbScanner()
    scanner.scan(timeout=10)
    for device in scanner.getBulbInfo():
        ipaddr = device['ipaddr']
        if ipaddr in light_ips:
            continue
        device['name'] = device['id'] + " " + ipaddr
        light = FluxLight(device)
        if light.is_valid:
            lights.append(light)
            light_ips.append(ipaddr)

    add_devices(lights)

class FluxLight(Light):
    """Representation of a Flux light."""

    def __init__(self, device):
        """Initialize the light."""
        import flux_led

        self._name = device['name']
        self._ipaddr = device['ipaddr']
        self.is_valid = True
        self._bulb = None
        try:
            self._bulb = flux_led.WifiLedBulb(self._ipaddr)
        except socket.error:
            self.is_valid = False
            _LOGGER.error(
                "Failed to connect to bulb %s, %s", self._ipaddr, self._name)

    @property
    def unique_id(self):
        """Return the ID of this light."""
        return "{}.{}".format(self.__class__, self._ipaddr)

    @property
    def name(self):
        """Return the name of the device if any."""
        return self._name

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._bulb.isOn()

    @property
    def brightness(self):
        """Return the brightness of this light between 0..255."""
        return self._bulb.getWarmWhite255()

    @property
    def rgb_color(self):
        """Return the color property."""
        return self._bulb.getRgb()

    @property
    def supported_features(self):
        """Flag supported features."""
        return SUPPORT_FLUX_LED

    def turn_on(self, **kwargs):
        """Turn the specified or all lights on."""
        if not self.is_on:
            self._bulb.turnOn()

        rgb = kwargs.get(ATTR_RGB_COLOR)
        brightness = kwargs.get(ATTR_BRIGHTNESS)
        effect = kwargs.get(ATTR_EFFECT)
        if rgb:
            self._bulb.setRgb(*tuple(rgb))
        elif brightness:
            self._bulb.setWarmWhite255(brightness)
        elif effect == EFFECT_RANDOM:
            self._bulb.setRgb(random.randrange(0, 255),
                              random.randrange(0, 255),
                              random.randrange(0, 255))

    def turn_off(self, **kwargs):
        """Turn the specified or all lights off."""
        self._bulb.turnOff()

    def update(self):
        """Synchronize state with bulb."""
        self._bulb.refreshState()
<commit_msg>Add support for rgb light in led flux, fixes issue #4303 (#4332)<commit_after>"""
Support for Flux lights.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.flux_led/
"""
import logging
import socket
import random

import voluptuous as vol

from homeassistant.const import CONF_DEVICES, CONF_NAME
from homeassistant.components.light import (
    ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_EFFECT, EFFECT_RANDOM,
    SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, SUPPORT_RGB_COLOR, Light,
    PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['https://github.com/Danielhiversen/flux_led/archive/0.8.zip'
                '#flux_led==0.8']

_LOGGER = logging.getLogger(__name__)

CONF_AUTOMATIC_ADD = 'automatic_add'
ATTR_MODE = 'mode'

DOMAIN = 'flux_led'

SUPPORT_FLUX_LED = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT |
                    SUPPORT_RGB_COLOR)

DEVICE_SCHEMA = vol.Schema({
    vol.Optional(CONF_NAME): cv.string,
    vol.Optional(ATTR_MODE, default='rgbw'):
        vol.All(cv.string, vol.In(['rgbw', 'rgb'])),
})

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA},
    vol.Optional(CONF_AUTOMATIC_ADD, default=False):  cv.boolean,
})

def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Flux lights."""
    import flux_led
    lights = []
    light_ips = []
    for ipaddr, device_config in config[CONF_DEVICES].items():
        device = {}
        device['name'] = device_config[CONF_NAME]
        device['ipaddr'] = ipaddr
        device[ATTR_MODE] = device_config[ATTR_MODE]
        light = FluxLight(device)
        if light.is_valid:
            lights.append(light)
            light_ips.append(ipaddr)

    if not config[CONF_AUTOMATIC_ADD]:
        add_devices(lights)
        return

    # Find the bulbs on the LAN
    scanner = flux_led.BulbScanner()
    scanner.scan(timeout=10)
    for device in scanner.getBulbInfo():
        ipaddr = device['ipaddr']
        if ipaddr in light_ips:
            continue
        device['name'] = device['id'] + " " + ipaddr
        device[ATTR_MODE] = 'rgbw'
        light = FluxLight(device)
        if light.is_valid:
            lights.append(light)
            light_ips.append(ipaddr)

    add_devices(lights)

class FluxLight(Light):
    """Representation of a Flux light."""

    def __init__(self, device):
        """Initialize the light."""
        import flux_led

        self._name = device['name']
        self._ipaddr = device['ipaddr']
        self._mode = device[ATTR_MODE]
        self.is_valid = True
        self._bulb = None
        try:
            self._bulb = flux_led.WifiLedBulb(self._ipaddr)
        except socket.error:
            self.is_valid = False
            _LOGGER.error(
                "Failed to connect to bulb %s, %s", self._ipaddr, self._name)

    @property
    def unique_id(self):
        """Return the ID of this light."""
        return "{}.{}".format(self.__class__, self._ipaddr)

    @property
    def name(self):
        """Return the name of the device if any."""
        return self._name

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._bulb.isOn()

    @property
    def brightness(self):
        """Return the brightness of this light between 0..255."""
        return self._bulb.getWarmWhite255()

    @property
    def rgb_color(self):
        """Return the color property."""
        return self._bulb.getRgb()

    @property
    def supported_features(self):
        """Flag supported features."""
        return SUPPORT_FLUX_LED

    def turn_on(self, **kwargs):
        """Turn the specified or all lights on."""
        if not self.is_on:
            self._bulb.turnOn()

        rgb = kwargs.get(ATTR_RGB_COLOR)
        brightness = kwargs.get(ATTR_BRIGHTNESS)
        effect = kwargs.get(ATTR_EFFECT)
        if rgb:
            self._bulb.setRgb(*tuple(rgb))
        elif brightness:
            if self._mode == 'rgbw':
                self._bulb.setWarmWhite255(brightness)
            elif self._mode == 'rgb':
                (red, green, blue) = self._bulb.getRgb()
                self._bulb.setRgb(red, green, blue, brightness=brightness)
        elif effect == EFFECT_RANDOM:
            self._bulb.setRgb(random.randrange(0, 255),
                              random.randrange(0, 255),
                              random.randrange(0, 255))

    def turn_off(self, **kwargs):
        """Turn the specified or all lights off."""
        self._bulb.turnOff()

    def update(self):
        """Synchronize state with bulb."""
        self._bulb.refreshState()
<|endoftext|>


<commit_before>from discord.ext import commands
from random import choice
import aiohttp
import re
import urllib

class AdvancedGoogle:

    def __init__(self, bot):
        self.bot = bot
        self.session = aiohttp.ClientSession()

    @commands.command(pass_context=True)
    @commands.cooldown(5, 60, commands.BucketType.channel)
    async def google(self, ctx, text):
        """Its google, you search with it.
        Example: google A magical pug

        Special search options are available; Image, Images, Maps
        Example: google image You know, for kids! > Returns first image
        Another example: google maps New York
        Another example: google images cats > Returns a random image
        based on the query
        LEGACY EDITION! SEE HERE!
        https://twentysix26.github.io/Red-Docs/red_cog_approved_repos/#refactored-cogs

        Originally made by Kowlin https://github.com/Kowlin/refactored-cogs
        edited by Aioxas"""
        result = await self.get_response(ctx)
        await self.bot.say(result)

    async def images(self, ctx, regex, option, images: bool=False):
        uri = "https://www.google.com/search?hl=en&tbm=isch&tbs=isz:m&q="
        num = 7
        if images:
            num = 8
        if isinstance(ctx, str):
            quary = str(ctx[num-1:].lower())
        else:
            quary = str(ctx.message.content
                        [len(ctx.prefix+ctx.command.name)+num:].lower())
        encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                         errors='replace')
        uir = uri+encode
        url = None
        async with self.session.get(uir, headers=option) as resp:
            test = await resp.content.read()
            unicoded = test.decode("unicode_escape")
            query_find = regex[0].findall(unicoded)
            try:
                if images:
                    url = choice(query_find)
                elif not images:
                    url = query_find[0]
                error = False
            except IndexError:
                error = True
        return url, error

    def parsed(self, find, regex, found: bool=True):
        find = find[:5]
        for r in find:
            if regex[3].search(r):
                m = regex[3].search(r)
                r = r[:m.start()] + r[m.end():]
            r = self.unescape(r)
        for i in range(len(find)):
            if i == 0:
                find[i] = "<" + find[i] + ">" + "\n\n**You might also want to check these out:**"
            else:
                find[i] = "<{}>".format(find[i])
        return find

    def unescape(self, msg):
        regex = ["
", "(?:\\\\[rn])", "(?:\\\\['])", "%25", "\(", "\)"]
        subs = ["\n", "", "'", "%", "%28", "%29"]
        for i in range(len(regex)):
            sub = re.sub(regex[i], subs[i], msg)
            msg = sub
        return msg

    async def get_response(self, ctx):
        if isinstance(ctx, str):
            search_type = ctx.lower().split(" ")
            search_valid = str(ctx.lower())
        else:
            search_type = ctx.message.content[len(ctx.prefix + ctx.command.name) + 1:].lower().split(" ")
            search_valid = str(ctx.message.content
                               [len(ctx.prefix + ctx.command.name) + 1:].lower())
        option = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
        }
        regex = [
            re.compile(",\"ou\":\"([^`]*?)\""),
            re.compile("
<a href=\"\/url\?url=([^`]*?)&"),
            re.compile("
<a href=\"([^`]*?)\""),
            re.compile("\/url?url=")
        ]

        # Start of Image
        if search_type[0] == "image" or search_type[0] == "images":
            msg = "Your search yielded no results."
            if search_valid == "image" or search_valid == "images":
                msg = "Please actually search something"
                return msg
            else:
                if search_type[0] == "image":
                    url, error = await self.images(ctx, regex, option)
                elif search_type[0] == "images":
                    url, error = await self.images(ctx, regex, option, images=True)
                if url and not error:
                    return url
                elif error:
                    return msg
                    # End of Image
        # Start of Maps
        elif search_type[0] == "maps":
            if search_valid == "maps":
                msg = "Please actually search something"
                return msg
            else:
                uri = "https://www.google.com/maps/search/"
                if isinstance(ctx, str):
                    quary = str(ctx[5:].lower())
                else:
                    quary = str(ctx.message.content
                                [len(ctx.prefix + ctx.command.name) + 6:].lower())
                encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                                 errors='replace')
                uir = uri + encode
                return uir
                # End of Maps
        # Start of generic search
        else:
            uri = "https://www.google.com/search?hl=en&q="
            if isinstance(ctx, str):
                quary = str(ctx)
            else:
                quary = str(ctx.message.content
                            [len(ctx.prefix + ctx.command.name) + 1:])
            encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                             errors='replace')
            uir = uri + encode
            async with self.session.get(uir, headers=option) as resp:
                test = str(await resp.content.read())
                query_find = regex[1].findall(test)
                if not query_find:
                    query_find = regex[2].findall(test)
                    try:
                        query_find = self.parsed(query_find, regex)
                    except IndexError:
                        return IndexError
                elif regex[3].search(query_find[0]):
                    query_find = self.parsed(query_find, regex)
                else:
                    query_find = self.parsed(query_find, regex, found=False)
            query_find = "\n".join(query_find)
            return query_find

            # End of generic search

    async def on_message(self, message):
        author = message.author

        if author == self.bot.user:
            return

        if not self.bot.user_allowed(message):
            return
        channel = message.channel
        str2find = "ok google "
        text = message.clean_content
        if not text.startswith(str2find):
            return
        text = text.replace(str2find, "", 1)
        await self.bot.send_typing(channel)
        try:
            result = await self.get_response(text)
            await self.bot.send_message(channel, result)
        except IndexError:
            await self.bot.send_message(channel, "Your search yielded no results.")

def setup(bot):
    n = AdvancedGoogle(bot)
    bot.add_cog(n)
<commit_msg>[advgoogle] Added session close on unload<commit_after>from discord.ext import commands
from random import choice
import aiohttp
import re
import urllib

class AdvancedGoogle:

    def __init__(self, bot):
        self.bot = bot
        self.session = aiohttp.ClientSession()

    def __unload(self):
        self.session.close()

    @commands.command(pass_context=True)
    @commands.cooldown(5, 60, commands.BucketType.channel)
    async def google(self, ctx, text):
        """Its google, you search with it.
        Example: google A magical pug

        Special search options are available; Image, Images, Maps
        Example: google image You know, for kids! > Returns first image
        Another example: google maps New York
        Another example: google images cats > Returns a random image
        based on the query
        LEGACY EDITION! SEE HERE!
        https://twentysix26.github.io/Red-Docs/red_cog_approved_repos/#refactored-cogs

        Originally made by Kowlin https://github.com/Kowlin/refactored-cogs
        edited by Aioxas"""
        result = await self.get_response(ctx)
        await self.bot.say(result)

    async def images(self, ctx, regex, option, images: bool=False):
        uri = "https://www.google.com/search?hl=en&tbm=isch&tbs=isz:m&q="
        num = 7
        if images:
            num = 8
        if isinstance(ctx, str):
            quary = str(ctx[num-1:].lower())
        else:
            quary = str(ctx.message.content
                        [len(ctx.prefix+ctx.command.name)+num:].lower())
        encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                         errors='replace')
        uir = uri+encode
        url = None
        async with self.session.get(uir, headers=option) as resp:
            test = await resp.content.read()
            unicoded = test.decode("unicode_escape")
            query_find = regex[0].findall(unicoded)
            try:
                if images:
                    url = choice(query_find)
                elif not images:
                    url = query_find[0]
                error = False
            except IndexError:
                error = True
        return url, error

    def parsed(self, find, regex, found: bool=True):
        find = find[:5]
        for r in find:
            if regex[3].search(r):
                m = regex[3].search(r)
                r = r[:m.start()] + r[m.end():]
            r = self.unescape(r)
        for i in range(len(find)):
            if i == 0:
                find[i] = "<" + find[i] + ">" + "\n\n**You might also want to check these out:**"
            else:
                find[i] = "<{}>".format(find[i])
        return find

    def unescape(self, msg):
        regex = ["
", "(?:\\\\[rn])", "(?:\\\\['])", "%25", "\(", "\)"]
        subs = ["\n", "", "'", "%", "%28", "%29"]
        for i in range(len(regex)):
            sub = re.sub(regex[i], subs[i], msg)
            msg = sub
        return msg

    async def get_response(self, ctx):
        if isinstance(ctx, str):
            search_type = ctx.lower().split(" ")
            search_valid = str(ctx.lower())
        else:
            search_type = ctx.message.content[len(ctx.prefix + ctx.command.name) + 1:].lower().split(" ")
            search_valid = str(ctx.message.content
                               [len(ctx.prefix + ctx.command.name) + 1:].lower())
        option = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
        }
        regex = [
            re.compile(",\"ou\":\"([^`]*?)\""),
            re.compile("
<a href=\"\/url\?url=([^`]*?)&"),
            re.compile("
<a href=\"([^`]*?)\""),
            re.compile("\/url?url=")
        ]

        # Start of Image
        if search_type[0] == "image" or search_type[0] == "images":
            msg = "Your search yielded no results."
            if search_valid == "image" or search_valid == "images":
                msg = "Please actually search something"
                return msg
            else:
                if search_type[0] == "image":
                    url, error = await self.images(ctx, regex, option)
                elif search_type[0] == "images":
                    url, error = await self.images(ctx, regex, option, images=True)
                if url and not error:
                    return url
                elif error:
                    return msg
                    # End of Image
        # Start of Maps
        elif search_type[0] == "maps":
            if search_valid == "maps":
                msg = "Please actually search something"
                return msg
            else:
                uri = "https://www.google.com/maps/search/"
                if isinstance(ctx, str):
                    quary = str(ctx[5:].lower())
                else:
                    quary = str(ctx.message.content
                                [len(ctx.prefix + ctx.command.name) + 6:].lower())
                encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                                 errors='replace')
                uir = uri + encode
                return uir
                # End of Maps
        # Start of generic search
        else:
            uri = "https://www.google.com/search?hl=en&q="
            if isinstance(ctx, str):
                quary = str(ctx)
            else:
                quary = str(ctx.message.content
                            [len(ctx.prefix + ctx.command.name) + 1:])
            encode = urllib.parse.quote_plus(quary, encoding='utf-8',
                                             errors='replace')
            uir = uri + encode
            async with self.session.get(uir, headers=option) as resp:
                test = str(await resp.content.read())
                query_find = regex[1].findall(test)
                if not query_find:
                    query_find = regex[2].findall(test)
                    try:
                        query_find = self.parsed(query_find, regex)
                    except IndexError:
                        return IndexError
                elif regex[3].search(query_find[0]):
                    query_find = self.parsed(query_find, regex)
                else:
                    query_find = self.parsed(query_find, regex, found=False)
            query_find = "\n".join(query_find)
            return query_find

            # End of generic search

    async def on_message(self, message):
        author = message.author

        if author == self.bot.user:
            return

        if not self.bot.user_allowed(message):
            return
        channel = message.channel
        str2find = "ok google "
        text = message.clean_content
        if not text.startswith(str2find):
            return
        text = text.replace(str2find, "", 1)
        await self.bot.send_typing(channel)
        try:
            result = await self.get_response(text)
            await self.bot.send_message(channel, result)
        except IndexError:
            await self.bot.send_message(channel, "Your search yielded no results.")

def setup(bot):
    n = AdvancedGoogle(bot)
    bot.add_cog(n)
<|endoftext|>


<commit_before>"""
Enable ptvsd debugger to attach to HA.

Attach ptvsd debugger by default to port 5678.
"""

from asyncio import Event
import logging
from threading import Thread

import voluptuous as vol

from homeassistant.const import CONF_HOST, CONF_PORT
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, HomeAssistantType

DOMAIN = "ptvsd"

CONF_WAIT = "wait"

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Optional(CONF_HOST, default="0.0.0.0"): cv.string,
                vol.Optional(CONF_PORT, default=5678): cv.port,
                vol.Optional(CONF_WAIT, default=False): cv.boolean,
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)

async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up ptvsd debugger."""

    # This is a local import, since importing this at the top, will cause
    # ptvsd to hook into `sys.settrace`. So does `coverage` to generate
    # coverage, resulting in a battle and incomplete code test coverage.
    import ptvsd  # pylint: disable=import-outside-toplevel

    conf = config[DOMAIN]
    host = conf[CONF_HOST]
    port = conf[CONF_PORT]

    ptvsd.enable_attach((host, port))

    wait = conf[CONF_WAIT]
    if wait:
        _LOGGER.warning("Waiting for ptvsd connection on %s:%s", host, port)
        ready = Event()

        def waitfor():
            ptvsd.wait_for_attach()
            hass.loop.call_soon_threadsafe(ready.set)

        Thread(target=waitfor).start()

        await ready.wait()
    else:
        _LOGGER.warning("Listening for ptvsd connection on %s:%s", host, port)

    return True
<commit_msg>Deprecate ptvsd integration (#42351)<commit_after>"""
Enable ptvsd debugger to attach to HA.

Attach ptvsd debugger by default to port 5678.
"""

from asyncio import Event
import logging
from threading import Thread

import voluptuous as vol

from homeassistant.const import CONF_HOST, CONF_PORT
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, HomeAssistantType

DOMAIN = "ptvsd"

CONF_WAIT = "wait"

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Optional(CONF_HOST, default="0.0.0.0"): cv.string,
                vol.Optional(CONF_PORT, default=5678): cv.port,
                vol.Optional(CONF_WAIT, default=False): cv.boolean,
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)

async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up ptvsd debugger."""
    _LOGGER.warning(
        "ptvsd is deprecated and will be removed in Home Assistant Core 0.120."
        "The debugpy integration can be used as a full replacement for ptvsd"
    )

    # This is a local import, since importing this at the top, will cause
    # ptvsd to hook into `sys.settrace`. So does `coverage` to generate
    # coverage, resulting in a battle and incomplete code test coverage.
    import ptvsd  # pylint: disable=import-outside-toplevel

    conf = config[DOMAIN]
    host = conf[CONF_HOST]
    port = conf[CONF_PORT]

    ptvsd.enable_attach((host, port))

    wait = conf[CONF_WAIT]
    if wait:
        _LOGGER.warning("Waiting for ptvsd connection on %s:%s", host, port)
        ready = Event()

        def waitfor():
            ptvsd.wait_for_attach()
            hass.loop.call_soon_threadsafe(ready.set)

        Thread(target=waitfor).start()

        await ready.wait()
    else:
        _LOGGER.warning("Listening for ptvsd connection on %s:%s", host, port)

    return True
<|endoftext|>


<commit_before>import json
import urllib
import urllib2

class CirconusAPI(object):

    def __init__(self, token):
        self.hostname = 'circonus.com'
        self.token = token
        # List valid api methods and their parameters here
        # The two lists are required and optional parameters
        self.methods = {
            ### Check management
            'list_agents': {
                'form_method': 'GET'
            },
            'list_checks': {
                'form_method': 'GET',
                'optional': ['active']
            },
            'list_metrics': {
                'form_method': 'GET',
                'required': ['check_id']
            },
            'add_check_bundle': {
                'form_method': 'POST',
                'required': ['agent_id', 'target', 'metric_name'],
                'optional': ['module', 'period', 'timeout','*']
            },
            'edit_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id', 'metric_name'],
                'optional': ['*']
            },
            'enable_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id']
            },
            'disable_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id']
            },
            'enable_check': {
                'form_method': 'POST',
                'required': ['check_id']
            },
            'disable_check': {
                'form_method': 'POST',
                'required': ['check_id']
            },
            ### Account management
            'list_accounts': {
                'form_method': 'POST'
            },
            'list_users': {
                'form_method': 'GET',
                'required': ['check_id', 'metric_name']
            },
            'list_contact_groups': {
                'form_method': 'GET'
            },
            'add_contact_group': {
                'form_method': 'POST',
                'required': ['name'],
                'optional': ['agg_window']
            },
            'edit_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id'],
                'optional': ['name', 'agg_window']
            },
            'remove_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id']
            },
            'add_contact': {
                'form_method': 'POST',
                'required' : ['contact_group_id', 'contact_method'],
                'optional' : ['user_id', 'contact_info']
            },
            'remove_contact': {
                'form_method': 'POST',
                'required': ['contact_group_id'],
                'optional': ['user_id', 'id', 'contact_method']
            },
            ### Rule management
            'list_alerts': {
                'form_method': 'GET',
                'required': ['start', 'end']
            },
            'list_rules': {
                'form_method': 'GET',
                'required': ['check_id', 'metric_name']
            },
            'add_metric_rule': {
                'form_method': 'POST',
                'required': ['check_id', 'metric_name', 'order', 'severity',
                             'value']
            },
            'remove_metric_rule': {
                'form_method': 'POST',
                'required' : ['check_id', 'metric_name', 'order']
            },
            'add_metric_parent': {
                'form_method': 'POST',
                'required' : ['check_id', 'parent_check_id', 'metric_name',
                              'parent_metric_name']
            },
            'remove_metric_parent': {
                'form_method': 'POST',
                'required': ['check_id', 'metric_name']
            },
            'add_rule_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id', 'check_id', 'metric_name',
                             'severity']
            },
            'remove_rule_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id', 'check_id', 'metric_name',
                             'severity']
            },
            ### Graph management
            'get_graph': {
                'api_method': 'graph',
                'form_method': 'GET',
                'required': ['graph_id']
            },
            'add_graph': {
                'api_method': 'graph',
                'form_method': 'POST',
                'required': ['graph_data']
            },
            'edit_graph': {
                'api_method': 'graph',
                'form_method': 'POST',
                'required': ['graph_id', 'graph_data']
            },
            'remove_graph': {
                'form_method': 'POST',
                'required': ['graph_id']
            },
            'list_graphs': {
                'form_method': 'GET'
            },
            'get_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'GET',
                'required': ['worksheet_id']
            },
            'add_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'POST',
                'required': ['worksheet_data']
            },
            'edit_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'POST',
                'required': ['worksheet_id', 'worksheet_data']
            },
            'remove_worksheet': {
                'form_method': 'POST',
                'required': ['worksheet_id']
            },
            'list_worksheets': {
                'form_method': 'GET'
            }
        }

    def __getattr__(self, name):
        if name in self.methods:
            def f(**parameters):
                # Verify that we passed the right parameters
                required = set(self.methods[name].get('required', []))
                optional = set(self.methods[name].get('optional', []))

                params = set(parameters.keys())
                if not params >= required:
                    raise TypeError("%s requires the following arguments: %s" %
                                    (name, ' '.join(
                                        self.methods[name]['required'])))
                if '*' not in optional and not params <= (required | optional):
                    raise TypeError("Invalid parameters given to %s" % name)

                # Make the api call
                return self.api_call(
                    self.methods[name].get('form_method', 'GET'),
                    self.methods[name].get('api_method', name),
                    **parameters)
            return f
        else:
            raise AttributeError("%s instance has no attribute '%s'" % (
                self.__class__.__name__, name))

    def api_call(self, form_method, method, **parameters):
        """Performs a circonus api call.

        Post is always used, even for read only requests. The api says that
        post is always valid, so there is no need to decide if something is
        read/write and setting get/post appropriately
        """

        # Convert list to multiple values
        # i.e. "a" : [1,2,3] to (eventually) a=1&a=2&a=3
        plist = []
        for k in parameters:
            demunged_k = k.replace('_dot_', '.')
            if type(parameters[k]) == list:
                for v in parameters[k]:
                    plist.append((demunged_k,v))
            else:
                plist.append((demunged_k, parameters[k]))
        url = "https://%s/api/json/%s" % (self.hostname, method)
        if form_method == 'POST':
            data = urllib.urlencode(plist)
        elif form_method == 'GET':
            data = None
            url = "%s?%s" % (url, urllib.urlencode(plist))
        req = urllib2.Request(
            url = url, data = data,
            headers = {
                "X-Circonus-Auth-Token" : self.token,
                "X-Circonus-App-Name" : "Circus"
            }
        )
        try:
            fh = urllib2.urlopen(req)
        except urllib2.HTTPError, e:
            if e.code == 401:
                raise TokenNotValidated
            if e.code == 403:
                raise AccessDenied
            try:
                data = json.load(e)
            except ValueError:
                data = {}
            raise CirconusAPIError(e.code, data)
        response = json.load(fh)
        # Deal with the unlikely case that we get an error with a 200 return
        # code
        if type(response) == dict and not response.get('success', True):
            raise CirconusAPIError(200, data)
        fh.close()
        return response

class CirconusAPIException(Exception):
    pass

class TokenNotValidated(CirconusAPIException):
    pass

class AccessDenied(CirconusAPIException):
    pass

class CirconusAPIError(CirconusAPIException):
    """Exception class for any errors thrown by the circonus API.

    Attributes:
        code -- the http code returned
        data -- the json object returned by the API
        success -- whether the request succeeded or failed (this is usually
                    false)
        error -- the error message returned by the API
    """
    def __init__(self, code, data):
        self.code = code
        self.data = data
        self.success = data.get('success', False)
        self.error = data.get('error', '')

    def __str__(self):
        return "HTTP %s - %s" % (self.code, self.error)
<commit_msg>Fix required/optional for list_rules<commit_after>import json
import urllib
import urllib2

class CirconusAPI(object):

    def __init__(self, token):
        self.hostname = 'circonus.com'
        self.token = token
        # List valid api methods and their parameters here
        # The two lists are required and optional parameters
        self.methods = {
            ### Check management
            'list_agents': {
                'form_method': 'GET'
            },
            'list_checks': {
                'form_method': 'GET',
                'optional': ['active']
            },
            'list_metrics': {
                'form_method': 'GET',
                'required': ['check_id']
            },
            'add_check_bundle': {
                'form_method': 'POST',
                'required': ['agent_id', 'target', 'metric_name'],
                'optional': ['module', 'period', 'timeout','*']
            },
            'edit_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id', 'metric_name'],
                'optional': ['*']
            },
            'enable_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id']
            },
            'disable_check_bundle': {
                'form_method': 'POST',
                'required': ['bundle_id']
            },
            'enable_check': {
                'form_method': 'POST',
                'required': ['check_id']
            },
            'disable_check': {
                'form_method': 'POST',
                'required': ['check_id']
            },
            ### Account management
            'list_accounts': {
                'form_method': 'POST'
            },
            'list_users': {
                'form_method': 'GET',
                'required': ['check_id', 'metric_name']
            },
            'list_contact_groups': {
                'form_method': 'GET'
            },
            'add_contact_group': {
                'form_method': 'POST',
                'required': ['name'],
                'optional': ['agg_window']
            },
            'edit_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id'],
                'optional': ['name', 'agg_window']
            },
            'remove_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id']
            },
            'add_contact': {
                'form_method': 'POST',
                'required' : ['contact_group_id', 'contact_method'],
                'optional' : ['user_id', 'contact_info']
            },
            'remove_contact': {
                'form_method': 'POST',
                'required': ['contact_group_id'],
                'optional': ['user_id', 'id', 'contact_method']
            },
            ### Rule management
            'list_alerts': {
                'form_method': 'GET',
                'required': ['start', 'end']
            },
            'list_rules': {
                'form_method': 'GET',
                'optional': ['check_id', 'metric_name']
            },
            'add_metric_rule': {
                'form_method': 'POST',
                'required': ['check_id', 'metric_name', 'order', 'severity',
                             'value']
            },
            'remove_metric_rule': {
                'form_method': 'POST',
                'required' : ['check_id', 'metric_name', 'order']
            },
            'add_metric_parent': {
                'form_method': 'POST',
                'required' : ['check_id', 'parent_check_id', 'metric_name',
                              'parent_metric_name']
            },
            'remove_metric_parent': {
                'form_method': 'POST',
                'required': ['check_id', 'metric_name']
            },
            'add_rule_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id', 'check_id', 'metric_name',
                             'severity']
            },
            'remove_rule_contact_group': {
                'form_method': 'POST',
                'required': ['contact_group_id', 'check_id', 'metric_name',
                             'severity']
            },
            ### Graph management
            'get_graph': {
                'api_method': 'graph',
                'form_method': 'GET',
                'required': ['graph_id']
            },
            'add_graph': {
                'api_method': 'graph',
                'form_method': 'POST',
                'required': ['graph_data']
            },
            'edit_graph': {
                'api_method': 'graph',
                'form_method': 'POST',
                'required': ['graph_id', 'graph_data']
            },
            'remove_graph': {
                'form_method': 'POST',
                'required': ['graph_id']
            },
            'list_graphs': {
                'form_method': 'GET'
            },
            'get_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'GET',
                'required': ['worksheet_id']
            },
            'add_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'POST',
                'required': ['worksheet_data']
            },
            'edit_worksheet': {
                'api_method': 'worksheet',
                'form_method': 'POST',
                'required': ['worksheet_id', 'worksheet_data']
            },
            'remove_worksheet': {
                'form_method': 'POST',
                'required': ['worksheet_id']
            },
            'list_worksheets': {
                'form_method': 'GET'
            }
        }

    def __getattr__(self, name):
        if name in self.methods:
            def f(**parameters):
                # Verify that we passed the right parameters
                required = set(self.methods[name].get('required', []))
                optional = set(self.methods[name].get('optional', []))

                params = set(parameters.keys())
                if not params >= required:
                    raise TypeError("%s requires the following arguments: %s" %
                                    (name, ' '.join(
                                        self.methods[name]['required'])))
                if '*' not in optional and not params <= (required | optional):
                    raise TypeError("Invalid parameters given to %s" % name)

                # Make the api call
                return self.api_call(
                    self.methods[name].get('form_method', 'GET'),
                    self.methods[name].get('api_method', name),
                    **parameters)
            return f
        else:
            raise AttributeError("%s instance has no attribute '%s'" % (
                self.__class__.__name__, name))

    def api_call(self, form_method, method, **parameters):
        """Performs a circonus api call.

        Post is always used, even for read only requests. The api says that
        post is always valid, so there is no need to decide if something is
        read/write and setting get/post appropriately
        """

        # Convert list to multiple values
        # i.e. "a" : [1,2,3] to (eventually) a=1&a=2&a=3
        plist = []
        for k in parameters:
            demunged_k = k.replace('_dot_', '.')
            if type(parameters[k]) == list:
                for v in parameters[k]:
                    plist.append((demunged_k,v))
            else:
                plist.append((demunged_k, parameters[k]))
        url = "https://%s/api/json/%s" % (self.hostname, method)
        if form_method == 'POST':
            data = urllib.urlencode(plist)
        elif form_method == 'GET':
            data = None
            url = "%s?%s" % (url, urllib.urlencode(plist))
        req = urllib2.Request(
            url = url, data = data,
            headers = {
                "X-Circonus-Auth-Token" : self.token,
                "X-Circonus-App-Name" : "Circus"
            }
        )
        try:
            fh = urllib2.urlopen(req)
        except urllib2.HTTPError, e:
            if e.code == 401:
                raise TokenNotValidated
            if e.code == 403:
                raise AccessDenied
            try:
                data = json.load(e)
            except ValueError:
                data = {}
            raise CirconusAPIError(e.code, data)
        response = json.load(fh)
        # Deal with the unlikely case that we get an error with a 200 return
        # code
        if type(response) == dict and not response.get('success', True):
            raise CirconusAPIError(200, data)
        fh.close()
        return response

class CirconusAPIException(Exception):
    pass

class TokenNotValidated(CirconusAPIException):
    pass

class AccessDenied(CirconusAPIException):
    pass

class CirconusAPIError(CirconusAPIException):
    """Exception class for any errors thrown by the circonus API.

    Attributes:
        code -- the http code returned
        data -- the json object returned by the API
        success -- whether the request succeeded or failed (this is usually
                    false)
        error -- the error message returned by the API
    """
    def __init__(self, code, data):
        self.code = code
        self.data = data
        self.success = data.get('success', False)
        self.error = data.get('error', '')

    def __str__(self):
        return "HTTP %s - %s" % (self.code, self.error)
<|endoftext|>