@kalisio/kdk 2.0.1 → 2.1.1

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 (471) hide show
  1. package/.codeclimate.yml +0 -1
  2. package/.travis.test.sh +3 -0
  3. package/core/api/application.js +13 -9
  4. package/core/api/db.js +34 -30
  5. package/core/api/hooks/hooks.authentication.js +11 -0
  6. package/core/api/hooks/hooks.authorisations.js +7 -3
  7. package/core/api/hooks/hooks.model.js +32 -43
  8. package/core/api/hooks/hooks.organisations.js +26 -116
  9. package/core/api/hooks/hooks.push.js +56 -0
  10. package/core/api/hooks/hooks.query.js +0 -5
  11. package/core/api/hooks/hooks.schemas.js +23 -3
  12. package/core/api/hooks/hooks.users.js +15 -22
  13. package/core/api/hooks/index.js +1 -4
  14. package/core/api/services/account/account.hooks.js +3 -3
  15. package/core/api/services/account/account.service.js +6 -7
  16. package/core/api/services/groups/groups.hooks.js +2 -4
  17. package/core/api/services/index.js +11 -16
  18. package/core/api/services/{devices/devices.hooks.js → push/push.hooks.js} +5 -5
  19. package/core/api/services/push/push.service.js +12 -0
  20. package/core/api/services/tags/tags.hooks.js +6 -20
  21. package/core/api/services/users/users.hooks.js +12 -13
  22. package/core/api/utils.js +11 -0
  23. package/core/client/api.js +6 -0
  24. package/core/client/capabilities.js +8 -12
  25. package/core/client/components/KAction.vue +10 -3
  26. package/core/client/components/KAvatar.vue +31 -35
  27. package/core/client/components/KChipsPane.vue +23 -0
  28. package/core/client/components/account/KAccount.vue +68 -0
  29. package/core/client/components/account/KDeleteAccountManager.vue +62 -0
  30. package/core/client/components/account/KEmailManager.vue +128 -0
  31. package/core/client/components/account/KPasswordManager.vue +90 -0
  32. package/core/client/components/account/KProfile.vue +109 -0
  33. package/core/client/components/account/KResetPassword.vue +100 -111
  34. package/core/client/components/account/KSendResetPassword.vue +71 -87
  35. package/core/client/components/account/KSubscription.vue +71 -0
  36. package/core/client/components/account/KSubscriptionsManager.vue +46 -0
  37. package/core/client/components/account/KVerifyEmailManager.vue +105 -0
  38. package/core/client/components/account/index.js +4 -2
  39. package/core/client/components/app/KAbout.vue +27 -14
  40. package/core/client/components/app/KPlatform.vue +2 -2
  41. package/core/client/components/app/KWelcome.vue +71 -45
  42. package/core/client/components/collection/KBoard.vue +50 -40
  43. package/core/client/components/collection/KCard.vue +16 -7
  44. package/core/client/components/collection/KColumn.vue +146 -111
  45. package/core/client/components/collection/KGrid.vue +77 -58
  46. package/core/client/components/collection/KHistory.vue +19 -3
  47. package/core/client/components/collection/KItem.vue +5 -1
  48. package/core/client/components/collection/KList.vue +80 -56
  49. package/core/client/components/collection/KTable.vue +181 -142
  50. package/core/client/components/editor/KEditor.vue +10 -3
  51. package/core/client/components/form/KFileField.vue +22 -8
  52. package/core/client/components/form/KForm.vue +27 -14
  53. package/core/client/components/form/KItemField.vue +2 -2
  54. package/core/client/components/form/KOptionsField.vue +11 -2
  55. package/core/client/components/form/KSelectField.vue +12 -3
  56. package/core/client/components/form/KTextField.vue +6 -0
  57. package/core/client/components/form/KTokenField.vue +80 -0
  58. package/core/client/components/layout/KOpener.vue +8 -8
  59. package/core/client/components/layout/KPage.vue +8 -4
  60. package/core/client/components/layout/KWindow.vue +172 -141
  61. package/core/client/components/media/KMediaBrowser.vue +28 -12
  62. package/core/client/components/media/KShape.vue +58 -56
  63. package/core/client/components/menu/KMenu.vue +22 -13
  64. package/core/client/components/menu/KRadialFab.vue +83 -56
  65. package/core/client/components/menu/KRadialFabItem.vue +39 -19
  66. package/core/client/components/screen/KLoginScreen.vue +0 -17
  67. package/core/client/components/screen/KScreen.vue +3 -3
  68. package/core/client/components/screen/KScreenFooter.vue +0 -3
  69. package/core/client/components/team/KAddMember.vue +1 -1
  70. package/core/client/components/team/KAddTag.vue +121 -0
  71. package/core/client/components/team/KMemberCard.vue +42 -13
  72. package/core/client/components/team/KMembersActivity.vue +9 -3
  73. package/core/client/components/team/KTagCard.vue +16 -1
  74. package/core/client/composables/collection.js +181 -0
  75. package/core/client/composables/index.js +2 -0
  76. package/core/client/composables/pwa.js +71 -0
  77. package/core/client/composables/session.js +6 -9
  78. package/core/client/composables/version.js +1 -22
  79. package/core/client/i18n/core_en.json +124 -153
  80. package/core/client/i18n/core_fr.json +124 -155
  81. package/core/client/index.js +37 -110
  82. package/core/client/layout.js +37 -14
  83. package/core/client/local-storage.js +4 -3
  84. package/core/client/mixins/mixin.account.js +9 -5
  85. package/core/client/mixins/mixin.base-editor.js +19 -3
  86. package/core/client/mixins/mixin.base-item.js +3 -3
  87. package/core/client/mixins/mixin.base-viewer.js +14 -0
  88. package/core/client/mixins/mixin.object-proxy.js +2 -21
  89. package/core/client/services/index.js +0 -1
  90. package/core/client/storage.js +19 -16
  91. package/core/client/theme.js +11 -5
  92. package/core/client/utils/index.js +5 -13
  93. package/core/client/utils/utils.account.js +47 -0
  94. package/core/client/utils/utils.colors.js +6 -2
  95. package/core/client/utils/utils.content.js +7 -5
  96. package/core/client/utils/utils.platform.js +1 -20
  97. package/core/client/utils/utils.push.js +53 -0
  98. package/core/client/utils/utils.pwa.js +63 -0
  99. package/core/client/utils/utils.session.js +27 -12
  100. package/core/common/permissions.js +12 -4
  101. package/core/common/schemas/tags.create.json +35 -0
  102. package/core/common/schemas/users.update-profile.json +1 -1
  103. package/coverage/base.css +224 -0
  104. package/coverage/block-navigation.js +87 -0
  105. package/coverage/core/api/application.js.html +1849 -0
  106. package/coverage/core/api/authentication.js.html +694 -0
  107. package/coverage/core/api/db.js.html +763 -0
  108. package/coverage/core/api/hooks/hooks.account.js.html +169 -0
  109. package/coverage/core/api/hooks/hooks.authentication.js.html +274 -0
  110. package/coverage/core/api/hooks/hooks.authorisations.js.html +1213 -0
  111. package/coverage/core/api/hooks/hooks.groups.js.html +229 -0
  112. package/coverage/core/api/hooks/hooks.logger.js.html +163 -0
  113. package/coverage/core/api/hooks/hooks.model.js.html +994 -0
  114. package/coverage/core/api/hooks/hooks.organisations.js.html +553 -0
  115. package/coverage/core/api/hooks/hooks.push.js.html +232 -0
  116. package/coverage/core/api/hooks/hooks.query.js.html +838 -0
  117. package/coverage/core/api/hooks/hooks.schemas.js.html +304 -0
  118. package/coverage/core/api/hooks/hooks.service.js.html +319 -0
  119. package/coverage/core/api/hooks/hooks.storage.js.html +193 -0
  120. package/coverage/core/api/hooks/hooks.tags.js.html +850 -0
  121. package/coverage/core/api/hooks/hooks.users.js.html +826 -0
  122. package/coverage/core/api/hooks/index.html +296 -0
  123. package/coverage/core/api/hooks/index.js.html +121 -0
  124. package/coverage/core/api/index.html +191 -0
  125. package/coverage/core/api/index.js.html +148 -0
  126. package/coverage/core/api/marshall.js.html +355 -0
  127. package/coverage/core/api/models/groups.model.mongodb.js.html +109 -0
  128. package/coverage/core/api/models/index.html +161 -0
  129. package/coverage/core/api/models/organisations.model.mongodb.js.html +94 -0
  130. package/coverage/core/api/models/tags.model.mongodb.js.html +115 -0
  131. package/coverage/core/api/models/users.model.mongodb.js.html +115 -0
  132. package/coverage/core/api/services/account/account.hooks.js.html +196 -0
  133. package/coverage/core/api/services/account/account.service.js.html +445 -0
  134. package/coverage/core/api/services/account/index.html +131 -0
  135. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +184 -0
  136. package/coverage/core/api/services/authorisations/authorisations.service.js.html +502 -0
  137. package/coverage/core/api/services/authorisations/index.html +131 -0
  138. package/coverage/core/api/services/databases/databases.hooks.js.html +193 -0
  139. package/coverage/core/api/services/databases/databases.service.js.html +100 -0
  140. package/coverage/core/api/services/databases/index.html +131 -0
  141. package/coverage/core/api/services/groups/groups.hooks.js.html +178 -0
  142. package/coverage/core/api/services/groups/index.html +116 -0
  143. package/coverage/core/api/services/index.html +116 -0
  144. package/coverage/core/api/services/index.js.html +475 -0
  145. package/coverage/core/api/services/mailer/index.html +131 -0
  146. package/coverage/core/api/services/mailer/mailer.hooks.js.html +190 -0
  147. package/coverage/core/api/services/mailer/mailer.service.js.html +118 -0
  148. package/coverage/core/api/services/organisations/index.html +131 -0
  149. package/coverage/core/api/services/organisations/organisations.hooks.js.html +178 -0
  150. package/coverage/core/api/services/organisations/organisations.service.js.html +343 -0
  151. package/coverage/core/api/services/push/index.html +131 -0
  152. package/coverage/core/api/services/push/push.hooks.js.html +193 -0
  153. package/coverage/core/api/services/push/push.service.js.html +121 -0
  154. package/coverage/core/api/services/storage/index.html +131 -0
  155. package/coverage/core/api/services/storage/storage.hooks.js.html +190 -0
  156. package/coverage/core/api/services/storage/storage.service.js.html +172 -0
  157. package/coverage/core/api/services/tags/index.html +116 -0
  158. package/coverage/core/api/services/tags/tags.hooks.js.html +178 -0
  159. package/coverage/core/api/services/users/index.html +116 -0
  160. package/coverage/core/api/services/users/users.hooks.js.html +313 -0
  161. package/coverage/core/api/utils.js.html +118 -0
  162. package/coverage/core/common/errors.js.html +88 -0
  163. package/coverage/core/common/index.html +176 -0
  164. package/coverage/core/common/index.js.html +115 -0
  165. package/coverage/core/common/permissions.js.html +1039 -0
  166. package/coverage/core/common/schema.js.html +190 -0
  167. package/coverage/core/common/utils.js.html +220 -0
  168. package/coverage/favicon.png +0 -0
  169. package/coverage/index.html +476 -0
  170. package/coverage/lcov-report/base.css +224 -0
  171. package/coverage/lcov-report/block-navigation.js +87 -0
  172. package/coverage/lcov-report/core/api/application.js.html +1849 -0
  173. package/coverage/lcov-report/core/api/authentication.js.html +694 -0
  174. package/coverage/lcov-report/core/api/db.js.html +763 -0
  175. package/coverage/lcov-report/core/api/hooks/hooks.account.js.html +169 -0
  176. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +274 -0
  177. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +1213 -0
  178. package/coverage/lcov-report/core/api/hooks/hooks.groups.js.html +229 -0
  179. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +163 -0
  180. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +994 -0
  181. package/coverage/lcov-report/core/api/hooks/hooks.organisations.js.html +553 -0
  182. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +232 -0
  183. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +838 -0
  184. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +304 -0
  185. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +319 -0
  186. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +193 -0
  187. package/coverage/lcov-report/core/api/hooks/hooks.tags.js.html +850 -0
  188. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +826 -0
  189. package/coverage/lcov-report/core/api/hooks/index.html +296 -0
  190. package/coverage/lcov-report/core/api/hooks/index.js.html +121 -0
  191. package/coverage/lcov-report/core/api/index.html +191 -0
  192. package/coverage/lcov-report/core/api/index.js.html +148 -0
  193. package/coverage/lcov-report/core/api/marshall.js.html +355 -0
  194. package/coverage/lcov-report/core/api/models/groups.model.mongodb.js.html +109 -0
  195. package/coverage/lcov-report/core/api/models/index.html +161 -0
  196. package/coverage/lcov-report/core/api/models/organisations.model.mongodb.js.html +94 -0
  197. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +115 -0
  198. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +115 -0
  199. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +196 -0
  200. package/coverage/lcov-report/core/api/services/account/account.service.js.html +445 -0
  201. package/coverage/lcov-report/core/api/services/account/index.html +131 -0
  202. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +184 -0
  203. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +502 -0
  204. package/coverage/lcov-report/core/api/services/authorisations/index.html +131 -0
  205. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +193 -0
  206. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +100 -0
  207. package/coverage/lcov-report/core/api/services/databases/index.html +131 -0
  208. package/coverage/lcov-report/core/api/services/groups/groups.hooks.js.html +178 -0
  209. package/coverage/lcov-report/core/api/services/groups/index.html +116 -0
  210. package/coverage/lcov-report/core/api/services/index.html +116 -0
  211. package/coverage/lcov-report/core/api/services/index.js.html +475 -0
  212. package/coverage/lcov-report/core/api/services/mailer/index.html +131 -0
  213. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +190 -0
  214. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +118 -0
  215. package/coverage/lcov-report/core/api/services/organisations/index.html +131 -0
  216. package/coverage/lcov-report/core/api/services/organisations/organisations.hooks.js.html +178 -0
  217. package/coverage/lcov-report/core/api/services/organisations/organisations.service.js.html +343 -0
  218. package/coverage/lcov-report/core/api/services/push/index.html +131 -0
  219. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +193 -0
  220. package/coverage/lcov-report/core/api/services/push/push.service.js.html +121 -0
  221. package/coverage/lcov-report/core/api/services/storage/index.html +131 -0
  222. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +190 -0
  223. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +172 -0
  224. package/coverage/lcov-report/core/api/services/tags/index.html +116 -0
  225. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +178 -0
  226. package/coverage/lcov-report/core/api/services/users/index.html +116 -0
  227. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +313 -0
  228. package/coverage/lcov-report/core/api/utils.js.html +118 -0
  229. package/coverage/lcov-report/core/common/errors.js.html +88 -0
  230. package/coverage/lcov-report/core/common/index.html +176 -0
  231. package/coverage/lcov-report/core/common/index.js.html +115 -0
  232. package/coverage/lcov-report/core/common/permissions.js.html +1039 -0
  233. package/coverage/lcov-report/core/common/schema.js.html +190 -0
  234. package/coverage/lcov-report/core/common/utils.js.html +220 -0
  235. package/coverage/lcov-report/favicon.png +0 -0
  236. package/coverage/lcov-report/index.html +476 -0
  237. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +340 -0
  238. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +337 -0
  239. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +1168 -0
  240. package/coverage/lcov-report/map/api/hooks/index.html +161 -0
  241. package/coverage/lcov-report/map/api/hooks/index.js.html +94 -0
  242. package/coverage/lcov-report/map/api/index.html +131 -0
  243. package/coverage/lcov-report/map/api/index.js.html +139 -0
  244. package/coverage/lcov-report/map/api/marshall.js.html +178 -0
  245. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +106 -0
  246. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +127 -0
  247. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +196 -0
  248. package/coverage/lcov-report/map/api/models/index.html +146 -0
  249. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +274 -0
  250. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +610 -0
  251. package/coverage/lcov-report/map/api/services/alerts/index.html +131 -0
  252. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +313 -0
  253. package/coverage/lcov-report/map/api/services/catalog/index.html +116 -0
  254. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +1510 -0
  255. package/coverage/lcov-report/map/api/services/daptiles/index.html +116 -0
  256. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +205 -0
  257. package/coverage/lcov-report/map/api/services/features/features.service.js.html +241 -0
  258. package/coverage/lcov-report/map/api/services/features/index.html +131 -0
  259. package/coverage/lcov-report/map/api/services/geocoder/geocoder.hooks.js.html +178 -0
  260. package/coverage/lcov-report/map/api/services/geocoder/geocoder.service.js.html +322 -0
  261. package/coverage/lcov-report/map/api/services/geocoder/index.html +131 -0
  262. package/coverage/lcov-report/map/api/services/index.html +116 -0
  263. package/coverage/lcov-report/map/api/services/index.js.html +769 -0
  264. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +466 -0
  265. package/coverage/lcov-report/map/common/errors.js.html +94 -0
  266. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +535 -0
  267. package/coverage/lcov-report/map/common/grid.js.html +1612 -0
  268. package/coverage/lcov-report/map/common/index.html +371 -0
  269. package/coverage/lcov-report/map/common/index.js.html +172 -0
  270. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +556 -0
  271. package/coverage/lcov-report/map/common/moment-utils.js.html +157 -0
  272. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +868 -0
  273. package/coverage/lcov-report/map/common/opendap-utils.js.html +826 -0
  274. package/coverage/lcov-report/map/common/permissions.js.html +118 -0
  275. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +418 -0
  276. package/coverage/lcov-report/map/common/tms-utils.js.html +274 -0
  277. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +364 -0
  278. package/coverage/lcov-report/map/common/wcs-utils.js.html +586 -0
  279. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +1033 -0
  280. package/coverage/lcov-report/map/common/wfs-utils.js.html +574 -0
  281. package/coverage/lcov-report/map/common/wms-utils.js.html +436 -0
  282. package/coverage/lcov-report/map/common/wmts-utils.js.html +547 -0
  283. package/coverage/lcov-report/prettify.css +1 -0
  284. package/coverage/lcov-report/prettify.js +2 -0
  285. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  286. package/coverage/lcov-report/sorter.js +196 -0
  287. package/coverage/lcov.info +10742 -0
  288. package/coverage/map/api/hooks/hooks.catalog.js.html +340 -0
  289. package/coverage/map/api/hooks/hooks.features.js.html +337 -0
  290. package/coverage/map/api/hooks/hooks.query.js.html +1168 -0
  291. package/coverage/map/api/hooks/index.html +161 -0
  292. package/coverage/map/api/hooks/index.js.html +94 -0
  293. package/coverage/map/api/index.html +131 -0
  294. package/coverage/map/api/index.js.html +139 -0
  295. package/coverage/map/api/marshall.js.html +178 -0
  296. package/coverage/map/api/models/alerts.model.mongodb.js.html +106 -0
  297. package/coverage/map/api/models/catalog.model.mongodb.js.html +127 -0
  298. package/coverage/map/api/models/features.model.mongodb.js.html +196 -0
  299. package/coverage/map/api/models/index.html +146 -0
  300. package/coverage/map/api/services/alerts/alerts.hooks.js.html +274 -0
  301. package/coverage/map/api/services/alerts/alerts.service.js.html +610 -0
  302. package/coverage/map/api/services/alerts/index.html +131 -0
  303. package/coverage/map/api/services/catalog/catalog.hooks.js.html +313 -0
  304. package/coverage/map/api/services/catalog/index.html +116 -0
  305. package/coverage/map/api/services/daptiles/daptiles.service.js.html +1510 -0
  306. package/coverage/map/api/services/daptiles/index.html +116 -0
  307. package/coverage/map/api/services/features/features.hooks.js.html +205 -0
  308. package/coverage/map/api/services/features/features.service.js.html +241 -0
  309. package/coverage/map/api/services/features/index.html +131 -0
  310. package/coverage/map/api/services/geocoder/geocoder.hooks.js.html +178 -0
  311. package/coverage/map/api/services/geocoder/geocoder.service.js.html +322 -0
  312. package/coverage/map/api/services/geocoder/index.html +131 -0
  313. package/coverage/map/api/services/index.html +116 -0
  314. package/coverage/map/api/services/index.js.html +769 -0
  315. package/coverage/map/common/dynamic-grid-source.js.html +466 -0
  316. package/coverage/map/common/errors.js.html +94 -0
  317. package/coverage/map/common/geotiff-grid-source.js.html +535 -0
  318. package/coverage/map/common/grid.js.html +1612 -0
  319. package/coverage/map/common/index.html +371 -0
  320. package/coverage/map/common/index.js.html +172 -0
  321. package/coverage/map/common/meteo-model-grid-source.js.html +556 -0
  322. package/coverage/map/common/moment-utils.js.html +157 -0
  323. package/coverage/map/common/opendap-grid-source.js.html +868 -0
  324. package/coverage/map/common/opendap-utils.js.html +826 -0
  325. package/coverage/map/common/permissions.js.html +118 -0
  326. package/coverage/map/common/time-based-grid-source.js.html +418 -0
  327. package/coverage/map/common/tms-utils.js.html +274 -0
  328. package/coverage/map/common/wcs-grid-source.js.html +364 -0
  329. package/coverage/map/common/wcs-utils.js.html +586 -0
  330. package/coverage/map/common/weacast-grid-source.js.html +1033 -0
  331. package/coverage/map/common/wfs-utils.js.html +574 -0
  332. package/coverage/map/common/wms-utils.js.html +436 -0
  333. package/coverage/map/common/wmts-utils.js.html +547 -0
  334. package/coverage/prettify.css +1 -0
  335. package/coverage/prettify.js +2 -0
  336. package/coverage/sort-arrow-sprite.png +0 -0
  337. package/coverage/sorter.js +196 -0
  338. package/coverage/tmp/coverage-59096-1692631696256-0.json +1 -0
  339. package/coverage/tmp/coverage-59108-1692631696233-0.json +1 -0
  340. package/coverage/tmp/coverage-59119-1692631696222-0.json +1 -0
  341. package/coverage/tmp/coverage-59131-1692631696200-0.json +1 -0
  342. package/coverage/tmp/coverage-59138-1692631696175-0.json +1 -0
  343. package/extras/css/core.variables.scss +5 -1
  344. package/extras/tours/core/account-profile.js +14 -31
  345. package/extras/tours/core/account.js +143 -0
  346. package/extras/tours/core/add-member.js +7 -6
  347. package/extras/tours/core/add-tag.js +13 -0
  348. package/extras/tours/core/create-tag.js +26 -0
  349. package/extras/tours/core/edit-member-role.js +13 -0
  350. package/extras/tours/core/join-group.js +0 -12
  351. package/extras/tours/core/login.js +0 -7
  352. package/extras/tours/core/members.js +13 -26
  353. package/extras/tours/core/send-reset-password.js +1 -1
  354. package/extras/tours/core/tags.js +17 -4
  355. package/extras/tours/map/navigation-bar.js +1 -1
  356. package/extras/tours/map/side-nav.js +3 -2
  357. package/map/api/hooks/hooks.query.js +5 -3
  358. package/map/client/cesium/utils.js +68 -0
  359. package/map/client/components/KFeatureActionButton.vue +27 -27
  360. package/map/client/components/KFeaturesChart.vue +1 -1
  361. package/map/client/components/KFeaturesTable.vue +2 -2
  362. package/map/client/components/KLayerEditionToolbar.vue +1 -0
  363. package/map/client/components/KPositionIndicator.vue +1 -1
  364. package/map/client/components/catalog/KViewSelector.vue +1 -2
  365. package/map/client/components/catalog/KViewsPanel.vue +17 -15
  366. package/map/client/components/form/KDirectionField.vue +0 -1
  367. package/map/client/components/form/KLocationField.vue +16 -29
  368. package/map/client/components/legend/KSymbolsLegend.vue +2 -1
  369. package/map/client/components/location/KLocationCardSection.vue +61 -0
  370. package/map/client/components/location/KLocationMap.vue +24 -13
  371. package/map/client/components/location/KLocationSearch.vue +144 -0
  372. package/map/client/components/location/KLocationTip.vue +29 -0
  373. package/map/client/components/tools/KGeolocateTool.vue +46 -0
  374. package/map/client/components/tools/KSearchTool.vue +93 -0
  375. package/map/client/components/widget/KElevationProfile.vue +2 -2
  376. package/map/client/components/widget/KInformationBox.vue +3 -3
  377. package/map/client/composables/location.js +35 -43
  378. package/map/client/geolocation.js +65 -8
  379. package/map/client/i18n/map_en.json +15 -13
  380. package/map/client/i18n/map_fr.json +15 -13
  381. package/map/client/init.js +10 -18
  382. package/map/client/leaflet/GradientPath.js +2 -1
  383. package/map/client/leaflet/utils.js +61 -0
  384. package/map/client/mixins/globe/mixin.base-globe.js +6 -5
  385. package/map/client/mixins/globe/mixin.popup.js +3 -0
  386. package/map/client/mixins/globe/mixin.style.js +9 -64
  387. package/map/client/mixins/globe/mixin.tooltip.js +3 -0
  388. package/map/client/mixins/index.js +0 -1
  389. package/map/client/mixins/map/mixin.base-map.js +13 -9
  390. package/map/client/mixins/map/mixin.edit-layers.js +82 -15
  391. package/map/client/mixins/map/mixin.geojson-layers.js +8 -1
  392. package/map/client/mixins/map/mixin.style.js +8 -56
  393. package/map/client/mixins/mixin.activity.js +20 -12
  394. package/map/client/mixins/mixin.feature-service.js +34 -1
  395. package/map/client/readers/reader.geojson.js +1 -1
  396. package/map/client/utils/utils.location.js +45 -0
  397. package/package.json +13 -14
  398. package/test/api/core/account.test.js +162 -153
  399. package/test/api/core/config/default.cjs +7 -11
  400. package/test/api/core/config/email-templates/confirmInvitation/html.ejs +1 -1
  401. package/test/api/core/config/email-templates/identityChange/html.ejs +6 -4
  402. package/test/api/core/config/email-templates/newDevice/html.ejs +1 -1
  403. package/test/api/core/config/email-templates/newSubscription/html.ejs +7 -0
  404. package/test/api/core/config/email-templates/passwordChange/html.ejs +1 -1
  405. package/test/api/core/config/email-templates/resendVerifySignup/html.ejs +6 -4
  406. package/test/api/core/config/email-templates/resetPwd/html.ejs +1 -1
  407. package/test/api/core/config/email-templates/sendResetPwd/html.ejs +8 -4
  408. package/test/api/core/hooks.test.js +166 -18
  409. package/test/api/core/index.test.js +32 -70
  410. package/test/api/core/push.test.js +197 -0
  411. package/test/api/core/team.test.js +38 -32
  412. package/test/api/core/test-log-2023-07-04.log +0 -0
  413. package/test/api/core/test-log-2023-07-10.log +2 -0
  414. package/test/api/core/test-log-2023-07-12.log +0 -0
  415. package/test/api/core/test-log-2023-07-18.log +78 -0
  416. package/test/api/core/test-log-2023-07-19.log +44 -0
  417. package/test/api/core/test-log-2023-08-01.log +162 -0
  418. package/test/api/core/test-log-2023-08-21.log +66 -0
  419. package/test/api/core/test-log-2023-08-22.log +96 -0
  420. package/test/api/core/test-log-2023-08-23.log +22 -0
  421. package/test/api/core/test-log-2023-09-20.log +22 -0
  422. package/test/api/core/test-log-2023-09-21.log +105 -0
  423. package/test/api/core/utils.js +11 -2
  424. package/test/api/map/alerts.test.js +1 -1
  425. package/test/api/map/test-log-2023-07-18.log +62 -0
  426. package/test/api/map/test-log-2023-07-19.log +13 -0
  427. package/test/api/map/test-log-2023-08-21.log +65 -0
  428. package/test/api/map/test-log-2023-09-20.log +60 -0
  429. package/test/api/map/test-log-2023-09-21.log +12 -0
  430. package/test/client/core/account.js +15 -32
  431. package/test/client/core/api.js +99 -44
  432. package/test/client/core/layout.js +4 -0
  433. package/test/client/core/runner.js +66 -14
  434. package/test/client/core/time.js +1 -1
  435. package/test/client/map/controls.js +17 -3
  436. package/core/api/hooks/hooks.account.js +0 -28
  437. package/core/api/hooks/hooks.devices.js +0 -42
  438. package/core/api/hooks/hooks.pusher.js +0 -215
  439. package/core/api/hooks/hooks.tags.js +0 -255
  440. package/core/api/services/devices/devices.service.js +0 -99
  441. package/core/api/services/pusher/pusher.channels.js +0 -3
  442. package/core/api/services/pusher/pusher.hooks.js +0 -36
  443. package/core/api/services/pusher/pusher.service.js +0 -449
  444. package/core/client/components/KInstallApp.vue +0 -43
  445. package/core/client/components/account/KAccountActivity.vue +0 -58
  446. package/core/client/components/account/KAccountDZ.vue +0 -66
  447. package/core/client/components/account/KAccountDevices.vue +0 -56
  448. package/core/client/components/account/KAccountSecurity.vue +0 -87
  449. package/core/client/components/account/KChangeIdentity.vue +0 -102
  450. package/core/client/components/account/KChangePassword.vue +0 -132
  451. package/core/client/components/account/KDeviceCard.vue +0 -75
  452. package/core/client/components/account/KIdentityPanel.vue +0 -34
  453. package/core/client/components/account/KResendVerifySignup.vue +0 -108
  454. package/core/client/components/account/KSendChangeIdentity.vue +0 -115
  455. package/core/client/components/account/KSignupAlert.vue +0 -63
  456. package/core/client/components/account/KVerifySignup.vue +0 -102
  457. package/core/client/components/form/KTagField.vue +0 -148
  458. package/core/common/schemas/members.update.json +0 -18
  459. package/extras/tours/core/account-dz.js +0 -37
  460. package/extras/tours/core/account-security.js +0 -52
  461. package/extras/tours/core/change-password.js +0 -34
  462. package/extras/tours/core/edit-member-tags.js +0 -18
  463. package/extras/tours/core/send-change-identity.js +0 -28
  464. package/map/client/components/KLocateUser.vue +0 -36
  465. package/map/client/components/KLocationInput.vue +0 -217
  466. package/map/client/components/KLocationMap.vue +0 -301
  467. package/map/client/components/KSearchLocation.vue +0 -88
  468. package/map/client/components/input/KPlaceChooser.vue +0 -78
  469. package/map/client/components/location/KLocation.vue +0 -24
  470. package/map/client/mixins/mixin.navigator.js +0 -36
  471. package/test/api/core/notifications.test.js +0 -502
package/.codeclimate.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  exclude_patterns:
2
2
  - "lib/"
3
- - "**/client/**"
4
3
  plugins:
5
4
  fixme:
6
5
  enabled: true
package/.travis.test.sh CHANGED
@@ -20,6 +20,9 @@ git clone https://github.com/kalisio/kdk-workspaces workspace
20
20
  git clone https://github.com/kalisio/feathers-distributed && cd feathers-distributed && yarn install && yarn link && cd ..
21
21
  yarn link @kalisio/feathers-distributed
22
22
 
23
+ git clone https://github.com/kalisio/feathers-webpush && cd feathers-webpush && yarn install && yarn link && cd ..
24
+ yarn link @kalisio/feathers-webpush
25
+
23
26
  git clone https://github.com/weacast/weacast && cd weacast && yarn install && cd packages
24
27
  cd core && yarn link && cd .. && cd gfs && yarn link && cd .. && cd probe && yarn link && cd ..
25
28
  cd ../..
@@ -89,8 +89,8 @@ export function declareService (name, app, service, serviceOptions = {}) {
89
89
  }
90
90
 
91
91
  export async function configureService (name, service, servicesPath) {
92
+ let filepath = path.join(servicesPath, name, `${name}.hooks.js`)
92
93
  try {
93
- const filepath = path.join(servicesPath, name, `${name}.hooks.js`)
94
94
  const fileExists = await fs.pathExists(filepath)
95
95
  if (fileExists) {
96
96
  const hooks = (await import(url.pathToFileURL(filepath))).default
@@ -101,13 +101,13 @@ export async function configureService (name, service, servicesPath) {
101
101
  debug('No ' + name + ' service hooks configured on path ' + servicesPath)
102
102
  if (error.code !== 'ERR_MODULE_NOT_FOUND') {
103
103
  // Log error in this case as this might be linked to a syntax error in required file
104
- debug(error)
104
+ debug(filepath, error)
105
105
  }
106
106
  // As this is optionnal this require has to fail silently
107
107
  }
108
108
 
109
+ filepath = path.join(servicesPath, name, `${name}.channels.js`)
109
110
  try {
110
- const filepath = path.join(servicesPath, name, `${name}.channels.js`)
111
111
  const fileExists = await fs.pathExists(filepath)
112
112
  if (fileExists) {
113
113
  const channels = (await import(url.pathToFileURL(filepath))).default
@@ -121,7 +121,7 @@ export async function configureService (name, service, servicesPath) {
121
121
  debug('No ' + name + ' service channels configured on path ' + servicesPath)
122
122
  if (error.code !== 'ERR_MODULE_NOT_FOUND') {
123
123
  // Log error in this case as this might be linked to a syntax error in required file
124
- debug(error)
124
+ debug(filepath, error)
125
125
  }
126
126
  // As this is optionnal this require has to fail silently
127
127
  }
@@ -176,7 +176,8 @@ async function createService (name, app, options = {}) {
176
176
  whitelist: [
177
177
  '$exists', '$and', '$or', '$eq', '$elemMatch', '$distinct', '$groupBy', '$group', '$regex',
178
178
  '$text', '$search', '$caseSensitive', '$language', '$diacriticSensitive',
179
- '$aggregate', '$near', '$geoIntersects', '$geometry', '$maxDistance'
179
+ '$aggregate', '$near', '$nearSphere', '$geoIntersects', '$geoWithin',
180
+ '$maxDistance', '$minDistance', '$geometry', '$box', '$polygon', '$center', '$centerSphere'
180
181
  ]
181
182
  }, options)
182
183
  if (serviceOptions.disabled) return undefined
@@ -199,7 +200,7 @@ async function createService (name, app, options = {}) {
199
200
  debug('No ' + fileName + ' service model configured on path ' + serviceOptions.modelsPath)
200
201
  if (error.code !== 'ERR_MODULE_NOT_FOUND') {
201
202
  // Log error in this case as this might be linked to a syntax error in required file
202
- debug(error)
203
+ debug(fileName, error)
203
204
  }
204
205
  // As this is optionnal this require has to fail silently
205
206
  }
@@ -224,8 +225,8 @@ async function createService (name, app, options = {}) {
224
225
  }
225
226
  // Optionnally a specific service mixin can be provided, apply it
226
227
  if (dbService && serviceOptions.servicesPath) {
228
+ const filepath = path.join(serviceOptions.servicesPath, fileName, `${fileName}.service.js`)
227
229
  try {
228
- const filepath = path.join(serviceOptions.servicesPath, fileName, `${fileName}.service.js`)
229
230
  const fileExists = await fs.pathExists(filepath)
230
231
  if (fileExists) {
231
232
  let serviceMixin = (await import(url.pathToFileURL(filepath))).default
@@ -240,7 +241,7 @@ async function createService (name, app, options = {}) {
240
241
  debug('No ' + fileName + ' service mixin configured on path ' + serviceOptions.servicesPath)
241
242
  // if (error.code !== 'ERR_MODULE_NOT_FOUND') {
242
243
  // Log error in this case as this might be linked to a syntax error in required file
243
- debug(error)
244
+ debug(filepath, error)
244
245
  // }
245
246
  // As this is optionnal this require has to fail silently
246
247
  }
@@ -434,7 +435,10 @@ function setupSockets (app) {
434
435
  // e.g. like [service_method, service_path, id or data, params]
435
436
  // Bypass rate limiting on whitelist
436
437
  if ((packet.length > 1) && (typeof packet[1] === 'string')) {
437
- const service = app.service(packet[1])
438
+ // Service path includes API prefix (but without trailing /)
439
+ // Get name from service path without api prefix
440
+ const serviceName = packet[1].replace(app.get('apiPath').substring(1) + '/', '')
441
+ const service = app.getService(serviceName)
438
442
  if (service && services(service)) {
439
443
  debugLimiter('By-pass rate limiting on whitelisted service operation', socket.id, socket.conn.remoteAddress, packet[0], packet[1])
440
444
  next()
package/core/api/db.js CHANGED
@@ -33,43 +33,47 @@ export function createObjectID (id) {
33
33
  }
34
34
 
35
35
  // Utility function used to convert from string to MongoDB IDs as required eg by queries
36
+ // It only processes _id properties or operators (eg $ne, $in) to be converted
37
+ // If you have others properties to be converted use toObjectIDs
36
38
  export function objectifyIDs (object) {
37
- _.forOwn(object, (value, key) => {
38
- // Process current attributes or recurse
39
- // Take care to nested fields like 'field._id'
40
- if (key === '_id' || key.endsWith('._id') || key === '$ne') {
41
- if (typeof value === 'string') {
42
- debug('Objectify ID ' + key)
43
- const id = createObjectID(value)
44
- if (id) {
45
- object[key] = id
46
- }
47
- } else if (Array.isArray(value)) {
39
+ // Avoid destructuring already transformed Date, ObjectID or arrays
40
+ if (_.isPlainObject(object)) {
41
+ _.forOwn(object, (value, key) => {
42
+ // Process current attributes or recurse
43
+ // Take care to nested fields like 'field._id'
44
+ if (key === '_id' || key.endsWith('._id') || key === '$ne') {
45
+ if (typeof value === 'string') {
46
+ const id = createObjectID(value)
47
+ if (id) {
48
+ object[key] = id
49
+ }
50
+ debug('Objectify ID ' + key, id)
51
+ } else if (Array.isArray(value)) {
52
+ debug('Objectify ID array ' + key)
53
+ object[key] = value.map(id => createObjectID(id)).filter(id => id)
54
+ } else objectifyIDs(value)
55
+ } else if (['$in', '$nin'].includes(key)) {
48
56
  debug('Objectify ID array ' + key)
49
- object[key] = value.map(id => createObjectID(id)).filter(id => id)
50
- } else if ((typeof value === 'object') && !isObjectID(value)) objectifyIDs(value) // Avoid jumping inside an already transformed ObjectID
51
- } else if (['$in', '$nin'].includes(key)) {
52
- debug('Objectify ID array ' + key)
53
- const ids = value.map(id => createObjectID(id)).filter(id => id)
54
- // Take care that $in/$nin can be used for others types than Object IDs so conversion might fail
55
- if (ids.length > 0) object[key] = ids
56
- } else if (key === '$or') {
57
- value.forEach(entry => objectifyIDs(entry))
58
- // Avoid jumping inside an already transformed Date, ObjectID or arrays
59
- } else if ((typeof value === 'object') && !(value instanceof Date) && !isObjectID(value) && !Array.isArray(value)) {
60
- objectifyIDs(value)
61
- }
62
- })
57
+ const ids = value.map(id => createObjectID(id)).filter(id => id)
58
+ // Take care that $in/$nin can be used for others types than Object IDs so conversion might fail
59
+ if (ids.length > 0) object[key] = ids
60
+ } else if ((key === '$or') || (key === '$and')) {
61
+ value.forEach(entry => objectifyIDs(entry))
62
+ } else {
63
+ if (!Array.isArray(value)) objectifyIDs(value)
64
+ else value.forEach(entry => objectifyIDs(entry))
65
+ }
66
+ })
67
+ }
63
68
  return object
64
69
  }
65
70
 
66
- // Utility function used to convert from string to MongoDB IDs a fixed set of properties on a given object
71
+ // Utility function used to convert a fixed set of properties on a given object from string to MongoDB IDs
67
72
  export function toObjectIDs (object, properties) {
68
73
  properties.forEach(property => {
69
- const id = createObjectID(_.get(object, property))
70
- if (id) {
71
- _.set(object, property, id)
72
- }
74
+ const value = _.get(object, property)
75
+ const id = createObjectID(value)
76
+ if (id) _.set(object, property, id)
73
77
  })
74
78
  }
75
79
 
@@ -1,7 +1,9 @@
1
1
  import makeDebug from 'debug'
2
+ import common from 'feathers-hooks-common'
2
3
  import local from '@feathersjs/authentication-local'
3
4
 
4
5
  const debug = makeDebug('kdk:core:authentication:hooks')
6
+ const { discard } = common
5
7
 
6
8
  // Make it more easy to acces
7
9
  export const hashPassword = local.hooks.hashPassword
@@ -61,3 +63,12 @@ export async function consentGuest (hook) {
61
63
 
62
64
  return hook
63
65
  }
66
+
67
+ export function discardAuthenticationProviders (hook) {
68
+ const providers = hook.app.authenticationProviders || []
69
+
70
+ // Iterate through known providers
71
+ for (const provider of providers) {
72
+ discard(provider)(hook)
73
+ }
74
+ }
@@ -8,7 +8,7 @@ import {
8
8
  hasServiceAbilities, hasResourceAbilities, getQueryForAbilities,
9
9
  Roles, RoleNames, countSubjectsForResource
10
10
  } from '../../common/permissions.js'
11
- import { isTagEqual } from './hooks.tags.js'
11
+ import { isTagEqual } from '../utils.js'
12
12
 
13
13
  const { getItems, replaceItems } = common
14
14
  const { Forbidden } = errors
@@ -233,7 +233,11 @@ export async function authorise (hook) {
233
233
  // this has to be implemented by the service itself
234
234
  } else if (typeof hook.service.get === 'function') {
235
235
  // In this case (single get/update/patch/remove) we need to fetch the item first
236
- const resource = await hook.service.get(hook.id, Object.assign({ checkAuthorisation: false }, hook.params))
236
+ // Take care we might have additional query parameters to be "catched" by before hooks,
237
+ // however at this stage these query parameters might cause get to fail
238
+ const params = Object.assign({ checkAuthorisation: false }, hook.params)
239
+ _.unset(params, 'query')
240
+ const resource = await hook.service.get(hook.id, params)
237
241
  debug('Target resource is', resource)
238
242
  // Then check against the object we'd like to manage
239
243
  if (!hasResourceAbilities(abilities, operation, resourceType, context, resource)) {
@@ -362,7 +366,7 @@ export async function removeOrganisationTagsAuthorisations (hook) {
362
366
  const notFromOrg = _.differenceWith(tags, orgTags, isTagEqual)
363
367
  // Update subject if required
364
368
  if (fromOrg.length > 0) {
365
- promises.push(subjectService.patch(subject._id.toString(), { tags: notFromOrg, devices: subject.devices }))
369
+ promises.push(subjectService.patch(subject._id.toString(), { tags: notFromOrg }))
366
370
  }
367
371
  })
368
372
  // Perform subject updates in parallel
@@ -7,7 +7,7 @@ import { marshallTimes, unmarshallTimes } from '../marshall.js'
7
7
  import common from 'feathers-hooks-common'
8
8
  import makeDebug from 'debug'
9
9
 
10
- const { Conflict } = errors
10
+ const { Conflict, BadRequest } = errors
11
11
  const { discard, disallow, getItems, replaceItems } = common
12
12
  const sift = siftModule.default
13
13
  const debug = makeDebug('kdk:core:model:hooks')
@@ -36,47 +36,6 @@ export function unprocessTimes (properties) {
36
36
  }
37
37
  }
38
38
 
39
- export function processPerspectives (hook) {
40
- const params = hook.params
41
- const query = params.query
42
- const service = hook.service
43
-
44
- // Test if some perspectives are defined on the model
45
- if (!service.options || !service.options.perspectives) return
46
-
47
- // Iterate through known perspectives of the model
48
- service.options.perspectives.forEach(perspective => {
49
- // Only discard if not explicitely asked by $select
50
- let filterPerspective = true
51
- if (!_.isNil(query) && !_.isNil(query.$select)) {
52
- // Transform to array to unify processing
53
- const selectedFields = (typeof query.$select === 'string' ? [query.$select] : query.$select)
54
- if (Array.isArray(selectedFields)) {
55
- selectedFields.forEach(field => {
56
- // Take care that we might only ask for a subset of perspective fields like ['perspective.fieldName']
57
- if ((field === perspective) || field.startsWith(perspective + '.')) {
58
- filterPerspective = false
59
- }
60
- })
61
- }
62
- }
63
- if (filterPerspective) {
64
- discard(perspective)(hook)
65
- }
66
- })
67
- }
68
-
69
- // When perspectives are present we disallow update in order to avoid erase them.
70
- // Indeed when requesting an object they are not retrieved by default
71
- export function preventUpdatePerspectives (hook) {
72
- const service = hook.service
73
-
74
- // Test if some perspectives are defined on the model
75
- if (!service.options || !service.options.perspectives) return
76
-
77
- disallow()(hook)
78
- }
79
-
80
39
  // The hook serialize allows to copy/move some properties within the objects holded by the hook
81
40
  // It applies an array of rules defined by:
82
41
  // - source: the path to the property to be copied
@@ -108,8 +67,10 @@ export function serialize (rules, options = {}) {
108
67
  }
109
68
  }
110
69
 
111
- // The hook allows to transform the values bound to '_id' like keys as strings into Mongo ObjectIds
70
+ // This hook allows to transform the values bound to '_id' like keys or
71
+ // operators (eg $ne, $in) provided as strings into Mongo ObjectIds
112
72
  // It inspects hook data as well as query data
73
+ // If you have others properties to be converted use convertObjectIDs
113
74
  export function processObjectIDs (hook) {
114
75
  let items = getItems(hook)
115
76
  const isArray = Array.isArray(items)
@@ -299,3 +260,31 @@ export function checkUnique (options = {}) {
299
260
  return hook
300
261
  }
301
262
  }
263
+
264
+ // Prevent patch service calls from changing certain fields.
265
+ // Based on https://hooks-common.feathersjs.com/hooks.html#preventchanges
266
+ // but updated to handle dot notation
267
+ export function preventChanges(ifThrow, fieldNames) {
268
+ return (hook) => {
269
+ if ((hook.type !== 'before') || (hook.method !== 'patch')) {
270
+ throw new Error('The \'preventChanges\' hook should only be used as a \'before\' patch hook.')
271
+ }
272
+
273
+ let data = { ...hook.data }
274
+ // Check all data fields
275
+ _.forOwn(hook.data, (value, key) => {
276
+ fieldNames.forEach(name => {
277
+ // If a prevented field is found or dot notation with a prevented field is used
278
+ if ((key === name) || key.startsWith(`${name}.`)) {
279
+ if (ifThrow) {
280
+ throw new BadRequest(`Field ${name} may not be patched. (preventChanges)`);
281
+ }
282
+ delete data[key]
283
+ }
284
+ })
285
+ })
286
+ hook.data = data
287
+
288
+ return hook
289
+ }
290
+ }
@@ -5,21 +5,6 @@ const debug = makeDebug('kdk:core:organisations:hooks')
5
5
 
6
6
  const { Forbidden } = errors
7
7
 
8
- export function addOrganisationPlan (hook) {
9
- if (hook.type !== 'before') {
10
- throw new Error('The \'addOrganisationPlan\' hook should only be used as a \'before\' hook.')
11
- }
12
-
13
- const plans = _.keys(hook.app.get('plans') || {})
14
- const plan = _.get(hook.data, 'billing.plan')
15
- if (!plan && (plans.length > 0)) {
16
- // Add defaul plan
17
- _.set(hook.data, 'billing.plan', plans[0])
18
- debug('Added default plan to organisation: ', hook.data)
19
- }
20
- return hook
21
- }
22
-
23
8
  export async function createOrganisationServices (hook) {
24
9
  if (hook.type !== 'after') {
25
10
  throw new Error('The \'createOrganisationServices\' hook should only be used as a \'after\' hook.')
@@ -119,10 +104,14 @@ export function updateOrganisationResource (resourceScope) {
119
104
  if (hook.type !== 'after') {
120
105
  throw new Error('The \'updateOrganisationResource\' hook should only be used as a \'after\' hook.')
121
106
  }
107
+ // Only applicable to update/remove operations
108
+ if ((hook.method === 'get' || hook.method === 'find' || hook.method === 'create')) return hook
122
109
 
123
110
  const app = hook.app
124
111
  // Retrieve the list of members
125
- const orgMembersService = app.getService('members', hook.service.getContextId())
112
+ const context = hook.service.getContextId()
113
+ // Use members service if any or global users service
114
+ const orgMembersService = (context ? app.getService('members', context) : app.getService('users'))
126
115
  const members = await orgMembersService.find({
127
116
  query: { [resourceScope]: { $elemMatch: { _id: hook.result._id } } },
128
117
  paginate: false
@@ -130,13 +119,15 @@ export function updateOrganisationResource (resourceScope) {
130
119
  // Update each members
131
120
  await Promise.all(members.map(member => {
132
121
  const resources = _.get(member, resourceScope, [])
133
- const resource = _.find(resources, { _id: hook.result._id })
134
- if (resource) {
135
- Object.assign(resource, hook.result)
136
- return orgMembersService.patch(member._id, { [resourceScope]: resources })
122
+ const resource = _.find(resources, item => item._id.toString() === hook.result._id.toString())
123
+ if (!resource) return Promise.resolve()
124
+ // Check for removal or update
125
+ if (hook.method === 'remove') {
126
+ _.remove(resources, item => resource._id.toString() === item._id.toString())
137
127
  } else {
138
- return Promise.resolve()
128
+ Object.assign(resource, hook.result)
139
129
  }
130
+ return orgMembersService.patch(member._id, { [resourceScope]: resources })
140
131
  }))
141
132
 
142
133
  debug(`Updated resource ${hook.result._id} on scope ${resourceScope} for members of organisation ` + hook.result._id)
@@ -144,103 +135,22 @@ export function updateOrganisationResource (resourceScope) {
144
135
  }
145
136
  }
146
137
 
147
- export function removeOrganisationGroups (hook) {
148
- if (hook.type !== 'after') {
149
- throw new Error('The \'removeOrganisationGroups\' hook should only be used as a \'after\' hook.')
150
- }
151
-
152
- const app = hook.app
153
- const orgGroupService = app.getService('groups', hook.result)
154
- return orgGroupService.find({ paginate: false })
155
- .then(groups => {
156
- return Promise.all(groups.map(group => {
157
- return orgGroupService.remove(group._id.toString(), {
158
- user: hook.params.user
159
- })
160
- }))
161
- })
162
- .then(groups => {
163
- debug('Removed groups for organisation ' + hook.result._id)
164
- return hook
165
- })
166
- }
167
-
168
- export async function removeOrganisationTags (hook) {
169
- if (hook.type !== 'after') {
170
- throw new Error('The \'removeOrganisationTags\' hook should only be used as a \'after\' hook.')
171
- }
172
-
173
- const app = hook.app
174
- // Retrieve the list of tags
175
- const orgTagsService = app.getService('tags', hook.result)
176
- const tags = await orgTagsService.find({ paginate: false })
177
- // Retrieve the list of members
178
- const orgMembersService = app.getService('members', hook.result)
179
- const members = await orgMembersService.find({ paginate: false })
180
- // Update each members
181
- for (const i in members) {
182
- const member = members[i]
183
- if (member.tags) {
184
- const filteredTagsMember = _.filter(member.tags, (tag) => {
185
- return _.findIndex(tags, { _id: tag._id }) === -1
186
- })
187
- await orgMembersService.patch(member._id, { tags: filteredTagsMember })
138
+ export function removeOrganisationResources (resourceScope) {
139
+ return async function (hook) {
140
+ if (hook.type !== 'after') {
141
+ throw new Error('The \'removeOrganisationResources\' hook should only be used as a \'after\' hook.')
188
142
  }
189
- }
190
-
191
- debug('Removed tags from organisation ' + hook.result._id)
192
- return hook
193
- }
194
143
 
195
- export async function createPrivateOrganisation (hook) {
196
- if (hook.type !== 'after') {
197
- throw new Error('The \'createPrivateOrganisation\' hook should only be used as a \'after\' hook.')
198
- }
199
-
200
- const app = hook.app
201
- const organisationService = app.getService('organisations')
202
- // Create a private organisation for the user
203
- await organisationService.create({
204
- _id: hook.result._id, // Same ID as user, fine because in another service
205
- name: hook.result.profile.name // Same name as user
206
- }, {
207
- user: hook.result
208
- })
209
-
210
- debug('Private organisation created for user ' + hook.result._id)
211
- return hook
212
- }
213
-
214
- export async function removePrivateOrganisation (hook) {
215
- if (hook.type !== 'after') {
216
- throw new Error('The \'removePrivateOrganisation\' hook should only be used as a \'after\' hook.')
144
+ const app = hook.app
145
+ const orgResourceService = app.getService(resourceScope, hook.result)
146
+ const resources = await orgResourceService.find({ paginate: false })
147
+ await Promise.all(resources.map(resource => {
148
+ return orgResourceService.remove(resource._id.toString(), {
149
+ user: hook.params.user
150
+ })
151
+ }))
152
+ debug(`Removed ${resourceScope} for organisation ` + hook.result._id)
153
+ return hook
217
154
  }
218
-
219
- const app = hook.app
220
- const organisationService = app.getService('organisations')
221
- // Remove the private user's organisation
222
- await organisationService.remove(hook.result._id.toString(), {
223
- user: hook.result
224
- })
225
-
226
- debug('Private organisation removed for user ' + hook.result._id)
227
- return hook
228
155
  }
229
156
 
230
- export async function preventRemoveOrganisation (hook) {
231
- if (hook.type !== 'before') {
232
- throw new Error('The \'preventRemoveOrganisations\' hook should only be used as a \'before\' hook.')
233
- }
234
-
235
- // By pass check ?
236
- if (hook.params.force) return hook
237
- const app = hook.app
238
- const orgGroupService = app.getService('groups', hook.id)
239
- const result = await orgGroupService.find({ $limit: 0 })
240
- if (result.total > 0) {
241
- throw new Forbidden('You are not allowed to delete the organisation', {
242
- translation: { key: 'CANNOT_REMOVE_ORGANISATION' }
243
- })
244
- }
245
- return hook
246
- }
@@ -0,0 +1,56 @@
1
+ import emails from 'email-templates'
2
+ import path from 'path'
3
+ import makeDebug from 'debug'
4
+ import _ from 'lodash'
5
+
6
+ const debug = makeDebug('kdk:core:push:hooks')
7
+
8
+ // Helper functions to be used in iff hooks
9
+ export function disallowExternalPush (hook) {
10
+ return _.get(hook.app.get('push'), 'disallowExternalPush', true)
11
+ }
12
+
13
+ export async function sendNewSubscriptionEmail (hook) {
14
+ if (hook.type !== 'after') {
15
+ throw new Error('The \'sendNewSubscriptionEmail\' hook should only be used as a \'after\' hook.')
16
+ }
17
+
18
+ // Check for a new subscription if any
19
+ const updatedUser = hook.result
20
+ const previousUser = hook.params.user
21
+ // If we can't compare abort, eg f-a-m might patch user to update tokens
22
+ if (!updatedUser || !previousUser) return hook
23
+ const newSubscription = _.differenceBy(_.get(updatedUser, 'subscriptions', []), _.get(previousUser, 'subscriptions', []), 'endpoint')
24
+ if (_.size(newSubscription) !== 1) return
25
+
26
+ // Data
27
+ const app = hook.app
28
+ const mailerService = app.getService('mailer')
29
+ const domainPath = app.get('domain') + '/#/'
30
+ const email = {
31
+ subject: 'Security alert - new browser detected',
32
+ from: mailerService.options.auth.user,
33
+ // When changing email send to the new one so that it can be verified
34
+ to: updatedUser.email,
35
+ link: domainPath,
36
+ domainPath
37
+ }
38
+
39
+ // Build the subject & link to the app to perform the different actions
40
+ const templateDir = path.join(mailerService.options.templateDir, 'newSubscription')
41
+ const template = new emails.EmailTemplate(templateDir)
42
+ // Errors does not seem to be correctly catched by the caller
43
+ // so we catch them here to avoid any problem
44
+ try {
45
+ const emailContent = await template.render({ email, user: updatedUser, subscription: _.first(newSubscription) }, updatedUser.locale || 'en-us')
46
+ // Update compiled content
47
+ email.html = emailContent.html
48
+ debug('Sending email ', email)
49
+ await mailerService.create(email)
50
+ } catch (error) {
51
+ debug('Sending email failed', error)
52
+ app.logger.error(error)
53
+ }
54
+
55
+ return hook
56
+ }
@@ -97,9 +97,6 @@ export function populateObject (options) {
97
97
  if (options.throwOnNotFound) throw new Error(`Cannot find the ${options.idField} to dynamically populate.`)
98
98
  else return hook
99
99
  }
100
- // Then the perspective if any
101
- const perspective = _.get(data, options.perspectiveField) || _.get(query, options.perspectiveField)
102
-
103
100
  debug(`Populating ${idProperty} with ID ${id}`)
104
101
  // Set the retrieved service on the same field or given one in hook params
105
102
  _.set(params, serviceProperty, service)
@@ -110,11 +107,9 @@ export function populateObject (options) {
110
107
  try {
111
108
  // Get by ID or name ?
112
109
  if (ObjectID.isValid(id)) {
113
- if (perspective) Object.assign(args, { query: { $select: [perspective] } })
114
110
  object = await service.get(id.toString(), args)
115
111
  } else {
116
112
  Object.assign(args, { query: { name: id.toString() }, paginate: false })
117
- if (perspective) Object.assign(args.query, { $select: [perspective] })
118
113
  const results = await service.find(args)
119
114
  if (results.length >= 0) object = results[0]
120
115
  }
@@ -1,3 +1,4 @@
1
+ import _ from 'lodash'
1
2
  import makeDebug from 'debug'
2
3
  import errors from '@feathersjs/errors'
3
4
  import commonHooks from 'feathers-hooks-common'
@@ -24,9 +25,27 @@ export function validateData (schema) {
24
25
  items = await Promise.allSettled(items.map((item) => schema.validate(item)))
25
26
  // Keep track of validation errors, even if invalid data will be filtered this ensure
26
27
  // original data with validation error will be "tagged"
27
- items.forEach(item => {
28
+
29
+ items.forEach((item, index) => {
28
30
  if (item.status === 'rejected') {
29
- item.validationError = (item.reason.ajv ? new BadRequest(item.reason.message, item.reason.errors) : item.reason)
31
+ console.log(item.reason)
32
+ item.validationError = {
33
+ message: item.reason.message,
34
+ data: item.reason.data.map(error => {
35
+ // retrieve the data corresponding to the item
36
+ const data = isArray ? hook.data[index] : hook.data
37
+ // compute the property path
38
+ let propertyPath = error.instancePath
39
+ if (_.startsWith(propertyPath, '/')) propertyPath = propertyPath.substring(1)
40
+ propertyPath = propertyPath.replace('/', '.')
41
+ // return the error
42
+ return {
43
+ message: error.message,
44
+ propertyPath: error.instancePath,
45
+ propertyValue: _.get(data, propertyPath)
46
+ }
47
+ })
48
+ }
30
49
  }
31
50
  })
32
51
  // Filter errors/valid data
@@ -39,8 +58,9 @@ export function validateData (schema) {
39
58
  const hasError = (errors.length > 0)
40
59
  if (hasError) {
41
60
  const firstError = errors[0]
61
+ console.log(firstError)
42
62
  // Single item case => raise the error
43
- if (!isArray) throw firstError
63
+ if (!isArray) throw new BadRequest(firstError.message, firstError.data)
44
64
  // Multiple items case => raise if no valid data found
45
65
  else if (!hasValidData) {
46
66
  // Keep track of all errors