@kalisio/kdk 2.5.2 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/core/client/components/input/KShapePicker.vue +4 -4
  2. package/coverage/core/api/application.js.html +344 -344
  3. package/coverage/core/api/authentication.js.html +79 -79
  4. package/coverage/core/api/db.js.html +167 -167
  5. package/coverage/core/api/hooks/hooks.authentication.js.html +12 -12
  6. package/coverage/core/api/hooks/hooks.authorisations.js.html +166 -163
  7. package/coverage/core/api/hooks/hooks.groups.js.html +1 -1
  8. package/coverage/core/api/hooks/hooks.logger.js.html +18 -18
  9. package/coverage/core/api/hooks/hooks.model.js.html +280 -268
  10. package/coverage/core/api/hooks/hooks.organisations.js.html +1 -1
  11. package/coverage/core/api/hooks/hooks.push.js.html +12 -12
  12. package/coverage/core/api/hooks/hooks.query.js.html +92 -92
  13. package/coverage/core/api/hooks/hooks.schemas.js.html +13 -13
  14. package/coverage/core/api/hooks/hooks.service.js.html +28 -28
  15. package/coverage/core/api/hooks/hooks.storage.js.html +7 -7
  16. package/coverage/core/api/hooks/hooks.users.js.html +48 -48
  17. package/coverage/core/api/hooks/index.html +49 -49
  18. package/coverage/core/api/hooks/index.js.html +11 -11
  19. package/coverage/core/api/index.html +42 -42
  20. package/coverage/core/api/index.js.html +22 -22
  21. package/coverage/core/api/marshall.js.html +127 -127
  22. package/coverage/core/api/models/groups.model.mongodb.js.html +1 -1
  23. package/coverage/core/api/models/index.html +1 -1
  24. package/coverage/core/api/models/messages.model.mongodb.js.html +1 -1
  25. package/coverage/core/api/models/organisations.model.mongodb.js.html +1 -1
  26. package/coverage/core/api/models/tags.model.mongodb.js.html +1 -1
  27. package/coverage/core/api/models/users.model.mongodb.js.html +11 -11
  28. package/coverage/core/api/services/account/account.hooks.js.html +42 -42
  29. package/coverage/core/api/services/account/account.service.js.html +34 -34
  30. package/coverage/core/api/services/account/index.html +1 -1
  31. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +34 -34
  32. package/coverage/core/api/services/authorisations/authorisations.service.js.html +108 -120
  33. package/coverage/core/api/services/authorisations/index.html +19 -19
  34. package/coverage/core/api/services/databases/databases.hooks.js.html +1 -1
  35. package/coverage/core/api/services/databases/databases.service.js.html +1 -1
  36. package/coverage/core/api/services/databases/index.html +1 -1
  37. package/coverage/core/api/services/groups/groups.hooks.js.html +1 -1
  38. package/coverage/core/api/services/groups/index.html +1 -1
  39. package/coverage/core/api/services/import-export/import-export.hooks.js.html +1 -1
  40. package/coverage/core/api/services/import-export/import-export.service.js.html +1 -1
  41. package/coverage/core/api/services/import-export/index.html +1 -1
  42. package/coverage/core/api/services/index.html +15 -15
  43. package/coverage/core/api/services/index.js.html +97 -85
  44. package/coverage/core/api/services/mailer/index.html +1 -1
  45. package/coverage/core/api/services/mailer/mailer.hooks.js.html +1 -1
  46. package/coverage/core/api/services/mailer/mailer.service.js.html +1 -1
  47. package/coverage/core/api/services/messages/index.html +5 -5
  48. package/coverage/core/api/services/messages/messages.hooks.js.html +11 -8
  49. package/coverage/core/api/services/organisations/index.html +1 -1
  50. package/coverage/core/api/services/organisations/organisations.hooks.js.html +1 -1
  51. package/coverage/core/api/services/organisations/organisations.service.js.html +1 -1
  52. package/coverage/core/api/services/push/index.html +1 -1
  53. package/coverage/core/api/services/push/push.hooks.js.html +1 -1
  54. package/coverage/core/api/services/push/push.service.js.html +1 -1
  55. package/coverage/core/api/services/storage/index.html +1 -1
  56. package/coverage/core/api/services/storage/storage.hooks.js.html +36 -36
  57. package/coverage/core/api/services/storage/storage.service.js.html +30 -30
  58. package/coverage/core/api/services/tags/index.html +1 -1
  59. package/coverage/core/api/services/tags/tags.hooks.js.html +1 -1
  60. package/coverage/core/api/services/users/index.html +7 -7
  61. package/coverage/core/api/services/users/users.hooks.js.html +83 -80
  62. package/coverage/core/api/services/users/users.service.js.html +4 -4
  63. package/coverage/core/api/utils.js.html +1 -1
  64. package/coverage/core/common/errors.js.html +2 -2
  65. package/coverage/core/common/index.html +30 -30
  66. package/coverage/core/common/index.js.html +11 -11
  67. package/coverage/core/common/permissions.js.html +187 -187
  68. package/coverage/core/common/schema.js.html +26 -26
  69. package/coverage/core/common/utils.js.html +61 -61
  70. package/coverage/core/common/utils.offline.js.html +6 -6
  71. package/coverage/index.html +179 -164
  72. package/coverage/lcov-report/core/api/application.js.html +344 -344
  73. package/coverage/lcov-report/core/api/authentication.js.html +79 -79
  74. package/coverage/lcov-report/core/api/db.js.html +167 -167
  75. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +12 -12
  76. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +166 -163
  77. package/coverage/lcov-report/core/api/hooks/hooks.groups.js.html +1 -1
  78. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +18 -18
  79. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +280 -268
  80. package/coverage/lcov-report/core/api/hooks/hooks.organisations.js.html +1 -1
  81. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +12 -12
  82. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +92 -92
  83. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +13 -13
  84. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +28 -28
  85. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +7 -7
  86. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +48 -48
  87. package/coverage/lcov-report/core/api/hooks/index.html +49 -49
  88. package/coverage/lcov-report/core/api/hooks/index.js.html +11 -11
  89. package/coverage/lcov-report/core/api/index.html +42 -42
  90. package/coverage/lcov-report/core/api/index.js.html +22 -22
  91. package/coverage/lcov-report/core/api/marshall.js.html +127 -127
  92. package/coverage/lcov-report/core/api/models/groups.model.mongodb.js.html +1 -1
  93. package/coverage/lcov-report/core/api/models/index.html +1 -1
  94. package/coverage/lcov-report/core/api/models/messages.model.mongodb.js.html +1 -1
  95. package/coverage/lcov-report/core/api/models/organisations.model.mongodb.js.html +1 -1
  96. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +1 -1
  97. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +11 -11
  98. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +42 -42
  99. package/coverage/lcov-report/core/api/services/account/account.service.js.html +34 -34
  100. package/coverage/lcov-report/core/api/services/account/index.html +1 -1
  101. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +34 -34
  102. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +108 -120
  103. package/coverage/lcov-report/core/api/services/authorisations/index.html +19 -19
  104. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +1 -1
  105. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +1 -1
  106. package/coverage/lcov-report/core/api/services/databases/index.html +1 -1
  107. package/coverage/lcov-report/core/api/services/groups/groups.hooks.js.html +1 -1
  108. package/coverage/lcov-report/core/api/services/groups/index.html +1 -1
  109. package/coverage/lcov-report/core/api/services/import-export/import-export.hooks.js.html +1 -1
  110. package/coverage/lcov-report/core/api/services/import-export/import-export.service.js.html +1 -1
  111. package/coverage/lcov-report/core/api/services/import-export/index.html +1 -1
  112. package/coverage/lcov-report/core/api/services/index.html +15 -15
  113. package/coverage/lcov-report/core/api/services/index.js.html +97 -85
  114. package/coverage/lcov-report/core/api/services/mailer/index.html +1 -1
  115. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +1 -1
  116. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +1 -1
  117. package/coverage/lcov-report/core/api/services/messages/index.html +5 -5
  118. package/coverage/lcov-report/core/api/services/messages/messages.hooks.js.html +11 -8
  119. package/coverage/lcov-report/core/api/services/organisations/index.html +1 -1
  120. package/coverage/lcov-report/core/api/services/organisations/organisations.hooks.js.html +1 -1
  121. package/coverage/lcov-report/core/api/services/organisations/organisations.service.js.html +1 -1
  122. package/coverage/lcov-report/core/api/services/push/index.html +1 -1
  123. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +1 -1
  124. package/coverage/lcov-report/core/api/services/push/push.service.js.html +1 -1
  125. package/coverage/lcov-report/core/api/services/storage/index.html +1 -1
  126. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +36 -36
  127. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +30 -30
  128. package/coverage/lcov-report/core/api/services/tags/index.html +1 -1
  129. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +1 -1
  130. package/coverage/lcov-report/core/api/services/users/index.html +7 -7
  131. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +83 -80
  132. package/coverage/lcov-report/core/api/services/users/users.service.js.html +4 -4
  133. package/coverage/lcov-report/core/api/utils.js.html +1 -1
  134. package/coverage/lcov-report/core/common/errors.js.html +2 -2
  135. package/coverage/lcov-report/core/common/index.html +30 -30
  136. package/coverage/lcov-report/core/common/index.js.html +11 -11
  137. package/coverage/lcov-report/core/common/permissions.js.html +187 -187
  138. package/coverage/lcov-report/core/common/schema.js.html +26 -26
  139. package/coverage/lcov-report/core/common/utils.js.html +61 -61
  140. package/coverage/lcov-report/core/common/utils.offline.js.html +6 -6
  141. package/coverage/lcov-report/index.html +179 -164
  142. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +348 -258
  143. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +218 -218
  144. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +795 -810
  145. package/coverage/lcov-report/map/api/hooks/index.html +54 -54
  146. package/coverage/lcov-report/map/api/hooks/index.js.html +16 -16
  147. package/coverage/lcov-report/map/api/index.html +32 -32
  148. package/coverage/lcov-report/map/api/index.js.html +46 -46
  149. package/coverage/lcov-report/map/api/marshall.js.html +72 -72
  150. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +24 -24
  151. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +69 -27
  152. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +80 -80
  153. package/coverage/lcov-report/map/api/models/index.html +69 -54
  154. package/coverage/lcov-report/map/api/models/projects.model.mongodb.js.html +26 -26
  155. package/coverage/lcov-report/map/api/models/styles.model.mongodb.js.html +112 -0
  156. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +136 -136
  157. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +343 -343
  158. package/coverage/lcov-report/map/api/services/alerts/index.html +32 -32
  159. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +177 -162
  160. package/coverage/lcov-report/map/api/services/catalog/index.html +21 -21
  161. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +1 -1
  162. package/coverage/lcov-report/map/api/services/daptiles/index.html +1 -1
  163. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +160 -160
  164. package/coverage/lcov-report/map/api/services/features/features.service.js.html +117 -117
  165. package/coverage/lcov-report/map/api/services/features/index.html +31 -31
  166. package/coverage/lcov-report/map/api/services/index.html +21 -21
  167. package/coverage/lcov-report/map/api/services/index.js.html +404 -296
  168. package/coverage/lcov-report/map/api/services/projects/index.html +21 -21
  169. package/coverage/lcov-report/map/api/services/projects/projects.hooks.js.html +237 -237
  170. package/coverage/lcov-report/map/api/services/styles/index.html +116 -0
  171. package/coverage/lcov-report/map/api/services/styles/styles.hooks.js.html +196 -0
  172. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +68 -68
  173. package/coverage/lcov-report/map/common/errors.js.html +16 -16
  174. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +267 -267
  175. package/coverage/lcov-report/map/common/grid.js.html +554 -554
  176. package/coverage/lcov-report/map/common/index.html +158 -158
  177. package/coverage/lcov-report/map/common/index.js.html +68 -68
  178. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +73 -73
  179. package/coverage/lcov-report/map/common/moment-utils.js.html +18 -18
  180. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +484 -484
  181. package/coverage/lcov-report/map/common/opendap-utils.js.html +353 -353
  182. package/coverage/lcov-report/map/common/permissions.js.html +42 -36
  183. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +59 -59
  184. package/coverage/lcov-report/map/common/tms-utils.js.html +6 -6
  185. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +190 -190
  186. package/coverage/lcov-report/map/common/wcs-utils.js.html +339 -339
  187. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +345 -345
  188. package/coverage/lcov-report/map/common/wfs-utils.js.html +11 -11
  189. package/coverage/lcov-report/map/common/wms-utils.js.html +8 -8
  190. package/coverage/lcov-report/map/common/wmts-utils.js.html +7 -7
  191. package/coverage/lcov.info +7022 -5894
  192. package/coverage/map/api/hooks/hooks.catalog.js.html +348 -258
  193. package/coverage/map/api/hooks/hooks.features.js.html +218 -218
  194. package/coverage/map/api/hooks/hooks.query.js.html +795 -810
  195. package/coverage/map/api/hooks/index.html +54 -54
  196. package/coverage/map/api/hooks/index.js.html +16 -16
  197. package/coverage/map/api/index.html +32 -32
  198. package/coverage/map/api/index.js.html +46 -46
  199. package/coverage/map/api/marshall.js.html +72 -72
  200. package/coverage/map/api/models/alerts.model.mongodb.js.html +24 -24
  201. package/coverage/map/api/models/catalog.model.mongodb.js.html +69 -27
  202. package/coverage/map/api/models/features.model.mongodb.js.html +80 -80
  203. package/coverage/map/api/models/index.html +69 -54
  204. package/coverage/map/api/models/projects.model.mongodb.js.html +26 -26
  205. package/coverage/map/api/models/styles.model.mongodb.js.html +112 -0
  206. package/coverage/map/api/services/alerts/alerts.hooks.js.html +136 -136
  207. package/coverage/map/api/services/alerts/alerts.service.js.html +343 -343
  208. package/coverage/map/api/services/alerts/index.html +32 -32
  209. package/coverage/map/api/services/catalog/catalog.hooks.js.html +177 -162
  210. package/coverage/map/api/services/catalog/index.html +21 -21
  211. package/coverage/map/api/services/daptiles/daptiles.service.js.html +1 -1
  212. package/coverage/map/api/services/daptiles/index.html +1 -1
  213. package/coverage/map/api/services/features/features.hooks.js.html +160 -160
  214. package/coverage/map/api/services/features/features.service.js.html +117 -117
  215. package/coverage/map/api/services/features/index.html +31 -31
  216. package/coverage/map/api/services/index.html +21 -21
  217. package/coverage/map/api/services/index.js.html +404 -296
  218. package/coverage/map/api/services/projects/index.html +21 -21
  219. package/coverage/map/api/services/projects/projects.hooks.js.html +237 -237
  220. package/coverage/map/api/services/styles/index.html +116 -0
  221. package/coverage/map/api/services/styles/styles.hooks.js.html +196 -0
  222. package/coverage/map/common/dynamic-grid-source.js.html +68 -68
  223. package/coverage/map/common/errors.js.html +16 -16
  224. package/coverage/map/common/geotiff-grid-source.js.html +267 -267
  225. package/coverage/map/common/grid.js.html +554 -554
  226. package/coverage/map/common/index.html +158 -158
  227. package/coverage/map/common/index.js.html +68 -68
  228. package/coverage/map/common/meteo-model-grid-source.js.html +73 -73
  229. package/coverage/map/common/moment-utils.js.html +18 -18
  230. package/coverage/map/common/opendap-grid-source.js.html +484 -484
  231. package/coverage/map/common/opendap-utils.js.html +353 -353
  232. package/coverage/map/common/permissions.js.html +42 -36
  233. package/coverage/map/common/time-based-grid-source.js.html +59 -59
  234. package/coverage/map/common/tms-utils.js.html +6 -6
  235. package/coverage/map/common/wcs-grid-source.js.html +190 -190
  236. package/coverage/map/common/wcs-utils.js.html +339 -339
  237. package/coverage/map/common/weacast-grid-source.js.html +345 -345
  238. package/coverage/map/common/wfs-utils.js.html +11 -11
  239. package/coverage/map/common/wms-utils.js.html +8 -8
  240. package/coverage/map/common/wmts-utils.js.html +7 -7
  241. package/coverage/tmp/coverage-151198-1753351220086-0.json +1 -0
  242. package/coverage/tmp/coverage-151210-1753351220070-0.json +1 -0
  243. package/coverage/tmp/coverage-151221-1753351129816-0.json +1 -0
  244. package/coverage/tmp/coverage-151233-1753351129803-0.json +1 -0
  245. package/coverage/tmp/coverage-151240-1753351129770-0.json +1 -0
  246. package/coverage/tmp/coverage-151307-1753351220058-0.json +1 -0
  247. package/coverage/tmp/coverage-151319-1753351220044-0.json +1 -0
  248. package/coverage/tmp/coverage-151326-1753351220010-0.json +1 -0
  249. package/map/api/services/styles/styles.hooks.js +1 -1
  250. package/map/client/components/KLayerEditor.vue +4 -0
  251. package/map/client/components/catalog/KLayerCategories.vue +2 -0
  252. package/map/client/components/stickies/KLevelSlider.vue +10 -8
  253. package/map/client/components/styles/KStyleEditor.vue +1 -1
  254. package/map/client/components/styles/KStyleManager.vue +7 -1
  255. package/map/client/composables/highlight.js +5 -1
  256. package/map/client/i18n/map_en.json +4 -1
  257. package/map/client/i18n/map_fr.json +4 -1
  258. package/map/client/mixins/globe/mixin.geojson-layers.js +11 -5
  259. package/map/client/mixins/mixin.activity.js +9 -0
  260. package/map/client/utils/utils.layers.js +0 -2
  261. package/package.json +1 -1
  262. package/test/api/core/push.test.js +1 -1
  263. package/test/api/core/test-log-2025-02-05.log +23 -0
  264. package/test/api/core/test-log-2025-05-21.log +15 -0
  265. package/test/api/core/test-log-2025-06-25.log +9 -0
  266. package/test/api/core/test-log-2025-07-24.log +44 -0
  267. package/test/api/map/test-log-2025-05-27.log +13 -0
  268. package/test/api/map/test-log-2025-06-23.log +7 -0
  269. package/test/api/map/{test-log-2025-05-26.log → test-log-2025-07-24.log} +3 -4
  270. package/coverage/tmp/coverage-122123-1739872365211-0.json +0 -1
  271. package/coverage/tmp/coverage-122135-1739872365196-0.json +0 -1
  272. package/coverage/tmp/coverage-122146-1739872365184-0.json +0 -1
  273. package/coverage/tmp/coverage-122158-1739872365169-0.json +0 -1
  274. package/coverage/tmp/coverage-122165-1739872365141-0.json +0 -1
  275. package/test/api/core/test-log-2025-05-26.log +0 -22
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">0% </span>
26
+ <span class="strong">90.28% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>0/175</span>
28
+ <span class='fraction'>158/175</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">0% </span>
33
+ <span class="strong">74.07% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>0/1</span>
35
+ <span class='fraction'>20/27</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">0% </span>
40
+ <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>0/1</span>
42
+ <span class='fraction'>6/6</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">0% </span>
47
+ <span class="strong">90.28% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>0/175</span>
49
+ <span class='fraction'>158/175</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line low'></div>
64
+ <div class='status-line high'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -238,356 +238,356 @@
238
238
  <a name='L173'></a><a href='#L173'>173</a>
239
239
  <a name='L174'></a><a href='#L174'>174</a>
240
240
  <a name='L175'></a><a href='#L175'>175</a>
241
- <a name='L176'></a><a href='#L176'>176</a></td><td class="line-coverage quiet"><span class="cline-any cline-no">&nbsp;</span>
242
- <span class="cline-any cline-no">&nbsp;</span>
243
- <span class="cline-any cline-no">&nbsp;</span>
244
- <span class="cline-any cline-no">&nbsp;</span>
245
- <span class="cline-any cline-no">&nbsp;</span>
246
- <span class="cline-any cline-no">&nbsp;</span>
247
- <span class="cline-any cline-no">&nbsp;</span>
248
- <span class="cline-any cline-no">&nbsp;</span>
249
- <span class="cline-any cline-no">&nbsp;</span>
250
- <span class="cline-any cline-no">&nbsp;</span>
251
- <span class="cline-any cline-no">&nbsp;</span>
252
- <span class="cline-any cline-no">&nbsp;</span>
253
- <span class="cline-any cline-no">&nbsp;</span>
254
- <span class="cline-any cline-no">&nbsp;</span>
255
- <span class="cline-any cline-no">&nbsp;</span>
256
- <span class="cline-any cline-no">&nbsp;</span>
257
- <span class="cline-any cline-no">&nbsp;</span>
258
- <span class="cline-any cline-no">&nbsp;</span>
259
- <span class="cline-any cline-no">&nbsp;</span>
260
- <span class="cline-any cline-no">&nbsp;</span>
261
- <span class="cline-any cline-no">&nbsp;</span>
262
- <span class="cline-any cline-no">&nbsp;</span>
263
- <span class="cline-any cline-no">&nbsp;</span>
264
- <span class="cline-any cline-no">&nbsp;</span>
265
- <span class="cline-any cline-no">&nbsp;</span>
266
- <span class="cline-any cline-no">&nbsp;</span>
267
- <span class="cline-any cline-no">&nbsp;</span>
268
- <span class="cline-any cline-no">&nbsp;</span>
269
- <span class="cline-any cline-no">&nbsp;</span>
270
- <span class="cline-any cline-no">&nbsp;</span>
271
- <span class="cline-any cline-no">&nbsp;</span>
272
- <span class="cline-any cline-no">&nbsp;</span>
273
- <span class="cline-any cline-no">&nbsp;</span>
274
- <span class="cline-any cline-no">&nbsp;</span>
275
- <span class="cline-any cline-no">&nbsp;</span>
276
- <span class="cline-any cline-no">&nbsp;</span>
277
- <span class="cline-any cline-no">&nbsp;</span>
278
- <span class="cline-any cline-no">&nbsp;</span>
279
- <span class="cline-any cline-no">&nbsp;</span>
280
- <span class="cline-any cline-no">&nbsp;</span>
281
- <span class="cline-any cline-no">&nbsp;</span>
282
- <span class="cline-any cline-no">&nbsp;</span>
283
- <span class="cline-any cline-no">&nbsp;</span>
284
- <span class="cline-any cline-no">&nbsp;</span>
285
- <span class="cline-any cline-no">&nbsp;</span>
286
- <span class="cline-any cline-no">&nbsp;</span>
287
- <span class="cline-any cline-no">&nbsp;</span>
288
- <span class="cline-any cline-no">&nbsp;</span>
289
- <span class="cline-any cline-no">&nbsp;</span>
290
- <span class="cline-any cline-no">&nbsp;</span>
291
- <span class="cline-any cline-no">&nbsp;</span>
292
- <span class="cline-any cline-no">&nbsp;</span>
293
- <span class="cline-any cline-no">&nbsp;</span>
294
- <span class="cline-any cline-no">&nbsp;</span>
295
- <span class="cline-any cline-no">&nbsp;</span>
296
- <span class="cline-any cline-no">&nbsp;</span>
297
- <span class="cline-any cline-no">&nbsp;</span>
298
- <span class="cline-any cline-no">&nbsp;</span>
299
- <span class="cline-any cline-no">&nbsp;</span>
300
- <span class="cline-any cline-no">&nbsp;</span>
301
- <span class="cline-any cline-no">&nbsp;</span>
302
- <span class="cline-any cline-no">&nbsp;</span>
303
- <span class="cline-any cline-no">&nbsp;</span>
304
- <span class="cline-any cline-no">&nbsp;</span>
305
- <span class="cline-any cline-no">&nbsp;</span>
306
- <span class="cline-any cline-no">&nbsp;</span>
307
- <span class="cline-any cline-no">&nbsp;</span>
308
- <span class="cline-any cline-no">&nbsp;</span>
309
- <span class="cline-any cline-no">&nbsp;</span>
310
- <span class="cline-any cline-no">&nbsp;</span>
311
- <span class="cline-any cline-no">&nbsp;</span>
312
- <span class="cline-any cline-no">&nbsp;</span>
313
- <span class="cline-any cline-no">&nbsp;</span>
314
- <span class="cline-any cline-no">&nbsp;</span>
315
- <span class="cline-any cline-no">&nbsp;</span>
316
- <span class="cline-any cline-no">&nbsp;</span>
317
- <span class="cline-any cline-no">&nbsp;</span>
318
- <span class="cline-any cline-no">&nbsp;</span>
319
- <span class="cline-any cline-no">&nbsp;</span>
320
- <span class="cline-any cline-no">&nbsp;</span>
321
- <span class="cline-any cline-no">&nbsp;</span>
322
- <span class="cline-any cline-no">&nbsp;</span>
323
- <span class="cline-any cline-no">&nbsp;</span>
324
- <span class="cline-any cline-no">&nbsp;</span>
325
- <span class="cline-any cline-no">&nbsp;</span>
326
- <span class="cline-any cline-no">&nbsp;</span>
327
- <span class="cline-any cline-no">&nbsp;</span>
328
- <span class="cline-any cline-no">&nbsp;</span>
329
- <span class="cline-any cline-no">&nbsp;</span>
330
- <span class="cline-any cline-no">&nbsp;</span>
331
- <span class="cline-any cline-no">&nbsp;</span>
332
- <span class="cline-any cline-no">&nbsp;</span>
333
- <span class="cline-any cline-no">&nbsp;</span>
334
- <span class="cline-any cline-no">&nbsp;</span>
335
- <span class="cline-any cline-no">&nbsp;</span>
336
- <span class="cline-any cline-no">&nbsp;</span>
337
- <span class="cline-any cline-no">&nbsp;</span>
338
- <span class="cline-any cline-no">&nbsp;</span>
339
- <span class="cline-any cline-no">&nbsp;</span>
340
- <span class="cline-any cline-no">&nbsp;</span>
341
- <span class="cline-any cline-no">&nbsp;</span>
342
- <span class="cline-any cline-no">&nbsp;</span>
343
- <span class="cline-any cline-no">&nbsp;</span>
344
- <span class="cline-any cline-no">&nbsp;</span>
345
- <span class="cline-any cline-no">&nbsp;</span>
346
- <span class="cline-any cline-no">&nbsp;</span>
347
- <span class="cline-any cline-no">&nbsp;</span>
348
- <span class="cline-any cline-no">&nbsp;</span>
349
- <span class="cline-any cline-no">&nbsp;</span>
350
- <span class="cline-any cline-no">&nbsp;</span>
351
- <span class="cline-any cline-no">&nbsp;</span>
352
- <span class="cline-any cline-no">&nbsp;</span>
353
- <span class="cline-any cline-no">&nbsp;</span>
354
- <span class="cline-any cline-no">&nbsp;</span>
355
- <span class="cline-any cline-no">&nbsp;</span>
356
- <span class="cline-any cline-no">&nbsp;</span>
357
- <span class="cline-any cline-no">&nbsp;</span>
358
- <span class="cline-any cline-no">&nbsp;</span>
359
- <span class="cline-any cline-no">&nbsp;</span>
360
- <span class="cline-any cline-no">&nbsp;</span>
361
- <span class="cline-any cline-no">&nbsp;</span>
362
- <span class="cline-any cline-no">&nbsp;</span>
363
- <span class="cline-any cline-no">&nbsp;</span>
364
- <span class="cline-any cline-no">&nbsp;</span>
365
- <span class="cline-any cline-no">&nbsp;</span>
366
- <span class="cline-any cline-no">&nbsp;</span>
367
- <span class="cline-any cline-no">&nbsp;</span>
368
- <span class="cline-any cline-no">&nbsp;</span>
369
- <span class="cline-any cline-no">&nbsp;</span>
370
- <span class="cline-any cline-no">&nbsp;</span>
371
- <span class="cline-any cline-no">&nbsp;</span>
372
- <span class="cline-any cline-no">&nbsp;</span>
373
- <span class="cline-any cline-no">&nbsp;</span>
374
- <span class="cline-any cline-no">&nbsp;</span>
375
- <span class="cline-any cline-no">&nbsp;</span>
376
- <span class="cline-any cline-no">&nbsp;</span>
377
- <span class="cline-any cline-no">&nbsp;</span>
378
- <span class="cline-any cline-no">&nbsp;</span>
379
- <span class="cline-any cline-no">&nbsp;</span>
380
- <span class="cline-any cline-no">&nbsp;</span>
381
- <span class="cline-any cline-no">&nbsp;</span>
382
- <span class="cline-any cline-no">&nbsp;</span>
383
- <span class="cline-any cline-no">&nbsp;</span>
384
- <span class="cline-any cline-no">&nbsp;</span>
385
- <span class="cline-any cline-no">&nbsp;</span>
386
- <span class="cline-any cline-no">&nbsp;</span>
387
- <span class="cline-any cline-no">&nbsp;</span>
388
- <span class="cline-any cline-no">&nbsp;</span>
389
- <span class="cline-any cline-no">&nbsp;</span>
390
- <span class="cline-any cline-no">&nbsp;</span>
391
- <span class="cline-any cline-no">&nbsp;</span>
392
- <span class="cline-any cline-no">&nbsp;</span>
393
- <span class="cline-any cline-no">&nbsp;</span>
394
- <span class="cline-any cline-no">&nbsp;</span>
395
- <span class="cline-any cline-no">&nbsp;</span>
396
- <span class="cline-any cline-no">&nbsp;</span>
397
- <span class="cline-any cline-no">&nbsp;</span>
398
- <span class="cline-any cline-no">&nbsp;</span>
399
- <span class="cline-any cline-no">&nbsp;</span>
400
- <span class="cline-any cline-no">&nbsp;</span>
401
- <span class="cline-any cline-no">&nbsp;</span>
402
- <span class="cline-any cline-no">&nbsp;</span>
403
- <span class="cline-any cline-no">&nbsp;</span>
404
- <span class="cline-any cline-no">&nbsp;</span>
405
- <span class="cline-any cline-no">&nbsp;</span>
406
- <span class="cline-any cline-no">&nbsp;</span>
407
- <span class="cline-any cline-no">&nbsp;</span>
408
- <span class="cline-any cline-no">&nbsp;</span>
409
- <span class="cline-any cline-no">&nbsp;</span>
410
- <span class="cline-any cline-no">&nbsp;</span>
411
- <span class="cline-any cline-no">&nbsp;</span>
412
- <span class="cline-any cline-no">&nbsp;</span>
413
- <span class="cline-any cline-no">&nbsp;</span>
414
- <span class="cline-any cline-no">&nbsp;</span>
415
- <span class="cline-any cline-no">&nbsp;</span>
416
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" >import _ from 'lodash'</span></span></span>
417
- <span class="cstat-no" title="statement not covered" >import moment from 'moment'</span>
418
- <span class="cstat-no" title="statement not covered" >import siftModule from 'sift'</span>
419
- <span class="cstat-no" title="statement not covered" >import request from 'superagent'</span>
420
- <span class="cstat-no" title="statement not covered" >import cron from 'cron'</span>
421
- <span class="cstat-no" title="statement not covered" >import errors from '@feathersjs/errors'</span>
422
- <span class="cstat-no" title="statement not covered" >import makeDebug from 'debug'</span>
423
- <span class="cstat-no" title="statement not covered" >const debug = makeDebug('kdk:map:alerts:service')</span>
424
- <span class="cstat-no" title="statement not covered" ></span>
425
- <span class="cstat-no" title="statement not covered" >const { CronJob } = cron</span>
426
- <span class="cstat-no" title="statement not covered" >const { Unprocessable } = errors</span>
427
- <span class="cstat-no" title="statement not covered" >const sift = siftModule.default</span>
428
- <span class="cstat-no" title="statement not covered" ></span>
429
- <span class="cstat-no" title="statement not covered" >// Alert map</span>
430
- <span class="cstat-no" title="statement not covered" >const alerts = {}</span>
431
- <span class="cstat-no" title="statement not covered" ></span>
432
- <span class="cstat-no" title="statement not covered" >export default {</span>
433
- <span class="cstat-no" title="statement not covered" > async registerAlert (alert, check = true) {</span>
434
- <span class="cstat-no" title="statement not covered" > if (alerts[alert._id.toString()]) return</span>
435
- <span class="cstat-no" title="statement not covered" > debug('Registering new alert ', alert)</span>
436
- <span class="cstat-no" title="statement not covered" > const cronJob = new CronJob(alert.cron, () =&gt; this.checkAlert(alert))</span>
437
- <span class="cstat-no" title="statement not covered" > alerts[alert._id.toString()] = cronJob</span>
438
- <span class="cstat-no" title="statement not covered" > if (check) await this.checkAlert(alert)</span>
439
- <span class="cstat-no" title="statement not covered" > cronJob.start()</span>
440
- <span class="cstat-no" title="statement not covered" > },</span>
441
- <span class="cstat-no" title="statement not covered" ></span>
442
- <span class="cstat-no" title="statement not covered" > async unregisterAlert (alert) {</span>
443
- <span class="cstat-no" title="statement not covered" > const id = (typeof alert === 'string' ? alert : alert._id)</span>
444
- <span class="cstat-no" title="statement not covered" > const cronJob = alerts[id.toString()]</span>
445
- <span class="cstat-no" title="statement not covered" > if (!cronJob) return</span>
446
- <span class="cstat-no" title="statement not covered" > debug('Unregistering alert ', alert)</span>
447
- <span class="cstat-no" title="statement not covered" > cronJob.stop()</span>
448
- <span class="cstat-no" title="statement not covered" > delete alerts[id.toString()]</span>
449
- <span class="cstat-no" title="statement not covered" > },</span>
450
- <span class="cstat-no" title="statement not covered" ></span>
451
- <span class="cstat-no" title="statement not covered" > getConditions (alert) {</span>
452
- <span class="cstat-no" title="statement not covered" > return _.mapKeys(alert.conditions, (value, key) =&gt; 'properties.' + key)</span>
453
- <span class="cstat-no" title="statement not covered" > },</span>
454
- <span class="cstat-no" title="statement not covered" ></span>
455
- <span class="cstat-no" title="statement not covered" > async checkWeatherAlert (alert) {</span>
456
- <span class="cstat-no" title="statement not covered" > const now = moment.utc()</span>
457
- <span class="cstat-no" title="statement not covered" > // Convert conditions to internal data model</span>
458
- <span class="cstat-no" title="statement not covered" > const conditions = this.getConditions(alert)</span>
459
- <span class="cstat-no" title="statement not covered" > const probesService = this.app.getService('probes')</span>
460
- <span class="cstat-no" title="statement not covered" > if (!probesService) {</span>
241
+ <a name='L176'></a><a href='#L176'>176</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
242
+ <span class="cline-any cline-yes">1x</span>
243
+ <span class="cline-any cline-yes">1x</span>
244
+ <span class="cline-any cline-yes">1x</span>
245
+ <span class="cline-any cline-yes">1x</span>
246
+ <span class="cline-any cline-yes">1x</span>
247
+ <span class="cline-any cline-yes">1x</span>
248
+ <span class="cline-any cline-yes">1x</span>
249
+ <span class="cline-any cline-yes">1x</span>
250
+ <span class="cline-any cline-yes">1x</span>
251
+ <span class="cline-any cline-yes">1x</span>
252
+ <span class="cline-any cline-yes">1x</span>
253
+ <span class="cline-any cline-yes">1x</span>
254
+ <span class="cline-any cline-yes">1x</span>
255
+ <span class="cline-any cline-yes">1x</span>
256
+ <span class="cline-any cline-yes">1x</span>
257
+ <span class="cline-any cline-yes">1x</span>
258
+ <span class="cline-any cline-yes">1x</span>
259
+ <span class="cline-any cline-yes">6x</span>
260
+ <span class="cline-any cline-yes">6x</span>
261
+ <span class="cline-any cline-yes">6x</span>
262
+ <span class="cline-any cline-yes">6x</span>
263
+ <span class="cline-any cline-yes">6x</span>
264
+ <span class="cline-any cline-yes">6x</span>
265
+ <span class="cline-any cline-yes">1x</span>
266
+ <span class="cline-any cline-yes">1x</span>
267
+ <span class="cline-any cline-yes">1x</span>
268
+ <span class="cline-any cline-yes">6x</span>
269
+ <span class="cline-any cline-yes">6x</span>
270
+ <span class="cline-any cline-yes">6x</span>
271
+ <span class="cline-any cline-yes">6x</span>
272
+ <span class="cline-any cline-yes">6x</span>
273
+ <span class="cline-any cline-yes">6x</span>
274
+ <span class="cline-any cline-yes">1x</span>
275
+ <span class="cline-any cline-yes">1x</span>
276
+ <span class="cline-any cline-yes">1x</span>
277
+ <span class="cline-any cline-yes">14x</span>
278
+ <span class="cline-any cline-yes">1x</span>
279
+ <span class="cline-any cline-yes">1x</span>
280
+ <span class="cline-any cline-yes">1x</span>
281
+ <span class="cline-any cline-yes">7x</span>
282
+ <span class="cline-any cline-yes">7x</span>
283
+ <span class="cline-any cline-yes">7x</span>
284
+ <span class="cline-any cline-yes">7x</span>
285
+ <span class="cline-any cline-yes">7x</span>
286
+ <span class="cline-any cline-no">&nbsp;</span>
287
+ <span class="cline-any cline-no">&nbsp;</span>
288
+ <span class="cline-any cline-no">&nbsp;</span>
289
+ <span class="cline-any cline-no">&nbsp;</span>
290
+ <span class="cline-any cline-no">&nbsp;</span>
291
+ <span class="cline-any cline-no">&nbsp;</span>
292
+ <span class="cline-any cline-yes">7x</span>
293
+ <span class="cline-any cline-yes">7x</span>
294
+ <span class="cline-any cline-yes">7x</span>
295
+ <span class="cline-any cline-yes">7x</span>
296
+ <span class="cline-any cline-yes">7x</span>
297
+ <span class="cline-any cline-yes">7x</span>
298
+ <span class="cline-any cline-yes">7x</span>
299
+ <span class="cline-any cline-yes">7x</span>
300
+ <span class="cline-any cline-yes">7x</span>
301
+ <span class="cline-any cline-yes">7x</span>
302
+ <span class="cline-any cline-yes">7x</span>
303
+ <span class="cline-any cline-yes">7x</span>
304
+ <span class="cline-any cline-yes">7x</span>
305
+ <span class="cline-any cline-yes">7x</span>
306
+ <span class="cline-any cline-yes">7x</span>
307
+ <span class="cline-any cline-yes">7x</span>
308
+ <span class="cline-any cline-yes">7x</span>
309
+ <span class="cline-any cline-yes">7x</span>
310
+ <span class="cline-any cline-yes">7x</span>
311
+ <span class="cline-any cline-yes">1x</span>
312
+ <span class="cline-any cline-yes">1x</span>
313
+ <span class="cline-any cline-yes">1x</span>
314
+ <span class="cline-any cline-yes">1x</span>
315
+ <span class="cline-any cline-yes">1x</span>
316
+ <span class="cline-any cline-yes">1x</span>
317
+ <span class="cline-any cline-yes">6x</span>
318
+ <span class="cline-any cline-yes">6x</span>
319
+ <span class="cline-any cline-yes">1x</span>
320
+ <span class="cline-any cline-yes">1x</span>
321
+ <span class="cline-any cline-yes">1x</span>
322
+ <span class="cline-any cline-yes">7x</span>
323
+ <span class="cline-any cline-yes">7x</span>
324
+ <span class="cline-any cline-yes">7x</span>
325
+ <span class="cline-any cline-yes">7x</span>
326
+ <span class="cline-any cline-yes">7x</span>
327
+ <span class="cline-any cline-no">&nbsp;</span>
328
+ <span class="cline-any cline-no">&nbsp;</span>
329
+ <span class="cline-any cline-no">&nbsp;</span>
330
+ <span class="cline-any cline-no">&nbsp;</span>
331
+ <span class="cline-any cline-no">&nbsp;</span>
332
+ <span class="cline-any cline-no">&nbsp;</span>
333
+ <span class="cline-any cline-yes">7x</span>
334
+ <span class="cline-any cline-yes">7x</span>
335
+ <span class="cline-any cline-yes">7x</span>
336
+ <span class="cline-any cline-yes">7x</span>
337
+ <span class="cline-any cline-yes">7x</span>
338
+ <span class="cline-any cline-yes">7x</span>
339
+ <span class="cline-any cline-yes">7x</span>
340
+ <span class="cline-any cline-yes">7x</span>
341
+ <span class="cline-any cline-yes">7x</span>
342
+ <span class="cline-any cline-yes">7x</span>
343
+ <span class="cline-any cline-no">&nbsp;</span>
344
+ <span class="cline-any cline-no">&nbsp;</span>
345
+ <span class="cline-any cline-yes">7x</span>
346
+ <span class="cline-any cline-yes">7x</span>
347
+ <span class="cline-any cline-yes">7x</span>
348
+ <span class="cline-any cline-yes">7x</span>
349
+ <span class="cline-any cline-yes">1x</span>
350
+ <span class="cline-any cline-yes">1x</span>
351
+ <span class="cline-any cline-yes">1x</span>
352
+ <span class="cline-any cline-yes">1x</span>
353
+ <span class="cline-any cline-yes">1x</span>
354
+ <span class="cline-any cline-yes">1x</span>
355
+ <span class="cline-any cline-yes">6x</span>
356
+ <span class="cline-any cline-yes">6x</span>
357
+ <span class="cline-any cline-yes">6x</span>
358
+ <span class="cline-any cline-yes">1x</span>
359
+ <span class="cline-any cline-yes">1x</span>
360
+ <span class="cline-any cline-yes">1x</span>
361
+ <span class="cline-any cline-yes">14x</span>
362
+ <span class="cline-any cline-yes">14x</span>
363
+ <span class="cline-any cline-yes">14x</span>
364
+ <span class="cline-any cline-yes">14x</span>
365
+ <span class="cline-any cline-no">&nbsp;</span>
366
+ <span class="cline-any cline-no">&nbsp;</span>
367
+ <span class="cline-any cline-no">&nbsp;</span>
368
+ <span class="cline-any cline-yes">14x</span>
369
+ <span class="cline-any cline-yes">14x</span>
370
+ <span class="cline-any cline-yes">14x</span>
371
+ <span class="cline-any cline-yes">14x</span>
372
+ <span class="cline-any cline-yes">14x</span>
373
+ <span class="cline-any cline-yes">14x</span>
374
+ <span class="cline-any cline-yes">14x</span>
375
+ <span class="cline-any cline-yes">6x</span>
376
+ <span class="cline-any cline-yes">6x</span>
377
+ <span class="cline-any cline-yes">6x</span>
378
+ <span class="cline-any cline-yes">6x</span>
379
+ <span class="cline-any cline-yes">6x</span>
380
+ <span class="cline-any cline-yes">6x</span>
381
+ <span class="cline-any cline-yes">6x</span>
382
+ <span class="cline-any cline-yes">2x</span>
383
+ <span class="cline-any cline-yes">2x</span>
384
+ <span class="cline-any cline-yes">6x</span>
385
+ <span class="cline-any cline-yes">6x</span>
386
+ <span class="cline-any cline-yes">6x</span>
387
+ <span class="cline-any cline-yes">12x</span>
388
+ <span class="cline-any cline-yes">14x</span>
389
+ <span class="cline-any cline-yes">2x</span>
390
+ <span class="cline-any cline-yes">2x</span>
391
+ <span class="cline-any cline-yes">2x</span>
392
+ <span class="cline-any cline-yes">14x</span>
393
+ <span class="cline-any cline-yes">14x</span>
394
+ <span class="cline-any cline-yes">14x</span>
395
+ <span class="cline-any cline-yes">14x</span>
396
+ <span class="cline-any cline-yes">14x</span>
397
+ <span class="cline-any cline-yes">14x</span>
398
+ <span class="cline-any cline-yes">14x</span>
399
+ <span class="cline-any cline-yes">14x</span>
400
+ <span class="cline-any cline-yes">14x</span>
401
+ <span class="cline-any cline-yes">14x</span>
402
+ <span class="cline-any cline-yes">14x</span>
403
+ <span class="cline-any cline-yes">14x</span>
404
+ <span class="cline-any cline-yes">14x</span>
405
+ <span class="cline-any cline-yes">14x</span>
406
+ <span class="cline-any cline-yes">14x</span>
407
+ <span class="cline-any cline-yes">14x</span>
408
+ <span class="cline-any cline-yes">14x</span>
409
+ <span class="cline-any cline-yes">14x</span>
410
+ <span class="cline-any cline-yes">14x</span>
411
+ <span class="cline-any cline-yes">14x</span>
412
+ <span class="cline-any cline-yes">14x</span>
413
+ <span class="cline-any cline-yes">14x</span>
414
+ <span class="cline-any cline-yes">14x</span>
415
+ <span class="cline-any cline-yes">1x</span>
416
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import _ from 'lodash'
417
+ import moment from 'moment'
418
+ import siftModule from 'sift'
419
+ import request from 'superagent'
420
+ import cron from 'cron'
421
+ import errors from '@feathersjs/errors'
422
+ import makeDebug from 'debug'
423
+ const debug = makeDebug('kdk:map:alerts:service')
424
+ &nbsp;
425
+ const { CronJob } = cron
426
+ const { Unprocessable } = errors
427
+ const sift = siftModule.default
428
+ &nbsp;
429
+ // Alert map
430
+ const alerts = {}
431
+ &nbsp;
432
+ export default {
433
+ async registerAlert (alert, check = true) {
434
+ if (alerts[alert._id.toString()]) <span class="branch-0 cbranch-no" title="branch not covered" >return</span>
435
+ debug('Registering new alert ', alert)
436
+ const cronJob = new CronJob(alert.cron, () =&gt; this.checkAlert(alert))
437
+ alerts[alert._id.toString()] = cronJob
438
+ if (check) await this.checkAlert(alert)
439
+ cronJob.start()
440
+ },
441
+ &nbsp;
442
+ async unregisterAlert (alert) {
443
+ const id = (typeof alert === 'string' ? alert <span class="branch-0 cbranch-no" title="branch not covered" >: alert._id)</span>
444
+ const cronJob = alerts[id.toString()]
445
+ if (!cronJob) <span class="branch-0 cbranch-no" title="branch not covered" >return</span>
446
+ debug('Unregistering alert ', alert)
447
+ cronJob.stop()
448
+ delete alerts[id.toString()]
449
+ },
450
+ &nbsp;
451
+ getConditions (alert) {
452
+ return _.mapKeys(alert.conditions, (value, key) =&gt; 'properties.' + key)
453
+ },
454
+ &nbsp;
455
+ async checkWeatherAlert (alert) {
456
+ const now = moment.utc()
457
+ // Convert conditions to internal data model
458
+ const conditions = this.getConditions(alert)
459
+ const probesService = this.app.getService('probes')
460
+ if (!probesService) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
461
461
  <span class="cstat-no" title="statement not covered" > throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as target probes service is not available', {</span>
462
462
  <span class="cstat-no" title="statement not covered" > translation: {</span>
463
463
  <span class="cstat-no" title="statement not covered" > key: 'CANNOT_CHECK_ALERT_MISSING_SERVICE'</span>
464
464
  <span class="cstat-no" title="statement not covered" > }</span>
465
465
  <span class="cstat-no" title="statement not covered" > })</span>
466
466
  <span class="cstat-no" title="statement not covered" > }</span>
467
- <span class="cstat-no" title="statement not covered" > // Perform aggregation over time range</span>
468
- <span class="cstat-no" title="statement not covered" > const query = Object.assign({</span>
469
- <span class="cstat-no" title="statement not covered" > forecastTime: {</span>
470
- <span class="cstat-no" title="statement not covered" > $gte: now.clone().add(_.get(alert, 'period.start', { seconds: 0 })).toDate(),</span>
471
- <span class="cstat-no" title="statement not covered" > $lte: now.clone().add(_.get(alert, 'period.end', { seconds: 24 * 3600 })).toDate()</span>
472
- <span class="cstat-no" title="statement not covered" > },</span>
473
- <span class="cstat-no" title="statement not covered" > geometry: {</span>
474
- <span class="cstat-no" title="statement not covered" > $geoIntersects: {</span>
475
- <span class="cstat-no" title="statement not covered" > $geometry: _.get(alert, 'geometry')</span>
476
- <span class="cstat-no" title="statement not covered" > }</span>
477
- <span class="cstat-no" title="statement not covered" > },</span>
478
- <span class="cstat-no" title="statement not covered" > aggregate: false</span>
479
- <span class="cstat-no" title="statement not covered" > })</span>
480
- <span class="cstat-no" title="statement not covered" > const result = await probesService.create({</span>
481
- <span class="cstat-no" title="statement not covered" > forecast: alert.forecast,</span>
482
- <span class="cstat-no" title="statement not covered" > elements: alert.elements</span>
483
- <span class="cstat-no" title="statement not covered" > }, { query })</span>
484
- <span class="cstat-no" title="statement not covered" > // Check for available data so that we will not close an alert because data is missing</span>
485
- <span class="cstat-no" title="statement not covered" > if (result.features.length === 0) {</span>
486
- <span class="cstat-no" title="statement not covered" > throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as no data is available for ' + alert.forecast, {</span>
487
- <span class="cstat-no" title="statement not covered" > translation: {</span>
488
- <span class="cstat-no" title="statement not covered" > key: 'CANNOT_CHECK_ALERT_MISSING_DATA'</span>
489
- <span class="cstat-no" title="statement not covered" > }</span>
490
- <span class="cstat-no" title="statement not covered" > })</span>
491
- <span class="cstat-no" title="statement not covered" > }</span>
492
- <span class="cstat-no" title="statement not covered" > // Let sift performs condition matching as in this case MongoDB cannot</span>
493
- <span class="cstat-no" title="statement not covered" > return result.features.filter(sift(conditions))</span>
494
- <span class="cstat-no" title="statement not covered" > },</span>
495
- <span class="cstat-no" title="statement not covered" ></span>
496
- <span class="cstat-no" title="statement not covered" > async checkMeasureAlert (alert) {</span>
497
- <span class="cstat-no" title="statement not covered" > const now = moment.utc()</span>
498
- <span class="cstat-no" title="statement not covered" > // Convert conditions to internal data model</span>
499
- <span class="cstat-no" title="statement not covered" > const conditions = this.getConditions(alert)</span>
500
- <span class="cstat-no" title="statement not covered" > const featureService = this.app.getService(_.get(alert, 'layer.service'))</span>
501
- <span class="cstat-no" title="statement not covered" > if (!featureService) {</span>
467
+ // Perform aggregation over time range
468
+ const query = Object.assign({
469
+ forecastTime: {
470
+ $gte: now.clone().add(_.get(alert, 'period.start', { seconds: 0 })).toDate(),
471
+ $lte: now.clone().add(_.get(alert, 'period.end', { seconds: 24 * 3600 })).toDate()
472
+ },
473
+ geometry: {
474
+ $geoIntersects: {
475
+ $geometry: _.get(alert, 'geometry')
476
+ }
477
+ },
478
+ aggregate: false
479
+ })
480
+ const result = await probesService.create({
481
+ forecast: alert.forecast,
482
+ elements: alert.elements
483
+ }, { query })
484
+ // Check for available data so that we will not close an alert because data is missing
485
+ if (result.features.length === 0) {
486
+ throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as no data is available for ' + alert.forecast, {
487
+ translation: {
488
+ key: 'CANNOT_CHECK_ALERT_MISSING_DATA'
489
+ }
490
+ })
491
+ }
492
+ // Let sift performs condition matching as in this case MongoDB cannot
493
+ return result.features.filter(sift(conditions))
494
+ },
495
+ &nbsp;
496
+ async checkMeasureAlert (alert) {
497
+ const now = moment.utc()
498
+ // Convert conditions to internal data model
499
+ const conditions = this.getConditions(alert)
500
+ const featureService = this.app.getService(_.get(alert, 'layer.service'))
501
+ if (!featureService) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
502
502
  <span class="cstat-no" title="statement not covered" > throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as target features service ' + _.get(alert, 'layer.service') + ' is not available', {</span>
503
503
  <span class="cstat-no" title="statement not covered" > translation: {</span>
504
504
  <span class="cstat-no" title="statement not covered" > key: 'CANNOT_CHECK_ALERT_MISSING_SERVICE'</span>
505
505
  <span class="cstat-no" title="statement not covered" > }</span>
506
506
  <span class="cstat-no" title="statement not covered" > })</span>
507
507
  <span class="cstat-no" title="statement not covered" > }</span>
508
- <span class="cstat-no" title="statement not covered" > // Build base query for time range and target feature</span>
509
- <span class="cstat-no" title="statement not covered" > const query = {</span>
510
- <span class="cstat-no" title="statement not covered" > time: {</span>
511
- <span class="cstat-no" title="statement not covered" > $gte: now.clone().add(_.get(alert, 'period.start', { seconds: 0 })).toDate(),</span>
512
- <span class="cstat-no" title="statement not covered" > $lte: now.clone().add(_.get(alert, 'period.end', { seconds: 24 * 3600 })).toDate()</span>
513
- <span class="cstat-no" title="statement not covered" > }</span>
514
- <span class="cstat-no" title="statement not covered" > }</span>
515
- <span class="cstat-no" title="statement not covered" > if (_.has(alert, 'layer.featureId')) {</span>
516
- <span class="cstat-no" title="statement not covered" > query['properties.' + _.get(alert, 'layer.featureId')] = alert.feature</span>
517
- <span class="cstat-no" title="statement not covered" > } else {</span>
508
+ // Build base query for time range and target feature
509
+ const query = {
510
+ time: {
511
+ $gte: now.clone().add(_.get(alert, 'period.start', { seconds: 0 })).toDate(),
512
+ $lte: now.clone().add(_.get(alert, 'period.end', { seconds: 24 * 3600 })).toDate()
513
+ }
514
+ }
515
+ if (_.has(alert, 'layer.featureId')) {
516
+ query['properties.' + _.get(alert, 'layer.featureId')] = alert.feature
517
+ }<span class="branch-0 cbranch-no" title="branch not covered" > else {</span>
518
518
  <span class="cstat-no" title="statement not covered" > query._id = alert.feature</span>
519
519
  <span class="cstat-no" title="statement not covered" > }</span>
520
- <span class="cstat-no" title="statement not covered" > // Check for available data so that we will not close an alert because data is missing</span>
521
- <span class="cstat-no" title="statement not covered" > // $limit = 0 performs a simple count query</span>
522
- <span class="cstat-no" title="statement not covered" > let result = await featureService.find({ query: Object.assign({ $limit: 0 }, query) })</span>
523
- <span class="cstat-no" title="statement not covered" > if (result.total === 0) {</span>
524
- <span class="cstat-no" title="statement not covered" > throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as no data is available for features service ' + _.get(alert, 'layer.service'), {</span>
525
- <span class="cstat-no" title="statement not covered" > translation: {</span>
526
- <span class="cstat-no" title="statement not covered" > key: 'CANNOT_CHECK_ALERT_MISSING_DATA'</span>
527
- <span class="cstat-no" title="statement not covered" > }</span>
528
- <span class="cstat-no" title="statement not covered" > })</span>
529
- <span class="cstat-no" title="statement not covered" > }</span>
530
- <span class="cstat-no" title="statement not covered" > // Perform aggregation over time range</span>
531
- <span class="cstat-no" title="statement not covered" > result = await featureService.find({ query: Object.assign(query, conditions) })</span>
532
- <span class="cstat-no" title="statement not covered" > return result.features</span>
533
- <span class="cstat-no" title="statement not covered" > },</span>
534
- <span class="cstat-no" title="statement not covered" ></span>
535
- <span class="cstat-no" title="statement not covered" > async checkAlert (alert, options = { patch: true, callWebhook: true }) {</span>
536
- <span class="cstat-no" title="statement not covered" > const now = moment.utc()</span>
537
- <span class="cstat-no" title="statement not covered" > debug('Checking alert at ' + now.format(), _.omit(alert, ['status', 'webhook']))</span>
538
- <span class="cstat-no" title="statement not covered" > // First check if still valid</span>
539
- <span class="cstat-no" title="statement not covered" > if (now.isAfter(alert.expireAt)) {</span>
520
+ // Check for available data so that we will not close an alert because data is missing
521
+ // $limit = 0 performs a simple count query
522
+ let result = await featureService.find({ query: Object.assign({ $limit: 0 }, query) })
523
+ if (result.total === 0) {
524
+ throw new Unprocessable('Cannot check alert ' + alert._id.toString() + ' as no data is available for features service ' + _.get(alert, 'layer.service'), {
525
+ translation: {
526
+ key: 'CANNOT_CHECK_ALERT_MISSING_DATA'
527
+ }
528
+ })
529
+ }
530
+ // Perform aggregation over time range
531
+ result = await featureService.find({ query: Object.assign(query, conditions) })
532
+ return result.features
533
+ },
534
+ &nbsp;
535
+ async checkAlert (alert, options = { patch: true, callWebhook: true }) {
536
+ const now = moment.utc()
537
+ debug('Checking alert at ' + now.format(), _.omit(alert, ['status', 'webhook']))
538
+ // First check if still valid
539
+ if (now.isAfter(alert.expireAt)) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
540
540
  <span class="cstat-no" title="statement not covered" > await this.unregisterAlert(alert)</span>
541
541
  <span class="cstat-no" title="statement not covered" > return</span>
542
542
  <span class="cstat-no" title="statement not covered" > }</span>
543
- <span class="cstat-no" title="statement not covered" > // Then update alert status starting from previous one (i.e. trigger time stamp, etc.)</span>
544
- <span class="cstat-no" title="statement not covered" > const status = _.get(alert, 'status', {})</span>
545
- <span class="cstat-no" title="statement not covered" > status.checkedAt = now.clone()</span>
546
- <span class="cstat-no" title="statement not covered" > // Clean any error state</span>
547
- <span class="cstat-no" title="statement not covered" > delete status.error</span>
548
- <span class="cstat-no" title="statement not covered" > try {</span>
549
- <span class="cstat-no" title="statement not covered" > const results = (alert.feature ? await this.checkMeasureAlert(alert) : await this.checkWeatherAlert(alert))</span>
550
- <span class="cstat-no" title="statement not covered" > // FIXME: check for a specific duration where conditions are met</span>
551
- <span class="cstat-no" title="statement not covered" > const isActive = (results.length &gt; 0)</span>
552
- <span class="cstat-no" title="statement not covered" > const wasActive = status.active</span>
553
- <span class="cstat-no" title="statement not covered" > status.active = isActive</span>
554
- <span class="cstat-no" title="statement not covered" > if (isActive) {</span>
555
- <span class="cstat-no" title="statement not covered" > // If not previously active and it is now add first time stamp</span>
556
- <span class="cstat-no" title="statement not covered" > if (!wasActive) {</span>
557
- <span class="cstat-no" title="statement not covered" > status.triggeredAt = now.clone()</span>
558
- <span class="cstat-no" title="statement not covered" > }</span>
559
- <span class="cstat-no" title="statement not covered" > // Update triggers</span>
560
- <span class="cstat-no" title="statement not covered" > status.triggers = results</span>
561
- <span class="cstat-no" title="statement not covered" > }</span>
562
- <span class="cstat-no" title="statement not covered" > debug('Alert ' + alert._id.toString() + ' status', status, ' with ' + results.length + ' triggers')</span>
563
- <span class="cstat-no" title="statement not covered" > } catch (error) { // Possible if no data</span>
564
- <span class="cstat-no" title="statement not covered" > this.app.logger.error(error.message)</span>
565
- <span class="cstat-no" title="statement not covered" > status.error = error.toJSON()</span>
566
- <span class="cstat-no" title="statement not covered" > }</span>
567
- <span class="cstat-no" title="statement not covered" ></span>
568
- <span class="cstat-no" title="statement not covered" > // As we keep in-memory objects avoid them being mutated by hooks processing operation payload</span>
569
- <span class="cstat-no" title="statement not covered" > if (options.patch) {</span>
570
- <span class="cstat-no" title="statement not covered" > await this.patch(alert._id.toString(), { status: Object.assign({}, status) })</span>
571
- <span class="cstat-no" title="statement not covered" > // DEBUG code to simulate alert closing</span>
572
- <span class="cstat-no" title="statement not covered" > /*</span>
573
- <span class="cstat-no" title="statement not covered" > setTimeout(async () =&gt; {</span>
574
- <span class="cstat-no" title="statement not covered" > await this.patch(alert._id.toString(), {</span>
575
- <span class="cstat-no" title="statement not covered" > status: { active: false, checkedAt: now.clone() }</span>
576
- <span class="cstat-no" title="statement not covered" > })</span>
577
- <span class="cstat-no" title="statement not covered" > }, 10000)</span>
578
- <span class="cstat-no" title="statement not covered" > */</span>
579
- <span class="cstat-no" title="statement not covered" > }</span>
580
- <span class="cstat-no" title="statement not covered" > // Keep track of changes in memory as well</span>
581
- <span class="cstat-no" title="statement not covered" > Object.assign(alert, { status })</span>
582
- <span class="cstat-no" title="statement not covered" > // If a webhook is configured call it</span>
583
- <span class="cstat-no" title="statement not covered" > const webhook = alert.webhook</span>
584
- <span class="cstat-no" title="statement not covered" > if (options.callWebhook &amp;&amp; webhook) {</span>
585
- <span class="cstat-no" title="statement not covered" > const body = Object.assign({ alert: _.omit(alert, ['webhook']) }, _.omit(webhook, ['url']))</span>
586
- <span class="cstat-no" title="statement not covered" > await request.post(webhook.url, body)</span>
587
- <span class="cstat-no" title="statement not covered" > }</span>
588
- <span class="cstat-no" title="statement not covered" > return alert</span>
589
- <span class="cstat-no" title="statement not covered" > }</span>
590
- <span class="cstat-no" title="statement not covered" >}</span>
543
+ // Then update alert status starting from previous one (i.e. trigger time stamp, etc.)
544
+ const status = _.get(alert, 'status', {})
545
+ status.checkedAt = now.clone()
546
+ // Clean any error state
547
+ delete status.error
548
+ try {
549
+ const results = (alert.feature ? await this.checkMeasureAlert(alert) : await this.checkWeatherAlert(alert))
550
+ // FIXME: check for a specific duration where conditions are met
551
+ const isActive = (results.length &gt; 0)
552
+ const wasActive = status.active
553
+ status.active = isActive
554
+ if (isActive) {
555
+ // If not previously active and it is now add first time stamp
556
+ if (!wasActive) {
557
+ status.triggeredAt = now.clone()
558
+ }
559
+ // Update triggers
560
+ status.triggers = results
561
+ }
562
+ debug('Alert ' + alert._id.toString() + ' status', status, ' with ' + results.length + ' triggers')
563
+ } catch (error) { // Possible if no data
564
+ this.app.logger.error(error.message)
565
+ status.error = error.toJSON()
566
+ }
567
+ &nbsp;
568
+ // As we keep in-memory objects avoid them being mutated by hooks processing operation payload
569
+ if (options.patch) {
570
+ await this.patch(alert._id.toString(), { status: Object.assign({}, status) })
571
+ // DEBUG code to simulate alert closing
572
+ /*
573
+ setTimeout(async () =&gt; {
574
+ await this.patch(alert._id.toString(), {
575
+ status: { active: false, checkedAt: now.clone() }
576
+ })
577
+ }, 10000)
578
+ */
579
+ }
580
+ // Keep track of changes in memory as well
581
+ Object.assign(alert, { status })
582
+ // If a webhook is configured call it
583
+ const webhook = alert.webhook
584
+ if (options.callWebhook &amp;&amp; webhook) {
585
+ const body = Object.assign({ alert: _.omit(alert, ['webhook']) }, _.omit(webhook, ['url']))
586
+ await request.post(webhook.url, body)
587
+ }
588
+ return alert
589
+ }
590
+ }
591
591
  &nbsp;</pre></td></tr></table></pre>
592
592
 
593
593
  <div class='push'></div><!-- for sticky footer -->
@@ -595,7 +595,7 @@
595
595
  <div class='footer quiet pad2 space-top1 center small'>
596
596
  Code coverage generated by
597
597
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
598
- at 2025-02-18T09:52:45.605Z
598
+ at 2025-07-24T10:00:20.476Z
599
599
  </div>
600
600
  <script src="../../../../prettify.js"></script>
601
601
  <script>