schema.py 8.26 KB
Newer Older
1
# copyright 2016-2021 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
Denis Laxalde's avatar
Denis Laxalde committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# contact http://www.logilab.fr -- mailto:contact@logilab.fr
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""cubicweb-dataprocessing schema"""
18

François Ferry's avatar
François Ferry committed
19
from yams.buildobjs import ComputedRelation, EntityType, RelationDefinition, Int, String
20

Denis Laxalde's avatar
Denis Laxalde committed
21
from cubicweb import _
François Ferry's avatar
François Ferry committed
22
23
24
25
26
27
from cubicweb.schema import (
    RRQLExpression,
    ERQLExpression,
    RQLConstraint,
    WorkflowableEntityType,
)
28

29
from cubicweb_file.schema import File
30
31
32


DATAPROCESS_UPDATE_PERMS_RQLEXPR = (
33
    'U in_group G, G name "users", '
François Ferry's avatar
François Ferry committed
34
35
    'X in_state S, S name "wfs_dataprocess_initialized"'
)
36
37
38
39
40


class _DataProcess(WorkflowableEntityType):
    __abstract__ = True
    __permissions__ = {
François Ferry's avatar
François Ferry committed
41
42
43
44
        "read": ("managers", "users", "guests"),
        "update": ("managers", ERQLExpression(DATAPROCESS_UPDATE_PERMS_RQLEXPR)),
        "delete": ("managers", ERQLExpression(DATAPROCESS_UPDATE_PERMS_RQLEXPR)),
        "add": ("managers", "users"),
45
46
47
48
49
50
51
52
53
54
55
56
    }


class DataTransformationProcess(_DataProcess):
    """Data transformation process"""


class DataValidationProcess(_DataProcess):
    """Data validation process"""


class process_depends_on(RelationDefinition):
François Ferry's avatar
François Ferry committed
57
58
59
    subject = "DataTransformationProcess"
    object = "DataValidationProcess"
    cardinality = "??"
60
61
62
63


class process_input_file(RelationDefinition):
    __permissions__ = {
François Ferry's avatar
François Ferry committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        "read": ("managers", "users", "guests"),
        "add": (
            "managers",
            RRQLExpression(
                'U in_group G, G name "users", '
                'S in_state ST, ST name "wfs_dataprocess_initialized"'
            ),
        ),
        "delete": ("managers", RRQLExpression("U has_update_permission S")),
    }
    subject = ("DataTransformationProcess", "DataValidationProcess")
    object = "File"
    cardinality = "?*"
    description = _("input file of the data process")
78
    constraints = [
François Ferry's avatar
François Ferry committed
79
80
81
        RQLConstraint(
            "NOT EXISTS(SC implemented_by O)", msg=_("file is used by a script")
        ),
82
    ]
83
84
85
86


class validated_by(RelationDefinition):
    """A File may be validated by a validation process"""
François Ferry's avatar
François Ferry committed
87
88
89
90
91

    __permissions__ = {"read": ("managers", "users", "guests"), "add": (), "delete": ()}
    subject = "File"
    object = "DataValidationProcess"
    cardinality = "**"
92
93
94
95


class produced_by(RelationDefinition):
    """A File may be produced by a transformation process"""
François Ferry's avatar
François Ferry committed
96
97
98
99
100

    __permissions__ = {"read": ("managers", "users", "guests"), "add": (), "delete": ()}
    subject = "File"
    object = "DataTransformationProcess"
    cardinality = "?*"
101
102


103
104
class process_stderr(RelationDefinition):
    __permissions__ = {
François Ferry's avatar
François Ferry committed
105
106
107
108
109
110
111
        "read": (
            "managers",
            "users",
            "guests",
        ),
        "add": (),
        "delete": (),
112
    }
François Ferry's avatar
François Ferry committed
113
114
115
    subject = ("DataTransformationProcess", "DataValidationProcess")
    object = "File"
    cardinality = "??"
116
    inlined = True
François Ferry's avatar
François Ferry committed
117
118
    composite = "subject"
    description = _("standard error output")
119
120


121
122
123
124
# Set File permissions:
#  * use `produced_by` relation to prevent modification of generated files
#  * bind the update permissions on the Script which uses the File as
#    implementation if any
François Ferry's avatar
François Ferry committed
125
126
127
128
129
130
131
132
133
_update_file_perms = (
    "managers",
    ERQLExpression(
        'U in_group G, G name "users", '
        "NOT EXISTS(X produced_by Y), "
        "NOT EXISTS(S1 implemented_by X)"
        " OR EXISTS(S implemented_by X, U has_update_permission S)"
    ),
)
134
File.__permissions__ = File.__permissions__.copy()
François Ferry's avatar
François Ferry committed
135
136
137
File.__permissions__.update(
    {"update": _update_file_perms, "delete": _update_file_perms}
)
138
139


Denis Laxalde's avatar
Denis Laxalde committed
140
141
142
143
144
145
class _Script(EntityType):
    name = String(required=True, fulltextindexed=True)


class implemented_by(RelationDefinition):
    __permissions__ = {
François Ferry's avatar
François Ferry committed
146
147
148
        "read": ("managers", "users", "guests"),
        "add": (RRQLExpression("U has_update_permission S"),),
        "delete": (RRQLExpression("U has_update_permission S"),),
Denis Laxalde's avatar
Denis Laxalde committed
149
    }
François Ferry's avatar
François Ferry committed
150
151
152
    subject = ("ValidationScript", "TransformationScript")
    object = "File"
    cardinality = "1?"
Denis Laxalde's avatar
Denis Laxalde committed
153
    inlined = True
François Ferry's avatar
François Ferry committed
154
155
    composite = "subject"
    description = _("the resource (file) implementing a script")
Denis Laxalde's avatar
Denis Laxalde committed
156
157
158


_validationscript_update_perms = (
François Ferry's avatar
François Ferry committed
159
160
161
162
163
164
165
    "managers",
    ERQLExpression(
        'U in_group G, G name "users", '
        "NOT EXISTS(P1 validation_script X) OR "
        "EXISTS(P2 validation_script X, P2 in_state S,"
        '       S name "wfs_dataprocess_initialized")'
    ),
Denis Laxalde's avatar
Denis Laxalde committed
166
167
168
169
170
)


class ValidationScript(_Script):
    __permissions__ = {
François Ferry's avatar
François Ferry committed
171
172
173
174
        "read": ("managers", "users", "guests"),
        "update": _validationscript_update_perms,
        "delete": _validationscript_update_perms,
        "add": ("managers", "users"),
Denis Laxalde's avatar
Denis Laxalde committed
175
176
    }
    parameters = String(
François Ferry's avatar
François Ferry committed
177
178
179
180
        description=_(
            "parameters for the script, will be used as JSON data " "structure"
        )
    )
Denis Laxalde's avatar
Denis Laxalde committed
181
182


183
class validation_script(RelationDefinition):
184
    __permissions__ = {
François Ferry's avatar
François Ferry committed
185
186
187
        "read": ("managers", "users", "guests"),
        "add": ("managers", "users"),
        "delete": (RRQLExpression("U has_update_permission S"),),
188
    }
François Ferry's avatar
François Ferry committed
189
190
191
    subject = "DataValidationProcess"
    object = "ValidationScript"
    cardinality = "1*"
192
    inlined = True
193
194


Denis Laxalde's avatar
Denis Laxalde committed
195
_transformationscript_update_perms = (
François Ferry's avatar
François Ferry committed
196
197
198
199
200
201
202
203
204
    "managers",
    ERQLExpression(
        'U in_group G, G name "users", '
        "NOT EXISTS(S1 step_script X, S1 in_sequence SQ1,"
        "           P1 transformation_sequence SQ1) OR "
        "EXISTS(S2 step_script X, S2 in_sequence SQ2,"
        "       P2 transformation_sequence SQ2, P2 in_state S,"
        '       S name "wfs_dataprocess_initialized")'
    ),
Denis Laxalde's avatar
Denis Laxalde committed
205
206
207
208
209
)


class TransformationScript(_Script):
    __permissions__ = {
François Ferry's avatar
François Ferry committed
210
211
212
213
        "read": ("managers", "users", "guests"),
        "update": _transformationscript_update_perms,
        "delete": _transformationscript_update_perms,
        "add": ("managers", "users"),
Denis Laxalde's avatar
Denis Laxalde committed
214
    }
François Ferry's avatar
François Ferry committed
215
216
217
    output_format = String(
        maxsize=128, description=_("format (MIME type) of stderr data")
    )
Denis Laxalde's avatar
Denis Laxalde committed
218
219


220
class transformation_sequence(RelationDefinition):
221
    __permissions__ = {
François Ferry's avatar
François Ferry committed
222
223
224
        "read": ("managers", "users"),
        "add": (RRQLExpression("U has_update_permission S"),),
        "delete": (RRQLExpression("U has_update_permission S"),),
225
    }
François Ferry's avatar
François Ferry committed
226
227
228
    subject = "DataTransformationProcess"
    object = "TransformationSequence"
    cardinality = "1*"
229
230


231
_transformationsequence_update_perms = (
François Ferry's avatar
François Ferry committed
232
233
234
235
236
237
    ERQLExpression(
        'U in_group G, G name IN ("managers", "users"), '
        "NOT EXISTS(P transformation_sequence X) OR "
        "EXISTS(P transformation_sequence X,"
        '       P name "wfs_dataprocess_initialized")'
    ),
238
239
240
)


Denis Laxalde's avatar
Denis Laxalde committed
241
242
class TransformationSequence(EntityType):
    """A sequence of scripts involved in a given process."""
François Ferry's avatar
François Ferry committed
243

244
    __permissions__ = {
François Ferry's avatar
François Ferry committed
245
246
247
248
        "read": ("managers", "users", "guests"),
        "update": _transformationsequence_update_perms,
        "delete": _transformationsequence_update_perms,
        "add": ("managers", "users"),
249
    }
250
251


Denis Laxalde's avatar
Denis Laxalde committed
252
253
class TransformationStep(EntityType):
    """A step in a transformation sequence."""
François Ferry's avatar
François Ferry committed
254

255
    # TODO __permissions__
François Ferry's avatar
François Ferry committed
256
    index = Int(required=True, description=_("position in the transformation sequence"))
Denis Laxalde's avatar
Denis Laxalde committed
257
    parameters = String(
François Ferry's avatar
François Ferry committed
258
259
260
261
262
        description=_(
            "parameters for the script, will be used as JSON data " "structure"
        )
    )
    __unique_together__ = [("index", "in_sequence"), ("in_sequence", "step_script")]
263
264


Denis Laxalde's avatar
Denis Laxalde committed
265
class step_script(RelationDefinition):
266
    # TODO __permissions__
François Ferry's avatar
François Ferry committed
267
268
269
    subject = "TransformationStep"
    object = "TransformationScript"
    cardinality = "1*"
270
271
272
    inlined = True


Denis Laxalde's avatar
Denis Laxalde committed
273
class in_sequence(RelationDefinition):
274
    # TODO __permissions__
François Ferry's avatar
François Ferry committed
275
276
277
278
    subject = "TransformationStep"
    object = "TransformationSequence"
    cardinality = "1+"
    composite = "object"
Denis Laxalde's avatar
Denis Laxalde committed
279
    inlined = True
280
281


282
class transformation_scripts(ComputedRelation):
François Ferry's avatar
François Ferry committed
283
    rule = "S transformation_sequence SEQ, O in_sequence SEQ"