Write and edit FeatureEntry entities when creating Features (#2278)
* Double write Feature and FeatureEntity entries * Update tests * tuples as needed
This commit is contained in:
Родитель
2eab43d7af
Коммит
7b08f2a6b8
|
@ -83,4 +83,10 @@ class FeaturesAPI(basehandlers.APIHandler):
|
|||
feature.put()
|
||||
rediscache.delete_keys_with_prefix(core_models.feature_cache_prefix())
|
||||
|
||||
# Write for new FeatureEntry entity.
|
||||
feature_entry = core_models.FeatureEntry.get_by_id(feature_id)
|
||||
if feature_entry:
|
||||
feature_entry.deleted = True
|
||||
feature_entry.put()
|
||||
|
||||
return {'message': 'Done'}
|
||||
|
|
117
pages/guide.py
117
pages/guide.py
|
@ -66,6 +66,28 @@ class FeatureCreateHandler(basehandlers.FlaskHandler):
|
|||
created_by=signed_in_user,
|
||||
updated_by=signed_in_user)
|
||||
key = feature.put()
|
||||
|
||||
# Write for new FeatureEntry entity.
|
||||
feature_entry = core_models.FeatureEntry(
|
||||
id=feature.key.integer_id(),
|
||||
category=int(self.form.get('category')),
|
||||
name=self.form.get('name'),
|
||||
feature_type=feature_type,
|
||||
intent_stage=core_enums.INTENT_NONE,
|
||||
summary=self.form.get('summary'),
|
||||
owners=owners,
|
||||
editors=editors,
|
||||
cc_recipients=cc_recipients,
|
||||
creator=signed_in_user.email(),
|
||||
updater=signed_in_user.email(),
|
||||
accurate_as_of=datetime.now(),
|
||||
impl_status_chrome=core_enums.NO_ACTIVE_DEV,
|
||||
unlisted=self.form.get('unlisted') == 'on',
|
||||
web_dev_views=core_enums.DEV_NO_SIGNALS,
|
||||
blink_components=blink_components,
|
||||
tag_review_status=processes.initial_tag_review_status(feature_type))
|
||||
feature_entry.put()
|
||||
|
||||
# Remove all feature-related cache.
|
||||
rediscache.delete_keys_with_prefix(core_models.feature_cache_prefix())
|
||||
|
||||
|
@ -118,6 +140,7 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
if feature_id:
|
||||
# Load feature directly from NDB so as to never get a stale cached copy.
|
||||
feature = core_models.Feature.get_by_id(feature_id)
|
||||
feature_entry = core_models.FeatureEntry.get_by_id(feature_id)
|
||||
if feature is None:
|
||||
self.abort(404, msg='Feature not found')
|
||||
else:
|
||||
|
@ -125,35 +148,51 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
|
||||
logging.info('POST is %r', self.form)
|
||||
|
||||
update_items = []
|
||||
if self.touched('spec_link'):
|
||||
feature.spec_link = self.parse_link('spec_link')
|
||||
update_items.append(('spec_link', self.parse_link('spec_link')))
|
||||
|
||||
if self.touched('standard_maturity'):
|
||||
feature.standard_maturity = self.parse_int('standard_maturity')
|
||||
update_items.append(('standard_maturity',
|
||||
self.parse_int('standard_maturity')))
|
||||
|
||||
if self.touched('api_spec'):
|
||||
feature.api_spec = self.form.get('api_spec') == 'on'
|
||||
update_items.append(('api_spec', self.form.get('api_spec') == 'on'))
|
||||
|
||||
if self.touched('spec_mentors'):
|
||||
feature.spec_mentors = self.split_emails('spec_mentors')
|
||||
update_items.append(('spec_mentors', self.split_emails('spec_mentors')))
|
||||
|
||||
if self.touched('security_review_status'):
|
||||
feature.security_review_status = self.parse_int('security_review_status')
|
||||
update_items.append(('security_review_status',
|
||||
self.parse_int('security_review_status')))
|
||||
|
||||
if self.touched('privacy_review_status'):
|
||||
feature.privacy_review_status = self.parse_int('privacy_review_status')
|
||||
update_items.append(('privacy_review_status',
|
||||
self.parse_int('privacy_review_status')))
|
||||
|
||||
if self.touched('initial_public_proposal_url'):
|
||||
feature.initial_public_proposal_url = self.parse_link(
|
||||
'initial_public_proposal_url')
|
||||
update_items.append(('initial_public_proposal_url',
|
||||
self.parse_link('initial_public_proposal_url')))
|
||||
|
||||
if self.touched('explainer_links'):
|
||||
feature.explainer_links = self.parse_links('explainer_links')
|
||||
update_items.append(('explainer_links',
|
||||
self.parse_links('explainer_links')))
|
||||
|
||||
if self.touched('bug_url'):
|
||||
feature.bug_url = self.parse_link('bug_url')
|
||||
update_items.append(('bug_url', self.parse_link('bug_url')))
|
||||
if self.touched('launch_bug_url'):
|
||||
feature.launch_bug_url = self.parse_link('launch_bug_url')
|
||||
update_items.append(('launch_bug_url', self.parse_link('launch_bug_url')))
|
||||
|
||||
if self.touched('intent_to_implement_url'):
|
||||
feature.intent_to_implement_url = self.parse_link(
|
||||
|
@ -182,6 +221,8 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
if self.touched('anticipated_spec_changes'):
|
||||
feature.anticipated_spec_changes = self.form.get(
|
||||
'anticipated_spec_changes')
|
||||
update_items.append(('anticipated_spec_changes',
|
||||
self.form.get('anticipated_spec_changes')))
|
||||
|
||||
if self.touched('finch_url'):
|
||||
feature.finch_url = self.parse_link('finch_url')
|
||||
|
@ -240,9 +281,13 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
if self.touched('requires_embedder_support'):
|
||||
feature.requires_embedder_support = (
|
||||
self.form.get('requires_embedder_support') == 'on')
|
||||
update_items.append(('requires_embedder_support',
|
||||
self.form.get('requires_embedder_support') == 'on'))
|
||||
|
||||
if self.touched('devtrial_instructions'):
|
||||
feature.devtrial_instructions = self.parse_link('devtrial_instructions')
|
||||
update_items.append(('devtrial_instructions',
|
||||
self.parse_link('devtrial_instructions')))
|
||||
|
||||
if self.touched('dt_milestone_desktop_start'):
|
||||
feature.dt_milestone_desktop_start = self.parse_int(
|
||||
|
@ -262,84 +307,125 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
|
||||
if self.touched('flag_name'):
|
||||
feature.flag_name = self.form.get('flag_name')
|
||||
update_items.append(('flag_name', self.form.get('flag_name')))
|
||||
|
||||
if self.touched('owner'):
|
||||
feature.owner = self.split_emails('owner')
|
||||
update_items.append(('owners', self.split_emails('owner')))
|
||||
|
||||
if self.touched('editors'):
|
||||
feature.editors = self.split_emails('editors')
|
||||
update_items.append(('editors', self.split_emails('editors')))
|
||||
|
||||
if self.touched('cc_recipients'):
|
||||
feature.cc_recipients = self.split_emails('cc_recipients')
|
||||
update_items.append(('cc_recipients', self.split_emails('cc_recipients')))
|
||||
|
||||
if self.touched('doc_links'):
|
||||
feature.doc_links = self.parse_links('doc_links')
|
||||
update_items.append(('doc_links', self.parse_links('doc_links')))
|
||||
|
||||
if self.touched('measurement'):
|
||||
feature.measurement = self.form.get('measurement')
|
||||
update_items.append(('measurement', self.form.get('measurement')))
|
||||
|
||||
if self.touched('sample_links'):
|
||||
feature.sample_links = self.parse_links('sample_links')
|
||||
update_items.append(('sample_links', self.parse_links('sample_links')))
|
||||
|
||||
if self.touched('search_tags'):
|
||||
feature.search_tags = self.split_input('search_tags', delim=',')
|
||||
update_items.append(('search_tags',
|
||||
self.split_input('search_tags', delim=',')))
|
||||
|
||||
if self.touched('blink_components'):
|
||||
feature.blink_components = (
|
||||
self.split_input('blink_components', delim=',') or
|
||||
[settings.DEFAULT_COMPONENT])
|
||||
update_items.append(('blink_components', (
|
||||
self.split_input('blink_components', delim=',') or
|
||||
[settings.DEFAULT_COMPONENT])))
|
||||
|
||||
if self.touched('devrel'):
|
||||
feature.devrel = self.split_emails('devrel')
|
||||
update_items.append(('devrel', self.split_emails('devrel')))
|
||||
|
||||
if self.touched('feature_type'):
|
||||
feature.feature_type = int(self.form.get('feature_type'))
|
||||
update_items.append(('feature_type', int(self.form.get('feature_type'))))
|
||||
|
||||
# intent_stage can be be set either by <select> or a checkbox
|
||||
if self.touched('intent_stage'):
|
||||
feature.intent_stage = int(self.form.get('intent_stage'))
|
||||
update_items.append(('intent_stage', int(self.form.get('intent_stage'))))
|
||||
elif self.form.get('set_stage') == 'on':
|
||||
feature.intent_stage = stage_id
|
||||
update_items.append(('intent_stage', stage_id))
|
||||
|
||||
if self.touched('category'):
|
||||
feature.category = int(self.form.get('category'))
|
||||
update_items.append(('category', int(self.form.get('category'))))
|
||||
if self.touched('name'):
|
||||
feature.name = self.form.get('name')
|
||||
update_items.append(('name', self.form.get('name')))
|
||||
if self.touched('summary'):
|
||||
feature.summary = self.form.get('summary')
|
||||
update_items.append(('summary', self.form.get('summary')))
|
||||
if self.touched('motivation'):
|
||||
feature.motivation = self.form.get('motivation')
|
||||
update_items.append(('motivation', self.form.get('motivation')))
|
||||
|
||||
# impl_status_chrome can be be set either by <select> or a checkbox
|
||||
if self.touched('impl_status_chrome'):
|
||||
feature.impl_status_chrome = int(self.form.get('impl_status_chrome'))
|
||||
update_items.append(('impl_status_chrome',
|
||||
int(self.form.get('impl_status_chrome'))))
|
||||
elif self.form.get('set_impl_status') == 'on':
|
||||
feature.impl_status_chrome = self.parse_int('impl_status_offered')
|
||||
update_items.append(('impl_status_chrome',
|
||||
self.parse_int('impl_status_offered')))
|
||||
|
||||
if self.touched('interop_compat_risks'):
|
||||
feature.interop_compat_risks = self.form.get('interop_compat_risks')
|
||||
update_items.append(('interop_compat_risks',
|
||||
self.form.get('interop_compat_risks')))
|
||||
if self.touched('ergonomics_risks'):
|
||||
feature.ergonomics_risks = self.form.get('ergonomics_risks')
|
||||
update_items.append(('ergonomics_risks',
|
||||
self.form.get('ergonomics_risks')))
|
||||
if self.touched('activation_risks'):
|
||||
feature.activation_risks = self.form.get('activation_risks')
|
||||
update_items.append(('activation_risks',
|
||||
self.form.get('activation_risks')))
|
||||
if self.touched('security_risks'):
|
||||
feature.security_risks = self.form.get('security_risks')
|
||||
update_items.append(('security_risks', self.form.get('security_risks')))
|
||||
if self.touched('debuggability'):
|
||||
feature.debuggability = self.form.get('debuggability')
|
||||
update_items.append(('debuggability', self.form.get('debuggability')))
|
||||
if self.touched('all_platforms'):
|
||||
feature.all_platforms = self.form.get('all_platforms') == 'on'
|
||||
update_items.append(('all_platforms',
|
||||
self.form.get('all_platforms') == 'on'))
|
||||
if self.touched('all_platforms_descr'):
|
||||
feature.all_platforms_descr = self.form.get('all_platforms_descr')
|
||||
update_items.append(('all_platforms_descr',
|
||||
self.form.get('all_platforms_descr')))
|
||||
if self.touched('wpt'):
|
||||
feature.wpt = self.form.get('wpt') == 'on'
|
||||
update_items.append(('wpt', self.form.get('wpt') == 'on'))
|
||||
if self.touched('wpt_descr'):
|
||||
feature.wpt_descr = self.form.get('wpt_descr')
|
||||
update_items.append(('wpt_descr', self.form.get('wpt_descr')))
|
||||
if self.touched('ff_views'):
|
||||
feature.ff_views = int(self.form.get('ff_views'))
|
||||
update_items.append(('ff_views', int(self.form.get('ff_views'))))
|
||||
if self.touched('ff_views_link'):
|
||||
feature.ff_views_link = self.parse_link('ff_views_link')
|
||||
update_items.append(('ff_views_link', self.parse_link('ff_views_link')))
|
||||
if self.touched('ff_views_notes'):
|
||||
feature.ff_views_notes = self.form.get('ff_views_notes')
|
||||
update_items.append(('ff_views_notes', self.form.get('ff_views_notes')))
|
||||
|
||||
# TODO(jrobbins): Delete after the next deployment
|
||||
if self.touched('ie_views'):
|
||||
|
@ -351,38 +437,60 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
|
||||
if self.touched('safari_views'):
|
||||
feature.safari_views = int(self.form.get('safari_views'))
|
||||
update_items.append(('safari_views', int(self.form.get('safari_views'))))
|
||||
if self.touched('safari_views_link'):
|
||||
feature.safari_views_link = self.parse_link('safari_views_link')
|
||||
update_items.append(('safari_views_link',
|
||||
self.parse_link('safari_views_link')))
|
||||
if self.touched('safari_views_notes'):
|
||||
feature.safari_views_notes = self.form.get('safari_views_notes')
|
||||
update_items.append(('safari_views_notes',
|
||||
self.form.get('safari_views_notes')))
|
||||
if self.touched('web_dev_views'):
|
||||
feature.web_dev_views = int(self.form.get('web_dev_views'))
|
||||
update_items.append(('web_dev_views',
|
||||
int(self.form.get('web_dev_views'))))
|
||||
if self.touched('web_dev_views'):
|
||||
feature.web_dev_views_link = self.parse_link('web_dev_views_link')
|
||||
update_items.append(('web_dev_views',
|
||||
self.parse_link('web_dev_views_link')))
|
||||
if self.touched('web_dev_views_notes'):
|
||||
feature.web_dev_views_notes = self.form.get('web_dev_views_notes')
|
||||
update_items.append(('web_dev_views_notes',
|
||||
self.form.get('web_dev_views_notes')))
|
||||
if self.touched('other_views_notes'):
|
||||
feature.other_views_notes = self.form.get('other_views_notes')
|
||||
update_items.append(('other_views_notes',
|
||||
self.form.get('other_views_notes')))
|
||||
if self.touched('prefixed'):
|
||||
feature.prefixed = self.form.get('prefixed') == 'on'
|
||||
update_items.append(('prefixed', self.form.get('prefixed') == 'on'))
|
||||
if self.touched('non_oss_deps'):
|
||||
feature.non_oss_deps = self.form.get('non_oss_deps')
|
||||
update_items.append(('non_oss_deps', self.form.get('non_oss_deps')))
|
||||
|
||||
if self.touched('tag_review'):
|
||||
feature.tag_review = self.form.get('tag_review')
|
||||
update_items.append(('tag_review', self.form.get('tag_review')))
|
||||
if self.touched('tag_review_status'):
|
||||
feature.tag_review_status = self.parse_int('tag_review_status')
|
||||
update_items.append(('tag_review_status',
|
||||
self.parse_int('tag_review_status')))
|
||||
if self.touched('webview_risks'):
|
||||
feature.webview_risks = self.form.get('webview_risks')
|
||||
update_items.append(('webview_risks', self.form.get('webview_risks')))
|
||||
|
||||
if self.touched('standardization'):
|
||||
feature.standardization = int(self.form.get('standardization'))
|
||||
if self.form.get('accurate_as_of'):
|
||||
feature.accurate_as_of = datetime.now()
|
||||
update_items.append(('accurate_as_of', datetime.now()))
|
||||
if self.touched('unlisted'):
|
||||
feature.unlisted = self.form.get('unlisted') == 'on'
|
||||
update_items.append(('unlisted', self.form.get('unlisted') == 'on'))
|
||||
if self.touched('comments'):
|
||||
feature.comments = self.form.get('comments')
|
||||
update_items.append(('feature_notes', self.form.get('comments')))
|
||||
if self.touched('experiment_goals'):
|
||||
feature.experiment_goals = self.form.get('experiment_goals')
|
||||
if self.touched('experiment_timeline'):
|
||||
|
@ -394,12 +502,21 @@ class FeatureEditHandler(basehandlers.FlaskHandler):
|
|||
'experiment_extension_reason')
|
||||
if self.touched('ongoing_constraints'):
|
||||
feature.ongoing_constraints = self.form.get('ongoing_constraints')
|
||||
update_items.append(('ongoing_constraints',
|
||||
self.form.get('ongoing_constraints')))
|
||||
|
||||
feature.updated_by = ndb.User(
|
||||
email=self.get_current_user().email(),
|
||||
_auth_domain='gmail.com')
|
||||
update_items.append(('updater', self.get_current_user().email()))
|
||||
key = feature.put()
|
||||
|
||||
# Write for new FeatureEntry entity.
|
||||
if feature_entry:
|
||||
for field, value in update_items:
|
||||
setattr(feature_entry, field, value)
|
||||
feature_entry.put()
|
||||
|
||||
# Remove all feature-related cache.
|
||||
rediscache.delete_keys_with_prefix(core_models.feature_cache_prefix())
|
||||
|
||||
|
|
|
@ -80,7 +80,16 @@ class FeatureCreateTest(testing_config.CustomTestCase):
|
|||
self.assertEqual(1, feature.category)
|
||||
self.assertEqual('Feature name', feature.name)
|
||||
self.assertEqual('Feature summary', feature.summary)
|
||||
|
||||
# Ensure FeatureEntry entity was also created.
|
||||
feature_entry = core_models.FeatureEntry.get_by_id(new_feature_id)
|
||||
self.assertEqual(1, feature_entry.category)
|
||||
self.assertEqual('Feature name', feature_entry.name)
|
||||
self.assertEqual('Feature summary', feature_entry.summary)
|
||||
self.assertEqual('user1@google.com', feature_entry.creator)
|
||||
|
||||
feature.key.delete()
|
||||
feature_entry.key.delete()
|
||||
|
||||
|
||||
class FeatureEditHandlerTest(testing_config.CustomTestCase):
|
||||
|
@ -93,6 +102,12 @@ class FeatureEditHandlerTest(testing_config.CustomTestCase):
|
|||
self.feature_1.put()
|
||||
self.stage = core_enums.INTENT_INCUBATE # Shows first form
|
||||
|
||||
self.feature_entry_1 = core_models.FeatureEntry(
|
||||
id=self.feature_1.key.integer_id(), name='feature one',
|
||||
summary='sum', owners=['user1@google.com'], category=1,
|
||||
standard_maturity=1, web_dev_views=1, impl_status_chrome=1)
|
||||
self.feature_entry_1.put()
|
||||
|
||||
self.request_path = ('/guide/stage/%d/%d' % (
|
||||
self.feature_1.key.integer_id(), self.stage))
|
||||
self.handler = guide.FeatureEditHandler()
|
||||
|
@ -173,3 +188,10 @@ class FeatureEditHandlerTest(testing_config.CustomTestCase):
|
|||
self.assertEqual('Revised feature name', revised_feature.name)
|
||||
self.assertEqual('Revised feature summary', revised_feature.summary)
|
||||
self.assertEqual(84, revised_feature.shipped_milestone)
|
||||
|
||||
# Ensure changes were also made to FeatureEntry entity
|
||||
revised_entry = core_models.FeatureEntry.get_by_id(
|
||||
self.feature_1.key.integer_id())
|
||||
self.assertEqual(2, revised_entry.category)
|
||||
self.assertEqual('Revised feature name', revised_entry.name)
|
||||
self.assertEqual('Revised feature summary', revised_entry.summary)
|
||||
|
|
Загрузка…
Ссылка в новой задаче