diff --git a/runbot/controllers/__init__.py b/runbot/controllers/__init__.py index 96d149ab..24126c66 100644 --- a/runbot/controllers/__init__.py +++ b/runbot/controllers/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from . import api from . import frontend from . import hook -from . import badge +from . import badge \ No newline at end of file diff --git a/runbot/controllers/api.py b/runbot/controllers/api.py new file mode 100644 index 00000000..8ff065f9 --- /dev/null +++ b/runbot/controllers/api.py @@ -0,0 +1,69 @@ +import json +import logging +import time + +from odoo import http +from odoo.http import request +from odoo.tools import consteq + +_logger = logging.getLogger(__name__) + + +class RunbotController(http.Controller): + + @http.route('/runbot/api/web_search_read', type='http', auth='public', csrf=False) + def api_web_search_read(self, uid=None, token=None, model=None, specification=None, id=None, ids=None, domain=None, limit=200, offset=0, order=None): + """ + model: the model to read + fields: dictionnary + + Example of usage: + + requests.post( + 'http://127.0.0.1:8069/runbot/api/read', + data={ + 'uid': + 'token': '', + 'model': 'runbot.bundle', + 'domain':json.dumps([('sticky', '=', True), ('project_id', '=', 1)]), + 'specification': json.dumps({ + "id": {}, + 'name': {}, + 'last_done_batch': { + 'fields': { + 'commit_ids': { + 'fields': { + 'name': {} + } + } + } + } + }) + } + ).json() + """ + user = request.env['res.users'].sudo().browse(int(uid)) + if not user or not token or len(token) < 32 or not consteq(user.runbot_api_token, token): + time.sleep(1) + return json.dumps({'error': 'Invalid user or token'}) + request.env.cache.clear() + limit = max(min(2000, limit), 1) + if not model.startswith('runbot.'): + return json.dumps({'error': 'Invalid model'}) + if id: + ids = [id] + if ids: + domain = [('id', '=', ids)] + else: + domain = json.loads(domain) + if not domain: + return json.dumps({'error': 'Invalid domain'}) + specification = json.loads(specification) + + try: + user_env = request.env(user=user) + result = user_env[model].web_search_read(domain, specification, limit=limit, offset=offset, order=order) + return json.dumps(result) + except Exception: + _logger.exception('Something went wrong reading %s %s %s', model, specification, domain) + return json.dumps({'error': 'Something went wrong'}) diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index 438e5a6d..84dec69c 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -19,7 +19,7 @@ class BuildErrorLink(models.Model): _order = 'log_date desc, build_id desc' build_id = fields.Many2one('runbot.build', required=True, index=True) - build_error_id =fields.Many2one('runbot.build.error', required=True, index=True) + build_error_id = fields.Many2one('runbot.build.error', required=True, index=True, ondelete='cascade') log_date = fields.Datetime(string='Log date') host = fields.Char(related='build_id.host') dest = fields.Char(related='build_id.dest') diff --git a/runbot/models/user.py b/runbot/models/user.py index 1c14c773..b530c0c5 100644 --- a/runbot/models/user.py +++ b/runbot/models/user.py @@ -1,3 +1,4 @@ +import uuid from odoo import models, fields @@ -8,3 +9,9 @@ class User(models.Model): # Add default action_id action_id = fields.Many2one('ir.actions.actions', default=lambda self: self.env.ref('runbot.open_view_warning_tree', raise_if_not_found=False)) + runbot_api_token = fields.Char('API Token', help='The token to use to authenticate against the API') + + + def action_generate_token(self): + self.ensure_one() + self.runbot_api_token = uuid.uuid4().hex diff --git a/runbot/views/user.xml b/runbot/views/user.xml index ea901ec3..b901821d 100644 --- a/runbot/views/user.xml +++ b/runbot/views/user.xml @@ -46,6 +46,8 @@ +