Add support for user correction

When user_id changes, the obsoleted association between old user_id
and emails needs to be corrected. This is done by extending user profile
update method to apply user corrections from `corrections.json`

Related-Bug: #1634020
Change-Id: I580826afbdc2322555a22b12f80b15a0ef3167fb
This commit is contained in:
Yujun Zhang 2017-01-28 21:04:15 +08:00
parent 96ec7c6c63
commit bac722a749
6 changed files with 97 additions and 5 deletions

View File

@ -2995,5 +2995,12 @@
"module": "openstack-manuals", "module": "openstack-manuals",
"subject": "Cleanup the common/ directory" "subject": "Cleanup the common/ directory"
} }
],
"user_corrections": [
{
"correction_comment": "Reset emails (Related-Bug: #1634020)",
"user_id": "zhangyujun",
"emails": ["yujun.zhang@easystack.cn","284517620@qq.com"]
}
] ]
} }

View File

@ -1,7 +1,7 @@
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"type": "object", "type": "object",
"required": ["corrections"], "required": ["corrections", "user_corrections"],
"properties": { "properties": {
"corrections": { "corrections": {
"type": "array", "type": "array",
@ -41,6 +41,28 @@
}, },
"required": ["primary_key", "correction_comment"] "required": ["primary_key", "correction_comment"]
} }
},
"user_corrections": {
"type": "array",
"items": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"pattern": "^[\\S]+$"
},
"emails": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-z\\d_\\.-]+@([a-z\\d\\.-]+\\.)+[a-z]+$"
}
},
"correction_comment": {
"type": "string"
}
}
}
} }
} }
} }

View File

@ -262,6 +262,14 @@ def apply_corrections(uri, runtime_storage_inst):
LOG.warning('Correction misses primary key: %s', c) LOG.warning('Correction misses primary key: %s', c)
runtime_storage_inst.apply_corrections(valid_corrections) runtime_storage_inst.apply_corrections(valid_corrections)
valid_user_corrections = []
for u in corrections['user_corrections']:
if 'user_id' in u:
valid_user_corrections.append(c)
else:
LOG.warning('User correction misses user_id: %s', u)
runtime_storage_inst.apply_user_corrections(valid_user_corrections)
def process_project_list(runtime_storage_inst): def process_project_list(runtime_storage_inst):
module_groups = runtime_storage_inst.get_by_key('module_groups') or {} module_groups = runtime_storage_inst.get_by_key('module_groups') or {}

View File

@ -19,6 +19,8 @@ import memcache
from oslo_log import log as logging from oslo_log import log as logging
import six import six
from stackalytics.processor import user_processor
from stackalytics.processor import utils from stackalytics.processor import utils
@ -123,6 +125,15 @@ class MemcachedStorage(RuntimeStorage):
self.set_by_key(self._get_record_name(record_id), original) self.set_by_key(self._get_record_name(record_id), original)
self._commit_update(record_id) self._commit_update(record_id)
def apply_user_corrections(self, user_corrections_iterator):
for user_correction in user_corrections_iterator:
stored_user = user_processor.load_user(self,
user_id=user_correction[
'user_id'])
updated_user = user_processor.update_user_profile(
stored_user, user_correction, is_correction=True)
user_processor.store_user(self, updated_user)
def inc_user_count(self): def inc_user_count(self):
return self.memcached.incr('user:count') return self.memcached.incr('user:count')

View File

@ -91,13 +91,19 @@ def delete_user(runtime_storage_inst, user):
runtime_storage_inst.delete_by_key('user:%s' % user['seq']) runtime_storage_inst.delete_by_key('user:%s' % user['seq'])
def update_user_profile(stored_user, user): def update_user_profile(stored_user, user, is_correction=False):
# update stored_user with user and return it # update stored_user with user and return it
if stored_user: if stored_user:
updated_user = copy.deepcopy(stored_user) updated_user = copy.deepcopy(stored_user)
updated_user.update(user) updated_user.update(user)
updated_user['emails'] = list(set(stored_user.get('emails', [])) | if is_correction:
set(user.get('emails', []))) updated_user['emails'] = user.get('emails',
stored_user.get('emails', []))
updated_user['corrections'] = stored_user.get('corrections', [])\
+ [user.get('correction_comment', '')]
else:
updated_user['emails'] = list(set(stored_user.get('emails', [])) |
set(user.get('emails', [])))
else: else:
updated_user = copy.deepcopy(user) updated_user = copy.deepcopy(user)
updated_user['static'] = True updated_user['static'] = True

View File

@ -66,6 +66,44 @@ class TestUserProcessor(testtools.TestCase):
# static flag must present # static flag must present
self.assertTrue(updated_user.get('static')) self.assertTrue(updated_user.get('static'))
def test_update_user_with_correction(self):
user_correction = {
"user_id": "user",
"correction_comment": "Reset emails",
"emails": ["updated@smith.com"]
}
stored_user = {
"launchpad_id": "user",
"companies": [
{
"company_name": "Rackspace",
"end_date": "2011-Nov-20"
},
{
"company_name": "IBM",
"end_date": None
}
],
"user_name": "Johnny",
"emails": ["obsoleted@smith.com"],
"corrections": ["Old correction"],
"static": True
}
updated_user = user_processor.update_user_profile(stored_user,
user_correction,
is_correction=True)
# reset emails from correction
self.assertEqual(set(user_correction['emails']),
set(updated_user['emails']))
# save correction history
self.assertEqual(updated_user['corrections'],
["Old correction", "Reset emails"])
# static flag must present
self.assertTrue(updated_user.get('static'))
def test_update_user_unknown_user(self): def test_update_user_unknown_user(self):
user = { user = {
"launchpad_id": "user", "launchpad_id": "user",