2
2
3
3
const debug = require ( 'debug' ) ( 'loopback:mixin:readonly' )
4
4
5
+ function deletePropertiesFrom ( properties , data ) {
6
+ Object . keys ( properties ) . forEach ( key => {
7
+ debug ( 'The \'%s\' property is read only, removing incoming data' , key )
8
+ delete data [ key ]
9
+ } )
10
+ }
11
+
12
+ function replacePropertiesWithValuesFrom ( properties , from , to ) {
13
+ Object . keys ( properties ) . forEach ( key => {
14
+ const value = from [ key ]
15
+
16
+ debug ( 'The \'%s\' property is read only, replacing incoming data with existing value: %o' , key , value )
17
+ to [ key ] = value
18
+ } )
19
+ }
20
+
5
21
module . exports = Model => {
6
22
debug ( 'ReadOnly mixin for Model %s' , Model . modelName )
7
23
8
24
Model . on ( 'attached' , ( ) => {
9
- Model . stripReadOnlyProperties = ( modelName , ctx , next ) => {
25
+ Model . stripReadOnlyProperties = ( modelName , ctx , modelInstance , next ) => {
10
26
debug ( 'stripReadOnlyProperties for model %s (via remote method %o)' , modelName , ctx . methodString )
11
27
const { body } = ctx . req
12
28
@@ -17,14 +33,29 @@ module.exports = Model => {
17
33
const AffectedModel = Model . app . loopback . getModel ( modelName )
18
34
const options = AffectedModel . settings . mixins . ReadOnly
19
35
const properties = ( Object . keys ( options ) . length ) ? options : null
36
+ const instanceId = ctx . args [ AffectedModel . getIdName ( ) ]
20
37
21
38
if ( properties ) {
22
39
debug ( 'Found read only properties for model %s: %o' , modelName , properties )
23
- Object . keys ( properties ) . forEach ( key => {
24
- debug ( 'The \'%s\' property is read only, removing incoming data' , key )
25
- delete body [ key ]
26
- } )
40
+
41
+ // Handle the case for updating an existing instance.
42
+ if ( instanceId ) {
43
+ return AffectedModel . findById ( instanceId )
44
+ . then ( instance => {
45
+ if ( instance ) {
46
+ replacePropertiesWithValuesFrom ( properties , instance , body )
47
+ }
48
+ else {
49
+ deletePropertiesFrom ( properties , body )
50
+ }
51
+ return next ( )
52
+ } )
53
+ }
54
+
55
+ // Handle the case creating a new instance.
56
+ deletePropertiesFrom ( properties , body )
27
57
return next ( )
58
+
28
59
}
29
60
const err = new Error ( `Unable to update: ${ modelName } is read only.` )
30
61
@@ -34,31 +65,31 @@ module.exports = Model => {
34
65
35
66
// Handle native model methods.
36
67
Model . beforeRemote ( 'create' , ( ctx , modelInstance , next ) => {
37
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
68
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
38
69
} )
39
70
Model . beforeRemote ( 'upsert' , ( ctx , modelInstance , next ) => {
40
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
71
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
41
72
} )
42
73
Model . beforeRemote ( 'replaceOrCreate' , ( ctx , modelInstance , next ) => {
43
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
74
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
44
75
} )
45
76
Model . beforeRemote ( 'patchOrCreate' , ( ctx , modelInstance , next ) => {
46
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
77
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
47
78
} )
48
79
Model . beforeRemote ( 'prototype.updateAttributes' , ( ctx , modelInstance , next ) => {
49
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
80
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
50
81
} )
51
82
Model . beforeRemote ( 'prototype.patchAttributes' , ( ctx , modelInstance , next ) => {
52
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
83
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
53
84
} )
54
85
Model . beforeRemote ( 'updateAll' , ( ctx , modelInstance , next ) => {
55
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
86
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
56
87
} )
57
88
Model . beforeRemote ( 'upsertWithWhere' , ( ctx , modelInstance , next ) => {
58
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
89
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
59
90
} )
60
91
Model . beforeRemote ( 'replaceById' , ( ctx , modelInstance , next ) => {
61
- Model . stripReadOnlyProperties ( Model . modelName , ctx , next )
92
+ Model . stripReadOnlyProperties ( Model . modelName , ctx , modelInstance , next )
62
93
} )
63
94
64
95
// Handle updates via relationship.
@@ -71,7 +102,7 @@ module.exports = Model => {
71
102
72
103
Model . beforeRemote ( `prototype.__updateById__${ relationName } ` , ( ctx , modelInstance , next ) => {
73
104
if ( typeof AffectedModel . stripReadOnlyProperties === 'function' ) {
74
- return AffectedModel . stripReadOnlyProperties ( modelName , ctx , next )
105
+ return AffectedModel . stripReadOnlyProperties ( modelName , ctx , modelInstance , next )
75
106
}
76
107
return next ( )
77
108
} )
0 commit comments