blueprints.py 7.04 KB
Newer Older
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
1
2
#!/usr/bin/python
# -*- coding: utf-8 -*-
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
3
4
# Copyright 2014 J. Fernando Sánchez Rada - Grupo de Sistemas Inteligentes
# DIT, UPM
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
5
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
6
7
8
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
9
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
10
# http://www.apache.org/licenses/LICENSE-2.0
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
11
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
12
# Unless required by applicable law or agreed to in writing, software
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
13
14
15
16
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
17
18
19
"""
Blueprints for Senpy
"""
20
21
from flask import Blueprint, request, current_app, render_template, url_for, jsonify
from .models import Error, Response, Plugins, read_schema
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
22
from future.utils import iteritems
23
from functools import wraps
24

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
25
import json
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
26
import logging
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
27

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
28
29
logger = logging.getLogger(__name__)

30
31
api_blueprint = Blueprint("api", __name__)
demo_blueprint = Blueprint("demo", __name__)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
32

33
API_PARAMS = {
34
35
36
37
38
39
40
41
    "algorithm": {
        "aliases": ["algorithm", "a", "algo"],
        "required": False,
    },
    "inHeaders": {
        "aliases": ["inHeaders", "headers"],
        "required": True,
        "default": "0"
42
43
44
45
46
47
48
    },
    "prefix": {
        "@id": "prefix",
        "aliases": ["prefix", "p"],
        "required": True,
        "default": "",
    },
49
50
}

51
NIF_PARAMS = {
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    "algorithm": {
        "aliases": ["algorithm", "a", "algo"],
        "required": False,
    },
    "inHeaders": {
        "aliases": ["inHeaders", "headers"],
        "required": True,
        "default": "0"
    },
    "input": {
        "@id": "input",
        "aliases": ["i", "input"],
        "required": True,
        "help": "Input text"
    },
    "informat": {
        "@id": "informat",
        "aliases": ["f", "informat"],
        "required": False,
        "default": "text",
        "options": ["turtle", "text"],
    },
    "intype": {
        "@id": "intype",
        "aliases": ["intype", "t"],
        "required": False,
        "default": "direct",
        "options": ["direct", "url", "file"],
    },
    "outformat": {
        "@id": "outformat",
        "aliases": ["outformat", "o"],
        "default": "json-ld",
        "required": False,
        "options": ["json-ld"],
    },
    "language": {
        "@id": "language",
        "aliases": ["language", "l"],
        "required": False,
    },
    "prefix": {
        "@id": "prefix",
        "aliases": ["prefix", "p"],
        "required": True,
        "default": "",
    },
    "urischeme": {
        "@id": "urischeme",
        "aliases": ["urischeme", "u"],
        "required": False,
        "default": "RFC5147String",
        "options": "RFC5147String"
    },
}

108
def update_params(req, params=NIF_PARAMS):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
109
110
    if req.method == 'POST':
        indict = req.form
J. Fernando Sánchez's avatar
Oups    
J. Fernando Sánchez committed
111
    elif req.method == 'GET':
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
112
113
        indict = req.args
    else:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
114
        raise Error(message="Invalid data")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
115
116

    outdict = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
117
    wrong_params = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
118
    for param, options in iteritems(params):
119
120
121
122
123
124
125
126
127
128
129
        if param[0] != "@":  # Exclude json-ld properties
            logger.debug("Param: %s - Options: %s", param, options)
            for alias in options["aliases"]:
                if alias in indict:
                    outdict[param] = indict[alias]
            if param not in outdict:
                if options.get("required", False) and "default" not in options:
                    wrong_params[param] = params[param]
                else:
                    if "default" in options:
                        outdict[param] = options["default"]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
130
            else:
131
132
133
                if "options" in params[param] and \
                   outdict[param] not in params[param]["options"]:
                    wrong_params[param] = params[param]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
134
    if wrong_params:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
135
136
137
138
139
        message = Error(status=404,
                        message="Missing or invalid parameters",
                        parameters=outdict,
                        errors={param: error for param, error in
                                iteritems(wrong_params)})
140
141
142
143
144
        raise message
    if hasattr(request, 'params'):
        request.params.update(outdict)
    else:
        request.params = outdict
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
145
146
    return outdict

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
147

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
148
@demo_blueprint.route('/')
Ignacio Corcuera's avatar
Ignacio Corcuera committed
149
150
151
def index():
    return render_template("index.html")

152
153
154
@api_blueprint.route('/contexts/<entity>.jsonld')
def context(entity="context"):
    return jsonify({"@context": Response.context})
Ignacio Corcuera's avatar
Ignacio Corcuera committed
155

156
157
@api_blueprint.route('/schemas/<schema>')
def schema(schema="definitions"):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
158
    try:
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
        return jsonify(read_schema(schema))
    except Exception: # Should be FileNotFoundError, but it's missing from py2
        return Error(message="Schema not found", status=404).flask()

def basic_api(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        print('Getting request:')
        print(request)
        update_params(request, params=API_PARAMS)
        print('Params: %s' % request.params)
        try:
            response = f(*args, **kwargs)
        except Error as ex:
            response = ex
        in_headers = request.params["inHeaders"] != "0"
        prefix = request.params["prefix"]
        headers = {'X-ORIGINAL-PARAMS': request.params}
        return response.flask(in_headers=in_headers,
                              prefix=prefix,
                              headers=headers,
                              context_uri=url_for('api.context', entity=type(response).__name__,
                                                  _external=True))
    return decorated_function
    
@api_blueprint.route('/', methods=['POST', 'GET'])
@basic_api
def api():
    algo = request.params.get("algorithm", None)
    specific_params = current_app.senpy.parameters(algo)
    update_params(request, params=NIF_PARAMS)
    logger.debug("Specific params: %s", json.dumps(specific_params, indent=4))
    update_params(request, specific_params)
    response = current_app.senpy.analyse(**request.params)
    return response


@api_blueprint.route('/plugins/', methods=['POST', 'GET'])
@basic_api
198
199
200
def plugins():
    sp = current_app.senpy
    dic = Plugins(plugins=list(sp.plugins.values()))
201
    return dic
202
    
203
204
205
@api_blueprint.route('/plugins/<plugin>/', methods=['POST', 'GET'])
@api_blueprint.route('/plugins/<plugin>/<action>', methods=['POST', 'GET'])
@basic_api
206
def plugin(plugin=None, action="list"):
207
    filt = {}
208
    sp = current_app.senpy
209
210
211
212
213
214
215
    plugs = sp.filter_plugins(name=plugin)
    if plugin == 'default' and sp.default_plugin:
        response = sp.default_plugin
        plugin = response.name
    elif plugin in sp.plugins:
        response = sp.plugins[plugin]
    else:
216
        return Error(message="Plugin not found", status=404)
217
    if action == "list":
218
        return response
219
220
221
    method = "{}_plugin".format(action)
    if(hasattr(sp, method)):
        getattr(sp, method)(plugin)
222
        return Response(message="Ok")
223
    else:
224
        return Error(message="action '{}' not allowed".format(action))
225

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
226
if __name__ == '__main__':
227
    import config
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
228

229
    app.register_blueprint(api_blueprint)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
230
    app.debug = config.DEBUG
Ignacio Corcuera's avatar
Ignacio Corcuera committed
231
    app.run(host='0.0.0.0', port=5000)