underworld 1.0.0

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 (365) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +339 -0
  5. data/Rakefile +48 -0
  6. data/app/assets/fonts/DroidNaskh-Bold.ttf +0 -0
  7. data/app/assets/fonts/DroidNaskh-Regular.ttf +0 -0
  8. data/app/assets/fonts/OpenSans-Bold.ttf +0 -0
  9. data/app/assets/fonts/OpenSans-BoldItalic.ttf +0 -0
  10. data/app/assets/fonts/OpenSans-ExtraBold.ttf +0 -0
  11. data/app/assets/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
  12. data/app/assets/fonts/OpenSans-Italic.ttf +0 -0
  13. data/app/assets/fonts/OpenSans-Light.ttf +0 -0
  14. data/app/assets/fonts/OpenSans-LightItalic.ttf +0 -0
  15. data/app/assets/fonts/OpenSans-Regular.ttf +0 -0
  16. data/app/assets/fonts/OpenSans-Semibold.ttf +0 -0
  17. data/app/assets/fonts/OpenSans-SemiboldItalic.ttf +0 -0
  18. data/app/assets/images/underworld/select2-spinner.gif +0 -0
  19. data/app/assets/images/underworld/select2.png +0 -0
  20. data/app/assets/images/underworld/select2x2.png +0 -0
  21. data/app/assets/javascripts/underworld/application.js +16 -0
  22. data/app/assets/javascripts/underworld/dashboard/application.js.erb +30 -0
  23. data/app/assets/javascripts/underworld/dashboard/functions.js.erb +50 -0
  24. data/app/assets/javascripts/underworld/dashboard/init.js.coffee +33 -0
  25. data/app/assets/javascripts/underworld/dashboard/lib/actions.js +7 -0
  26. data/app/assets/javascripts/underworld/dashboard/lib/amd.js.coffee.erb +0 -0
  27. data/app/assets/javascripts/underworld/dashboard/lib/flash_message.js +71 -0
  28. data/app/assets/javascripts/underworld/dashboard/lib/locale.js +14 -0
  29. data/app/assets/javascripts/underworld/dashboard/lib/misc.js +5 -0
  30. data/app/assets/javascripts/underworld/dashboard/lib/string.js +3 -0
  31. data/app/assets/javascripts/underworld/dashboard/lib/ujs_patches.js.coffee +28 -0
  32. data/app/assets/javascripts/underworld/dashboard/manifest.js +5 -0
  33. data/app/assets/javascripts/underworld/dashboard/variables.js.erb +6 -0
  34. data/app/assets/javascripts/underworld/groups.js +2 -0
  35. data/app/assets/javascripts/underworld/home.js +2 -0
  36. data/app/assets/javascripts/underworld/i18n.js +13 -0
  37. data/app/assets/javascripts/underworld/simple.js +20 -0
  38. data/app/assets/javascripts/underworld/users.js +2 -0
  39. data/app/assets/stylesheets/underworld/dashboard/loadindicator.scss +17 -0
  40. data/app/assets/stylesheets/underworld/dashboard/ltr/application.css +38 -0
  41. data/app/assets/stylesheets/underworld/dashboard/ltr/base.css.scss +0 -0
  42. data/app/assets/stylesheets/underworld/dashboard/rtl/application.css +11 -0
  43. data/app/assets/stylesheets/underworld/dashboard/rtl/base.css.scss +0 -0
  44. data/app/assets/stylesheets/underworld/dashboard/share.scss +62 -0
  45. data/app/assets/stylesheets/underworld/dashboard/variables.scss +9 -0
  46. data/app/assets/stylesheets/underworld/ltr/application.css +0 -0
  47. data/app/assets/stylesheets/underworld/rtl/application.css +0 -0
  48. data/app/assets/stylesheets/underworld/simple/ltr/application.css +2 -0
  49. data/app/assets/stylesheets/underworld/simple/rtl/application.css +2 -0
  50. data/app/assets/stylesheets/underworld/simple/rtl/rtl.scss +16 -0
  51. data/app/assets/stylesheets/underworld/simple/share.scss +11 -0
  52. data/app/controllers/underworld/api_controller.rb +133 -0
  53. data/app/controllers/underworld/application_controller.rb +16 -0
  54. data/app/controllers/underworld/assets_controller.rb +6 -0
  55. data/app/controllers/underworld/dashboard/application_controller.rb +43 -0
  56. data/app/controllers/underworld/dashboard/groups_controller.rb +85 -0
  57. data/app/controllers/underworld/dashboard/profile_controller.rb +49 -0
  58. data/app/controllers/underworld/dashboard/user_messages_controller.rb +27 -0
  59. data/app/controllers/underworld/dashboard/users_controller.rb +116 -0
  60. data/app/controllers/underworld/dashboard_controller.rb +16 -0
  61. data/app/controllers/underworld/omniauth/callbacks_controller.rb +24 -0
  62. data/app/helpers/underworld/application_helper.rb +4 -0
  63. data/app/helpers/underworld/dashboard_helper.rb +107 -0
  64. data/app/helpers/underworld/groups_helper.rb +4 -0
  65. data/app/helpers/underworld/home_helper.rb +4 -0
  66. data/app/helpers/underworld/users_helper.rb +8 -0
  67. data/app/models/application_record.rb +3 -0
  68. data/app/models/underworld/concerns/assignment.rb +16 -0
  69. data/app/models/underworld/concerns/user/auth_definitions.rb +87 -0
  70. data/app/models/underworld/concerns/user/gravatar.rb +11 -0
  71. data/app/models/underworld/concerns/user/mongoid_fields.rb +81 -0
  72. data/app/models/underworld/concerns/user/permission.rb +47 -0
  73. data/app/models/underworld/concerns/user/user_roles.rb +24 -0
  74. data/app/models/underworld/group.rb +57 -0
  75. data/app/models/underworld/permission.rb +43 -0
  76. data/app/models/underworld/user.rb +81 -0
  77. data/app/models/underworld/user_message.rb +6 -0
  78. data/app/policies/underworld/admin_only_policy.rb +66 -0
  79. data/app/policies/underworld/application_policy.rb +55 -0
  80. data/app/policies/underworld/group_policy.rb +8 -0
  81. data/app/policies/underworld/user_message_policy.rb +9 -0
  82. data/app/policies/underworld/user_policy.rb +9 -0
  83. data/app/views/angular/auth/groups/details.html +2 -0
  84. data/app/views/angular/auth/groups/index.html +2 -0
  85. data/app/views/angular/auth/groups/new.html +2 -0
  86. data/app/views/angular/auth/index.html +30 -0
  87. data/app/views/angular/auth/profile/edit.html +54 -0
  88. data/app/views/angular/auth/users/details.html +28 -0
  89. data/app/views/angular/auth/users/index.html +6 -0
  90. data/app/views/angular/auth/users/new.html +57 -0
  91. data/app/views/angular/conversations/details.html +19 -0
  92. data/app/views/angular/conversations/index.html +13 -0
  93. data/app/views/angular/conversations/new.html +39 -0
  94. data/app/views/angular/conversations/show.html +6 -0
  95. data/app/views/angular/conversations/show_details.html +15 -0
  96. data/app/views/angular/fields/boolean/boolean.html +4 -0
  97. data/app/views/angular/fields/control-combo/control-list.html +19 -0
  98. data/app/views/angular/fields/datetime/datetime.html +10 -0
  99. data/app/views/angular/fields/datetime/time.html +25 -0
  100. data/app/views/angular/fields/file/file.html.slim +0 -0
  101. data/app/views/angular/fields/float/float.html +4 -0
  102. data/app/views/angular/fields/image/image.html +1 -0
  103. data/app/views/angular/fields/integer/integer.html +4 -0
  104. data/app/views/angular/fields/relation/relation.html +44 -0
  105. data/app/views/angular/fields/string/string.html +22 -0
  106. data/app/views/angular/fields/tag/tag.html +1 -0
  107. data/app/views/angular/fields/text/text.html +4 -0
  108. data/app/views/angular/filter/index.html +15 -0
  109. data/app/views/angular/index.html +3 -0
  110. data/app/views/angular/locale/fa.po +25 -0
  111. data/app/views/angular/locale/templates.pot +24 -0
  112. data/app/views/angular/logs/index.html +6 -0
  113. data/app/views/angular/modules.html +0 -0
  114. data/app/views/angular/nav.html.erb +39 -0
  115. data/app/views/angular/underworld/views/generic_add_view.html.slim +5 -0
  116. data/app/views/devise/registrations/edit.html.erb +29 -0
  117. data/app/views/devise/registrations/new.html.erb +38 -0
  118. data/app/views/devise/sessions/new.html.erb +37 -0
  119. data/app/views/devise/shared/_links.erb +19 -0
  120. data/app/views/devise/shared/_omni_link.erb +33 -0
  121. data/app/views/kaminari/_first_page.html.slim +3 -0
  122. data/app/views/kaminari/_gap.html.slim +2 -0
  123. data/app/views/kaminari/_last_page.html.slim +3 -0
  124. data/app/views/kaminari/_next_page.html.slim +3 -0
  125. data/app/views/kaminari/_page.html.slim +3 -0
  126. data/app/views/kaminari/_paginator.html.slim +13 -0
  127. data/app/views/kaminari/_prev_page.html.slim +3 -0
  128. data/app/views/layouts/underworld/application.html.erb +79 -0
  129. data/app/views/layouts/underworld/dashboard.html.erb +52 -0
  130. data/app/views/layouts/underworld/simple.html.erb +27 -0
  131. data/app/views/underworld/api/v1/conversations/create.json.jbuilder +1 -0
  132. data/app/views/underworld/api/v1/conversations/destroy.json.jbuilder +1 -0
  133. data/app/views/underworld/api/v1/conversations/index.json.jbuilder +1 -0
  134. data/app/views/underworld/api/v1/conversations/reply.json.jbuilder +1 -0
  135. data/app/views/underworld/api/v1/conversations/show.json.jbuilder +14 -0
  136. data/app/views/underworld/api/v1/conversations/trash.json.jbuilder +1 -0
  137. data/app/views/underworld/api/v1/groups/create.json.jbuilder +4 -0
  138. data/app/views/underworld/api/v1/groups/destroy.html.erb +2 -0
  139. data/app/views/underworld/api/v1/groups/destroy.json.jbuilder +1 -0
  140. data/app/views/underworld/api/v1/groups/edit.html.erb +2 -0
  141. data/app/views/underworld/api/v1/groups/index.html.erb +2 -0
  142. data/app/views/underworld/api/v1/groups/index.json.jbuilder +6 -0
  143. data/app/views/underworld/api/v1/groups/new.html.erb +2 -0
  144. data/app/views/underworld/api/v1/groups/show.html.erb +2 -0
  145. data/app/views/underworld/api/v1/groups/show.json.jbuilder +5 -0
  146. data/app/views/underworld/api/v1/groups/update.json.jbuilder +4 -0
  147. data/app/views/underworld/api/v1/logs/index.json.jbuilder +1 -0
  148. data/app/views/underworld/api/v1/permissions/index.json.jbuilder +1 -0
  149. data/app/views/underworld/api/v1/permissions/user_permissions.json.jbuilder +1 -0
  150. data/app/views/underworld/api/v1/users/create.html.erb +2 -0
  151. data/app/views/underworld/api/v1/users/create.json.jbuilder +1 -0
  152. data/app/views/underworld/api/v1/users/destroy.json.jbuilder +1 -0
  153. data/app/views/underworld/api/v1/users/distroy.html.erb +2 -0
  154. data/app/views/underworld/api/v1/users/edit.html.erb +2 -0
  155. data/app/views/underworld/api/v1/users/index.html.erb +2 -0
  156. data/app/views/underworld/api/v1/users/index.json.jbuilder +4 -0
  157. data/app/views/underworld/api/v1/users/show.html.erb +2 -0
  158. data/app/views/underworld/api/v1/users/show.json.jbuilder +2 -0
  159. data/app/views/underworld/api/v1/users/update.json.jbuilder +1 -0
  160. data/app/views/underworld/dashboard/groups/_form.html.slim +68 -0
  161. data/app/views/underworld/dashboard/groups/create.js.erb +3 -0
  162. data/app/views/underworld/dashboard/groups/edit.html.slim +3 -0
  163. data/app/views/underworld/dashboard/groups/errors.js.erb +3 -0
  164. data/app/views/underworld/dashboard/groups/index.html.slim +47 -0
  165. data/app/views/underworld/dashboard/groups/new.html.slim +2 -0
  166. data/app/views/underworld/dashboard/groups/update.js.erb +3 -0
  167. data/app/views/underworld/dashboard/index.html.erb +0 -0
  168. data/app/views/underworld/dashboard/login_required_page.html.erb +5 -0
  169. data/app/views/underworld/dashboard/not_found.html.slim +9 -0
  170. data/app/views/underworld/dashboard/not_found.js.erb +1 -0
  171. data/app/views/underworld/dashboard/profile/_form.html.erb +33 -0
  172. data/app/views/underworld/dashboard/profile/_profile_form.html.erb +33 -0
  173. data/app/views/underworld/dashboard/profile/create.js.erb +3 -0
  174. data/app/views/underworld/dashboard/profile/edit.html.erb +2 -0
  175. data/app/views/underworld/dashboard/profile/edit_password.html.erb +2 -0
  176. data/app/views/underworld/dashboard/profile/errors.js.erb +3 -0
  177. data/app/views/underworld/dashboard/resource/_form.html.slim +33 -0
  178. data/app/views/underworld/dashboard/resource/_input.html.slim +3 -0
  179. data/app/views/underworld/dashboard/resource/create.js.erb +3 -0
  180. data/app/views/underworld/dashboard/resource/destroy.js.erb +2 -0
  181. data/app/views/underworld/dashboard/resource/edit.html.slim +3 -0
  182. data/app/views/underworld/dashboard/resource/index.html.slim +60 -0
  183. data/app/views/underworld/dashboard/resource/new.html.slim +2 -0
  184. data/app/views/underworld/dashboard/resource/show.html.slim +22 -0
  185. data/app/views/underworld/dashboard/resource/update.js.erb +3 -0
  186. data/app/views/underworld/dashboard/shared/_content_header.html.slim +15 -0
  187. data/app/views/underworld/dashboard/shared/_control_sidebar.html.slim +50 -0
  188. data/app/views/underworld/dashboard/shared/_footer.html.slim +7 -0
  189. data/app/views/underworld/dashboard/shared/_header.html.erb +98 -0
  190. data/app/views/underworld/dashboard/shared/_sidebar.html.erb +69 -0
  191. data/app/views/underworld/dashboard/shared/_toolbar.html.slim +0 -0
  192. data/app/views/underworld/dashboard/shared/errors.js.erb +3 -0
  193. data/app/views/underworld/dashboard/user_messages/_form.html.slim +0 -0
  194. data/app/views/underworld/dashboard/user_messages/create.js.erb +0 -0
  195. data/app/views/underworld/dashboard/user_messages/destroy.js.erb +0 -0
  196. data/app/views/underworld/dashboard/user_messages/new.html.slim +72 -0
  197. data/app/views/underworld/dashboard/users/_form.html.slim +73 -0
  198. data/app/views/underworld/dashboard/users/_password_form.html.slim +37 -0
  199. data/app/views/underworld/dashboard/users/create.js.erb +3 -0
  200. data/app/views/underworld/dashboard/users/destroy.js.erb +2 -0
  201. data/app/views/underworld/dashboard/users/edit.html.slim +3 -0
  202. data/app/views/underworld/dashboard/users/edit_password.html.slim +1 -0
  203. data/app/views/underworld/dashboard/users/errors.js.erb +3 -0
  204. data/app/views/underworld/dashboard/users/index.html.slim +66 -0
  205. data/app/views/underworld/dashboard/users/new.html.slim +2 -0
  206. data/app/views/underworld/dashboard/users/show.html.slim +6 -0
  207. data/app/views/underworld/dashboard/users/update.js.erb +3 -0
  208. data/app/views/underworld/dashboard/users/update_password.js.erb +3 -0
  209. data/app/views/underworld/relations/_belongs_to.json.jbuilder +11 -0
  210. data/config/initializers/devise.rb +24 -0
  211. data/config/locales/devise.en.yml +59 -0
  212. data/config/locales/devise.fa.yml +58 -0
  213. data/config/locales/underworld.en.yml +96 -0
  214. data/config/locales/underworld.fa.yml +108 -0
  215. data/config/routes.rb +43 -0
  216. data/config/spring.rb +1 -0
  217. data/db/migrate/20131013091000_devise_create_underworld_users.rb +65 -0
  218. data/db/migrate/20131020124701_create_underworld_groups.rb +15 -0
  219. data/db/migrate/20131021170923_create_underworld_permissions.rb +15 -0
  220. data/db/migrate/20131123120422_add_permissions_groups_table.rb +16 -0
  221. data/db/migrate/20140613120923_add_users_groups_table.rb +13 -0
  222. data/db/migrate/20151122115129_add_uniqueness_index_to_users_groups.rb +11 -0
  223. data/db/migrate/20160310105736_create_underworld_user_messages.rb +25 -0
  224. data/db/seeds.rb +49 -0
  225. data/lib/generators/underworld/install_generator.rb +108 -0
  226. data/lib/generators/underworld/resource_generator.rb +70 -0
  227. data/lib/generators/underworld/resources_generator.rb +20 -0
  228. data/lib/generators/underworld/templates/README +21 -0
  229. data/lib/generators/underworld/templates/SPECS +13 -0
  230. data/lib/generators/underworld/templates/api/controller.rb.erb +60 -0
  231. data/lib/generators/underworld/templates/api_controller.rb +2 -0
  232. data/lib/generators/underworld/templates/dashboard/controller.rb.erb +2 -0
  233. data/lib/generators/underworld/templates/dashboard_controller.rb +18 -0
  234. data/lib/generators/underworld/templates/devise.rb +251 -0
  235. data/lib/generators/underworld/templates/features/api.feature +92 -0
  236. data/lib/generators/underworld/templates/features/api.step.rb +7 -0
  237. data/lib/generators/underworld/templates/features/step_definitions/email_steps.rb +206 -0
  238. data/lib/generators/underworld/templates/features/support/email_spec.rb +1 -0
  239. data/lib/generators/underworld/templates/features/support/env.rb +79 -0
  240. data/lib/generators/underworld/templates/javascripts/application.js +19 -0
  241. data/lib/generators/underworld/templates/policy/application_policy.rb +2 -0
  242. data/lib/generators/underworld/templates/policy/policy.rb.erb +2 -0
  243. data/lib/generators/underworld/templates/seeds.rb +1 -0
  244. data/lib/generators/underworld/templates/spec/factories/groups.rb +5 -0
  245. data/lib/generators/underworld/templates/spec/factories/users.rb +10 -0
  246. data/lib/generators/underworld/templates/spec/spec_helper.rb +69 -0
  247. data/lib/generators/underworld/templates/spec/support/devise.rb +3 -0
  248. data/lib/generators/underworld/templates/stylesheets/dashboard/ltr/application.css +3 -0
  249. data/lib/generators/underworld/templates/stylesheets/dashboard/rtl/application.css +3 -0
  250. data/lib/generators/underworld/templates/stylesheets/ltr/application.css +3 -0
  251. data/lib/generators/underworld/templates/stylesheets/rtl/application.css +3 -0
  252. data/lib/generators/underworld/templates/underworld.rb +12 -0
  253. data/lib/generators/underworld/templates/views/create.json.jbuilder.erb +3 -0
  254. data/lib/generators/underworld/templates/views/destroy.json.jbuilder.erb +1 -0
  255. data/lib/generators/underworld/templates/views/index.json.jbuilder.erb +13 -0
  256. data/lib/generators/underworld/templates/views/show.json.jbuilder.erb +6 -0
  257. data/lib/generators/underworld/templates/views/update.json.jbuilder.erb +6 -0
  258. data/lib/generators/underworld/views_generator.rb +57 -0
  259. data/lib/tasks/docs.rake +6 -0
  260. data/lib/tasks/sync.rake +9 -0
  261. data/lib/tasks/underworld_tasks.rake +38 -0
  262. data/lib/underworld.rb +35 -0
  263. data/lib/underworld/action_dispatch.rb +3 -0
  264. data/lib/underworld/api.rb +42 -0
  265. data/lib/underworld/api/groups_api.rb +41 -0
  266. data/lib/underworld/api/permissions_api.rb +24 -0
  267. data/lib/underworld/api/root.rb +15 -0
  268. data/lib/underworld/api/users_api.rb +20 -0
  269. data/lib/underworld/concerns.rb +7 -0
  270. data/lib/underworld/concerns/authorizable.rb +81 -0
  271. data/lib/underworld/configuration.rb +97 -0
  272. data/lib/underworld/dashboard.rb +11 -0
  273. data/lib/underworld/dashboard/dsl.rb +41 -0
  274. data/lib/underworld/dashboard/dsl/base.rb +133 -0
  275. data/lib/underworld/dashboard/dsl/create.rb +116 -0
  276. data/lib/underworld/dashboard/dsl/form_fields_properties.rb +62 -0
  277. data/lib/underworld/dashboard/dsl/index.rb +45 -0
  278. data/lib/underworld/dashboard/dsl/show.rb +6 -0
  279. data/lib/underworld/dashboard/dsl/update.rb +6 -0
  280. data/lib/underworld/dashboard/helpers/box_helpers.rb +129 -0
  281. data/lib/underworld/dashboard/models.rb +2 -0
  282. data/lib/underworld/dashboard/models/sidebar.rb +139 -0
  283. data/lib/underworld/dashboard/sections.rb +2 -0
  284. data/lib/underworld/dashboard/sections/resource.rb +229 -0
  285. data/lib/underworld/dashboard/sections/resource_create.rb +263 -0
  286. data/lib/underworld/dashboard/sections/resource_destroy.rb +27 -0
  287. data/lib/underworld/dashboard/sections/resource_show.rb +96 -0
  288. data/lib/underworld/dashboard/sections/resources_index.rb +113 -0
  289. data/lib/underworld/dashboard/sections/sidebar.rb +41 -0
  290. data/lib/underworld/discovery.rb +8 -0
  291. data/lib/underworld/discovery/permissions.rb +49 -0
  292. data/lib/underworld/engine.rb +53 -0
  293. data/lib/underworld/exceptions.rb +7 -0
  294. data/lib/underworld/extension.rb +18 -0
  295. data/lib/underworld/extension/base.rb +29 -0
  296. data/lib/underworld/fake_assets.rb +5 -0
  297. data/lib/underworld/i18n.rb +101 -0
  298. data/lib/underworld/initialize.rb +0 -0
  299. data/lib/underworld/liquid.rb +7 -0
  300. data/lib/underworld/liquid/block.rb +14 -0
  301. data/lib/underworld/liquid/render_tag.rb +50 -0
  302. data/lib/underworld/liquid/tag.rb +51 -0
  303. data/lib/underworld/middlewares.rb +1 -0
  304. data/lib/underworld/middlewares/locale.rb +29 -0
  305. data/lib/underworld/omniauth.rb +8 -0
  306. data/lib/underworld/omniauth/callbacks.rb +39 -0
  307. data/lib/underworld/orm.rb +30 -0
  308. data/lib/underworld/routes.rb +117 -0
  309. data/lib/underworld/version.rb +3 -0
  310. data/test/controllers/underworld/dashboard/resource_test.rb +118 -0
  311. data/test/dummy/README.rdoc +28 -0
  312. data/test/dummy/Rakefile +6 -0
  313. data/test/dummy/app/assets/javascripts/application.js +13 -0
  314. data/test/dummy/app/assets/javascripts/dashboard/application.js +19 -0
  315. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  316. data/test/dummy/app/assets/stylesheets/dashboard/ltr/application.css +3 -0
  317. data/test/dummy/app/assets/stylesheets/dashboard/rtl/application.css +3 -0
  318. data/test/dummy/app/assets/stylesheets/ltr/application.css +3 -0
  319. data/test/dummy/app/assets/stylesheets/rtl/application.css +3 -0
  320. data/test/dummy/app/controllers/api_controller.rb +2 -0
  321. data/test/dummy/app/controllers/application_controller.rb +6 -0
  322. data/test/dummy/app/controllers/dashboard/application_controller.rb +18 -0
  323. data/test/dummy/app/helpers/application_helper.rb +2 -0
  324. data/test/dummy/app/policies/application_policy.rb +2 -0
  325. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  326. data/test/dummy/bin/bundle +3 -0
  327. data/test/dummy/bin/rails +4 -0
  328. data/test/dummy/bin/rake +4 -0
  329. data/test/dummy/config.ru +4 -0
  330. data/test/dummy/config/application.rb +23 -0
  331. data/test/dummy/config/boot.rb +5 -0
  332. data/test/dummy/config/database.yml +25 -0
  333. data/test/dummy/config/environment.rb +5 -0
  334. data/test/dummy/config/environments/development.rb +29 -0
  335. data/test/dummy/config/environments/production.rb +80 -0
  336. data/test/dummy/config/environments/test.rb +38 -0
  337. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  338. data/test/dummy/config/initializers/devise.rb +251 -0
  339. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  340. data/test/dummy/config/initializers/formstatic.rb +76 -0
  341. data/test/dummy/config/initializers/formtastic.rb +110 -0
  342. data/test/dummy/config/initializers/inflections.rb +16 -0
  343. data/test/dummy/config/initializers/kaminari_config.rb +10 -0
  344. data/test/dummy/config/initializers/mime_types.rb +5 -0
  345. data/test/dummy/config/initializers/secret_token.rb +12 -0
  346. data/test/dummy/config/initializers/session_store.rb +3 -0
  347. data/test/dummy/config/initializers/underworld.rb +11 -0
  348. data/test/dummy/config/initializers/underworld_assets.rb +1 -0
  349. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  350. data/test/dummy/config/locales/en.yml +23 -0
  351. data/test/dummy/config/routes.rb +13 -0
  352. data/test/dummy/lib/templates/slim/scaffold/_form.html.slim +8 -0
  353. data/test/dummy/public/404.html +58 -0
  354. data/test/dummy/public/422.html +58 -0
  355. data/test/dummy/public/500.html +57 -0
  356. data/test/dummy/public/favicon.ico +0 -0
  357. data/test/fabricators/underworld/groups.rb +27 -0
  358. data/test/fabricators/underworld/permissions.rb +14 -0
  359. data/test/fabricators/underworld/users.rb +17 -0
  360. data/test/generators/install_generator_test.rb +84 -0
  361. data/test/integration/underworld/authentication_test.rb +36 -0
  362. data/test/integration/underworld/dashboard_test.rb +64 -0
  363. data/test/test_helper.rb +72 -0
  364. metadata +1045 -0
  365. metadata.gz.sig +0 -0
@@ -0,0 +1,2 @@
1
+ module Underworld::Dashboard::Models
2
+ end
@@ -0,0 +1,139 @@
1
+ module Underworld::Dashboard::Models
2
+ class Item
3
+
4
+ attr_reader :title, :url, :icon, :model, :members_only
5
+ def initialize(title, options)
6
+ @title = title
7
+ @model = nil
8
+ extract_options(options)
9
+ end
10
+
11
+ def visible?(user)
12
+ return true if @model.nil?
13
+
14
+ if @model.respond_to? :map
15
+ permissions = @model.map do |model|
16
+ # Find the appropriate policy for each model
17
+ # and authorize the user against that.
18
+ Pundit.policy!(user, model.to_sym).index?
19
+ end
20
+ # If user don't have access to none of the models
21
+ # then the menu should not be visible
22
+ permissions.any?
23
+ else
24
+
25
+ # Authorize the menu visibility against user and given model
26
+ Pundit.policy!(user, @model.to_sym).index?
27
+ end
28
+ end
29
+
30
+ private
31
+ def extract_options(options)
32
+ options.each do |key, value|
33
+ instance_variable_set("@#{key}", value)
34
+ end
35
+ end
36
+ end
37
+
38
+ class Menu < Item
39
+ def children
40
+ @children || []
41
+ end
42
+
43
+ def add_child(child)
44
+ @children ||= []
45
+ @children << child
46
+ end
47
+
48
+ def initialize(title, options)
49
+ children = options.delete :children
50
+ if children
51
+ @children = children.map do |child|
52
+ Item.new(child.delete(:title), child)
53
+ end
54
+ end
55
+ super
56
+ end
57
+ end
58
+
59
+ class RootMenu < Array
60
+ alias :add_child :<<
61
+ end
62
+
63
+ class Sidebar
64
+
65
+ include ActionView::Helpers::TranslationHelper
66
+
67
+ def initialize(title, **options)
68
+ @title = title
69
+ extract_options(options)
70
+ @tree = RootMenu.new
71
+ @current_node = @tree
72
+ end
73
+
74
+ def children
75
+ @tree
76
+ end
77
+
78
+ def title
79
+ @title || I18n.t('underworld.dashboard.sidebar.title')
80
+ end
81
+
82
+ def menu(name, **options, &block)
83
+ item = Menu.new(name, options)
84
+
85
+
86
+ @current_node.add_child item
87
+
88
+ prev_node = @current_node
89
+ @current_node = item
90
+
91
+ block.call if block_given?
92
+
93
+ @current_node = prev_node
94
+ end
95
+
96
+ def item(name, **options)
97
+ item = Item.new(name, options)
98
+ @current_node.add_child item
99
+ end
100
+
101
+ def underworld_entries
102
+ menu(t('underworld.dashboard.user_management'),
103
+ icon: 'fa fa-users',
104
+ model: 'Underworld::User') do
105
+ item(I18n.t('underworld.dashboard.users'),
106
+ model: 'Underworld::User',
107
+ url: Underworld::Engine.routes.url_helpers.dashboard_auth_users_path)
108
+
109
+ item(I18n.t('underworld.dashboard.groups'),
110
+ model: 'Underworld::Group',
111
+ url: Underworld::Engine.routes.url_helpers.dashboard_auth_groups_path)
112
+
113
+ end
114
+
115
+ menu(t('underworld.dashboard.user_message'),
116
+ icon: 'fa fa-envelope-o',
117
+ model: 'Underworld::UserMessage') do
118
+
119
+ item(I18n.t('underworld.dashboard.user_messages.inbox'),
120
+ model: 'Underworld::UserMessage',
121
+ url: Underworld::Engine.routes.url_helpers.dashboard_user_messages_path)
122
+ item(I18n.t('underworld.dashboard.user_messages.sent'),
123
+ model: 'Underworld::UserMessage',
124
+ url: Underworld::Engine.routes.url_helpers.dashboard_user_messages_path)
125
+ item(I18n.t('underworld.dashboard.user_messages.draft'),
126
+ model: 'Underworld::UserMessage',
127
+ url: Underworld::Engine.routes.url_helpers.dashboard_user_messages_path)
128
+
129
+ end
130
+ end
131
+
132
+ private
133
+ def extract_options(options)
134
+ @icon = options.delete(:icon)
135
+ @id = options.delete(:id)
136
+ @class = options.delete(:class)
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,2 @@
1
+ module Underworld::Dashboard::Sections
2
+ end
@@ -0,0 +1,229 @@
1
+ module Underworld::Dashboard::Sections
2
+ # This module contains several helpers method which would
3
+ # be useful for the rest of underworld dashboard operation.
4
+ module Resource
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do |base|
9
+ base.before_action :setup_named_routes
10
+ end
11
+
12
+ def _resource_title
13
+ controller_name.humanize
14
+ end
15
+
16
+ protected
17
+
18
+ def _resources
19
+ instance_variable_get("@{plural_name")
20
+ end
21
+
22
+ def plural_name
23
+ controller_name.underscore
24
+ end
25
+
26
+ def model_name
27
+ "::#{controller_path.gsub('dashboard/', '').classify}"
28
+ end
29
+
30
+ def model
31
+ model_name.constantize
32
+ rescue
33
+ msg = "Can't find model '#{model_name}'. Please override 'model' method in your dashboard controller."
34
+ fail NameError, msg
35
+ end
36
+
37
+ def _namespace
38
+ pieces = controller_path.gsub('dashboard/', '').split('/')
39
+ return '' if pieces.length == 1
40
+
41
+ pieces.pop
42
+ pieces.join('/')
43
+ end
44
+
45
+ def _route_engine
46
+ if _namespace.empty?
47
+ Rails.application
48
+ else
49
+ engine = "#{_namespace.split('/')[0]}::Engine".classify
50
+ if Object.const_defined? engine
51
+ engine.constantize
52
+ else
53
+ logger.info 'You are using locale modules please define route_engine in your controller'
54
+ Rails.application
55
+ end
56
+ end
57
+ end
58
+
59
+ # Return the array of action buttons in given `property_object`.
60
+ # `property_object` is an instance of once of DSL classes.
61
+ def action_buttons(property_object)
62
+ @_action_buttons = property_object.action_buttons || []
63
+ end
64
+
65
+ def _engine
66
+ nil
67
+ end
68
+
69
+ private
70
+
71
+ def _route_name
72
+ nil
73
+ end
74
+
75
+ def attachment_fields
76
+ if model.respond_to? :attachment_definitions
77
+ return model.attachment_definitions.keys
78
+ end
79
+
80
+ []
81
+ end
82
+
83
+ def has_attachment?
84
+ !attachment_fields.empty?
85
+ end
86
+
87
+ def _index_route
88
+ if respond_to? :index
89
+ url_for(controller: params[:controller],
90
+ action: :index)
91
+ end
92
+ end
93
+
94
+ def _show_route(id)
95
+ if respond_to? :show
96
+ url_for(controller: params[:controller],
97
+ action: :show,
98
+ id: id)
99
+ end
100
+ end
101
+
102
+ def _edit_route(id)
103
+ if respond_to? :edit
104
+ url_for(controller: params[:controller],
105
+ action: :edit,
106
+ id: id)
107
+ end
108
+ end
109
+
110
+ def _new_route
111
+ if respond_to? :new
112
+ url_for(controller: params[:controller], action: :new)
113
+ end
114
+ end
115
+
116
+ def setup_named_routes
117
+ @engine = _engine || _route_engine
118
+ @index_route = method(:_index_route)
119
+ @new_route = method(:_new_route)
120
+ @show_route = method(:_show_route)
121
+ @edit_route = method(:_edit_route)
122
+ end
123
+
124
+ def successful_response(section, msg = nil)
125
+ @_msg = msg
126
+
127
+ respond_to do |f|
128
+ if _override_views.include? section.to_sym
129
+ f.js
130
+ f.html
131
+ else
132
+ flash[:success] = msg
133
+
134
+ f.js { render "underworld/dashboard/resource/#{section}" }
135
+ f.html { redirect_to _index_route }
136
+ end
137
+ end
138
+ end
139
+
140
+ def errorful_resopnse(section, msg = nil, &block)
141
+ @_msg = msg
142
+
143
+ respond_to do |f|
144
+ if _override_views.include? section.to_sym
145
+ f.js { render :errors }
146
+ f.html { render :errors }
147
+ else
148
+ flash[:error] = msg
149
+
150
+ f.js { render 'underworld/dashboard/shared/errors' }
151
+ if block_given?
152
+ f.html(&block)
153
+ else
154
+ f.html { redirect_to _index_route }
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ # TODO: Move this method to a suitable place
161
+ def symbolify_keys(hash)
162
+ hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
163
+ end
164
+
165
+ # The actual DSL for resource ages
166
+ module ClassMethods
167
+ # Via this method user can specify the engine or application name
168
+ # which current resource is defined under. Default value is:
169
+ # Rails.application
170
+ def route_engine(name = nil, &block)
171
+ define_method(:_route_engine) do
172
+ return block.call if block_given?
173
+ return name unless name.nil?
174
+ fail 'You have to provide a name or a block'
175
+ end
176
+ end
177
+
178
+ # Via this method user can specify the name of current resource
179
+ # scope, Default value is `dashboard`
180
+ def route_scope(name, &block)
181
+ define_method(:_route_scope) do
182
+ return block.call if block_given?
183
+ name
184
+ end
185
+ end
186
+
187
+ # Using this method user can override the route namespace guessed by
188
+ # Underworld.
189
+ def route_namespace(name, &block)
190
+ define_method(:_namespace) do
191
+ return block.call if block_given?
192
+ name
193
+ end
194
+ end
195
+ # Set the engine name of current controller. It's necessary to provide and
196
+ # engine name if the controller belongs to an engine other than Underworld or
197
+ # Rails.application.
198
+ def engine(name)
199
+ define_method(:_engine) do
200
+ name.constantize
201
+ end
202
+ end
203
+
204
+ # Specify the model name of controller. This method overrides the
205
+ # `model_class` **class method** and `model_name` instance method.
206
+ def model_name(name)
207
+ define_singleton_method :model_class do
208
+ name.constantize
209
+ end
210
+
211
+ define_method :model_name do
212
+ name
213
+ end
214
+ end
215
+
216
+ # Returns the actual model class by looking at `controller_name` and
217
+ # and `controller_path`. If user uses the `model_name` **class method**
218
+ # (the `model_name` DSL) then this method will override by the
219
+ # `model_name` defination of `model_class`
220
+ def model_class
221
+ name = controller_name
222
+ path = controller_path.gsub(name, '').gsub(/dashboard\//, '')
223
+
224
+ "#{path}#{name}".classify.constantize
225
+ end
226
+ end
227
+
228
+ end
229
+ end
@@ -0,0 +1,263 @@
1
+ require 'set'
2
+ require_dependency 'underworld/dashboard/dsl/create'
3
+
4
+ module Underworld::Dashboard::Sections
5
+ module ResourceCreate
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ # The actual action method of a dashboard controller
10
+ def new
11
+ authorize model, :create?
12
+
13
+ collect_model_fields_for_form
14
+
15
+ @resource = model.new
16
+ @resource_title = t(_resource_title.singularize)
17
+ @_fields_properties = form_properties._field_details
18
+ @multipart = has_attachment?
19
+
20
+ new_hook(@resource)
21
+ return if _override_views.include? :new
22
+ render 'underworld/dashboard/resource/new'
23
+ end
24
+
25
+ def edit
26
+ # TODO: Handle nested resource in here
27
+ @resource = model.find(params[:id])
28
+ authorize @resource, :update?
29
+
30
+ collect_model_fields_for_form
31
+
32
+ @resource_title = t(_resource_title.singularize)
33
+ @_fields_properties = form_properties._field_details
34
+ @multipart = has_attachment?
35
+
36
+ edit_hook(@resource)
37
+
38
+ return if _override_views.include? :edit
39
+ render 'underworld/dashboard/resource/edit'
40
+ end
41
+
42
+ def update
43
+ # TODO: Handle nested resource in here
44
+ @resource = model.find(params[:id])
45
+ authorize @resource
46
+
47
+ new_params = creation_params
48
+ new_params.merge(reflections_hash) if reflections_hash
49
+
50
+ # Customize update behaviour before updating resource
51
+ before_update_hook(@resource)
52
+
53
+ # TODO: Move this method to a suitable place instead of controller
54
+ # itself
55
+ new_params = symbolify_keys(new_params)
56
+
57
+ @resource.assign_attributes(**new_params)
58
+
59
+ if @resource.save
60
+ # Customize update behaviour after updating resource
61
+ after_update_hook(@resource)
62
+ successful_response(:update)
63
+ else
64
+ errorful_resopnse(:update, @resource.errors) do
65
+ redirect_to :edit
66
+ end
67
+ end
68
+ end
69
+
70
+ # The actual action method for creating new resource.
71
+ def create
72
+ authorize model
73
+
74
+ @resource = model.new(creation_params)
75
+ @resource.assign_attributes(**reflections_hash) unless reflections_hash.nil?
76
+
77
+ # Customize the create behaviour
78
+ before_create_hook(@resource)
79
+
80
+ # TODO: Handle M2M relations in here
81
+ if @resource.save
82
+ after_create_hook(@resource)
83
+ successful_response(:create)
84
+ else
85
+ errorful_resopnse(:create, @resource.errors) do
86
+ redirect_to Rails.application.routes.url_helpers.send(@new_route), turbolinks: true
87
+ end
88
+ end
89
+ end
90
+
91
+ protected
92
+
93
+ def collect_model_fields_for_form
94
+ @_fields ||= form_properties.fields_for_form
95
+ end
96
+
97
+ def reflections_hash
98
+ # TODO: cach the result using and instance_var or something
99
+ reflections = model.reflections
100
+ result = {}
101
+
102
+ reflections.each do |name, column|
103
+ unless is_reflection?(column)
104
+
105
+ value = creation_params[column.foreign_key]
106
+ result[column.foreign_key.to_sym] = value
107
+ end
108
+ end
109
+
110
+ return result unless result.empty?
111
+ nil
112
+ end
113
+
114
+ def creation_params
115
+ resource = controller_name.singularize.underscore.to_sym
116
+
117
+ # TODO: replace this line with a better solution to not
118
+ # allowing the blacklisted fields like id, created_at and ...
119
+ fields = model.columns_hash.keys.map(&:to_sym)
120
+ fields.concat(attachment_fields.map(&:to_sym ))
121
+ fields = Set.new(fields).map(&:to_sym)
122
+ params.require(resource).permit(*fields)
123
+ end
124
+
125
+ # Check whether the given column is a reflection or not.
126
+ def is_reflection?(c)
127
+ has_many = ActiveRecord::Reflection::HasManyReflection
128
+ has_and_belongs_to_many = ActiveRecord::Reflection::HasAndBelongsToManyReflection
129
+ has_many_through = ActiveRecord::Reflection::ThroughReflection
130
+
131
+ result = c.is_a?(has_many) || c.is_a?(has_and_belongs_to_many)
132
+ result || c.is_a?(has_many_through)
133
+ end
134
+
135
+ private
136
+
137
+ # You can override this method to change the behaviour of `create`
138
+ # action before save resource
139
+ def before_create_hook(resource)
140
+ end
141
+
142
+ # You can override this method to change the behaviour of `create`
143
+ # action afer save resource
144
+ def after_create_hook(resource)
145
+ end
146
+
147
+ # You can override this method to change the behaviour of `update`
148
+ # action before save resource
149
+ def before_update_hook(resource)
150
+ end
151
+
152
+
153
+ # You can override this method to change the behaviour of `update`
154
+ # action after save resource
155
+ def after_update_hook(resource)
156
+ end
157
+
158
+ # You can override this method to change the behaviour of `new`
159
+ # action
160
+ def new_hook(resource)
161
+ end
162
+
163
+ # You can override this method to change the behaviour of `edit`
164
+ # action
165
+ def edit_hook(resource)
166
+ end
167
+
168
+ def all_valid_columns_for_form
169
+ return @all_valid_columns_for_form unless @all_valid_columns_for_form.nil?
170
+ columns = model.columns_hash.dup
171
+ relations = model.reflections
172
+
173
+ relations.keys.each do |name|
174
+ has_many = ActiveRecord::Reflection::HasManyReflection
175
+ has_and_belongs_to_many = ActiveRecord::Reflection::HasAndBelongsToManyReflection
176
+
177
+ unless relations[name].is_a? has_many
178
+ if relations[name].is_a? has_and_belongs_to_many
179
+ columns[name] = Class.new { def self.type() :multiple_select end }
180
+ else
181
+ col = relations[name]
182
+ column = columns.delete col.foreign_key
183
+ columns[name] = column
184
+ end
185
+ end
186
+ end
187
+
188
+ columns.delete('id')
189
+ columns.delete('created_at')
190
+ columns.delete('updated_at')
191
+
192
+ @all_valid_columns_for_form = columns
193
+ end
194
+
195
+ def form_properties
196
+ Underworld::Dashboard::DSL::Create.new(model)
197
+ end
198
+
199
+ def _new_form_fields
200
+ all_valid_columns_for_form.keys.map(&:to_sym)
201
+ end
202
+
203
+ # The actual DSL for index ages
204
+ module ClassMethods
205
+
206
+ # To specify any property and action for `form` section both new and edit
207
+ # You must use `in_form` class method with block of properties. For
208
+ # example:
209
+ #
210
+ # class ExamplesController < Dashboard::Application
211
+ # in_form do
212
+ # attributes :name, :description
213
+ # action_button :close, dashboard_example_close_path
214
+ # end
215
+ # end
216
+ def in_form(&block)
217
+ model = model_class
218
+ form_props = Underworld::Dashboard::DSL::Create.new(model)
219
+
220
+ unless block_given?
221
+ fail ArgumentError, "You have to provide a block for 'in_form'"
222
+ end
223
+
224
+
225
+ define_method(:form_properties) do
226
+ unless defined? @__form_props__
227
+ instance_exec(form_props, &block)
228
+ @__form_props__ = form_props
229
+ end
230
+ return @__form_props__
231
+ end
232
+
233
+ private :form_properties
234
+ end
235
+
236
+ # User can provides the fields that he/she wants to be shown
237
+ # in the form for resource creation page.
238
+ # for example:
239
+ #
240
+ # class Dashboard::PostsController < Dashboard::ApplicationController
241
+ # new_form_fields :title, created_at
242
+ # end
243
+ def new_form_fields(*fields, **options)
244
+ define_method(:_new_form_fields) do
245
+ fields.map(&:to_sym)
246
+ end
247
+
248
+ private :_new_form_fields
249
+ end
250
+
251
+ def form_fields
252
+ form = ::Underworld::Dashboard::FormFieldsProperties.new
253
+ yield form
254
+
255
+ define_method(:_form_fields) do
256
+ form
257
+ end
258
+
259
+ private :_form_fields
260
+ end
261
+ end
262
+ end
263
+ end