cortex 0.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 (342) hide show
  1. checksums.yaml +7 -0
  2. data/.babelrc +18 -0
  3. data/.codeclimate.yml +43 -0
  4. data/.csslintrc +2 -0
  5. data/.editorconfig +9 -0
  6. data/.eslintignore +1 -0
  7. data/.eslintrc.yml +277 -0
  8. data/.github/PULL_REQUEST_TEMPLATE.md +47 -0
  9. data/.gitignore +82 -0
  10. data/.npmignore +34 -0
  11. data/.postcssrc.yml +3 -0
  12. data/.rspec +3 -0
  13. data/.rubocop.yml +1156 -0
  14. data/CODE_OF_CONDUCT.md +74 -0
  15. data/CONTRIBUTING.md +58 -0
  16. data/Gemfile +101 -0
  17. data/Gemfile.lock +604 -0
  18. data/Guardfile +23 -0
  19. data/LICENSE.md +201 -0
  20. data/README.md +239 -0
  21. data/Rakefile +22 -0
  22. data/app/assets/config/cortex_manifest.js +4 -0
  23. data/app/assets/fonts/cortex/Montserrat-Light.otf +0 -0
  24. data/app/assets/fonts/cortex/Montserrat-Medium.otf +0 -0
  25. data/app/assets/fonts/cortex/Montserrat-Regular.otf +0 -0
  26. data/app/assets/fonts/cortex/Montserrat-SemiBold.otf +0 -0
  27. data/app/assets/images/cortex/favicon.ico +0 -0
  28. data/app/assets/images/cortex/icons/add.svg +59 -0
  29. data/app/assets/images/cortex/icons/blog.png +0 -0
  30. data/app/assets/images/cortex/icons/media.png +0 -0
  31. data/app/assets/images/cortex/logo.svg +43 -0
  32. data/app/assets/javascripts/cortex/application.js +17 -0
  33. data/app/assets/javascripts/cortex/authentication.js +6 -0
  34. data/app/assets/javascripts/cortex/base.js +6 -0
  35. data/app/assets/javascripts/cortex/datepicker_init.js +29 -0
  36. data/app/assets/javascripts/cortex/flash.js +7 -0
  37. data/app/assets/javascripts/cortex/form.js +6 -0
  38. data/app/assets/javascripts/cortex/media_dialogs.js +40 -0
  39. data/app/assets/javascripts/cortex/quick_links.js +13 -0
  40. data/app/assets/stylesheets/cortex/application.scss +34 -0
  41. data/app/assets/stylesheets/cortex/authentication.scss +34 -0
  42. data/app/assets/stylesheets/cortex/base.scss +4 -0
  43. data/app/assets/stylesheets/cortex/bootstrap-namespaced.scss +57 -0
  44. data/app/assets/stylesheets/cortex/components/card.scss +9 -0
  45. data/app/assets/stylesheets/cortex/components/dialog.scss +67 -0
  46. data/app/assets/stylesheets/cortex/components/flash.scss +60 -0
  47. data/app/assets/stylesheets/cortex/components/form.scss +45 -0
  48. data/app/assets/stylesheets/cortex/components/header.scss +53 -0
  49. data/app/assets/stylesheets/cortex/components/index.scss +28 -0
  50. data/app/assets/stylesheets/cortex/components/jumbo-button.scss +41 -0
  51. data/app/assets/stylesheets/cortex/components/loaders.scss +76 -0
  52. data/app/assets/stylesheets/cortex/components/notes.scss +26 -0
  53. data/app/assets/stylesheets/cortex/components/sidebar.scss +120 -0
  54. data/app/assets/stylesheets/cortex/components/table.scss +7 -0
  55. data/app/assets/stylesheets/cortex/components/tenant-switcher.scss +209 -0
  56. data/app/assets/stylesheets/cortex/components/ui.scss +119 -0
  57. data/app/assets/stylesheets/cortex/demo.scss +140 -0
  58. data/app/assets/stylesheets/cortex/directives/aspect-ratio.scss +9 -0
  59. data/app/assets/stylesheets/cortex/helpers.scss +1701 -0
  60. data/app/assets/stylesheets/cortex/layout.scss +21 -0
  61. data/app/assets/stylesheets/cortex/material-icons.scss +13 -0
  62. data/app/assets/stylesheets/cortex/variables/_colors.scss +46 -0
  63. data/app/assets/stylesheets/cortex/variables/_material-overrides.scss +1 -0
  64. data/app/assets/stylesheets/cortex/variables/_typography.scss +114 -0
  65. data/app/cells/cortex/application_cell.rb +8 -0
  66. data/app/cells/cortex/content_type/nav.haml +5 -0
  67. data/app/cells/cortex/content_type_cell.rb +10 -0
  68. data/app/cells/cortex/field_cell.rb +35 -0
  69. data/app/cells/cortex/index/content_item/column.haml +4 -0
  70. data/app/cells/cortex/index/content_item_cell.rb +37 -0
  71. data/app/cells/cortex/index/index.haml +5 -0
  72. data/app/cells/cortex/index/table_body.haml +11 -0
  73. data/app/cells/cortex/index/table_headers.haml +5 -0
  74. data/app/cells/cortex/index_cell.rb +53 -0
  75. data/app/cells/cortex/wizard/column/show.haml +10 -0
  76. data/app/cells/cortex/wizard/column_cell.rb +21 -0
  77. data/app/cells/cortex/wizard/field/show.haml +30 -0
  78. data/app/cells/cortex/wizard/field_cell.rb +29 -0
  79. data/app/cells/cortex/wizard/plugin/show.haml +1 -0
  80. data/app/cells/cortex/wizard/plugin_cell.rb +28 -0
  81. data/app/cells/cortex/wizard/show.haml +1 -0
  82. data/app/cells/cortex/wizard/step/show.haml +2 -0
  83. data/app/cells/cortex/wizard/step_cell.rb +17 -0
  84. data/app/cells/cortex/wizard_cell.rb +15 -0
  85. data/app/containers/cortex/transaction_container.rb +23 -0
  86. data/app/controllers/concerns/cortex/decoratable.rb +16 -0
  87. data/app/controllers/cortex/admin_controller.rb +7 -0
  88. data/app/controllers/cortex/application_controller.rb +19 -0
  89. data/app/controllers/cortex/authentication/passwords_controller.rb +3 -0
  90. data/app/controllers/cortex/authentication/sessions_controller.rb +3 -0
  91. data/app/controllers/cortex/content_items_controller.rb +75 -0
  92. data/app/controllers/cortex/content_types_controller.rb +19 -0
  93. data/app/controllers/cortex/dashboards_controller.rb +7 -0
  94. data/app/controllers/cortex/graphql_controller.rb +40 -0
  95. data/app/controllers/cortex/tenants_controller.rb +12 -0
  96. data/app/devise/cortex/authentication_failure.rb +12 -0
  97. data/app/graphql/cortex/cortex_schema.rb +8 -0
  98. data/app/graphql/cortex/interfaces/.keep +0 -0
  99. data/app/graphql/cortex/mutations/.keep +0 -0
  100. data/app/graphql/cortex/types/content_item_type.rb +31 -0
  101. data/app/graphql/cortex/types/content_type_type.rb +23 -0
  102. data/app/graphql/cortex/types/contract_type.rb +10 -0
  103. data/app/graphql/cortex/types/date_time_type.rb +8 -0
  104. data/app/graphql/cortex/types/field_item_type.rb +15 -0
  105. data/app/graphql/cortex/types/field_type.rb +18 -0
  106. data/app/graphql/cortex/types/mutation_type.rb +5 -0
  107. data/app/graphql/cortex/types/query_type.rb +45 -0
  108. data/app/graphql/cortex/types/tenant_type.rb +19 -0
  109. data/app/graphql/cortex/types/user_type.rb +20 -0
  110. data/app/helpers/cortex/application_helper.rb +75 -0
  111. data/app/helpers/cortex/cells/association_helper.rb +25 -0
  112. data/app/helpers/cortex/content_item_helper.rb +106 -0
  113. data/app/helpers/cortex/dashboard_helper.rb +19 -0
  114. data/app/helpers/cortex/popup_helper.rb +27 -0
  115. data/app/jobs/cortex/application_job.rb +4 -0
  116. data/app/mailers/cortex/application_mailer.rb +6 -0
  117. data/app/mailers/cortex/password_reset_mailer.rb +13 -0
  118. data/app/models/concerns/cortex/belongs_to_tenant.rb +13 -0
  119. data/app/models/concerns/cortex/has_firstname_lastname.rb +11 -0
  120. data/app/models/concerns/cortex/has_gravatar.rb +18 -0
  121. data/app/models/concerns/cortex/searchable.rb +11 -0
  122. data/app/models/concerns/cortex/searchable_content_item.rb +31 -0
  123. data/app/models/concerns/cortex/searchable_content_item_for_content_type.rb +52 -0
  124. data/app/models/concerns/cortex/searchable_content_type.rb +11 -0
  125. data/app/models/cortex/application_record.rb +17 -0
  126. data/app/models/cortex/content_item.rb +71 -0
  127. data/app/models/cortex/content_type.rb +27 -0
  128. data/app/models/cortex/contentable_decorator.rb +8 -0
  129. data/app/models/cortex/contract.rb +12 -0
  130. data/app/models/cortex/decorator.rb +13 -0
  131. data/app/models/cortex/field.rb +36 -0
  132. data/app/models/cortex/field_item.rb +54 -0
  133. data/app/models/cortex/field_type.rb +44 -0
  134. data/app/models/cortex/permission.rb +11 -0
  135. data/app/models/cortex/role.rb +12 -0
  136. data/app/models/cortex/tenant.rb +41 -0
  137. data/app/models/cortex/user.rb +77 -0
  138. data/app/operations/cortex/database_transact_operation.rb +17 -0
  139. data/app/operations/cortex/execute_content_item_state_change_operation.rb +16 -0
  140. data/app/operations/cortex/parse_content_item_field_items_operation.rb +18 -0
  141. data/app/operations/cortex/persist_content_item_operation.rb +12 -0
  142. data/app/policies/cortex/application_policy.rb +55 -0
  143. data/app/policies/cortex/content_item_policy.rb +49 -0
  144. data/app/policies/cortex/content_type_policy.rb +38 -0
  145. data/app/transactions/concerns/cortex/content_itemable.rb +15 -0
  146. data/app/transactions/concerns/cortex/field_item_transactor.rb +28 -0
  147. data/app/transactions/concerns/cortex/widget_parsable.rb +19 -0
  148. data/app/transactions/cortex/application_transaction.rb +5 -0
  149. data/app/transactions/cortex/create_content_item_transaction.rb +35 -0
  150. data/app/transactions/cortex/get_content_item_transaction.rb +4 -0
  151. data/app/transactions/cortex/get_content_items_for_content_type_transaction.rb +34 -0
  152. data/app/transactions/cortex/get_publish_state_transaction.rb +28 -0
  153. data/app/transactions/cortex/new_field_item_transaction.rb +16 -0
  154. data/app/transactions/cortex/update_content_item_transaction.rb +45 -0
  155. data/app/transactions/cortex/update_field_item_transaction.rb +23 -0
  156. data/app/types/cortex/application_types.rb +21 -0
  157. data/app/types/cortex/content_item_transaction_type.rb +10 -0
  158. data/app/types/cortex/core_types.rb +5 -0
  159. data/app/types/cortex/transaction_type.rb +5 -0
  160. data/app/views/cortex/authentication/passwords/new.html.haml +13 -0
  161. data/app/views/cortex/authentication/sessions/new.html.haml +20 -0
  162. data/app/views/cortex/authentication/shared/_links.html.haml +19 -0
  163. data/app/views/cortex/content_items/_form.html.haml +13 -0
  164. data/app/views/cortex/content_items/_grid.html.haml +1 -0
  165. data/app/views/cortex/content_items/edit.html.haml +2 -0
  166. data/app/views/cortex/content_items/index.html.haml +4 -0
  167. data/app/views/cortex/content_items/new.html.haml +2 -0
  168. data/app/views/cortex/content_types/index.html.haml +2 -0
  169. data/app/views/cortex/content_types/new.html.haml +0 -0
  170. data/app/views/cortex/dashboards/index.html.haml +6 -0
  171. data/app/views/cortex/graphql/ide.haml +1 -0
  172. data/app/views/cortex/partials/_breadcrumb.html.haml +2 -0
  173. data/app/views/cortex/partials/_cortex_redux_state.html.haml +1 -0
  174. data/app/views/cortex/partials/_flash.html.haml +25 -0
  175. data/app/views/cortex/partials/_media_dialogs.html.haml +13 -0
  176. data/app/views/cortex/partials/_navigation.html.haml +15 -0
  177. data/app/views/cortex/partials/_notes.html.haml +17 -0
  178. data/app/views/cortex/partials/_quick_links.html.haml +22 -0
  179. data/app/views/cortex/partials/_sidebar.html.haml +7 -0
  180. data/app/views/cortex/partials/_topbar.html.haml +5 -0
  181. data/app/views/cortex/partials/_user_control.html.haml +7 -0
  182. data/app/views/cortex/partials/authentication/_header.html.haml +4 -0
  183. data/app/views/cortex/partials/trackers/_google_analytics.html.haml +10 -0
  184. data/app/views/cortex/partials/trackers/_qualtrics.html.haml +10 -0
  185. data/app/views/cortex/password_reset_mailer/send_password_reset.html.erb +5 -0
  186. data/app/views/cortex/password_reset_mailer/send_password_reset.text.erb +5 -0
  187. data/app/views/layouts/cortex/application.html.haml +30 -0
  188. data/app/views/layouts/cortex/devise.html.haml +19 -0
  189. data/app/views/layouts/cortex/mailer.html.erb +13 -0
  190. data/app/views/layouts/cortex/mailer.text.erb +1 -0
  191. data/bin/rails +25 -0
  192. data/config/config.yml +22 -0
  193. data/config/initializers/devise.rb +35 -0
  194. data/config/initializers/elasticsearch.rb +3 -0
  195. data/config/initializers/filter_parameter_logging.rb +4 -0
  196. data/config/initializers/flipper.rb +16 -0
  197. data/config/initializers/graphiql.rb +51 -0
  198. data/config/initializers/inflections.rb +16 -0
  199. data/config/initializers/load_config.rb +16 -0
  200. data/config/initializers/mime_types.rb +5 -0
  201. data/config/initializers/plugins.rb +17 -0
  202. data/config/initializers/react_on_rails.rb +15 -0
  203. data/config/initializers/rolify.rb +9 -0
  204. data/config/initializers/tag_parsers.rb +5 -0
  205. data/config/locales/devise.en.yml +64 -0
  206. data/config/routes.rb +41 -0
  207. data/cortex.gemspec +84 -0
  208. data/db/migrate/0_enable_pgcrypto_extension.rb +5 -0
  209. data/db/migrate/10_create_fields.rb +15 -0
  210. data/db/migrate/11_create_content_items.rb +14 -0
  211. data/db/migrate/12_create_field_items.rb +12 -0
  212. data/db/migrate/13_create_field_types.rb +5 -0
  213. data/db/migrate/1_create_users.rb +14 -0
  214. data/db/migrate/2_create_tenants.rb +26 -0
  215. data/db/migrate/3_add_devise_to_users.rb +49 -0
  216. data/db/migrate/4_create_roles.rb +15 -0
  217. data/db/migrate/5_create_permissions.rb +16 -0
  218. data/db/migrate/6_create_flipper_tables.rb +20 -0
  219. data/db/migrate/7_create_contracts.rb +11 -0
  220. data/db/migrate/8_create_decorators.rb +21 -0
  221. data/db/migrate/9_create_content_types.rb +17 -0
  222. data/db/seeds.rb +40 -0
  223. data/db/seeds.yml +33 -0
  224. data/lib/assets/.keep +0 -0
  225. data/lib/breadcrumbs/title_builder.rb +12 -0
  226. data/lib/cortex.rb +4 -0
  227. data/lib/cortex/engine.rb +41 -0
  228. data/lib/cortex/version.rb +3 -0
  229. data/lib/helpers/utility_helper.rb +7 -0
  230. data/lib/tasks/cortex_tasks.rake +13 -0
  231. data/lib/tasks/elasticsearch_tasks.rake +1 -0
  232. data/node_package/.babelrc +26 -0
  233. data/node_package/src/components/side_bar/environment_flag.jsx +21 -0
  234. data/node_package/src/components/side_bar/tenant_list.jsx +65 -0
  235. data/node_package/src/components/wizard/column.jsx +29 -0
  236. data/node_package/src/components/wizard/field.jsx +22 -0
  237. data/node_package/src/components/wizard/step.jsx +20 -0
  238. data/node_package/src/constants/tenant_switcher.jsx +17 -0
  239. data/node_package/src/constants/type_constants.jsx +12 -0
  240. data/node_package/src/constants/wizard.jsx +9 -0
  241. data/node_package/src/containers/layout.jsx +33 -0
  242. data/node_package/src/containers/tenant_switcher_container.jsx +115 -0
  243. data/node_package/src/containers/wizard_container.jsx +28 -0
  244. data/node_package/src/elements/loaders.jsx +7 -0
  245. data/node_package/src/helpers/formatting.jsx +5 -0
  246. data/node_package/src/helpers/tenant_ancestry.jsx +14 -0
  247. data/node_package/src/helpers/tenant_lookup.jsx +23 -0
  248. data/node_package/src/index.jsx +21 -0
  249. data/node_package/src/reducers/index.jsx +13 -0
  250. data/node_package/src/reducers/rails_context_reducer.jsx +5 -0
  251. data/node_package/src/reducers/tenant_switcher_reducer.jsx +74 -0
  252. data/node_package/src/reducers/wizard_reducer.jsx +32 -0
  253. data/node_package/src/services/rails_api_service.jsx +13 -0
  254. data/node_package/src/store/store.jsx +15 -0
  255. data/package.json +66 -0
  256. data/spec/dummy/Rakefile +7 -0
  257. data/spec/dummy/app/assets/config/manifest.js +4 -0
  258. data/spec/dummy/app/assets/javascripts/application.js +2 -0
  259. data/spec/dummy/app/assets/stylesheets/application.scss +2 -0
  260. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  261. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  262. data/spec/dummy/app/javascript/packs/application.js +8 -0
  263. data/spec/dummy/app/javascript/packs/cortex.jsx +1 -0
  264. data/spec/dummy/app/jobs/application_job.rb +2 -0
  265. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  266. data/spec/dummy/app/views/layouts/application.html.haml +11 -0
  267. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  268. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  269. data/spec/dummy/bin/bundle +105 -0
  270. data/spec/dummy/bin/rails +4 -0
  271. data/spec/dummy/bin/rake +4 -0
  272. data/spec/dummy/bin/rspec +17 -0
  273. data/spec/dummy/bin/setup +38 -0
  274. data/spec/dummy/bin/update +29 -0
  275. data/spec/dummy/bin/webpack +29 -0
  276. data/spec/dummy/bin/webpack-dev-server +29 -0
  277. data/spec/dummy/bin/yarn +11 -0
  278. data/spec/dummy/config.ru +7 -0
  279. data/spec/dummy/config/apollo_engine_proxy.yml +23 -0
  280. data/spec/dummy/config/application.rb +21 -0
  281. data/spec/dummy/config/boot.rb +11 -0
  282. data/spec/dummy/config/cable.yml +9 -0
  283. data/spec/dummy/config/config.yml +22 -0
  284. data/spec/dummy/config/database.yml +22 -0
  285. data/spec/dummy/config/environment.rb +5 -0
  286. data/spec/dummy/config/environments/development.rb +74 -0
  287. data/spec/dummy/config/environments/production.rb +103 -0
  288. data/spec/dummy/config/environments/staging.rb +103 -0
  289. data/spec/dummy/config/environments/test.rb +65 -0
  290. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  291. data/spec/dummy/config/initializers/assets.rb +14 -0
  292. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  293. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  294. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  295. data/spec/dummy/config/initializers/inflections.rb +16 -0
  296. data/spec/dummy/config/initializers/load_config.rb +9 -0
  297. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  298. data/spec/dummy/config/initializers/react_on_rails.rb +41 -0
  299. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  300. data/spec/dummy/config/initializers/sentry.rb +6 -0
  301. data/spec/dummy/config/initializers/session_store.rb +7 -0
  302. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  303. data/spec/dummy/config/locales/en.yml +8 -0
  304. data/spec/dummy/config/newrelic.yml +224 -0
  305. data/spec/dummy/config/puma.rb +47 -0
  306. data/spec/dummy/config/routes.rb +5 -0
  307. data/spec/dummy/config/secrets.yml +32 -0
  308. data/spec/dummy/config/sidekiq.yml +9 -0
  309. data/spec/dummy/config/webpack/development.js +3 -0
  310. data/spec/dummy/config/webpack/environment.js +3 -0
  311. data/spec/dummy/config/webpack/production.js +3 -0
  312. data/spec/dummy/config/webpack/test.js +3 -0
  313. data/spec/dummy/config/webpacker.yml +66 -0
  314. data/spec/dummy/db/migrate/20180118233001_enable_pgcrypto_extension.cortex.rb +6 -0
  315. data/spec/dummy/db/migrate/20180118233002_create_users.cortex.rb +15 -0
  316. data/spec/dummy/db/migrate/20180118233003_create_tenants.cortex.rb +27 -0
  317. data/spec/dummy/db/migrate/20180118233004_add_devise_to_users.cortex.rb +50 -0
  318. data/spec/dummy/db/migrate/20180118233005_create_roles.cortex.rb +16 -0
  319. data/spec/dummy/db/migrate/20180118233006_create_permissions.cortex.rb +17 -0
  320. data/spec/dummy/db/migrate/20180118233007_create_flipper_tables.cortex.rb +21 -0
  321. data/spec/dummy/db/migrate/20180118233008_create_contracts.cortex.rb +12 -0
  322. data/spec/dummy/db/migrate/20180118233009_create_decorators.cortex.rb +22 -0
  323. data/spec/dummy/db/migrate/20180118233010_create_content_types.cortex.rb +18 -0
  324. data/spec/dummy/db/migrate/20180118233011_create_fields.cortex.rb +16 -0
  325. data/spec/dummy/db/migrate/20180118233012_create_content_items.cortex.rb +15 -0
  326. data/spec/dummy/db/migrate/20180118233013_create_field_items.cortex.rb +13 -0
  327. data/spec/dummy/db/migrate/20180118233014_create_field_types.cortex.rb +6 -0
  328. data/spec/dummy/db/schema.rb +258 -0
  329. data/spec/dummy/db/seeds.rb +1 -0
  330. data/spec/dummy/lib/tasks/content_types_tasks.rake +31 -0
  331. data/spec/dummy/lib/tasks/employer/blog_tasks.rake +345 -0
  332. data/spec/dummy/package.json +28 -0
  333. data/spec/dummy/public/404.html +67 -0
  334. data/spec/dummy/public/422.html +67 -0
  335. data/spec/dummy/public/500.html +66 -0
  336. data/spec/dummy/public/robots.txt +5 -0
  337. data/spec/dummy/spec/javascripts/support/jasmine.yml +50 -0
  338. data/spec/dummy/yarn.lock +6615 -0
  339. data/spec/rails_helper.rb +57 -0
  340. data/spec/spec_helper.rb +96 -0
  341. data/yarn.lock +6032 -0
  342. metadata +1061 -0
@@ -0,0 +1,11 @@
1
+ module Cortex
2
+ module HasFirstnameLastname
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def fullname
7
+ lastname.to_s == '' ? firstname : "#{firstname} #{lastname}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Cortex
2
+ module HasGravatar
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def avatars
7
+ hash = email ? Digest::MD5.hexdigest(email) : '00000000000000000000000000000000'
8
+ url = "//www.gravatar.com/avatar/#{hash}"
9
+ {
10
+ default: "#{url}",
11
+ small: "#{url}?s=200",
12
+ medium: "#{url}?s=400",
13
+ large: "#{url}?s=1000"
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module Cortex
2
+ module Searchable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Elasticsearch::Model
7
+
8
+ index_name "#{Rails.env}_#{model_name.to_s.parameterize(separator: '_')}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module Cortex
2
+ module SearchableContentItem
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Cortex::Searchable
7
+
8
+ after_commit on: [:create] do
9
+ __elasticsearch__.index_document(index: content_type.content_items_index_name)
10
+ end
11
+
12
+ after_commit on: [:update] do
13
+ # Perform a full document re-index, as update_document ignores methods: https://github.com/elastic/elasticsearch-rails/issues/306#issuecomment-121817954
14
+ __elasticsearch__.index_document(index: content_type.content_items_index_name)
15
+ end
16
+
17
+ after_commit on: [:destroy] do
18
+ __elasticsearch__.delete_document(index: content_type.content_items_index_name)
19
+ end
20
+
21
+ def as_indexed_json(options = {})
22
+ json = as_json
23
+ field_items.each do |field_item|
24
+ field_type = field_item.field.field_type_instance(field_name: field_item.field.name)
25
+ json.merge!(field_type.field_item_as_indexed_json_for_field_type(field_item))
26
+ end
27
+ json
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,52 @@
1
+ module Cortex
2
+ module SearchableContentItemForContentType
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ after_commit on: [:create] do
7
+ self.class.__elasticsearch__.create_index!(index: content_items_index_name, mappings: content_item_mappings)
8
+ end
9
+
10
+ after_commit on: [:destroy] do
11
+ self.class.__elasticsearch__.delete_index!(index: content_items_index_name)
12
+ end
13
+
14
+ after_commit on: [:update] do
15
+ self.class.__elasticsearch__.delete_index!(index: content_items_index_name)
16
+ self.class.__elasticsearch__.create_index!(index: content_items_index_name, mappings: content_item_mappings)
17
+ # TODO: implement & move import to ContentItem to mass-refresh all ContentItems for a ContentType
18
+ #self.class.__elasticsearch__.import()
19
+ end
20
+
21
+ def content_items_index_name
22
+ @content_items_index_name ||= "#{Rails.env}_content_type_#{name_id}_content_items"
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def content_item_mappings
29
+ mappings = Elasticsearch::Model::Indexing::Mappings.new(content_items_index_name, { dynamic: false })
30
+ mappings.indexes :tenant_id, type: :keyword, index: :not_analyzed
31
+ mappings.indexes :content_type_id, type: :keyword, index: :not_analyzed
32
+ mappings.indexes :creator_id, type: :keyword, index: :not_analyzed
33
+ mappings.indexes :updated_by_id, type: :keyword, index: :not_analyzed
34
+ mappings.indexes :state, analyzer: :keyword, index: :not_analyzed
35
+ mappings.indexes :created_at, type: :date, include_in_all: false
36
+ mappings.indexes :updated_at, type: :date, include_in_all: false
37
+ mappings.indexes :deleted_at, type: :date, include_in_all: false
38
+
39
+ fields.each do |field|
40
+ mappings.indexes field.elasticsearch_mapping[:name], content_item_field_mappings(field)
41
+ end
42
+
43
+ mappings
44
+ end
45
+
46
+ def content_item_field_mappings(field)
47
+ mappings = { type: field.elasticsearch_mapping[:type] }
48
+ mappings[:analyzer] = field.elasticsearch_mapping[:analyzer] if field.elasticsearch_mapping[:analyzer]
49
+ mappings
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ module Cortex
2
+ module SearchableContentType
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Cortex::Searchable
7
+
8
+ # TODO: ContentType mappings
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Cortex
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+
5
+ acts_as_paranoid
6
+
7
+ # A bug in ES-Rails 5.x is breaking document updates:
8
+ # https://github.com/elastic/elasticsearch-rails/issues/669
9
+ after_commit :refresh_elasticsearch_index, on: :update
10
+
11
+ private
12
+
13
+ def refresh_elasticsearch_index
14
+ __elasticsearch__.index_document(refresh: true) if defined? __elasticsearch__
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,71 @@
1
+ module Cortex
2
+ class ContentItem < Cortex::ApplicationRecord
3
+ include ActiveModel::Transitions
4
+
5
+ include Cortex::SearchableContentItem
6
+ include Cortex::BelongsToTenant
7
+
8
+ scope :last_updated_at, -> { order(updated_at: :desc).select('updated_at').first.updated_at }
9
+
10
+ belongs_to :creator, class_name: 'User'
11
+ belongs_to :updated_by, class_name: 'User', optional: true
12
+ belongs_to :content_type
13
+ has_many :field_items, dependent: :destroy, autosave: true
14
+
15
+ accepts_nested_attributes_for :field_items
16
+
17
+ default_scope { order(created_at: :desc) }
18
+
19
+ validates :creator, :content_type, presence: true
20
+
21
+ state_machine do
22
+ state :draft
23
+ state :scheduled
24
+
25
+ event :schedule do
26
+ transitions :to => :scheduled, :from => [:draft]
27
+ end
28
+
29
+ event :draft do
30
+ transitions :to => :draft, :from => [:scheduled]
31
+ end
32
+ end
33
+
34
+ def publish_state
35
+ GetPublishStateTransaction.new.call(self).value!
36
+ end
37
+
38
+ # FieldItem and State Convenience Methods. TODO: move to concern? transactions?
39
+ def method_missing(method_name, *arguments, &block)
40
+ super unless dynamic_method?(method_name)
41
+
42
+ if dynamic_state_check?(method_name)
43
+ # Used to check state - allows for methods such as #published? and #expired?
44
+ # Will return true if the active_state corresponds to the name of the method
45
+ "#{publish_state.downcase}?" == method_name.to_s
46
+ else
47
+ # Used to query for any field on the relevant ContentType and return data from the content_item
48
+ field_items.find { |field_item| field_item.field.name.parameterize(separator: '_') == method_name.to_s }.data.values.first
49
+ end
50
+ end
51
+
52
+ def respond_to_missing?(method_name, include_private = false)
53
+ dynamic_method?(method_name) || super
54
+ end
55
+
56
+ private
57
+
58
+ def dynamic_method?(method_name)
59
+ dynamic_state_check?(method_name) || has_field_item?(method_name)
60
+ end
61
+
62
+ def dynamic_state_check?(method_name)
63
+ method_name.to_s.include? '?'
64
+ end
65
+
66
+ # TODO: this logic effectively gets called multiple times (slow?) - how do we optimize or cache the result?
67
+ def has_field_item?(method_name)
68
+ field_items.any? { |field_item| field_item.field.name.parameterize(separator: '_') == method_name.to_s }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ module Cortex
2
+ class ContentType < Cortex::ApplicationRecord
3
+ include Cortex::SearchableContentType
4
+ include Cortex::SearchableContentItemForContentType
5
+ include Cortex::BelongsToTenant
6
+
7
+ validates :name, :creator, :contract, presence: true
8
+ validates_uniqueness_of :name,
9
+ :name_id,
10
+ scope: :tenant_id,
11
+ message: 'should be unique within a Tenant'
12
+
13
+ belongs_to :creator, class_name: 'User'
14
+ belongs_to :contract
15
+ has_many :fields
16
+ has_many :content_items
17
+ has_many :contentable_decorators, as: :contentable
18
+ has_many :decorators, through: :contentable_decorators
19
+
20
+ accepts_nested_attributes_for :fields
21
+
22
+ # TODO: Extract to a concern
23
+ def self.permissions
24
+ Permission.select { |perm| perm.resource_type = self }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ module Cortex
2
+ class ContentableDecorator < Cortex::ApplicationRecord
3
+ include Cortex::BelongsToTenant
4
+
5
+ belongs_to :decorator
6
+ belongs_to :contentable, polymorphic: true
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # TODO: Refactor
2
+ module Cortex
3
+ class Contract < Cortex::ApplicationRecord
4
+ include Cortex::BelongsToTenant
5
+
6
+ validates :name, presence: true
7
+
8
+ has_many :content_types
9
+ has_many :contentable_decorators, as: :contentable
10
+ has_many :decorators, through: :contentable_decorators
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Cortex
2
+ class Decorator < Cortex::ApplicationRecord
3
+ include Cortex::BelongsToTenant
4
+
5
+ has_many :contentable_decorators
6
+
7
+ validates :name, :data, presence: true
8
+
9
+ def data
10
+ self[:data].deep_symbolize_keys
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ module Cortex
2
+ class Field < Cortex::ApplicationRecord
3
+ belongs_to :content_type, touch: true
4
+ has_many :field_items
5
+ has_many :content_items, through: :field_items
6
+
7
+ validates :name, :content_type, :field_type, presence: true
8
+ validate :acceptable_field_type
9
+ validates_uniqueness_of :name,
10
+ :name_id,
11
+ scope: :content_type_id,
12
+ message: 'should be unique within a ContentType'
13
+
14
+ def field_type_instance(options = {})
15
+ field_type.camelize.constantize.new(options)
16
+ end
17
+
18
+ def elasticsearch_mapping
19
+ field_type_instance(field_name: name).elasticsearch_mapping
20
+ end
21
+
22
+ def tenant
23
+ content_type.tenant
24
+ end
25
+
26
+ private
27
+
28
+ def acceptable_field_type
29
+ begin
30
+ Cortex::FieldType.get_subtype_constant(field_type)
31
+ rescue NameError
32
+ errors.add(:field_type, 'must be an available field type')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,54 @@
1
+ module Cortex
2
+ class FieldItem < Cortex::ApplicationRecord
3
+ belongs_to :field
4
+ belongs_to :content_item, touch: true
5
+
6
+ validates :field, :content_item, presence: true
7
+ validate :field_item_content_is_valid, if: :field_is_present
8
+
9
+ def data=(data_hash)
10
+ # Reset @field_type_instance so that massaged data can be re-generated every time @data is set, not just on init
11
+ @field_type_instance = nil
12
+ super(field_type_instance(data_hash).data || data_hash)
13
+ end
14
+
15
+ def tenant
16
+ content_item.tenant
17
+ end
18
+
19
+ private
20
+
21
+ def field_type_instance_params(data_hash)
22
+ # Carefully construct a params object so we don't trigger our fragile setters when a value is nil
23
+ params = { metadata: field.metadata.merge({ existing_data: data }), field: field, validations: field.validations }
24
+ params[:data] = data_hash if data_hash
25
+ params
26
+ end
27
+
28
+ def field_type_instance(data_hash = nil)
29
+ field_type_class = FieldType.get_subtype_constant(field.field_type)
30
+ # data_before_typecast will give us a non-mutilated hash with Objects intact, just in case validations get called first
31
+ @field_type_instance ||= field_type_class.new(field_type_instance_params(data_hash))
32
+ @field_type_instance.save
33
+ @field_type_instance
34
+ end
35
+
36
+ def field_is_present
37
+ field.present?
38
+ end
39
+
40
+ def field_item_content_is_valid
41
+ add_specific_errors unless field_item_validates
42
+ end
43
+
44
+ def field_item_validates
45
+ field_type_instance.valid?
46
+ end
47
+
48
+ def add_specific_errors
49
+ field_type_instance.errors.each do |k, v|
50
+ errors.add(field.name.to_sym, v)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ module Cortex
2
+ class FieldType < Cortex::ApplicationRecord
3
+ extend ActiveSupport::DescendantsTracker
4
+
5
+ attr_accessor :field_name, :field
6
+ attr_reader :data, :validations, :metadata
7
+
8
+ def self.direct_descendant_names
9
+ direct_descendants.map { |descendant| descendant.name.underscore }
10
+ end
11
+
12
+ def self.get_subtype_constant(descendant_name)
13
+ descendant_name.camelize.constantize
14
+ end
15
+
16
+ def elasticsearch_mapping
17
+ raise 'Not implemented'
18
+ end
19
+
20
+ def validations=(validations_hash)
21
+ @validations = validations_hash.deep_symbolize_keys if validations_hash
22
+ end
23
+
24
+ def metadata=(metadata_hash)
25
+ @metadata = metadata_hash.deep_symbolize_keys if metadata_hash
26
+ end
27
+
28
+ def acceptable_validations?
29
+ valid_types? && valid_options?
30
+ end
31
+
32
+ def valid_types?
33
+ validations.all? do |type, options|
34
+ VALIDATION_TYPES.include?(type.to_sym)
35
+ end
36
+ end
37
+
38
+ def valid_options?
39
+ validations.all? do |type, options|
40
+ self.send(VALIDATION_TYPES[type])
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module Cortex
2
+ class Permission < Cortex::ApplicationRecord
3
+ has_and_belongs_to_many :roles
4
+
5
+ validates :name, :resource_type, presence: true
6
+
7
+ def resource
8
+ resource_type.constantize
9
+ end
10
+ end
11
+ end