Test Failed
Push — master ( ef441d...0acd10 )
by Heiko 'riot'
04:41 queued 10s
created

isomer.schemata.base.geo_coordinate()   A

Complexity

Conditions 3

Size

Total Lines 33
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 23
nop 4
dl 0
loc 33
rs 9.328
c 0
b 0
f 0
1
#!/usr/bin/env python
2
# -*- coding: UTF-8 -*-
3
4
# Isomer - The distributed application framework
5
# ==============================================
6
# Copyright (C) 2011-2020 Heiko 'riot' Weinen <[email protected]> and others.
7
#
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU Affero General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU Affero General Public License for more details.
17
#
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21
"""
22
23
Schema: Base
24
============
25
26
Basic Isomer object schema utilities
27
28
Contains
29
--------
30
31
uuid_object: For inserting UUID fields
32
base_object: For generating a basic Isomer object schema
33
34
35
"""
36
37
from isomer.misc import all_languages
38
39
40
def geo_coordinate(
41
        title="Coordinate", description="A coordinate", default=None, display=True
42
):
43
    """Generates geo coordinate field"""
44
45
    result = {
46
        "type": "object",
47
        "title": title,
48
        "description": description,
49
        "additionalProperties": False,
50
        "properties": {
51
            'lat': {
52
                'type': 'string',
53
                'pattern': "^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)$",
54
                'title': 'Latitude',
55
                'description': 'From 90 Degrees North (+) to South (-)'
56
            },
57
            'lon': {
58
                'type': 'string',
59
                'pattern': '^[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$',
60
                'title': 'Longitude',
61
                'description': 'From 180 Degrees East (+) to West (-)'
62
            }
63
        }
64
    }
65
66
    if not display:
67
        result["x-schema-form"] = {"condition": "false"}
68
69
    if default is not None:
70
        result["default"] = default
71
72
    return result
73
74
75
def uuid_object(
76
        title="Reference", description="Select an object", default=None, display=True
77
):
78
    """Generates a regular expression controlled UUID field"""
79
80
    uuid = {
81
        "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]"
82
                   "{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$",
83
        "type": "string",
84
        "title": title,
85
        "description": description,
86
    }
87
88
    if not display:
89
        uuid["x-schema-form"] = {"condition": "false"}
90
91
    if default is not None:
92
        uuid["default"] = default
93
94
    return uuid
95
96
97
def base_object(
98
        name,
99
        no_additional=False,
100
        no_perms=False,
101
        no_color=False,
102
        has_owner=True,
103
        hide_owner=True,
104
        has_uuid=True,
105
        roles_write=None,
106
        roles_read=None,
107
        roles_list=None,
108
        roles_create=None,
109
        all_roles=None,
110
):
111
    """Generates a basic object with RBAC properties"""
112
    base_schema = {"id": "#" + name, "type": "object", "name": name, "properties": {}}
113
114
    if no_additional:
115
        base_schema['additionalProperties'] = False
116
117
    if not no_perms:
118
        if all_roles:
119
            roles_create = ["admin", all_roles]
120
            roles_write = ["admin", all_roles]
121
            roles_read = ["admin", all_roles]
122
            roles_list = ["admin", all_roles]
123
        else:
124
            if roles_write is None:
125
                roles_write = ["admin"]
126
            if roles_read is None:
127
                roles_read = ["admin"]
128
            if roles_list is None:
129
                roles_list = ["admin"]
130
            if roles_create is None:
131
                roles_create = ["admin"]
132
133
        if isinstance(roles_create, str):
134
            roles_create = [roles_create]
135
        if isinstance(roles_write, str):
136
            roles_write = [roles_write]
137
        if isinstance(roles_read, str):
138
            roles_read = [roles_read]
139
        if isinstance(roles_list, str):
140
            roles_list = [roles_list]
141
142
        if has_owner:
143
            roles_write.append("owner")
144
            roles_read.append("owner")
145
            roles_list.append("owner")
146
147
        base_schema["roles_create"] = roles_create
148
        base_schema["properties"].update(
149
            {
150
                "perms": {
151
                    "id": "#perms",
152
                    "type": "object",
153
                    "name": "perms",
154
                    "properties": {
155
                        "write": {
156
                            "type": "array",
157
                            "default": roles_write,
158
                            "items": {"type": "string"},
159
                        },
160
                        "read": {
161
                            "type": "array",
162
                            "default": roles_read,
163
                            "items": {"type": "string"},
164
                        },
165
                        "list": {
166
                            "type": "array",
167
                            "default": roles_list,
168
                            "items": {"type": "string"},
169
                        },
170
                    },
171
                    "default": {},
172
                    "x-schema-form": {"condition": "false"},
173
                },
174
                "name": {"type": "string", "description": "Name of " + name},
175
            }
176
        )
177
178
        if has_owner:
179
            # TODO: Schema should allow specification of non-local owners as
180
            #  well as special accounts like admin or even system perhaps
181
            # base_schema['required'] = base_schema.get('required', [])
182
            # base_schema['required'].append('owner')
183
            base_schema["properties"].update(
184
                {"owner": uuid_object(title="Unique Owner ID", display=hide_owner)}
185
            )
186
    else:
187
        base_schema["no_perms"] = True
188
189
    if not no_color:
190
        base_schema["properties"].update(
191
            {"color": {"type": "string", "format": "colorpicker"}}
192
        )
193
194
    # TODO: Using this causes all sorts of (obvious) problems with the object
195
    # manager
196
    if has_uuid:
197
        base_schema["properties"].update(
198
            {"uuid": uuid_object(title="Unique " + name + " ID", display=False)}
199
        )
200
        base_schema["required"] = ["uuid"]
201
202
    return base_schema
203
204
205
def sql_object(*args, **kwargs):
206
    """Generates a basic SQL object with RBAC properties"""
207
208
    base_schema = base_object(*args, **kwargs)
209
210
    base_schema["class-properties"] = base_schema["properties"]["perms"]
211
    del base_schema["properties"]["perms"]
212
213
    base_schema["sql"] = True
214
215
    return base_schema
216
217
218
def language_field():
219
    schema = {
220
        "type": "string",
221
        "enum": all_languages(),
222
        "title": "Language",
223
        "description": "Select a language",
224
    }
225
226
    return schema
227