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

"""Views for Organization App profiles.
"""

__authors__ = [
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms
from django.utils import simplejson

from soc.logic import cleaning
from soc.logic import dicts
from soc.logic import models as model_logic
from soc.logic.models import program as program_logic
from soc.logic.models import org_app as org_app_logic
from soc.views.helper import access
from soc.views.helper import decorators
from soc.views.helper import redirects
from soc.views.helper import responses
from soc.views.helper import widgets
from soc.views.models import group_app
from soc.views.models import program as program_view

import soc.logic.dicts

class View(group_app.View):
  """View methods for the Organization Application model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = access.Checker(params)
    rights['create'] = ['checkIsDeveloper']
    rights['delete'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic]),
                       ('checkIsActivePeriod', ['org_signup', 'scope_path'])]
    rights['edit'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic]),
                       ('checkIsActivePeriod', ['org_signup', 'scope_path'])]
    rights['list'] = ['checkIsDeveloper']
    rights['list_self'] = ['checkIsUser']
    rights['public'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic])]
    rights['review'] = ['checkIsHostForProgramInScope',
                        ('checkCanReviewGroupApp', [org_app_logic.logic])]
    rights['review_overview'] = ['checkIsHostForProgramInScope']
    rights['bulk_accept'] = ['checkIsHostForProgramInScope']
    rights['apply'] = ['checkIsUser',
                             ('checkCanCreateOrgApp', ['org_signup'])]

    new_params = {}

    new_params['rights'] = rights
    new_params['logic'] = org_app_logic.logic

    new_params['scope_view'] = program_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['sidebar_grouping'] = 'Organizations'

    patterns = [(r'^%(url_name)s/(?P<access_type>apply)/%(scope)s$',
        'soc.views.models.%(module_name)s.create',
        'Create an %(name_plural)s'),
        (r'^%(url_name)s/(?P<access_type>bulk_accept)/%(scope)s$',
        'soc.views.models.%(module_name)s.bulk_accept',
        'Bulk Acceptation of %(name_plural)s'),]

    new_params['extra_django_patterns'] = patterns
    new_params['extra_key_order'] = ['admin_agreement',
                                     'agreed_to_admin_agreement']

    new_params['extra_dynaexclude'] = ['applicant', 'backup_admin', 'status',
        'created_on', 'last_modified_on']

    new_params['create_extra_dynaproperties'] = {
        'scope_path': forms.fields.CharField(widget=forms.HiddenInput,
                                             required=True),
        'admin_agreement': forms.fields.Field(required=False,
            widget=widgets.AgreementField),
        'agreed_to_admin_agreement': forms.fields.BooleanField(
            initial=False, required=True),
        'clean_ideas': cleaning.clean_url('ideas'),
        'clean_contrib_template': cleaning.clean_url('contrib_template'),
        'clean': cleaning.validate_new_group('link_id', 'scope_path',
            model_logic.organization, org_app_logic)}

    # get rid of the clean method
    new_params['edit_extra_dynaproperties'] = {
        'clean': (lambda x: x.cleaned_data)}

    new_params['name'] = "Organization Application"
    new_params['name_plural'] = "Organization Applications"
    new_params['name_short'] = "Org App"
    new_params['url_name'] = "org_app"
    new_params['group_name'] = "Organization"
    new_params['group_url_name'] = 'org'

    new_params['review_template'] = 'soc/org_app/review.html'

    params = dicts.merge(params, new_params)

    super(View, self).__init__(params=params)

  @ decorators.merge_params
  def reviewOverview(self, request, access_type,
               page_name=None, params=None, **kwargs):

    params['list_template'] = 'soc/org_app/review_overview.html'
    context = {'bulk_accept_link': '/org_app/bulk_accept/%(scope_path)s' %(
        kwargs)}

    return super(View, self).reviewOverview(request, access_type,
        page_name=page_name, params=params, context=context, **kwargs)

  def _editContext(self, request, context):
    """See base.View._editContext.
    """

    entity = context['entity']
    form = context['form']

    if 'scope_path' in form.initial:
      scope_path = form.initial['scope_path']
    elif 'scope_path' in request.POST:
      # TODO: do this nicely
      scope_path = request.POST['scope_path']
    else:
      # TODO: is this always sufficient?
      del form.fields['admin_agreement']
      return

    entity = program_logic.logic.getFromKeyName(scope_path)

    if not entity or not entity.org_admin_agreement:
      return

    content = entity.org_admin_agreement.content

    form.fields['admin_agreement'].widget.text = content

  def _review(self, request, params, app_entity, status, **kwargs):
    """Sends out an email if an org_app has been reviewed and accepted.

    For params see group_app.View._review().
    """

    if status == 'accepted':
      #TODO(ljvderijk) create the email template
      pass

  @decorators.merge_params
  @decorators.check_access
  def bulkAccept(self, request, access_type,
               page_name=None, params=None, **kwargs):
    """Returns a HTTP Response containing JSON information needed
       to bulk-accept orgs.
    """

    program_entity = program_logic.logic.getFromKeyName(kwargs['scope_path'])

    # get all pre-accepted organization applications for the given program
    filter = {'scope' : program_entity,
              'status' : 'pre-accepted'}
    org_app_entities = org_app_logic.logic.getForFields(filter=filter)

    # convert each application into a dictionary containing only the fields
    # given by the dict_filter
    dict_filter = ['link_id', 'name']
    org_apps = [dicts.filter(i.toDict(), dict_filter) for i in org_app_entities]

    to_json = {
        'program' : program_entity.name,
        'nr_applications' : len(org_apps),
        'application_type' : params['name_plural'],
        'applications': org_apps,
        'link' : '/org_app/review/%s/(link_id)?status=accepted' %(
            program_entity.key().name()),
        }

    json = simplejson.dumps(to_json)

    # use the standard JSON template to return our response
    context = {'json': json}
    template = 'soc/json.html'

    return responses.respond(request, template, context)

view = View()

admin = view.admin
bulk_accept = view.bulkAccept
create = view.create
delete = view.delete
edit = view.edit
list = view.list
list_self = view.listSelf
public = view.public
export = view.export
review = view.review
review_overview = view.reviewOverview

<commit_msg>Added bulk reject to org_app view.<commit_after>#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for Organization App profiles.
"""

__authors__ = [
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms
from django.utils import simplejson

from soc.logic import cleaning
from soc.logic import dicts
from soc.logic import models as model_logic
from soc.logic.models import program as program_logic
from soc.logic.models import org_app as org_app_logic
from soc.views.helper import access
from soc.views.helper import decorators
from soc.views.helper import redirects
from soc.views.helper import responses
from soc.views.helper import widgets
from soc.views.models import group_app
from soc.views.models import program as program_view

import soc.logic.dicts

class View(group_app.View):
  """View methods for the Organization Application model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = access.Checker(params)
    rights['create'] = ['checkIsDeveloper']
    rights['delete'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic]),
                       ('checkIsActivePeriod', ['org_signup', 'scope_path'])]
    rights['edit'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic]),
                       ('checkIsActivePeriod', ['org_signup', 'scope_path'])]
    rights['list'] = ['checkIsDeveloper']
    rights['list_self'] = ['checkIsUser']
    rights['public'] = [('checkCanEditGroupApp',
                       [org_app_logic.logic])]
    rights['review'] = ['checkIsHostForProgramInScope',
                        ('checkCanReviewGroupApp', [org_app_logic.logic])]
    rights['review_overview'] = ['checkIsHostForProgramInScope']
    rights['bulk_accept'] = ['checkIsHostForProgramInScope']
    rights['bulk_reject'] = ['checkIsHostForProgramInScope']
    rights['apply'] = ['checkIsUser',
                             ('checkCanCreateOrgApp', ['org_signup'])]

    new_params = {}

    new_params['rights'] = rights
    new_params['logic'] = org_app_logic.logic

    new_params['scope_view'] = program_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['sidebar_grouping'] = 'Organizations'

    patterns = [(r'^%(url_name)s/(?P<access_type>apply)/%(scope)s$',
        'soc.views.models.%(module_name)s.create',
        'Create an %(name_plural)s'),
        (r'^%(url_name)s/(?P<access_type>bulk_accept)/%(scope)s$',
        'soc.views.models.%(module_name)s.bulk_accept',
        'Bulk Acceptation of %(name_plural)s'),
        (r'^%(url_name)s/(?P<access_type>bulk_reject)/%(scope)s$',
        'soc.views.models.%(module_name)s.bulk_reject',
        'Bulk Rejection of %(name_plural)s'),]

    new_params['extra_django_patterns'] = patterns
    new_params['extra_key_order'] = ['admin_agreement',
                                     'agreed_to_admin_agreement']

    new_params['extra_dynaexclude'] = ['applicant', 'backup_admin', 'status',
        'created_on', 'last_modified_on']

    new_params['create_extra_dynaproperties'] = {
        'scope_path': forms.fields.CharField(widget=forms.HiddenInput,
                                             required=True),
        'admin_agreement': forms.fields.Field(required=False,
            widget=widgets.AgreementField),
        'agreed_to_admin_agreement': forms.fields.BooleanField(
            initial=False, required=True),
        'clean_ideas': cleaning.clean_url('ideas'),
        'clean_contrib_template': cleaning.clean_url('contrib_template'),
        'clean': cleaning.validate_new_group('link_id', 'scope_path',
            model_logic.organization, org_app_logic)}

    # get rid of the clean method
    new_params['edit_extra_dynaproperties'] = {
        'clean': (lambda x: x.cleaned_data)}

    new_params['name'] = "Organization Application"
    new_params['name_plural'] = "Organization Applications"
    new_params['name_short'] = "Org App"
    new_params['url_name'] = "org_app"
    new_params['group_name'] = "Organization"
    new_params['group_url_name'] = 'org'

    new_params['review_template'] = 'soc/org_app/review.html'

    params = dicts.merge(params, new_params)

    super(View, self).__init__(params=params)

  @ decorators.merge_params
  def reviewOverview(self, request, access_type,
               page_name=None, params=None, **kwargs):

    params['list_template'] = 'soc/org_app/review_overview.html'
    context = {
        'bulk_accept_link': '/org_app/bulk_accept/%(scope_path)s' %(kwargs),
        'bulk_reject_link': '/org_app/bulk_reject/%(scope_path)s' %(kwargs),}

    return super(View, self).reviewOverview(request, access_type,
        page_name=page_name, params=params, context=context, **kwargs)

  def _editContext(self, request, context):
    """See base.View._editContext.
    """

    entity = context['entity']
    form = context['form']

    if 'scope_path' in form.initial:
      scope_path = form.initial['scope_path']
    elif 'scope_path' in request.POST:
      # TODO: do this nicely
      scope_path = request.POST['scope_path']
    else:
      # TODO: is this always sufficient?
      del form.fields['admin_agreement']
      return

    entity = program_logic.logic.getFromKeyName(scope_path)

    if not entity or not entity.org_admin_agreement:
      return

    content = entity.org_admin_agreement.content

    form.fields['admin_agreement'].widget.text = content

  def _review(self, request, params, app_entity, status, **kwargs):
    """Sends out an email if an org_app has been reviewed and accepted.

    For params see group_app.View._review().
    """

    if status == 'accepted':
      #TODO(ljvderijk) create the email template
      pass
    elif status == 'rejected':
      #TODO(ljvderijk) create the rejected email template
      pass

  @decorators.merge_params
  @decorators.check_access
  def bulkAccept(self, request, access_type,
               page_name=None, params=None, **kwargs):
    """Returns a HTTP Response containing JSON information needed
       to bulk-accept orgs.
    """

    program_keyname = kwargs['scope_path']
    return self._bulkReview(request, params, 'pre-accepted', 'accepted',
        program_keyname)

  @decorators.merge_params
  @decorators.check_access
  def bulkReject(self, request, access_type,
               page_name=None, params=None, **kwargs):
    """Returns a HTTP Response containing JSON information needed
       to bulk-accept orgs.
    """

    program_keyname = kwargs['scope_path']
    return self._bulkReview(request, params, 'pre-rejected', 'rejected',
                            program_keyname)

  def _bulkReview(self, request, params, from_status, to_status,
                  program_keyname):
    """Returns a HTTP Response containing JSON information needed
       to bulk-review organization applications.

       Args:
         request: Standard Django HTTP Request object
         params: Params for this view
         from_status: The status for the applications which should
                      be reviewed (can be a list)
         to_status: The status to which all applications should be changed to
         program_keyname: The keyname for the program to which
                          the application belongs
    """

    # get the program entity from the keyname
    program_entity = program_logic.logic.getFromKeyName(program_keyname)

    # get all the organization applications for the given program and from_status
    filter = {'scope': program_entity,
              'status': from_status}

    org_app_entities = params['logic'].getForFields(filter=filter)

    # convert each application into a dictionary containing only the fields
    # given by the dict_filter
    dict_filter = ['link_id', 'name']
    org_apps = [dicts.filter(i.toDict(), dict_filter) for i in org_app_entities]

    to_json = {
        'program' : program_entity.name,
        'nr_applications' : len(org_apps),
        'application_type' : params['name_plural'],
        'applications': org_apps,
        'link' : '/%s/review/%s/(link_id)?status=%s' %(
            params['url_name'] ,program_entity.key().name(), to_status),
        }

    json = simplejson.dumps(to_json)

    # use the standard JSON template to return our response
    context = {'json': json}
    template = 'soc/json.html'

    return responses.respond(request, template, context)

view = View()

admin = view.admin
bulk_accept = view.bulkAccept
bulk_reject = view.bulkReject
create = view.create
delete = view.delete
edit = view.edit
list = view.list
list_self = view.listSelf
public = view.public
export = view.export
review = view.review
review_overview = view.reviewOverview
<|endoftext|>


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

"""Views for Programs.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms
from django.utils.translation import ugettext

from soc.logic import dicts
from soc.logic.helper import timeline as timeline_helper
from soc.logic.models import program as program_logic
from soc.logic.models import host as host_logic
from soc.views import helper
from soc.views import out_of_band
from soc.views.helper import access
from soc.views.helper import decorators
from soc.views.helper import redirects
from soc.views.helper import widgets
from soc.views.models import presence_with_tos
from soc.views.models import document as document_view
from soc.views.models import sponsor as sponsor_view
from soc.views.sitemap import sidebar

import soc.logic.models.program
import soc.models.work

class View(presence_with_tos.View):
  """View methods for the Program model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = access.Checker(params)
    rights['any_access'] = ['allow']
    rights['show'] = ['allow']
    rights['create'] = [('checkSeeded', ['checkHasActiveRoleForScope', host_logic.logic])]
    rights['edit'] = ['checkIsHostForProgram']
    rights['delete'] = ['checkIsDeveloper']

    new_params = {}
    new_params['logic'] = soc.logic.models.program.logic
    new_params['rights'] = rights

    new_params['scope_view'] = sponsor_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['name'] = "Program"
    new_params['sidebar_grouping'] = 'Programs'

    new_params['extra_dynaexclude'] = ['timeline', 'org_admin_agreement',
        'mentor_agreement', 'student_agreement']

    # TODO add clean field to check for uniqueness in link_id and scope_path
    new_params['create_extra_dynafields'] = {
        'description': forms.fields.CharField(widget=helper.widgets.TinyMCE(
            attrs={'rows':10, 'cols':40})),
        'scope_path': forms.CharField(widget=forms.HiddenInput, required=True),
        'workflow': forms.ChoiceField(choices=[('gsoc','Project-based'),
            ('ghop','Task-based')], required=True),
        }

    new_params['edit_extra_dynafields'] = {
        'workflow': forms.CharField(widget=widgets.ReadOnlyInput(),
            required=True),
        'org_admin_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['scope_path'],
            required=False, label=ugettext(
                'Organization Admin Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        'mentor_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['scope_path'],
            required=False, label=ugettext('Mentor Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        'student_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['scope_path'],
            required=False, label=ugettext('Student Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        }

    params = dicts.merge(params, new_params, sub_merge=True)

    super(View, self).__init__(params=params)

  def _editPost(self, request, entity, fields):
    """See base._editPost().
    """

    if not entity:
      # there is no existing entity so create a new timeline
      fields['timeline'] = self._createTimelineForType(fields)
    else:
      # use the timeline from the entity
      fields['timeline'] = entity.timeline

    super(View, self)._editPost(request, entity, fields)

  def _createTimelineForType(self, fields):
    """Creates and stores a timeline model for the given type of program.
    """

    workflow = fields['workflow']

    timeline_logic = program_logic.logic.TIMELINE_LOGIC[workflow]

    key_name = self._logic.getKeyNameFromFields(fields)

    properties = {'scope_path': key_name}

    timeline = timeline_logic.updateOrCreateFromFields(properties, properties)
    return timeline

  @decorators.merge_params
  def getExtraMenus(self, id, user, params=None):
    """Returns the extra menu's for this view.

    A menu item is generated for each program that is currently
    running. The public page for each program is added as menu item,
    as well as all public documents for that program.

    Args:
      params: a dict with params for this View.
    """

    logic = params['logic']
    rights = params['rights']

    # only get all invisible and visible programs
    fields = {'status':['invisible', 'visible']}
    entities = logic.getForFields(fields)

    menus = []

    rights.setCurrentUser(id, user)
    filter_args = {}

    for entity in entities:
      items = []

      if entity.status == 'visible':
        # show the documents for this program, even for not logged in users
        items += document_view.view.getMenusForScope(entity, params)
        items += self._getTimeDependentEntries(entity, params)

      try:
        # check if the current user is a host for this program
        rights.doCachedCheck('checkIsHostForProgram',
            {'scope_path': entity.scope_path,
            'link_id': entity.link_id}, [])

        if entity.status == 'invisible':
          # still add the document links so hosts can see how it looks like
          items += document_view.view.getMenusForScope(entity, params)
          items += self._getTimeDependentEntries(entity, params)

        items += [(redirects.getReviewOverviewRedirect(
            entity, {'url_name': 'org_app'}),
            "Review Org Applications", 'any_access')]
        # add link to edit Program Profile
        items += [(redirects.getEditRedirect(entity, params),
            'Edit Program Profile','any_access')]
        # add link to edit Program Timeline
        items += [(redirects.getEditRedirect(entity, {'url_name': 'timeline'}),
            "Edit Program Timeline", 'any_access')]
        # add link to create a new Program Document
        items += [(redirects.getCreateDocumentRedirect(entity, 'program'),
            "Create a New Document", 'any_access')]

      except out_of_band.Error:
        pass

      items = sidebar.getSidebarMenu(id, user, items, params=params)
      if not items:
        continue

      menu = {}
      menu['heading'] = entity.short_name
      menu['items'] = items
      menu['group'] = 'Programs'
      menus.append(menu)

    return menus

  def _getTimeDependentEntries(self, program_entity, params):
    items = []

    #TODO(ljvderijk) Add more timeline dependent entries
    timeline_entity = program_entity.timeline

    if timeline_helper.isActivePeriod(timeline_entity, 'org_signup'):
      # add the organization signup link
      items += [
          (redirects.getApplyRedirect(program_entity, {'url_name': 'org_app'}),
          "Apply to become an Organization", 'any_access')]

      items += [
          (redirects.getListSelfRedirect(program_entity, {'url_name' : 'org_app'}),
           "List my Org Applications", 'any_access')]

    return items

view = View()

create = view.create
delete = view.delete
edit = view.edit
list = view.list
public = view.public
export = view.export
home = view.home
pick = view.pick
<commit_msg>Use the newly added __scoped__ and references for program's ToSes<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for Programs.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms
from django.utils.translation import ugettext

from soc.logic import dicts
from soc.logic.helper import timeline as timeline_helper
from soc.logic.models.document import logic as document_logic
from soc.logic.models import host as host_logic
from soc.logic.models import program as program_logic
from soc.views import helper
from soc.views import out_of_band
from soc.views.helper import access
from soc.views.helper import decorators
from soc.views.helper import redirects
from soc.views.helper import widgets
from soc.views.models import presence_with_tos
from soc.views.models import document as document_view
from soc.views.models import sponsor as sponsor_view
from soc.views.sitemap import sidebar

import soc.logic.models.program
import soc.models.work

class View(presence_with_tos.View):
  """View methods for the Program model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = access.Checker(params)
    rights['any_access'] = ['allow']
    rights['show'] = ['allow']
    rights['create'] = [('checkSeeded', ['checkHasActiveRoleForScope', host_logic.logic])]
    rights['edit'] = ['checkIsHostForProgram']
    rights['delete'] = ['checkIsDeveloper']

    new_params = {}
    new_params['logic'] = soc.logic.models.program.logic
    new_params['rights'] = rights

    new_params['scope_view'] = sponsor_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['name'] = "Program"
    new_params['sidebar_grouping'] = 'Programs'

    new_params['extra_dynaexclude'] = ['timeline', 'org_admin_agreement',
        'mentor_agreement', 'student_agreement']

    # TODO add clean field to check for uniqueness in link_id and scope_path
    new_params['create_extra_dynafields'] = {
        'description': forms.fields.CharField(widget=helper.widgets.TinyMCE(
            attrs={'rows':10, 'cols':40})),
        'scope_path': forms.CharField(widget=forms.HiddenInput, required=True),
        'workflow': forms.ChoiceField(choices=[('gsoc','Project-based'),
            ('ghop','Task-based')], required=True),
        }

    new_params['edit_extra_dynafields'] = {
        'workflow': forms.CharField(widget=widgets.ReadOnlyInput(),
            required=True),
        'org_admin_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['__scoped__'],
            field_name='org_admin_agreement',
            required=False, label=ugettext(
                'Organization Admin Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        'mentor_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['__scoped__'],
            required=False, label=ugettext('Mentor Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        'student_agreement_link_id': widgets.ReferenceField(
            reference_url='document', filter=['__scoped__'],
            required=False, label=ugettext('Student Agreement Document link ID'),
            help_text=soc.models.work.Work.link_id.help_text),
        }

    references = [
        ('org_admin_agreement_link_id', 'org_admin_agreement', document_logic,
         lambda x: x.org_admin_agreement),
        ('mentor_agreement_link_id', 'mentor_agreement', document_logic,
         lambda x: x.mentor_agreement),
        ('student_agreement_link_id', 'student_agreement', document_logic,
         lambda x: x.student_agreement),
        ]

    new_params['references'] = references

    params = dicts.merge(params, new_params, sub_merge=True)

    super(View, self).__init__(params=params)

  def _editPost(self, request, entity, fields):
    """See base._editPost().
    """

    if not entity:
      # there is no existing entity so create a new timeline
      fields['timeline'] = self._createTimelineForType(fields)
    else:
      # use the timeline from the entity
      fields['timeline'] = entity.timeline

    super(View, self)._editPost(request, entity, fields)

  def _createTimelineForType(self, fields):
    """Creates and stores a timeline model for the given type of program.
    """

    workflow = fields['workflow']

    timeline_logic = program_logic.logic.TIMELINE_LOGIC[workflow]

    key_name = self._logic.getKeyNameFromFields(fields)

    properties = {'scope_path': key_name}

    timeline = timeline_logic.updateOrCreateFromFields(properties, properties)
    return timeline

  @decorators.merge_params
  def getExtraMenus(self, id, user, params=None):
    """Returns the extra menu's for this view.

    A menu item is generated for each program that is currently
    running. The public page for each program is added as menu item,
    as well as all public documents for that program.

    Args:
      params: a dict with params for this View.
    """

    logic = params['logic']
    rights = params['rights']

    # only get all invisible and visible programs
    fields = {'status':['invisible', 'visible']}
    entities = logic.getForFields(fields)

    menus = []

    rights.setCurrentUser(id, user)
    filter_args = {}

    for entity in entities:
      items = []

      if entity.status == 'visible':
        # show the documents for this program, even for not logged in users
        items += document_view.view.getMenusForScope(entity, params)
        items += self._getTimeDependentEntries(entity, params)

      try:
        # check if the current user is a host for this program
        rights.doCachedCheck('checkIsHostForProgram',
            {'scope_path': entity.scope_path,
            'link_id': entity.link_id}, [])

        if entity.status == 'invisible':
          # still add the document links so hosts can see how it looks like
          items += document_view.view.getMenusForScope(entity, params)
          items += self._getTimeDependentEntries(entity, params)

        items += [(redirects.getReviewOverviewRedirect(
            entity, {'url_name': 'org_app'}),
            "Review Org Applications", 'any_access')]
        # add link to edit Program Profile
        items += [(redirects.getEditRedirect(entity, params),
            'Edit Program Profile','any_access')]
        # add link to edit Program Timeline
        items += [(redirects.getEditRedirect(entity, {'url_name': 'timeline'}),
            "Edit Program Timeline", 'any_access')]
        # add link to create a new Program Document
        items += [(redirects.getCreateDocumentRedirect(entity, 'program'),
            "Create a New Document", 'any_access')]

      except out_of_band.Error:
        pass

      items = sidebar.getSidebarMenu(id, user, items, params=params)
      if not items:
        continue

      menu = {}
      menu['heading'] = entity.short_name
      menu['items'] = items
      menu['group'] = 'Programs'
      menus.append(menu)

    return menus

  def _getTimeDependentEntries(self, program_entity, params):
    items = []

    #TODO(ljvderijk) Add more timeline dependent entries
    timeline_entity = program_entity.timeline

    if timeline_helper.isActivePeriod(timeline_entity, 'org_signup'):
      # add the organization signup link
      items += [
          (redirects.getApplyRedirect(program_entity, {'url_name': 'org_app'}),
          "Apply to become an Organization", 'any_access')]

      items += [
          (redirects.getListSelfRedirect(program_entity, {'url_name' : 'org_app'}),
           "List my Org Applications", 'any_access')]

    return items

view = View()

create = view.create
delete = view.delete
edit = view.edit
list = view.list
public = view.public
export = view.export
home = view.home
pick = view.pick
<|endoftext|>


<commit_before>import json
from unittest.mock import MagicMock

import os

from app import settings
from app.parser.schema_parser_factory import SchemaParserFactory

from app.questionnaire_state.state_answer import StateAnswer
from app.questionnaire_state.state_question import StateQuestion

from app.questionnaire_state.node import Node

from app.questionnaire.questionnaire_manager import QuestionnaireManager
from app.schema.block import Block
from app.schema.group import Group
from app.schema.questionnaire import Questionnaire
from tests.app.framework.sr_unittest import SurveyRunnerTestCase

class TestQuestionnaireManager(SurveyRunnerTestCase):
    def setUp(self):
        super().setUp()
        schema_file = open(os.path.join(settings.EQ_SCHEMA_DIRECTORY, "0_star_wars.json"))
        schema = schema_file.read()
        # create a parser
        parser = SchemaParserFactory.create_parser(json.loads(schema))
        self.questionnaire = parser.parse()
        settings.EQ_SERVER_SIDE_STORAGE_TYPE = "IN_MEMORY"

    def test_get_state_is_none(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)
        block1 = self.questionnaire.children[0].children[0]
        self.assertIsNone(questionnaire_manager.get_node(block1.id))

    def test_create_state(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)
        block1 = self.questionnaire.children[0].children[0]
        questionnaire_manager.go_to_node(block1.id)
        self.assertIsNotNone(questionnaire_manager.get_node(block1.id))

    def test_append(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")

        self.assertIsNone(questionnaire_manager._tail)
        self.assertIsNone(questionnaire_manager._first)
        questionnaire_manager._append(page1)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page1, questionnaire_manager._tail)
        self.assertIsNone(page1.previous)
        self.assertIsNone(page1.next)

        questionnaire_manager._append(page2)
        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page2, questionnaire_manager._tail)
        self.assertIsNone(page1.previous)
        self.assertEqual(page1.next, page2)
        self.assertEqual(page2.previous, page1)
        self.assertIsNone(page2.next)

        questionnaire_manager._append(page3)
        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page3, questionnaire_manager._tail)
        self.assertEqual(page2.previous, page1)
        self.assertEqual(page2.next, page3)
        self.assertEqual(page3.previous, page2)
        self.assertIsNone(page3.next)

    def test_pop(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")
        page4 = Node("fourth")

        questionnaire_manager._append(page1)
        questionnaire_manager._append(page2)
        questionnaire_manager._append(page3)
        questionnaire_manager._append(page4)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page4, questionnaire_manager._tail)

        popped = questionnaire_manager._pop()
        self.assertEqual(page4, popped)
        self.assertIsNone(popped.previous)
        self.assertIsNone(popped.next)
        self.assertEqual(page3, questionnaire_manager._tail)
        self.assertIsNone(page3.next)

    def test_truncate(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")
        page4 = Node("fourth")

        questionnaire_manager._append(page1)
        questionnaire_manager._append(page2)
        questionnaire_manager._append(page3)
        questionnaire_manager._append(page4)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page4, questionnaire_manager._tail)

        self.assertEqual(0, len(questionnaire_manager._archive))

        questionnaire_manager._truncate(page3)

        self.assertEqual(2, len(questionnaire_manager._archive))
        self.assertEqual(page4, questionnaire_manager._archive["fourth"])
        self.assertEqual(page3, questionnaire_manager._archive["third"])

        self.assertIsNone(page3.next)
        self.assertIsNone(page3.previous)

        self.assertIsNone(page4.next)
        self.assertIsNone(page4.previous)

        self.assertEqual(page2, questionnaire_manager._tail)
        self.assertIsNone(page2.next)

    def test_get_current_location(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            questionnaire_manager = QuestionnaireManager(schema)
            #  brand new session shouldn't have a current location
            self.assertEquals('block-1', questionnaire_manager.get_current_location())

    def test_get_current_location_with_intro(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            schema.introduction = "anything"

            questionnaire_manager = QuestionnaireManager(schema)

            #  brand new session shouldn't have a current location
            self.assertEquals("introduction", questionnaire_manager.get_current_location())

    def test_go_to(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            questionnaire_manager = QuestionnaireManager(schema)

            questionnaire_manager.go_to_node("block-1")
            self.assertEquals("block-1", questionnaire_manager.get_current_location())

    def test_go_to_invalid_location(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            schema.introduction = {'description': 'Some sort of intro'}

            questionnaire_manager = QuestionnaireManager(schema)
            questionnaire_manager.go_to_node("introduction")
            self.assertEquals("introduction", questionnaire_manager.get_current_location())
<commit_msg>Add unit tests for radio/checkbox other field.<commit_after>import json
from unittest.mock import MagicMock, Mock

import os

from app import settings
from app.parser.schema_parser_factory import SchemaParserFactory
from app.questionnaire.questionnaire_manager import QuestionnaireManager
from app.questionnaire_state.node import Node
from app.schema.block import Block
from app.schema.group import Group
from app.schema.questionnaire import Questionnaire
from tests.app.framework.sr_unittest import SurveyRunnerTestCase

class TestQuestionnaireManager(SurveyRunnerTestCase):
    def setUp(self):
        super().setUp()
        schema_file = open(os.path.join(settings.EQ_SCHEMA_DIRECTORY, "0_star_wars.json"))
        schema = schema_file.read()
        # create a parser
        parser = SchemaParserFactory.create_parser(json.loads(schema))
        self.questionnaire = parser.parse()
        settings.EQ_SERVER_SIDE_STORAGE_TYPE = "IN_MEMORY"

    def test_get_state_is_none(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)
        block1 = self.questionnaire.children[0].children[0]
        self.assertIsNone(questionnaire_manager.get_node(block1.id))

    def test_create_state(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)
        block1 = self.questionnaire.children[0].children[0]
        questionnaire_manager.go_to_node(block1.id)
        self.assertIsNotNone(questionnaire_manager.get_node(block1.id))

    def test_append(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")

        self.assertIsNone(questionnaire_manager._tail)
        self.assertIsNone(questionnaire_manager._first)
        questionnaire_manager._append(page1)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page1, questionnaire_manager._tail)
        self.assertIsNone(page1.previous)
        self.assertIsNone(page1.next)

        questionnaire_manager._append(page2)
        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page2, questionnaire_manager._tail)
        self.assertIsNone(page1.previous)
        self.assertEqual(page1.next, page2)
        self.assertEqual(page2.previous, page1)
        self.assertIsNone(page2.next)

        questionnaire_manager._append(page3)
        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page3, questionnaire_manager._tail)
        self.assertEqual(page2.previous, page1)
        self.assertEqual(page2.next, page3)
        self.assertEqual(page3.previous, page2)
        self.assertIsNone(page3.next)

    def test_pop(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")
        page4 = Node("fourth")

        questionnaire_manager._append(page1)
        questionnaire_manager._append(page2)
        questionnaire_manager._append(page3)
        questionnaire_manager._append(page4)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page4, questionnaire_manager._tail)

        popped = questionnaire_manager._pop()
        self.assertEqual(page4, popped)
        self.assertIsNone(popped.previous)
        self.assertIsNone(popped.next)
        self.assertEqual(page3, questionnaire_manager._tail)
        self.assertIsNone(page3.next)

    def test_truncate(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        page1 = Node("first")
        page2 = Node("second")
        page3 = Node("third")
        page4 = Node("fourth")

        questionnaire_manager._append(page1)
        questionnaire_manager._append(page2)
        questionnaire_manager._append(page3)
        questionnaire_manager._append(page4)

        self.assertEqual(page1, questionnaire_manager._first)
        self.assertEqual(page4, questionnaire_manager._tail)

        self.assertEqual(0, len(questionnaire_manager._archive))

        questionnaire_manager._truncate(page3)

        self.assertEqual(2, len(questionnaire_manager._archive))
        self.assertEqual(page4, questionnaire_manager._archive["fourth"])
        self.assertEqual(page3, questionnaire_manager._archive["third"])

        self.assertIsNone(page3.next)
        self.assertIsNone(page3.previous)

        self.assertIsNone(page4.next)
        self.assertIsNone(page4.previous)

        self.assertEqual(page2, questionnaire_manager._tail)
        self.assertIsNone(page2.next)

    def test_get_current_location(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            questionnaire_manager = QuestionnaireManager(schema)
            #  brand new session shouldn't have a current location
            self.assertEquals('block-1', questionnaire_manager.get_current_location())

    def test_get_current_location_with_intro(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            schema.introduction = "anything"

            questionnaire_manager = QuestionnaireManager(schema)

            #  brand new session shouldn't have a current location
            self.assertEquals("introduction", questionnaire_manager.get_current_location())

    def test_go_to(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            questionnaire_manager = QuestionnaireManager(schema)

            questionnaire_manager.go_to_node("block-1")
            self.assertEquals("block-1", questionnaire_manager.get_current_location())

    def test_go_to_invalid_location(self):
        with self.application.test_request_context():
            schema = Questionnaire()
            group = Group()
            group.id = 'group-1'
            schema.register(group)
            block = Block()
            block.id = 'block-1'
            schema.register(block)
            group.add_block(block)
            schema.add_group(group)

            schema.introduction = {'description': 'Some sort of intro'}

            questionnaire_manager = QuestionnaireManager(schema)
            questionnaire_manager.go_to_node("introduction")
            self.assertEquals("introduction", questionnaire_manager.get_current_location())

    def test_update_node_answers_should_use_other_value_if_present(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        mock_answer = MagicMock()
        mock_answer.id = 'answer id'
        mock_answer.other = 'other value'
        mock_answer.value = 'other'

        questionnaire_manager.state = Mock()
        questionnaire_manager.state.get_answers = MagicMock(return_value=[mock_answer])

        mock_node = MagicMock()
        questionnaire_manager.update_node_answers(mock_node)

        self.assertEquals(1, len(mock_node.answers))
        self.assertEquals({'answer id': 'other value'}, mock_node.answers)

    def test_update_node_answers_should_use_input_value_when_no_other_value(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        mock_answer = MagicMock()
        mock_answer.id = 'answer id'
        mock_answer.other = None
        mock_answer.value = 'input value'

        questionnaire_manager.state = Mock()
        questionnaire_manager.state.get_answers = MagicMock(return_value=[mock_answer])

        mock_node = MagicMock()
        questionnaire_manager.update_node_answers(mock_node)

        self.assertEquals(1, len(mock_node.answers))
        self.assertEquals({'answer id': 'input value'}, mock_node.answers)

    def test_update_node_answers_returns_empty_dict_when_no_answers(self):
        questionnaire_manager = QuestionnaireManager(self.questionnaire)

        questionnaire_manager.state = Mock()
        questionnaire_manager.state.get_answers = MagicMock(return_value=[])

        mock_node = MagicMock()
        questionnaire_manager.update_node_answers(mock_node)

        self.assertEquals(0, len(mock_node.answers))
        self.assertEquals({}, mock_node.answers)
<|endoftext|>


<commit_before># Copyright 2016 James Hensman, Mark van der Wilk,
#                Valentine Svensson, alexggmatthews,
#                PabloLeon, fujiisoup
# Copyright 2017 Artem Artemev @awav
# Copyright 2017 Thomas Viehmann
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy
import abc
import torch
from torch.autograd import Variable

class ParamWithPrior(torch.nn.Parameter):
    @abc.abstractmethod
    def get(self):
        pass
    @abc.abstractmethod
    def log_jacobian_tensor(self):
        pass
    @abc.abstractstaticmethod
    def untransform(t, out=None):
        pass
    def __init__(self, val, prior=None, ttype=torch.FloatTensor):
        pass
    def __new__(cls, val, prior=None, ttype=torch.FloatTensor): # for some reaosn unknown to me, it is impossible to pass a different tensor Type as ttype...
        if isinstance(val, torch.autograd.Variable):
            val = val.data
        elif numpy.isscalar(val):
            val = ttype([val])
        raw = cls.untransform(val)
        obj = super(ParamWithPrior, cls).__new__(cls, raw)
        obj.prior = prior
        return obj
    def set(self, t):
        if isinstance(t, torch.autograd.Variable):
            t = t.data
        elif numpy.isscalar(t):
            t = self.data.new(1).fill_(t)
        self.untransform(t, out=self.data)
    def get_prior(self):
        if self.prior is None:
            return 0.0

        log_jacobian = self.log_jacobian() #(unconstrained_tensor)
        logp_var = self.prior.logp(self.get())
        return log_jacobian+logp_var

class PositiveParam(ParamWithPrior): # log(1+exp(r))
    @staticmethod
    def untransform(t, out=None):
        return torch.log(torch.exp(t)-1, out=out)
    def get(self):
        return torch.log(1+torch.exp(self))
    def log_jacobian(self):
        return -(torch.nn.functional.softplus(-self))

class Param(ParamWithPrior): # unconstrained / untransformed
    @staticmethod
    def untransform(t, out=None):
        if out is None:
            return t
        else:
            return out.copy_(t)
    def get(self):
        return self
    def log_jacobian(self):
        return Variable(self.data.new(1).zero_()) # dimension?
<commit_msg>add triangular parameters<commit_after># Copyright 2016 James Hensman, Mark van der Wilk,
#                Valentine Svensson, alexggmatthews,
#                PabloLeon, fujiisoup
# Copyright 2017 Artem Artemev @awav
# Copyright 2017 Thomas Viehmann
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy
import abc
import torch
from torch.autograd import Variable

class ParamWithPrior(torch.nn.Parameter):
    @abc.abstractmethod
    def get(self):
        pass
    @abc.abstractmethod
    def log_jacobian_tensor(self):
        pass
    @abc.abstractstaticmethod
    def untransform(t, out=None):
        pass
    def __init__(self, val, prior=None, ttype=torch.FloatTensor):
        pass
    def __new__(cls, val, prior=None, ttype=torch.FloatTensor): # for some reaosn unknown to me, it is impossible to pass a different tensor Type as ttype...
        if isinstance(val, torch.autograd.Variable):
            val = val.data
        elif numpy.isscalar(val):
            val = ttype([val])
        raw = cls.untransform(val)
        obj = super(ParamWithPrior, cls).__new__(cls, raw)
        obj.prior = prior
        return obj
    def set(self, t):
        if isinstance(t, torch.autograd.Variable):
            t = t.data
        elif numpy.isscalar(t):
            t = self.data.new(1).fill_(t)
        self.untransform(t, out=self.data)
    def get_prior(self):
        if self.prior is None:
            return 0.0

        log_jacobian = self.log_jacobian() #(unconstrained_tensor)
        logp_var = self.prior.logp(self.get())
        return log_jacobian+logp_var

class PositiveParam(ParamWithPrior): # log(1+exp(r))
    @staticmethod
    def untransform(t, out=None):
        return torch.log(torch.exp(t)-1, out=out)
    def get(self):
        return torch.log(1+torch.exp(self))
    def log_jacobian(self):
        return -(torch.nn.functional.softplus(-self))

class Param(ParamWithPrior): # unconstrained / untransformed
    @staticmethod
    def untransform(t, out=None):
        if out is None:
            return t
        else:
            return out.copy_(t)
    def get(self):
        return self
    def log_jacobian(self):
        return Variable(self.data.new(1).zero_()) # dimension?

class LowerTriangularParam(ParamWithPrior):
    """
    A transform of the form

       tri_mat = vec_to_tri(x)

    x is a free variable, y is always a list of lower triangular matrices sized
    (N x N x D).
    """
    @staticmethod
    def untransform(t, out=None):
        ii,jj = numpy.tril_indices(t.size(0))
        return t[ii,jj]
    def get(self):
        numel = self.size(0)
        N = int((2*numel+0.25)**0.5-0.5)
        ii,jj = numpy.tril_indices(N)
        if self.dim()==2:
            mat = Variable(self.data.new(N,N, self.size(1)).zero_())
        else:
            mat = Variable(self.data.new(N,N).zero_())
        mat[ii,jj] = self
        return mat
    def log_jacobian(self):
        return Variable(self.data.new(1).zero_()) # dimension?
<|endoftext|>


<commit_before>import re
import enum
import binascii
import datetime

class TimestampFormat(enum.Enum):
    """Describes a type of timestamp. ABSOLUTE is referring to UNIX time
    (seconds since epoch). RELATIVE is seconds since start of log, or time
    since last frame depending of the contents of the log file. MISSING means
    that no timestamps is present in the log."""
    ABSOLUTE = 1
    RELATIVE = 2
    MISSING = 3

class DataFrame:
    """Container for a parsed log entry (ie. a CAN frame)."""

    def __init__(self, channel: str,
                 frame_id: int,
                 data: bytes,
                 timestamp: datetime.datetime,
                 timestamp_format: TimestampFormat):
        """Constructor for DataFrame

        :param channel: A string representation of the channel, eg. 'can0'
        :param frame_id: The numeric CAN frame ID :param data: The actual data
        :param timestamp: A timestamp, datetime.datetime if absolute, or
            datetime.timedelta if relative, None if missing
        :param timestamp_format: The format of the timestamp
        : """
        self.channel = channel
        self.frame_id = frame_id
        self.data = data
        self.timestamp = timestamp
        self.timestamp_format = timestamp_format

class BasePattern:
    @classmethod
    def match(clz, line):
        mo = clz.pattern.match(line)
        if mo:
            return clz.unpack(mo)

class CandumpDefaultPattern(BasePattern):
    #candump vcan0
    # vcan0  1F0   [8]  00 00 00 00 00 00 1B C1
    #candump vcan0 -a
    # vcan0  1F0   [8]  00 00 00 00 00 00 1B C1   '.......Á'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = None
        timestamp_format = TimestampFormat.MISSING

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class CandumpTimestampedPattern(BasePattern):
    #candump vcan0 -tz
    # (000.000000)  vcan0  0C8   [8]  F0 00 00 00 00 00 00 00
    #candump vcan0 -tz -a
    # (000.000000)  vcan0  0C8   [8]  31 30 30 2E 35 20 46 4D   '100.5 FM'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>[\d.]+)\)\s+(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)

        seconds = float(match_object.group('timestamp'))
        if seconds < 662688000:  # 1991-01-01 00:00:00, "Released in 1991, the Mercedes-Benz W140 was the first production vehicle to feature a CAN-based multiplex wiring system."
            timestamp = datetime.timedelta(seconds=seconds)
            timestamp_format = TimestampFormat.RELATIVE
        else:
            timestamp = datetime.datetime.utcfromtimestamp(seconds)
            timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class CandumpDefaultLogPattern(BasePattern):
    # (1579857014.345944) can2 486#82967A6B006B07F8
    # (1613656104.501098) can2 14C##16A0FFE00606E022400000000000000A0FFFF00FFFF25000600000000000000FE
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>[\d.]+)\)\s+(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)#(#[0-9A-F])?(?P<can_data>[0-9A-F]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = datetime.datetime.utcfromtimestamp(float(match_object.group('timestamp')))
        timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class CandumpAbsoluteLogPattern(BasePattern):
    #candump vcan0 -tA
    # (2020-12-19 12:04:45.485261)  vcan0  0C8   [8]  F0 00 00 00 00 00 00 00
    #candump vcan0 -tA -a
    # (2020-12-19 12:04:45.485261)  vcan0  0C8   [8]  31 30 30 2E 35 20 46 4D   '100.5 FM'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\)\s+(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = datetime.datetime.strptime(match_object.group('timestamp'), "%Y-%m-%d %H:%M:%S.%f")
        timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class Parser:
    """A CAN log file parser.

    Automatically detects the format of the logfile by trying parser patterns
    until the first successful match.

    >>> with open('candump.log') as fd:
            for frame in cantools.logreader.Parser(fd):
                print(f'{frame.timestamp}: {frame.frame_id}')
    """

    def __init__(self, stream=None):
        self.stream = stream
        self.pattern = None

    @staticmethod
    def detect_pattern(line):
        for p in [CandumpDefaultPattern, CandumpTimestampedPattern, CandumpDefaultLogPattern, CandumpAbsoluteLogPattern]:
            mo = p.pattern.match(line)
            if mo:
                return p

    def parse(self, line):
        if self.pattern is None:
            self.pattern = self.detect_pattern(line)
        if self.pattern is None:
            return None
        return self.pattern.match(line)

    def iterlines(self, keep_unknowns=False):
        """Returns an generator that yields (str, DataFrame) tuples with the
        raw log entry and a parsed log entry. If keep_unknowns=True, (str,
        None) tuples will be returned for log entries that couldn't be decoded.
        If keep_unknowns=False, non-parseable log entries is discarded.
        """
        if self.stream is None:
            return
        while True:
            nl = self.stream.readline()
            if nl == '':
                return
            nl = nl.strip('\r\n')
            frame = self.parse(nl)
            if frame:
                yield nl, frame
            elif keep_unknowns:
                yield nl, None
            else:
                continue

    def __iter__(self):
        """Returns DataFrame log entries. Non-parseable log entries is
        discarded."""
        for _, frame in self.iterlines():
            yield frame
<commit_msg>add logreader changes from master<commit_after>import re
import enum
import binascii
import datetime

class TimestampFormat(enum.Enum):
    """Describes a type of timestamp. ABSOLUTE is referring to UNIX time
    (seconds since epoch). RELATIVE is seconds since start of log, or time
    since last frame depending of the contents of the log file. MISSING means
    that no timestamps is present in the log."""
    ABSOLUTE = 1
    RELATIVE = 2
    MISSING = 3

class DataFrame:
    """Container for a parsed log entry (ie. a CAN frame)."""

    def __init__(self, channel: str,
                 frame_id: int,
                 data: bytes,
                 timestamp: datetime.datetime,
                 timestamp_format: TimestampFormat):
        """Constructor for DataFrame

        :param channel: A string representation of the channel, eg. 'can0'
        :param frame_id: The numeric CAN frame ID :param data: The actual data
        :param timestamp: A timestamp, datetime.datetime if absolute, or
            datetime.timedelta if relative, None if missing
        :param timestamp_format: The format of the timestamp
        : """
        self.channel = channel
        self.frame_id = frame_id
        self.data = data
        self.timestamp = timestamp
        self.timestamp_format = timestamp_format

class BasePattern:
    @classmethod
    def match(clz, line):
        mo = clz.pattern.match(line)
        if mo:
            return clz.unpack(mo)

class CandumpDefaultPattern(BasePattern):
    #candump vcan0
    # vcan0  1F0   [8]  00 00 00 00 00 00 1B C1
    #candump vcan0 -a
    # vcan0  1F0   [8]  00 00 00 00 00 00 1B C1   '.......Á'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = None
        timestamp_format = TimestampFormat.MISSING

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class CandumpTimestampedPattern(BasePattern):
    #candump vcan0 -tz
    # (000.000000)  vcan0  0C8   [8]  F0 00 00 00 00 00 00 00
    #candump vcan0 -tz -a
    # (000.000000)  vcan0  0C8   [8]  31 30 30 2E 35 20 46 4D   '100.5 FM'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>[\d.]+)\)\s+(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)

        seconds = float(match_object.group('timestamp'))
        if seconds < 662688000:  # 1991-01-01 00:00:00, "Released in 1991, the Mercedes-Benz W140 was the first production vehicle to feature a CAN-based multiplex wiring system."
            timestamp = datetime.timedelta(seconds=seconds)
            timestamp_format = TimestampFormat.RELATIVE
        else:
            timestamp = datetime.datetime.utcfromtimestamp(seconds)
            timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class CandumpDefaultLogPattern(BasePattern):
    # (1579857014.345944) can2 486#82967A6B006B07F8
    # (1613656104.501098) can2 14C##16A0FFE00606E022400000000000000A0FFFF00FFFF25000600000000000000FE
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>[\d.]+?)\)\s+?(?P<channel>[a-zA-Z0-9]+)\s+?(?P<can_id>[0-9A-F]+?)#(#[0-9A-F])?(?P<can_data>([0-9A-Fa-f]{2})*?$).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = datetime.datetime.utcfromtimestamp(float(match_object.group('timestamp')))
        timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

    @staticmethod
    def raw_unpack(line):
        split = line.split()

        if len(split) != 3:
            return None

        timestamp, channel, frame = split

        timestamp = datetime.datetime.utcfromtimestamp(float(timestamp[1:-1]))
        frame_id, data = frame.split("#")
        frame_id = int(frame_id, 16)

        # none if data not base16 encoded (divisable by 2)
        if len(data) % 2 != 0:
            return None

        data = data.replace(' ', '')
        data = binascii.unhexlify(data)

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=TimestampFormat.ABSOLUTE)

class CandumpAbsoluteLogPattern(BasePattern):
    #candump vcan0 -tA
    # (2020-12-19 12:04:45.485261)  vcan0  0C8   [8]  F0 00 00 00 00 00 00 00
    #candump vcan0 -tA -a
    # (2020-12-19 12:04:45.485261)  vcan0  0C8   [8]  31 30 30 2E 35 20 46 4D   '100.5 FM'
    #(Ignore anything after the end of the data to work with candump's ASCII decoding)
    pattern = re.compile(
        r'^\s*?\((?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\)\s+(?P<channel>[a-zA-Z0-9]+)\s+(?P<can_id>[0-9A-F]+)\s+\[\d+\]\s*(?P<can_data>[0-9A-F ]*).*?$')

    @staticmethod
    def unpack(match_object):
        channel = match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        timestamp = datetime.datetime.strptime(match_object.group('timestamp'), "%Y-%m-%d %H:%M:%S.%f")
        timestamp_format = TimestampFormat.ABSOLUTE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class PCANTracePattern(BasePattern):
    # 1)      6357.213 1  Rx        0401 -  8    00 00 00 00 00 00 00 00
    pattern = re.compile(
        r'^\s*?\d+\)\s*?(?P<timestamp>\d+.\d+)\s+(?P<channel>[0-9])\s+.+\s+(?P<can_id>[0-9A-F]+)\s+-\s+(?P<dlc>[0-9])\s+(?P<can_data>[0-9A-F ]*)$')

    @staticmethod
    def unpack(match_object):
        """
        >>> PCANTracePattern().match("  1)      6357.213 1  Rx        0401 -  8    00 00 00 00 00 00 00 00") #doctest: +ELLIPSIS
        <logreader.DataFrame object at ...>
        """
        channel = 'pcan' + match_object.group('channel')
        frame_id = int(match_object.group('can_id'), 16)
        data = match_object.group('can_data')
        data = data.replace(' ', '')
        data = binascii.unhexlify(data)
        millis = float(match_object.group('timestamp'))
        # timestamp = datetime.datetime.strptime(match_object.group('timestamp'), "%Y-%m-%d %H:%M:%S.%f")
        timestamp = datetime.timedelta(milliseconds=millis)
        timestamp_format = TimestampFormat.RELATIVE

        return DataFrame(channel=channel, frame_id=frame_id, data=data, timestamp=timestamp, timestamp_format=timestamp_format)

class Parser:
    """A CAN log file parser.

    Automatically detects the format of the logfile by trying parser patterns
    until the first successful match.

    >>> with open('candump.log') as fd: #doctest: +SKIP
            for frame in cantools.logreader.Parser(fd):
                print(f'{frame.timestamp}: {frame.frame_id}')
    """

    def __init__(self, stream=None, raw=False):
        self.stream = stream
        self.pattern = None
        self.matcher = None
        self.raw = raw

    @staticmethod
    def detect_pattern(line):
        for p in [CandumpDefaultPattern, CandumpTimestampedPattern, CandumpDefaultLogPattern, CandumpAbsoluteLogPattern]:
            mo = p.pattern.match(line)
            if mo:
                return p

    def parse(self, line):
        if self.pattern is None:
            self.pattern = self.detect_pattern(line)

        if self.pattern is None:
            return None
        if self.matcher is None:
            if self.raw:
                if getattr(self.pattern, 'raw_unpack', False):
                    self.matcher = self.pattern.raw_unpack
                else:
                    self.raw = False
                    self.matcher = self.pattern.match
            else:
                self.matcher = self.pattern.match
        return self.matcher(line)

    def iterlines(self, keep_unknowns=False):
        """Returns an generator that yields (str, DataFrame) tuples with the
        raw log entry and a parsed log entry. If keep_unknowns=True, (str,
        None) tuples will be returned for log entries that couldn't be decoded.
        If keep_unknowns=False, non-parseable log entries is discarded.
        """
        if self.stream is None:
            return
        while True:
            nl = self.stream.readline()
            if nl == '':
                return
            nl = nl.strip('\r\n')
            frame = self.parse(nl)
            if frame:
                yield nl, frame
            elif keep_unknowns:
                yield nl, None
            else:
                continue

    def __iter__(self):
        """Returns DataFrame log entries. Non-parseable log entries is
        discarded."""
        for _, frame in self.iterlines():
            yield frame
<|endoftext|>


<commit_before>import argparse
import requests
import time
import paramiko
import os
import logging

logger = logging.getLogger(__name__)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', help='target version')
    parser.add_argument('-s', help='server node')
    parser.add_argument('-u', help='ssh username of rancher server host')
    parser.add_argument('-i', help='ssh key path', default="~/.ssh/id_rsa")
    parser.add_argument('-o', help='timeout duration for rancher server to be ready', default=90)
    args = parser.parse_args()
    logger.info(args)
    upgrade(args.t, args.s, args.u, args.i, args.o)

def upgrade(target, servernode, username, keypath, timeout):

    logger.info("UPGRADING RANCHER SERVER TO TARGET")

    i = 1
    #
    # Try to connect to the host.
    # Retry a few times if it fails.
    #
    while True:
        logger.info("Trying to connect to %s (%i/30)", servernode, i)
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            privatekeyfile = os.path.expanduser(keypath)
            mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
            ssh.connect(servernode, username=username, pkey=mykey)
            logger.info("Connected to %s", servernode)
            break
        except paramiko.AuthenticationException:
            logger.info("Authentication failed when connecting to %s",
                        servernode)
            sys.exit(1)
        except:
            logger.info("Could not SSH to %s, waiting for it to start",
                        servernode)
            i += 1
            time.sleep(2)

        # If we could not connect within time limit
        if i == 30:
            logger.info("Could not connect to %s. Giving up. "
                        "Please check private key file.", servernode)
            ssh.close()
            sys.exit(1)
    try:
        cmd = "sudo docker ps"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker stop $(sudo docker ps -q | awk '{print $1}')"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        server_container_id = stdout.readlines()[0].strip("\n")
        logger.info(server_container_id)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps -a | awk ' NR>1 {print $2}' | cut -d \: -f 2"

        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        tag_of_previous_rancher_server = stdout.readlines()[0].strip("\n")
        logger.info("tag_of_previous_rancher_server is: %s,",
                    tag_of_previous_rancher_server)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker create --volumes-from " + server_container_id + \
              " --name rancher-data rancher/server:" \
              + tag_of_previous_rancher_server
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker pull rancher/server:" + target
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker run -d --volumes-from rancher-data " \
              "--restart=always -p 8080:8080 rancher/server:" + target
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps | awk ' NR>1 {print $2}' | cut -d \: -f 2"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        tag_of_rancher_version_after_upgrade = \
            stdout.readlines()[0].strip("\n")
        logger.info("tag_of_rancher_version_after_upgrade is: %s",
                    tag_of_rancher_version_after_upgrade)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps | awk ' NR>1 {print $8}' "
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        state_of_rancher_server_container_after_upgrade = \
            stdout.readlines()[0].strip("\n")
        logger.info("state_of_rancher_server_container_after_upgrade is: %s",
                    state_of_rancher_server_container_after_upgrade)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    time.sleep(int(timeout))

    if tag_of_rancher_version_after_upgrade == target and \
            state_of_rancher_server_container_after_upgrade == "Up":
        server = 'http://' + servernode + ":8080"
        if requests.get(server).status_code == 200:
            logger.info(
                "UPGRADE RANCHER SERVER TO TARGET COMPLETE AND SUCCESSFUL")

    ssh.close()

if __name__ == '__main__':
    main()
<commit_msg>Fix upgrade tool<commit_after>import argparse
import requests
import time
import paramiko
import os
import logging
import sys

logger = logging.getLogger(__name__)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', help='target version')
    parser.add_argument('-s', help='server node')
    parser.add_argument('-u', help='ssh username of rancher server host')
    parser.add_argument('-i', help='ssh key path', default="~/.ssh/id_rsa")
    parser.add_argument('-o', help='timeout duration for rancher server to be ready', default=90)
    args = parser.parse_args()
    logger.info(args)
    logger.setLevel(logging.INFO)
    upgrade(args.t, args.s, args.u, args.i, args.o)

def upgrade(target, servernode, username, keypath, timeout):

    logger.info("UPGRADING RANCHER SERVER TO TARGET")

    i = 1
    #
    # Try to connect to the host.
    # Retry a few times if it fails.
    #
    while True:
        logger.info("Trying to connect to %s (%i/30)", servernode, i)
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            privatekeyfile = os.path.expanduser(keypath)
            mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
            ssh.connect(servernode, username=username, pkey=mykey)
            logger.info("Connected to %s", servernode)
            break
        except paramiko.AuthenticationException:
            logger.info("Authentication failed when connecting to %s",
                        servernode)
            sys.exit(1)
        except:
            logger.info("Could not SSH to %s, waiting for it to start",
                        servernode)
            i += 1
            time.sleep(2)

        # If we could not connect within time limit
        if i == 30:
            logger.info("Could not connect to %s. Giving up. "
                        "Please check private key file.", servernode)
            ssh.close()
            sys.exit(1)
    try:
        cmd = "sudo docker ps"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker stop $(sudo docker ps -q | awk '{print $1}')"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        server_container_id = stdout.readlines()[0].strip("\n")
        logger.info(server_container_id)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps -a | awk ' NR>1 {print $2}' | cut -d \: -f 2"

        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        tag_of_previous_rancher_server = stdout.readlines()[0].strip("\n")
        logger.info("tag_of_previous_rancher_server is: %s,",
                    tag_of_previous_rancher_server)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker create --volumes-from " + server_container_id + \
              " --name rancher-data rancher/server:" \
              + tag_of_previous_rancher_server
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker pull rancher/server:" + target
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker run -d --volumes-from rancher-data " \
              "--restart=always -p 8080:8080 rancher/server:" + target
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        response = stdout.readlines()
        logger.info("response of cmd %s is: %s", cmd, response)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps | awk ' NR>1 {print $2}' | cut -d \: -f 2"
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        tag_of_rancher_version_after_upgrade = \
            stdout.readlines()[0].strip("\n")
        logger.info("tag_of_rancher_version_after_upgrade is: %s",
                    tag_of_rancher_version_after_upgrade)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    try:
        cmd = "sudo docker ps | awk ' NR>1 {print $8}' "
        # Send the command (non-blocking)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        state_of_rancher_server_container_after_upgrade = \
            stdout.readlines()[0].strip("\n")
        logger.info("state_of_rancher_server_container_after_upgrade is: %s",
                    state_of_rancher_server_container_after_upgrade)
    except:
        logger.info("Execution of cmd %s failed", cmd)

    time.sleep(int(timeout))

    if tag_of_rancher_version_after_upgrade == target and \
            state_of_rancher_server_container_after_upgrade == "Up":
        server = 'http://' + servernode + ":8080"
        if requests.get(server).status_code == 200:
            logger.info(
                "UPGRADE RANCHER SERVER TO TARGET COMPLETE AND SUCCESSFUL")

    ssh.close()

if __name__ == '__main__':
    logging.info("Starting upgrade tool...")
    main()
<|endoftext|>