[IMP] runbot_merge: provisioning features

A few fixes and improvements after testing the feature:

- ensure the provisioned users are created as internal (not portal)
- assume oauth is installed and just crash if it's not
- handle a user not having an email (ignore)
- return value from json handler, otherwise JsonRequest sends no
  payload which is *weird*
This commit is contained in:
Xavier Morel 2022-06-09 15:16:47 +02:00
parent 96f8f4e688
commit 4a3cde2faa
4 changed files with 30 additions and 21 deletions

View File

@ -1129,17 +1129,8 @@ class Model:
def create(self, values): def create(self, values):
return Model(self._env, self._model, [self._env(self._model, 'create', values)]) return Model(self._env, self._model, [self._env(self._model, 'create', values)])
def write(self, values): def check_object_reference(self, *args, **kwargs):
return self._env(self._model, 'write', self._ids, values) return self.env(self._model, 'check_object_reference', *args, **kwargs)
def read(self, fields):
return self._env(self._model, 'read', self._ids, fields)
def name_get(self):
return self._env(self._model, 'name_get', self._ids)
def unlink(self):
return self._env(self._model, 'unlink', self._ids)
def sorted(self, field): def sorted(self, field):
rs = sorted(self.read([field]), key=lambda r: r[field]) rs = sorted(self.read([field]), key=lambda r: r[field])

View File

@ -0,0 +1 @@
ADD: automated provisioning of accounts from odoo.com

View File

@ -20,6 +20,7 @@ class MergebotReviewerProvisioning(Controller):
'email': u.email, 'email': u.email,
} }
for u in env['res.users'].search([]) for u in env['res.users'].search([])
if u.github_login
] ]
@from_role('accounts') @from_role('accounts')
@ -56,22 +57,27 @@ class MergebotReviewerProvisioning(Controller):
# unique, and should not be able to collide with emails # unique, and should not be able to collide with emails
partners[p.github_login] = p partners[p.github_login] = p
if 'oauth_provider_id' in Users: internal = env.ref('base.group_user')
odoo_provider = env.ref('auth_oauth.provider_openerp', False) odoo_provider = env.ref('auth_oauth.provider_openerp')
if odoo_provider:
for new in users:
if 'sub' in new:
new['oauth_provider_id'] = odoo_provider.id
new['oauth_uid'] = new.pop('sub')
to_create = [] to_create = []
created = updated = 0 created = updated = 0
for new in users: for new in users:
if 'sub' in new:
new['oauth_provider_id'] = odoo_provider.id
new['oauth_uid'] = new.pop('sub')
# prioritise by github_login as that's the unique-est point of information # prioritise by github_login as that's the unique-est point of information
current = partners.get(new['github_login']) or partners.get(new['email']) or Partners current = partners.get(new['github_login']) or partners.get(new['email']) or Partners
# entry doesn't have user -> create user # entry doesn't have user -> create user
if not current.user_ids: if not current.user_ids:
# skip users without an email (= login) as that
# fails
if not new['email']:
continue
new['login'] = new['email'] new['login'] = new['email']
new['groups_id'] = [(4, internal.id)]
# entry has partner -> create user linked to existing partner # entry has partner -> create user linked to existing partner
# (and update partner implicitly) # (and update partner implicitly)
if current: if current:
@ -94,8 +100,9 @@ class MergebotReviewerProvisioning(Controller):
user.write(update_vals) user.write(update_vals)
updated += 1 updated += 1
if to_create: if to_create:
Users.create(to_create) # only create 100 users at a time to avoid request timeout
created = len(to_create) Users.create(to_create[:100])
created = len(to_create[:100])
_logger.info("Provisioning: created %d updated %d.", created, updated) _logger.info("Provisioning: created %d updated %d.", created, updated)
return [created, updated] return [created, updated]
@ -121,3 +128,4 @@ class MergebotReviewerProvisioning(Controller):
partners.mapped('user_ids').write({ partners.mapped('user_ids').write({
'groups_id': [(6, 0, [request.env.ref('base.group_portal').id])] 'groups_id': [(6, 0, [request.env.ref('base.group_portal').id])]
}) })
return True

View File

@ -8,7 +8,6 @@ GEORGE = {
'sub': '19321102' 'sub': '19321102'
} }
def test_basic_provisioning(env, port): def test_basic_provisioning(env, port):
r = provision_user(port, [GEORGE]) r = provision_user(port, [GEORGE])
assert r == [1, 0] assert r == [1, 0]
@ -16,6 +15,10 @@ def test_basic_provisioning(env, port):
assert g.partner_id.name == GEORGE['name'] assert g.partner_id.name == GEORGE['name']
assert g.partner_id.github_login == GEORGE['github_login'] assert g.partner_id.github_login == GEORGE['github_login']
assert g.oauth_uid == GEORGE['sub'] assert g.oauth_uid == GEORGE['sub']
(model, g_id) = env['ir.model.data']\
.check_object_reference('base', 'group_user')
assert model == 'res.groups'
assert g.groups_id.id == g_id, "check that users were provisioned as internal (not portal)"
# repeated provisioning should be a no-op # repeated provisioning should be a no-op
r = provision_user(port, [GEORGE]) r = provision_user(port, [GEORGE])
@ -79,6 +82,12 @@ def test_upgrade_partner(env, port):
p.user_ids.unlink() p.user_ids.unlink()
p.unlink() p.unlink()
def test_no_email(env, port):
""" Provisioning system should ignore email-less entries
"""
r = provision_user(port, [{**GEORGE, 'email': None}])
assert r == [0, 0]
def provision_user(port, users): def provision_user(port, users):
r = requests.post(f'http://localhost:{port}/runbot_merge/provision', json={ r = requests.post(f'http://localhost:{port}/runbot_merge/provision', json={
'jsonrpc': '2.0', 'jsonrpc': '2.0',