Esempio n. 1
0
  def get(self, path, feature_id):
    user = users.get_current_user()
    if user is None:
      # Redirect to public URL for unauthenticated users.
      return self.redirect(format_feature_url(feature_id))

    if not self.user_can_edit(user):
      common.handle_401(self.request, self.response, Exception)
      return

    f = models.Feature.get_by_id(long(feature_id))
    if f is None:
      self.abort(404)

    feature_process = processes.ALL_PROCESSES.get(
        f.feature_type, processes.BLINK_LAUNCH_PROCESS)
    template_data = {
        'overview_form': guideforms.MetadataForm(f.format_for_edit()),
        'process_json': json.dumps(processes.process_to_dict(feature_process)),
        }

    progress_so_far = self.detect_progress(f)

    # Provide new or populated form to template.
    template_data.update({
        'feature': f.format_for_template(),
        'feature_id': f.key().id,
        'feature_json': json.dumps(f.format_for_template()),
        'progress_so_far': json.dumps(progress_so_far),
    })

    self._add_common_template_values(template_data)
    self.render(data=template_data, template_path=os.path.join(path + '.html'))
Esempio n. 2
0
  def post(self, path):
    user = users.get_current_user()
    if user is None or (user and not self.user_can_edit(user)):
      common.handle_401(self.request, self.response, Exception)
      return

    owner_addrs = self.split_input('owner', delim=',')
    owners = [db.Email(addr) for addr in owner_addrs]

    blink_components = (
        self.split_input('blink_components', delim=',') or
        [models.BlinkComponent.DEFAULT_COMPONENT])

    # TODO(jrobbins): Validate input, even though it is done on client.

    feature = models.Feature(
        category=int(self.request.get('category')),
        name=self.request.get('name'),
        feature_type=int(self.request.get('feature_type', 0)),
        intent_stage=models.INTENT_NONE,
        summary=self.request.get('summary'),
        owner=owners,
        impl_status_chrome=models.NO_ACTIVE_DEV,
        standardization=models.EDITORS_DRAFT,
        unlisted=self.request.get('unlisted') == 'on',
        web_dev_views=models.DEV_NO_SIGNALS,
        blink_components=blink_components)
    key = feature.put()

    # TODO(jrobbins): enumerate and remove only the relevant keys.
    memcache.flush_all()

    redirect_url = '/guide/edit/' + str(key.id())
    return self.redirect(redirect_url)
Esempio n. 3
0
    def get(self, path, feature_id=None):
        user = users.get_current_user()
        if user is None:
            if feature_id:
                # Redirect to public URL for unauthenticated users.
                return self.redirect(self.DEFAULT_URL + '/' + feature_id)
            else:
                return self.redirect(users.create_login_url(self.request.uri))

        # Remove trailing slash from URL and redirect. e.g. /metrics/ -> /metrics
        if path[-1] == '/':
            return self.redirect(self.request.path.rstrip('/'))

        # TODO(ericbidelman): This creates a additional call to
        # _is_user_whitelisted() (also called in common.py), resulting in another
        # db query.
        if not self._is_user_whitelisted(user):
            #TODO(ericbidelman): Use render(status=401) instead.
            #self.render(data={}, template_path=os.path.join(path + '.html'), status=401)
            common.handle_401(self.request, self.response, Exception)
            return

        if not feature_id and not 'new' in path:
            # /features/edit|launch -> /features/new
            return self.redirect(self.ADD_NEW_URL)
        elif feature_id and 'new' in path:
            return self.redirect(self.ADD_NEW_URL)

        template_data = {'feature_form': models.FeatureForm()}

        if feature_id:
            f = models.Feature.get_by_id(long(feature_id))
            if f is None:
                return self.redirect(self.ADD_NEW_URL)

            # Provide new or populated form to template.
            template_data.update({
                'feature':
                f.format_for_template(),
                'feature_form':
                models.FeatureForm(f.format_for_edit()),
                'default_url':
                '%s://%s%s/%s' % (self.request.scheme, self.request.host,
                                  self.DEFAULT_URL, feature_id),
                'edit_url':
                '%s://%s%s/%s' % (self.request.scheme, self.request.host,
                                  self.EDIT_URL, feature_id)
            })

        if self.LAUNCH_PARAM in self.request.params:
            template_data[self.LAUNCH_PARAM] = True
        if self.INTENT_PARAM in self.request.params:
            template_data[self.INTENT_PARAM] = True

        self._add_common_template_values(template_data)

        self.render(data=template_data,
                    template_path=os.path.join(path + '.html'))
Esempio n. 4
0
  def get(self, path, feature_id=None):
    user = users.get_current_user()
    if user is None:
      if feature_id:
        # Redirect to public URL for unauthenticated users.
        return self.redirect(self.DEFAULT_URL + '/' + feature_id)
      else:
        return self.redirect(users.create_login_url(self.request.uri))

    # Remove trailing slash from URL and redirect. e.g. /metrics/ -> /metrics
    if path[-1] == '/':
      return self.redirect(self.request.path.rstrip('/'))

    # TODO(ericbidelman): This creates a additional call to
    # _is_user_whitelisted() (also called in common.py), resulting in another
    # db query.
    if not self._is_user_whitelisted(user):
      #TODO(ericbidelman): Use render(status=401) instead.
      #self.render(data={}, template_path=os.path.join(path + '.html'), status=401)
      common.handle_401(self.request, self.response, Exception)
      return

    if not feature_id and not 'new' in path:
      # /features/edit|launch -> /features/new
      return self.redirect(self.ADD_NEW_URL)
    elif feature_id and 'new' in path:
      return self.redirect(self.ADD_NEW_URL)

    feature = None

    template_data = {
        'feature_form': models.FeatureForm()
        }

    if feature_id:
      f = models.Feature.get_by_id(long(feature_id))
      if f is None:
        return self.redirect(self.ADD_NEW_URL)

      # Provide new or populated form to template.
      template_data.update({
          'feature': f.format_for_template(),
          'feature_form': models.FeatureForm(f.format_for_edit()),
          'default_url': '%s://%s%s/%s' % (self.request.scheme, self.request.host,
                                           self.DEFAULT_URL, feature_id),
          'edit_url': '%s://%s%s/%s' % (self.request.scheme, self.request.host,
                                        self.EDIT_URL, feature_id)
          })

    if self.LAUNCH_PARAM in self.request.params:
      template_data[self.LAUNCH_PARAM] = True
    if self.INTENT_PARAM in self.request.params:
      template_data[self.INTENT_PARAM] = True

    self._add_common_template_values(template_data)

    self.render(data=template_data, template_path=os.path.join(path + '.html'))
Esempio n. 5
0
  def get(self, path):
    user = users.get_current_user()
    if user is None:
      return self.redirect(users.create_login_url(self.request.uri))

    if not self.user_can_edit(user):
      common.handle_401(self.request, self.response, Exception)
      return

    template_data = {
        'overview_form': guideforms.NewFeatureForm(),
        }

    self._add_common_template_values(template_data)

    self.render(data=template_data, template_path=os.path.join(path + '.html'))
Esempio n. 6
0
  def get(self, path, feature_id, stage_id):
    stage_id = int(stage_id)
    user = users.get_current_user()
    if user is None:
      # Redirect to public URL for unauthenticated users.
      return self.redirect(format_feature_url(feature_id))

    if not self.user_can_edit(user):
      common.handle_401(self.request, self.response, Exception)
      return

    f = models.Feature.get_by_id(long(feature_id))
    if f is None:
      self.abort(404)

    feature_process = processes.ALL_PROCESSES.get(
        f.feature_type, processes.BLINK_LAUNCH_PROCESS)
    stage_name = ''
    for stage in feature_process.stages:
      if stage.outgoing_stage == stage_id:
        stage_name = stage.name

    template_data = {
        'stage_name': stage_name,
        'stage_id': stage_id,
        }

    # TODO(jrobbins): show useful error if stage not found.
    detail_form_class = STAGE_FORMS[f.feature_type][stage_id]

    # Provide new or populated form to template.
    template_data.update({
        'feature': f,
        'feature_id': f.key().id,
        'feature_form': detail_form_class(f.format_for_edit()),
    })

    if self.LAUNCH_PARAM in self.request.params:
      template_data[self.LAUNCH_PARAM] = True
    if self.INTENT_PARAM in self.request.params:
      template_data[self.INTENT_PARAM] = True

    self._add_common_template_values(template_data)

    self.render(data=template_data, template_path=os.path.join(path + '.html'))
Esempio n. 7
0
  def post(self, path, feature_id=None):
    user = users.get_current_user()
    if user is None or (user and not self.user_can_edit(user)):
      common.handle_401(self.request, self.response, Exception)
      return

    spec_link = self.__FullQualifyLink('spec_link')

    explainer_links = self.request.get('explainer_links') or []
    if explainer_links:
      explainer_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', explainer_links)])

    bug_url = self.__FullQualifyLink('bug_url')
    launch_bug_url = self.__FullQualifyLink('launch_bug_url')
    initial_public_proposal_url = self.__FullQualifyLink(
        'initial_public_proposal_url')
    intent_to_implement_url = self.__FullQualifyLink('intent_to_implement_url')
    origin_trial_feedback_url = self.__FullQualifyLink('origin_trial_feedback_url')

    ff_views_link = self.__FullQualifyLink('ff_views_link')
    ie_views_link = self.__FullQualifyLink('ie_views_link')
    safari_views_link = self.__FullQualifyLink('safari_views_link')
    web_dev_views_link = self.__FullQualifyLink('web_dev_views_link')

    # Cast incoming milestones to ints.
    shipped_milestone = self.__ToInt('shipped_milestone')
    shipped_android_milestone = self.__ToInt('shipped_android_milestone')
    shipped_ios_milestone = self.__ToInt('shipped_ios_milestone')
    shipped_webview_milestone = self.__ToInt('shipped_webview_milestone')
    shipped_opera_milestone = self.__ToInt('shipped_opera_milestone')
    shipped_opera_android_milestone = self.__ToInt('shipped_opera_android_milestone')

    owners = self.request.get('owner') or []
    if owners:
      owners = [db.Email(x.strip()) for x in owners.split(',')]

    doc_links = self.request.get('doc_links') or []
    if doc_links:
      doc_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', doc_links)])

    sample_links = self.request.get('sample_links') or []
    if sample_links:
      sample_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', sample_links)])

    search_tags = self.request.get('search_tags') or []
    if search_tags:
      search_tags = filter(bool, [x.strip() for x in search_tags.split(',')])

    blink_components = self.request.get('blink_components') or models.BlinkComponent.DEFAULT_COMPONENT
    if blink_components:
      blink_components = filter(bool, [x.strip() for x in blink_components.split(',')])

    devrel = self.request.get('devrel') or []
    if devrel:
      devrel = [db.Email(x.strip()) for x in devrel.split(',')]

    try:
      intent_stage = int(self.request.get('intent_stage'))
    except:
      logging.error('Invalid intent_stage \'{}\'' \
                    .format(self.request.get('intent_stage')))

      # Default the intent stage to 1 (Prototype) if we failed to get a valid
      # intent stage from the request. This should be removed once we
      # understand what causes this.
      intent_stage = 1

    if feature_id: # /admin/edit/1234
      feature = models.Feature.get_by_id(long(feature_id))

      if feature is None:
        return self.redirect(self.request.path)

      if 'delete' in path:
        feature.delete()
        memcache.flush_all()
        return # Bomb out early for AJAX delete. No need to redirect.

      # Update properties of existing feature.
      feature.category = int(self.request.get('category'))
      feature.name = self.request.get('name')
      feature.intent_stage = intent_stage
      feature.summary = self.request.get('summary')
      feature.unlisted = self.request.get('unlisted') == 'on'
      feature.intent_to_implement_url = intent_to_implement_url
      feature.origin_trial_feedback_url = origin_trial_feedback_url
      feature.motivation = self.request.get('motivation')
      feature.explainer_links = explainer_links
      feature.owner = owners
      feature.bug_url = bug_url
      feature.launch_bug_url = launch_bug_url
      feature.initial_public_proposal_url = initial_public_proposal_url
      feature.blink_components = blink_components
      feature.devrel = devrel
      feature.impl_status_chrome = int(self.request.get('impl_status_chrome'))
      feature.shipped_milestone = shipped_milestone
      feature.shipped_android_milestone = shipped_android_milestone
      feature.shipped_ios_milestone = shipped_ios_milestone
      feature.shipped_webview_milestone = shipped_webview_milestone
      feature.shipped_opera_milestone = shipped_opera_milestone
      feature.shipped_opera_android_milestone = shipped_opera_android_milestone
      feature.footprint = int(self.request.get('footprint'))
      feature.interop_compat_risks = self.request.get('interop_compat_risks')
      feature.ergonomics_risks = self.request.get('ergonomics_risks')
      feature.activation_risks = self.request.get('activation_risks')
      feature.security_risks = self.request.get('security_risks')
      feature.debuggability = self.request.get('debuggability')
      feature.all_platforms = self.request.get('all_platforms') == 'on'
      feature.all_platforms_descr = self.request.get('all_platforms_descr')
      feature.wpt = self.request.get('wpt') == 'on'
      feature.wpt_descr = self.request.get('wpt_descr')
      feature.ff_views = int(self.request.get('ff_views'))
      feature.ff_views_link = ff_views_link
      feature.ff_views_notes = self.request.get('ff_views_notes')
      feature.ie_views = int(self.request.get('ie_views'))
      feature.ie_views_link = ie_views_link
      feature.ie_views_notes = self.request.get('ie_views_notes')
      feature.safari_views = int(self.request.get('safari_views'))
      feature.safari_views_link = safari_views_link
      feature.safari_views_notes = self.request.get('safari_views_notes')
      feature.web_dev_views = int(self.request.get('web_dev_views'))
      feature.web_dev_views_link = web_dev_views_link
      feature.web_dev_views_notes = self.request.get('web_dev_views_notes')
      feature.prefixed = self.request.get('prefixed') == 'on'
      feature.spec_link = spec_link
      feature.tag_review = self.request.get('tag_review')
      feature.standardization = int(self.request.get('standardization'))
      feature.doc_links = doc_links
      feature.sample_links = sample_links
      feature.search_tags = search_tags
      feature.comments = self.request.get('comments')
      feature.experiment_goals = self.request.get('experiment_goals')
      feature.experiment_timeline = self.request.get('experiment_timeline')
      feature.experiment_risks = self.request.get('experiment_risks')
      feature.experiment_extension_reason = self.request.get('experiment_extension_reason')
      feature.ongoing_constraints = self.request.get('ongoing_constraints')
    else:
      # Check bug for existing blink component(s) used to label the bug. If
      # found, use the first component name instead of the generic "Blink" name.
      try:
        blink_components = self.__get_blink_component_from_bug(blink_components, bug_url)
      except Exception:
        pass

      feature = models.Feature(
          category=int(self.request.get('category')),
          name=self.request.get('name'),
          intent_stage=intent_stage,
          summary=self.request.get('summary'),
          intent_to_implement_url=intent_to_implement_url,
          origin_trial_feedback_url=origin_trial_feedback_url,
          motivation=self.request.get('motivation'),
          explainer_links=explainer_links,
          owner=owners,
          bug_url=bug_url,
          launch_bug_url=launch_bug_url,
          initial_public_proposal_url=initial_public_proposal_url,
          blink_components=blink_components,
          devrel=devrel,
          impl_status_chrome=int(self.request.get('impl_status_chrome')),
          shipped_milestone=shipped_milestone,
          shipped_android_milestone=shipped_android_milestone,
          shipped_ios_milestone=shipped_ios_milestone,
          shipped_webview_milestone=shipped_webview_milestone,
          shipped_opera_milestone=shipped_opera_milestone,
          shipped_opera_android_milestone=shipped_opera_android_milestone,
          interop_compat_risks=self.request.get('interop_compat_risks'),
          ergonomics_risks=self.request.get('ergonomics_risks'),
          activation_risks=self.request.get('activation_risks'),
          security_risks=self.request.get('security_risks'),
          debuggability=self.request.get('debuggability'),
          all_platforms=self.request.get('all_platforms') == 'on',
          all_platforms_descr=self.request.get('all_platforms_descr'),
          wpt=self.request.get('wpt') == 'on',
          wpt_descr=self.request.get('wpt_descr'),
          footprint=int(self.request.get('footprint')),
          ff_views=int(self.request.get('ff_views')),
          ff_views_link=ff_views_link,
          ff_views_notes=self.request.get('ff_views_notes'),
          ie_views=int(self.request.get('ie_views')),
          ie_views_link=ie_views_link,
          ie_views_notes=self.request.get('ie_views_notes'),
          safari_views=int(self.request.get('safari_views')),
          safari_views_link=safari_views_link,
          safari_views_notes=self.request.get('safari_views_notes'),
          web_dev_views=int(self.request.get('web_dev_views')),
          web_dev_views_link=web_dev_views_link,
          web_dev_views_notes=self.request.get('web_dev_views_notes'),
          prefixed=self.request.get('prefixed') == 'on',
          spec_link=spec_link,
          tag_review=self.request.get('tag_review'),
          standardization=int(self.request.get('standardization')),
          doc_links=doc_links,
          sample_links=sample_links,
          search_tags=search_tags,
          comments=self.request.get('comments'),
          experiment_goals=self.request.get('experiment_goals'),
          experiment_timeline=self.request.get('experiment_timeline'),
          experiment_risks=self.request.get('experiment_risks'),
          experiment_extension_reason=self.request.get('experiment_extension_reason'),
          ongoing_constraints=self.request.get('ongoing_constraints'),
          )

    params = []
    if self.request.get('create_launch_bug') == 'on':
      params.append(self.LAUNCH_PARAM)
    if self.request.get('intent_to_implement') == 'on':
      params.append(self.INTENT_PARAM)

      feature.intent_template_use_count += 1

    key = feature.put()

    # TODO(ericbidelman): enumerate and remove only the relevant keys.
    memcache.flush_all()

    redirect_url = '/feature/' + str(key.id())

    if len(params):
      redirect_url = '%s/%s?%s' % (self.LAUNCH_URL, key.id(),
                                   '&'.join(params))

    return self.redirect(redirect_url)
Esempio n. 8
0
  def post(self, path, feature_id=None):
    user = users.get_current_user()
    if user is None or (user and not self._is_user_whitelisted(user)):
      common.handle_401(self.request, self.response, Exception)
      return

    spec_link = self.__FullQualifyLink('spec_link')
    bug_url = self.__FullQualifyLink('bug_url')

    ff_views_link = self.__FullQualifyLink('ff_views_link')
    ie_views_link = self.__FullQualifyLink('ie_views_link')
    safari_views_link = self.__FullQualifyLink('safari_views_link')

    # Cast incoming milestones to ints.
    shipped_milestone = self.__ToInt('shipped_milestone')
    shipped_android_milestone = self.__ToInt('shipped_android_milestone')
    shipped_ios_milestone = self.__ToInt('shipped_ios_milestone')
    shipped_webview_milestone = self.__ToInt('shipped_webview_milestone')
    shipped_opera_milestone = self.__ToInt('shipped_opera_milestone')
    shipped_opera_android_milestone = self.__ToInt('shipped_opera_android_milestone')

    owners = self.request.get('owner') or []
    if owners:
      owners = [db.Email(x.strip()) for x in owners.split(',')]

    doc_links = self.request.get('doc_links') or []
    if doc_links:
      doc_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', doc_links)])

    sample_links = self.request.get('sample_links') or []
    if sample_links:
      sample_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', sample_links)])

    search_tags = self.request.get('search_tags') or []
    if search_tags:
      search_tags = filter(bool, [x.strip() for x in search_tags.split(',')])

    blink_components = self.request.get('blink_components') or models.BlinkComponent.DEFAULT_COMPONENT
    if blink_components:
      blink_components = filter(bool, [x.strip() for x in blink_components.split(',')])

    if feature_id: # /admin/edit/1234
      feature = models.Feature.get_by_id(long(feature_id))

      if feature is None:
        return self.redirect(self.request.path)

      if 'delete' in path:
        feature.delete()
        memcache.flush_all()
        return # Bomb out early for AJAX delete. No need to redirect.

      # Update properties of existing feature.
      feature.category = int(self.request.get('category'))
      feature.name = self.request.get('name')
      feature.summary = self.request.get('summary')
      feature.owner = owners
      feature.bug_url = bug_url
      feature.blink_components = blink_components
      feature.impl_status_chrome = int(self.request.get('impl_status_chrome'))
      feature.shipped_milestone = shipped_milestone
      feature.shipped_android_milestone = shipped_android_milestone
      feature.shipped_ios_milestone = shipped_ios_milestone
      feature.shipped_webview_milestone = shipped_webview_milestone
      feature.shipped_opera_milestone = shipped_opera_milestone
      feature.shipped_opera_android_milestone = shipped_opera_android_milestone
      feature.footprint = int(self.request.get('footprint'))
      feature.visibility = int(self.request.get('visibility'))
      feature.ff_views = int(self.request.get('ff_views'))
      feature.ff_views_link = ff_views_link
      feature.ie_views = int(self.request.get('ie_views'))
      feature.ie_views_link = ie_views_link
      feature.safari_views = int(self.request.get('safari_views'))
      feature.safari_views_link = safari_views_link
      feature.prefixed = self.request.get('prefixed') == 'on'
      feature.spec_link = spec_link
      feature.standardization = int(self.request.get('standardization'))
      feature.comments = self.request.get('comments')
      feature.web_dev_views = int(self.request.get('web_dev_views'))
      feature.doc_links = doc_links
      feature.sample_links = sample_links
      feature.search_tags = search_tags
    else:
      # Check bug for existing blink component(s) used to label the bug. If
      # found, use the first component name instead of the generic "Blink" name.
      try:
        blink_components = self.__get_blink_component_from_bug(blink_components, bug_url)
      except Exception:
        pass

      feature = models.Feature(
          category=int(self.request.get('category')),
          name=self.request.get('name'),
          summary=self.request.get('summary'),
          owner=owners,
          bug_url=bug_url,
          blink_components=blink_components,
          impl_status_chrome=int(self.request.get('impl_status_chrome')),
          shipped_milestone=shipped_milestone,
          shipped_android_milestone=shipped_android_milestone,
          shipped_ios_milestone=shipped_ios_milestone,
          shipped_webview_milestone=shipped_webview_milestone,
          shipped_opera_milestone=shipped_opera_milestone,
          shipped_opera_android_milestone=shipped_opera_android_milestone,
          footprint=int(self.request.get('footprint')),
          visibility=int(self.request.get('visibility')),
          ff_views=int(self.request.get('ff_views')),
          ff_views_link=ff_views_link,
          ie_views=int(self.request.get('ie_views')),
          ie_views_link=ie_views_link,
          safari_views=int(self.request.get('safari_views')),
          safari_views_link=safari_views_link,
          prefixed=self.request.get('prefixed') == 'on',
          spec_link=spec_link,
          standardization=int(self.request.get('standardization')),
          comments=self.request.get('comments'),
          web_dev_views=int(self.request.get('web_dev_views')),
          doc_links=doc_links,
          sample_links=sample_links,
          search_tags=search_tags,
          )

    key = feature.put()

    # TODO(ericbidelman): enumerate and remove only the relevant keys.
    memcache.flush_all()

    params = []
    if self.request.get('create_launch_bug') == 'on':
      params.append(self.LAUNCH_PARAM)
    if self.request.get('intent_to_implement') == 'on':
      params.append(self.INTENT_PARAM)

    redirect_url = '/feature/' + str(key.id())

    if len(params):
      redirect_url = '%s/%s?%s' % (self.LAUNCH_URL, key.id(),
                                   '&'.join(params))

    return self.redirect(redirect_url)
Esempio n. 9
0
  def post(self, path, feature_id=None):
    user = users.get_current_user()
    if user is None or (user and not self._is_user_whitelisted(user)):
      common.handle_401(self.request, self.response, Exception)
      return

    spec_link = self.__FullQualifyLink('spec_link')

    explainer_links = self.request.get('explainer_links') or []
    if explainer_links:
      explainer_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', explainer_links)])

    bug_url = self.__FullQualifyLink('bug_url')
    intent_to_implement_url = self.__FullQualifyLink('intent_to_implement_url')
    origin_trial_feedback_url = self.__FullQualifyLink('origin_trial_feedback_url')

    ff_views_link = self.__FullQualifyLink('ff_views_link')
    ie_views_link = self.__FullQualifyLink('ie_views_link')
    safari_views_link = self.__FullQualifyLink('safari_views_link')
    web_dev_views_link = self.__FullQualifyLink('web_dev_views_link')

    # Cast incoming milestones to ints.
    shipped_milestone = self.__ToInt('shipped_milestone')
    shipped_android_milestone = self.__ToInt('shipped_android_milestone')
    shipped_ios_milestone = self.__ToInt('shipped_ios_milestone')
    shipped_webview_milestone = self.__ToInt('shipped_webview_milestone')
    shipped_opera_milestone = self.__ToInt('shipped_opera_milestone')
    shipped_opera_android_milestone = self.__ToInt('shipped_opera_android_milestone')

    owners = self.request.get('owner') or []
    if owners:
      owners = [db.Email(x.strip()) for x in owners.split(',')]

    doc_links = self.request.get('doc_links') or []
    if doc_links:
      doc_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', doc_links)])

    sample_links = self.request.get('sample_links') or []
    if sample_links:
      sample_links = filter(bool, [x.strip() for x in re.split('\\r?\\n', sample_links)])

    search_tags = self.request.get('search_tags') or []
    if search_tags:
      search_tags = filter(bool, [x.strip() for x in search_tags.split(',')])

    blink_components = self.request.get('blink_components') or models.BlinkComponent.DEFAULT_COMPONENT
    if blink_components:
      blink_components = filter(bool, [x.strip() for x in blink_components.split(',')])

    try:
      intent_stage = int(self.request.get('intent_stage'))
    except:
      logging.error('Invalid intent_stage \'{}\'' \
                    .format(self.request.get('intent_stage')))

      # Default the intent stage to 1 (Implement) if we failed to get a valid
      # intent stage from the request. This should be removed once we
      # understand what causes this.
      intent_stage = 1

    if feature_id: # /admin/edit/1234
      feature = models.Feature.get_by_id(long(feature_id))

      if feature is None:
        return self.redirect(self.request.path)

      if 'delete' in path:
        feature.delete()
        memcache.flush_all()
        return # Bomb out early for AJAX delete. No need to redirect.

      # Update properties of existing feature.
      feature.category = int(self.request.get('category'))
      feature.name = self.request.get('name')
      feature.intent_stage = intent_stage
      feature.summary = self.request.get('summary')
      feature.intent_to_implement_url = intent_to_implement_url
      feature.origin_trial_feedback_url = origin_trial_feedback_url
      feature.motivation = self.request.get('motivation')
      feature.explainer_links = explainer_links
      feature.owner = owners
      feature.bug_url = bug_url
      feature.blink_components = blink_components
      feature.impl_status_chrome = int(self.request.get('impl_status_chrome'))
      feature.shipped_milestone = shipped_milestone
      feature.shipped_android_milestone = shipped_android_milestone
      feature.shipped_ios_milestone = shipped_ios_milestone
      feature.shipped_webview_milestone = shipped_webview_milestone
      feature.shipped_opera_milestone = shipped_opera_milestone
      feature.shipped_opera_android_milestone = shipped_opera_android_milestone
      feature.footprint = int(self.request.get('footprint'))
      feature.interop_compat_risks = self.request.get('interop_compat_risks')
      feature.ergonomics_risks = self.request.get('ergonomics_risks')
      feature.activation_risks = self.request.get('activation_risks')
      feature.security_risks = self.request.get('security_risks')
      feature.debuggability = self.request.get('debuggability')
      feature.all_platforms = self.request.get('all_platforms') == 'on'
      feature.all_platforms_descr = self.request.get('all_platforms_descr')
      feature.wpt = self.request.get('wpt') == 'on'
      feature.wpt_descr = self.request.get('wpt_descr')
      feature.visibility = int(self.request.get('visibility'))
      feature.ff_views = int(self.request.get('ff_views'))
      feature.ff_views_link = ff_views_link
      feature.ff_views_notes = self.request.get('ff_views_notes')
      feature.ie_views = int(self.request.get('ie_views'))
      feature.ie_views_link = ie_views_link
      feature.ie_views_notes = self.request.get('ie_views_notes')
      feature.safari_views = int(self.request.get('safari_views'))
      feature.safari_views_link = safari_views_link
      feature.safari_views_notes = self.request.get('safari_views_notes')
      feature.web_dev_views = int(self.request.get('web_dev_views'))
      feature.web_dev_views_link = web_dev_views_link
      feature.web_dev_views_notes = self.request.get('web_dev_views_notes')
      feature.prefixed = self.request.get('prefixed') == 'on'
      feature.spec_link = spec_link
      feature.tag_review = self.request.get('tag_review')
      feature.standardization = int(self.request.get('standardization'))
      feature.doc_links = doc_links
      feature.sample_links = sample_links
      feature.search_tags = search_tags
      feature.comments = self.request.get('comments')
      feature.experiment_goal = self.request.get('experiment_goal')
      feature.experiment_timeline = self.request.get('experiment_timeline')
      feature.experiment_risks = self.request.get('experiment_risks')
      feature.experiment_extension_reason = self.request.get('experiment_extension_reason')
      feature.ongoing_constraints = self.request.get('ongoing_constraints')
    else:
      # Check bug for existing blink component(s) used to label the bug. If
      # found, use the first component name instead of the generic "Blink" name.
      try:
        blink_components = self.__get_blink_component_from_bug(blink_components, bug_url)
      except Exception:
        pass

      feature = models.Feature(
          category=int(self.request.get('category')),
          name=self.request.get('name'),
          intent_stage=intent_stage,
          summary=self.request.get('summary'),
          intent_to_implement_url=intent_to_implement_url,
          origin_trial_feedback_url=origin_trial_feedback_url,
          motivation=self.request.get('motivation'),
          explainer_links=explainer_links,
          owner=owners,
          bug_url=bug_url,
          blink_components=blink_components,
          impl_status_chrome=int(self.request.get('impl_status_chrome')),
          shipped_milestone=shipped_milestone,
          shipped_android_milestone=shipped_android_milestone,
          shipped_ios_milestone=shipped_ios_milestone,
          shipped_webview_milestone=shipped_webview_milestone,
          shipped_opera_milestone=shipped_opera_milestone,
          shipped_opera_android_milestone=shipped_opera_android_milestone,
          interop_compat_risks=self.request.get('interop_compat_risks'),
          ergonomics_risks=self.request.get('ergonomics_risks'),
          activation_risks=self.request.get('activation_risks'),
          security_risks=self.request.get('security_risks'),
          debuggability=self.request.get('debuggability'),
          all_platforms=self.request.get('all_platforms') == 'on',
          all_platforms_descr=self.request.get('all_platforms_descr'),
          wpt=self.request.get('wpt') == 'on',
          wpt_descr=self.request.get('wpt_descr'),
          footprint=int(self.request.get('footprint')),
          visibility=int(self.request.get('visibility')),
          ff_views=int(self.request.get('ff_views')),
          ff_views_link=ff_views_link,
          ff_views_notes=self.request.get('ff_views_notes'),
          ie_views=int(self.request.get('ie_views')),
          ie_views_link=ie_views_link,
          ie_views_notes=self.request.get('ie_views_notes'),
          safari_views=int(self.request.get('safari_views')),
          safari_views_link=safari_views_link,
          safari_views_notes=self.request.get('safari_views_notes'),
          web_dev_views=int(self.request.get('web_dev_views')),
          web_dev_views_link=web_dev_views_link,
          web_dev_views_notes=self.request.get('web_dev_views_notes'),
          prefixed=self.request.get('prefixed') == 'on',
          spec_link=spec_link,
          tag_review=self.request.get('tag_review'),
          standardization=int(self.request.get('standardization')),
          doc_links=doc_links,
          sample_links=sample_links,
          search_tags=search_tags,
          comments=self.request.get('comments'),
          experiment_goal=self.request.get('experiment_goal'),
          experiment_timeline=self.request.get('experiment_timeline'),
          experiment_risks=self.request.get('experiment_risks'),
          experiment_extension_reason=self.request.get('experiment_extension_reason'),
          ongoing_constraints=self.request.get('ongoing_constraints'),
          )

    key = feature.put()

    # TODO(ericbidelman): enumerate and remove only the relevant keys.
    memcache.flush_all()

    params = []
    if self.request.get('create_launch_bug') == 'on':
      params.append(self.LAUNCH_PARAM)
    if self.request.get('intent_to_implement') == 'on':
      params.append(self.INTENT_PARAM)

    redirect_url = '/feature/' + str(key.id())

    if len(params):
      redirect_url = '%s/%s?%s' % (self.LAUNCH_URL, key.id(),
                                   '&'.join(params))

    return self.redirect(redirect_url)
Esempio n. 10
0
  def post(self, path, feature_id, stage_id):
    user = users.get_current_user()
    if user is None or (user and not self.user_can_edit(user)):
      common.handle_401(self.request, self.response, Exception)
      return

    if feature_id:
      feature = models.Feature.get_by_id(long(feature_id))
      if feature is None:
        self.abort(404)
    stage_id = int(stage_id)

    logging.info('POST is %r', self.request.POST)

    if self.touched('spec_link'):
      feature.spec_link = self.parse_link('spec_link')

    if self.touched('initial_public_proposal_url'):
      feature.initial_public_proposal_url = self.parse_link(
          'initial_public_proposal_url')

    if self.touched('explainer_links'):
      feature.explainer_links = self.split_input('explainer_links')

    if self.touched('bug_url'):
      feature.bug_url = self.parse_link('bug_url')
    if self.touched('launch_bug_url'):
      feature.launch_bug_url = self.parse_link('launch_bug_url')

    if self.touched('intent_to_implement_url'):
      feature.intent_to_implement_url = self.parse_link(
          'intent_to_implement_url')

    if self.touched('origin_trial_feedback_url'):
      feature.origin_trial_feedback_url = self.parse_link(
          'origin_trial_feedback_url')

    # Cast incoming milestones to ints.
    # TODO(jrobbins): Consider supporting milestones that are not ints.
    if self.touched('shipped_milestone = self'):
      feature.shipped_milestone = self.parse_int('shipped_milestone')

    if self.touched('shipped_android_milestone'):
      feature.shipped_android_milestone = self.parse_int(
          'shipped_android_milestone')

    if self.touched('shipped_ios_milestone'):
      feature.shipped_ios_milestone = self.parse_int('shipped_ios_milestone')

    if self.touched('shipped_webview_milestone'):
      feature.shipped_webview_milestone = self.parse_int(
          'shipped_webview_milestone')

    if self.touched('shipped_opera_milestone'):
      feature.shipped_opera_milestone = self.parse_int('shipped_opera_milestone')

    if self.touched('shipped_opera_android'):
      feature.shipped_opera_android_milestone = self.parse_int(
          'shipped_opera_android_milestone')

    if self.touched('owner'):
      owner_addrs = self.split_input('owner', delim=',')
      feature.owner = [db.Email(addr) for addr in owner_addrs]

    if self.touched('doc_links'):
      feature.doc_links = self.split_input('doc_links')

    if self.touched('sample_links'):
      feature.sample_links = self.split_input('sample_links')

    if self.touched('search_tags'):
      feature.search_tags = self.split_input('search_tags', delim=',')

    if self.touched('blink_components'):
      feature.blink_components = (
          self.split_input('blink_components', delim=',') or
          [models.BlinkComponent.DEFAULT_COMPONENT])

    if self.touched('devrel'):
      devrel_addrs = self.split_input('devrel', delim=',')
      feature.devrel = [db.Email(addr) for addr in devrel_addrs]

    if self.touched('feature_type'):
      feature.feature_type = int(self.request.get('feature_type'))

    if self.touched('intent_stage'):
      feature.intent_stage = int(self.request.get('intent_stage'))
    elif self.request.get('set_stage') == 'on':
      feature.intent_stage = stage_id

    if self.touched('category'):
      feature.category = int(self.request.get('category'))
    if self.touched('name'):
      feature.name = self.request.get('name')
    if self.touched('summary'):
      feature.summary = self.request.get('summary')
    if self.touched('motivation'):
      feature.motivation = self.request.get('motivation')
    if self.touched('impl_status_chrome'):
      feature.impl_status_chrome = int(self.request.get('impl_status_chrome'))
    if self.touched('footprint'):
      feature.footprint = int(self.request.get('footprint'))
    if self.touched('interop_compat_risks'):
      feature.interop_compat_risks = self.request.get('interop_compat_risks')
    if self.touched('ergonomics_risks'):
      feature.ergonomics_risks = self.request.get('ergonomics_risks')
    if self.touched('activation_risks'):
      feature.activation_risks = self.request.get('activation_risks')
    if self.touched('security_risks'):
      feature.security_risks = self.request.get('security_risks')
    if self.touched('debuggability'):
      feature.debuggability = self.request.get('debuggability')
    if self.touched('all_platforms'):
      feature.all_platforms = self.request.get('all_platforms') == 'on'
    if self.touched('all_platforms_descr'):
      feature.all_platforms_descr = self.request.get('all_platforms_descr')
    if self.touched('wpt'):
      feature.wpt = self.request.get('wpt') == 'on'
    if self.touched('wpt_descr'):
      feature.wpt_descr = self.request.get('wpt_descr')
    if self.touched('ff_views'):
      feature.ff_views = int(self.request.get('ff_views'))
    if self.touched('ff_views_link'):
      feature.ff_views_link = self.parse_link('ff_views_link')
    if self.touched('ff_views_notes'):
      feature.ff_views_notes = self.request.get('ff_views_notes')
    if self.touched('ie_views'):
      feature.ie_views = int(self.request.get('ie_views'))
    if self.touched('ie_views_link'):
      feature.ie_views_link = self.parse_link('ie_views_link')
    if self.touched('ie_views_notes'):
      feature.ie_views_notes = self.request.get('ie_views_notes')
    if self.touched('safari_views'):
      feature.safari_views = int(self.request.get('safari_views'))
    if self.touched('safari_views_link'):
      feature.safari_views_link = self.parse_link('safari_views_link')
    if self.touched('safari_views_notes'):
      feature.safari_views_notes = self.request.get('safari_views_notes')
    if self.touched('web_dev_views'):
      feature.web_dev_views = int(self.request.get('web_dev_views'))
    if self.touched('web_dev_views'):
      feature.web_dev_views_link = self.parse_link('web_dev_views_link')
    if self.touched('web_dev_views_notes'):
      feature.web_dev_views_notes = self.request.get('web_dev_views_notes')
    if self.touched('prefixed'):
      feature.prefixed = self.request.get('prefixed') == 'on'
    if self.touched('tag_review'):
      feature.tag_review = self.request.get('tag_review')
    if self.touched('standardization'):
      feature.standardization = int(self.request.get('standardization'))
    if self.touched('unlisted'):
      feature.unlisted = self.request.get('unlisted') == 'on'
    if self.touched('comments'):
      feature.comments = self.request.get('comments')
    if self.touched('experiment_goals'):
      feature.experiment_goals = self.request.get('experiment_goals')
    if self.touched('experiment_timeline'):
      feature.experiment_timeline = self.request.get('experiment_timeline')
    if self.touched('experiment_risks'):
      feature.experiment_risks = self.request.get('experiment_risks')
    if self.touched('experiment_extension_reason'):
      feature.experiment_extension_reason = self.request.get(
          'experiment_extension_reason')
    if self.touched('ongoing_constraints'):
      feature.ongoing_constraints = self.request.get('ongoing_constraints')

    params = []
    if self.request.get('create_launch_bug') == 'on':
      params.append(self.LAUNCH_PARAM)
    if self.request.get('intent_to_implement') == 'on':
      params.append(self.INTENT_PARAM)
      feature.intent_template_use_count += 1

    key = feature.put()

    # TODO(jrobbins): enumerate and remove only the relevant keys.
    memcache.flush_all()

    redirect_url = '/guide/edit/' + str(key.id())

    if len(params):
      redirect_url = '%s/%s?%s' % (self.LAUNCH_URL, key.id(),
                                   '&'.join(params))

    return self.redirect(redirect_url)