diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 00000000..e69de29b diff --git a/generate_api_doc.py b/generate_api_doc.py new file mode 100755 index 00000000..b1c3f05b --- /dev/null +++ b/generate_api_doc.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys +import yaml +import json +import requests +from yunohost import str_to_func + +def main(): + """ + + """ + with open('action_map.yml') as f: + action_map = yaml.load(f) + + try: + with open('/etc/yunohost/current_host', 'r') as f: + domain = f.readline().rstrip() + except IOError: + domain = requests.get('http://ip.yunohost.org').text + + with open('action_map.yml') as f: + action_map = yaml.load(f) + + base_info = { + 'apiVersion': '0.1', + 'swaggerVersion': '1.1', + 'basePath': 'http://'+ domain + ':6767', + 'apis': [] + } + + resource_list = base_info + resources = {} + + for category, category_params in action_map.items(): + if 'category_help' not in category_params: category_params['category_help'] = '' + resource_path = '/'+ category + resource_list['apis'].append({ + 'path': resource_path, + 'description': category_params['category_help'] + }) + resources[category] = base_info + resources[category]['resourcePath'] = resource_path + + registered_paths = {} + + for action, action_params in category_params['actions'].items(): + if 'action_help' not in action_params: + action_params['action_help'] = '' + if 'api' not in action_params: + action_params['api'] = 'GET /'+ category +'/'+ action + + method, path = action_params['api'].split(' ') + path = path.replace('(?P<', '{').replace('>[^/]+)', '}') + key_param = '' + if '{' in path: + key_param = path[path.find("{")+1:path.find("}")] + + notes = '' + if str_to_func('yunohost_'+ category +'.'+ category +'_'+ action) is None: + notes = 'Not yet implemented' + + operation = { + 'httpMethod': method, + 'nickname': category +'_'+ action, + 'responseClass': 'container', + 'summary': action_params['action_help'], + 'notes': notes, + 'parameters': [], + 'errorResponses': [] + } + + if 'arguments' in action_params: + for arg_name, arg_params in action_params['arguments'].items(): + if 'help' not in arg_params: + arg_params['help'] = '' + param_type = 'query' + allow_multiple = False + required = True + allowable_values = {} + name = arg_name.replace('-', '_') + if name[0] == '_': + required = False + if 'nargs' not in arg_params: + allow_multiple = False + if 'full' in arg_params: + name = arg_params['full'][2:].replace('-', '_') + else: + name = arg_params[2:].replace('-', '_') + + if name == key_param: + param_type = 'path' + required = True + allow_multiple = False + + if 'nargs' in arg_params: + if arg_params['nargs'] == '*': + allow_multiple = True + required = False + if arg_params['nargs'] == '+': + allow_multiple = False + required = True + if 'choices' in arg_params: + allowable_values = { + 'valueType': 'LIST', + 'values': arg_params['choices'] + } + if 'action' in arg_params and arg_params['action'] == 'store_true': + allowable_values = { + 'valueType': 'LIST', + 'values': ['true', 'True', 'yes', 'Yes'] + } + + operation['parameters'].append({ + 'paramType': param_type, + 'name': name, + 'description': arg_params['help'], + 'dataType': 'string', + 'required': required, + 'allowableValues': allowable_values, + 'allowMultiple': allow_multiple + }) + + + if path in registered_paths: + resources[category]['apis'][registered_paths[path]]['operations'].append(operation) + resources[category]['apis'][registered_paths[path]]['description'] = '' + else: + registered_paths[path] = len(resources[category]['apis']) + resources[category]['apis'].append({ + 'path': path, + 'description': action_params['action_help'], + 'operations': operation + }) + + + for category, api_dict in resources.items(): + with open(os.getcwd() +'/doc/'+ category +'.json', 'w') as f: + json.dump(api_dict, f) + + with open(os.getcwd() +'/doc/'+ resources +'.json', 'w') as f: + json.dump(resource_list, f) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/yunohost.tac b/yunohost.tac index 5fca7f2b..32bf9da5 100755 --- a/yunohost.tac +++ b/yunohost.tac @@ -32,7 +32,7 @@ def http_exec(request, **kwargs): request.setResponseCode(200, 'OK') request.setHeader('Access-Control-Allow-Headers', 'Authorization') return '' - + # Simple HTTP auth else: authorized = request.getUser() == 'admin' @@ -45,7 +45,7 @@ def http_exec(request, **kwargs): request.setHeader('Access-Control-Allow-Origin', '*') request.setHeader('www-authenticate', 'Basic realm="Restricted Area"') return 'Unauthorized' - + path = request.path given_args = request.args if kwargs: @@ -53,9 +53,9 @@ def http_exec(request, **kwargs): dynamic_key = path.split('/')[-1] path = path.replace(dynamic_key, '(?P<'+ k +'>[^/]+)') given_args[k] = [v] - + print given_args - # Sanitize arguments + # Sanitize arguments dict = action_dict[request.method +' '+ path] if 'arguments' in dict: possible_args = dict['arguments'] else: possible_args = {} @@ -69,10 +69,10 @@ def http_exec(request, **kwargs): if 'nargs' not in params: possible_args[arg]['nargs'] = '*' if 'full' in params: - new_key = params['full'][2:] + new_key = params['full'][2:].replace('-', '_') else: - new_key = arg[2:] - possible_args[new_key] = possible_args[arg] + new_key = arg[2:].replace('-', '_') + possible_args[new_key] = possible_args[arg] del possible_args[arg] try: @@ -90,7 +90,7 @@ def http_exec(request, **kwargs): raise YunoHostError(22, _('Invalid argument') + ' ' + value) if 'action' in possible_args[key] and possible_args[key]['action'] == 'store_true': yes = ['true', 'True', 'yes', 'Yes'] - value = value in yes + value = value in yes validated_args[key] = value func = str_to_func(dict['function']) @@ -113,7 +113,7 @@ def http_exec(request, **kwargs): request.setResponseCode(204, 'No Content') else: request.setResponseCode(200, 'OK') - + except YunoHostError, error: # Set response code with function's raised code @@ -123,7 +123,7 @@ def http_exec(request, **kwargs): request.setResponseCode(400, 'Bad Request') else: request.setResponseCode(500, 'Internal Server Error') - + result = { 'error' : error.message } return json.dumps(result) @@ -140,8 +140,8 @@ def main(): del action_map['general_arguments'] for category, category_params in action_map.items(): for action, action_params in category_params['actions'].items(): - if 'help' not in action_params: - action_params['help'] = '' + if 'action_help' not in action_params: + action_params['action_help'] = '' if 'api' not in action_params: action_params['api'] = 'GET /'+ category +'/'+ action method, path = action_params['api'].split(' ') @@ -150,12 +150,12 @@ def main(): api.register('OPTIONS', path, http_exec) action_dict[action_params['api']] = { 'function': 'yunohost_'+ category +'.'+ category +'_'+ action, - 'help' : action_params['help'] + 'help' : action_params['action_help'] } - if 'arguments' in action_params: + if 'arguments' in action_params: action_dict[action_params['api']]['arguments'] = action_params['arguments'] - + # Register only postinstall action if YunoHost isn't completely set up try: with open('/etc/yunohost/installed') as f: pass