droom 0.0.1 → 0.2.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 (459) hide show
  1. data/README.md +2 -2
  2. data/app/assets/images/droom/Untitled-1.png +0 -0
  3. data/app/assets/images/droom/acceptance.png +0 -0
  4. data/app/assets/images/droom/add.png +0 -0
  5. data/app/assets/images/droom/asterisk.png +0 -0
  6. data/app/assets/images/droom/asterisk_up.png +0 -0
  7. data/app/assets/images/droom/checkboxes.png +0 -0
  8. data/app/assets/images/droom/clear.png +0 -0
  9. data/app/assets/images/droom/cog.png +0 -0
  10. data/app/assets/images/droom/copy.png +0 -0
  11. data/app/assets/images/droom/copy_to_dropbox.png +0 -0
  12. data/app/assets/images/droom/crosses.png +0 -0
  13. data/app/assets/images/droom/dark_scrap_icons.png +0 -0
  14. data/app/assets/images/droom/defilter.png +0 -0
  15. data/app/assets/images/droom/delete.png +0 -0
  16. data/app/assets/images/droom/dropbox.png +0 -0
  17. data/app/assets/images/droom/dropbox_button.png +0 -0
  18. data/app/assets/images/droom/dropbox_button_small.png +0 -0
  19. data/app/assets/images/droom/edit.png +0 -0
  20. data/app/assets/images/droom/expand.png +0 -0
  21. data/app/assets/images/droom/expander.png +0 -0
  22. data/app/assets/images/droom/folder.png +0 -0
  23. data/app/assets/images/droom/image_box.png +0 -0
  24. data/app/assets/images/droom/in_dropbox.png +0 -0
  25. data/app/assets/images/droom/integration_buttons.png +0 -0
  26. data/app/assets/images/droom/leftright.png +0 -0
  27. data/app/assets/images/droom/manage.png +0 -0
  28. data/app/assets/images/droom/medium_object_icons.png +0 -0
  29. data/app/assets/images/droom/object_icons.png +0 -0
  30. data/app/assets/images/droom/playable.png +0 -0
  31. data/app/assets/images/droom/revoke.png +0 -0
  32. data/app/assets/images/droom/scrap_icons.png +0 -0
  33. data/app/assets/images/droom/search.png +0 -0
  34. data/app/assets/images/droom/small_asterisk.png +0 -0
  35. data/app/assets/images/droom/small_cog.png +0 -0
  36. data/app/assets/images/droom/small_download.png +0 -0
  37. data/app/assets/images/droom/small_image_box.png +0 -0
  38. data/app/assets/images/droom/smalladd.png +0 -0
  39. data/app/assets/images/droom/smallarrows.png +0 -0
  40. data/app/assets/images/droom/smallcopy.png +0 -0
  41. data/app/assets/images/droom/smalldelete.png +0 -0
  42. data/app/assets/images/droom/smalldownload.png +0 -0
  43. data/app/assets/images/droom/smalledit.png +0 -0
  44. data/app/assets/images/droom/smallmanage.png +0 -0
  45. data/app/assets/images/droom/star.png +0 -0
  46. data/app/assets/images/droom/symbols.png +0 -0
  47. data/app/assets/images/droom/tinyarrows.png +0 -0
  48. data/app/assets/images/droom/to_dropbox.png +0 -0
  49. data/app/assets/images/droom/twisty.png +0 -0
  50. data/app/assets/images/droom/youtube_icon.png +0 -0
  51. data/app/assets/javascripts/droom.js.coffee +62 -65
  52. data/app/assets/javascripts/droom/actions.js.coffee +492 -0
  53. data/app/assets/javascripts/droom/ajax.js.coffee +84 -0
  54. data/app/assets/javascripts/droom/{lib/extensions.js.coffee → extensions.js.coffee} +22 -15
  55. data/app/assets/javascripts/droom/lib/ZeroClipboard.js +334 -0
  56. data/app/assets/javascripts/droom/lib/ZeroClipboard.swf +0 -0
  57. data/app/assets/javascripts/droom/lib/ZeroClipboard10.swf +0 -0
  58. data/app/assets/javascripts/droom/map.js.coffee +124 -86
  59. data/app/assets/javascripts/droom/popups.js.coffee +252 -0
  60. data/app/assets/javascripts/droom/stream.js.coffee +92 -0
  61. data/app/assets/javascripts/droom/utilities.js.coffee +120 -0
  62. data/app/assets/javascripts/droom/widgets.js.coffee +1209 -0
  63. data/app/assets/stylesheets/_definitions.css.sass +189 -0
  64. data/app/assets/stylesheets/droom.css.sass +1429 -376
  65. data/app/assets/stylesheets/lib/_kalendae.css.sass +2 -5
  66. data/app/assets/stylesheets/lib/_popups.css.sass +86 -0
  67. data/app/assets/stylesheets/lib/_toolbar.css.sass +17 -11
  68. data/app/controllers/droom/agenda_categories_controller.rb +24 -0
  69. data/app/controllers/droom/calendars_controller.rb +29 -0
  70. data/app/controllers/droom/confirmations_controller.rb +38 -0
  71. data/app/controllers/droom/dashboard_controller.rb +2 -0
  72. data/app/controllers/droom/documents_controller.rb +42 -51
  73. data/app/controllers/droom/dropbox_tokens_controller.rb +61 -0
  74. data/app/controllers/droom/engine_controller.rb +8 -23
  75. data/app/controllers/droom/events_controller.rb +39 -27
  76. data/app/controllers/droom/folders_controller.rb +106 -0
  77. data/app/controllers/droom/group_invitations_controller.rb +15 -7
  78. data/app/controllers/droom/groups_controller.rb +4 -4
  79. data/app/controllers/droom/invitations_controller.rb +37 -9
  80. data/app/controllers/droom/memberships_controller.rb +5 -3
  81. data/app/controllers/droom/organisations_controller.rb +53 -0
  82. data/app/controllers/droom/people_controller.rb +46 -27
  83. data/app/controllers/droom/preferences_controller.rb +34 -0
  84. data/app/controllers/droom/scraps_controller.rb +77 -0
  85. data/app/controllers/droom/search_controller.rb +66 -0
  86. data/app/controllers/droom/suggestions_controller.rb +22 -35
  87. data/app/controllers/droom/users_controller.rb +69 -0
  88. data/app/controllers/droom/venues_controller.rb +1 -2
  89. data/app/controllers/droom/youtube_controller.rb +22 -0
  90. data/app/helpers/droom/droom_helper.rb +93 -5
  91. data/app/models/droom/agenda_category.rb +8 -1
  92. data/app/models/droom/calendar.rb +19 -0
  93. data/app/models/droom/category.rb +4 -6
  94. data/app/models/droom/document.rb +103 -64
  95. data/app/models/droom/document_attachment.rb +13 -47
  96. data/app/models/droom/dropbox_document.rb +41 -0
  97. data/app/models/droom/dropbox_token.rb +29 -0
  98. data/app/models/droom/event.rb +125 -90
  99. data/app/models/droom/folder.rb +134 -0
  100. data/app/models/droom/group.rb +68 -27
  101. data/app/models/droom/group_invitation.rb +12 -3
  102. data/app/models/droom/invitation.rb +50 -8
  103. data/app/models/droom/mailing_list_membership.rb +128 -0
  104. data/app/models/droom/membership.rb +71 -9
  105. data/app/models/droom/organisation.rb +22 -0
  106. data/app/models/droom/page.rb +3 -3
  107. data/app/models/droom/person.rb +180 -166
  108. data/app/models/droom/personal_folder.rb +31 -0
  109. data/app/models/droom/preference.rb +35 -0
  110. data/app/models/droom/recurrence_rule.rb +1 -1
  111. data/app/models/droom/scrap.rb +110 -0
  112. data/app/models/droom/tag.rb +120 -0
  113. data/app/models/droom/tagging.rb +13 -0
  114. data/app/models/droom/user.rb +211 -0
  115. data/app/models/droom/user_action_observer.rb +12 -0
  116. data/app/models/droom/venue.rb +56 -39
  117. data/app/views/cropper/uploads/_crop.html.haml +46 -0
  118. data/app/views/devise/mailer/confirmation_instructions.en.html.haml +24 -0
  119. data/app/views/devise/mailer/reset_password_instructions.en.html.haml +21 -0
  120. data/app/views/devise/passwords/edit.html.haml +31 -0
  121. data/app/views/devise/passwords/new.html.haml +21 -0
  122. data/app/views/devise/sessions/new.html.haml +33 -0
  123. data/app/views/droom/agenda_categories/_form.html.haml +22 -0
  124. data/app/views/droom/agenda_categories/new.html.haml +6 -0
  125. data/app/views/droom/calendars/_action_menu.html.haml +6 -0
  126. data/app/views/droom/calendars/index.html.haml +12 -0
  127. data/app/views/droom/calendars/show.rss.builder +0 -0
  128. data/app/views/droom/confirmations/show.html.haml +40 -0
  129. data/app/views/droom/dashboard/_calendar.html.haml +1 -0
  130. data/app/views/droom/dashboard/_folders.html.haml +5 -0
  131. data/app/views/droom/dashboard/_future_events.html.haml +18 -0
  132. data/app/views/droom/dashboard/_invitations.html.haml +1 -0
  133. data/app/views/droom/dashboard/_past_events.haml +14 -0
  134. data/app/views/droom/dashboard/_quicksearch.html.haml +6 -0
  135. data/app/views/droom/dashboard/_stream.html.haml +9 -0
  136. data/app/views/droom/dashboard/index.html.haml +5 -3
  137. data/app/views/droom/documents/_action_menu.html.haml +7 -0
  138. data/app/views/droom/documents/_documents.html.haml +5 -0
  139. data/app/views/droom/documents/_documents_list.html.haml +6 -6
  140. data/app/views/droom/documents/_documents_table.html.haml +29 -10
  141. data/app/views/droom/documents/_form.html.haml +3 -7
  142. data/app/views/droom/documents/_listing.html.haml +5 -6
  143. data/app/views/droom/documents/_pagination.html.haml +8 -0
  144. data/app/views/droom/documents/_search_result.html.haml +14 -0
  145. data/app/views/droom/documents/_suggested.html.haml +0 -5
  146. data/app/views/droom/documents/_table_document.html.haml +2 -8
  147. data/app/views/droom/documents/edit.html.haml +7 -1
  148. data/app/views/droom/documents/index.html.haml +10 -27
  149. data/app/views/droom/documents/new.html.haml +10 -1
  150. data/app/views/droom/dropbox_tokens/new.html.haml +6 -0
  151. data/app/views/droom/events/_action_menu.html.haml +15 -0
  152. data/app/views/droom/events/_event.html.haml +67 -57
  153. data/app/views/droom/events/_form.html.haml +15 -4
  154. data/app/views/droom/events/_invitations.html.haml +4 -19
  155. data/app/views/droom/events/_search_result.html.haml +19 -0
  156. data/app/views/droom/events/_views.html.haml +2 -2
  157. data/app/views/droom/events/edit.html.haml +7 -1
  158. data/app/views/droom/events/index.html.haml +27 -10
  159. data/app/views/droom/events/index.rss.builder +1 -1
  160. data/app/views/droom/events/new.html.haml +6 -1
  161. data/app/views/droom/events/show.html.haml +5 -1
  162. data/app/views/droom/folders/_action_menu.html.haml +14 -0
  163. data/app/views/droom/folders/_attachments.html.haml +3 -0
  164. data/app/views/droom/folders/_contents.html.haml +6 -0
  165. data/app/views/droom/folders/_folder.html.haml +20 -0
  166. data/app/views/droom/folders/_folders.html.haml +2 -0
  167. data/app/views/droom/folders/_form.html.haml +18 -0
  168. data/app/views/droom/folders/edit.html.haml +6 -0
  169. data/app/views/droom/folders/index.html.haml +32 -0
  170. data/app/views/droom/folders/new.html.haml +6 -0
  171. data/app/views/droom/folders/show.html.haml +1 -0
  172. data/app/views/droom/group_invitations/_form.html.haml +15 -4
  173. data/app/views/droom/group_invitations/new.html.haml +6 -1
  174. data/app/views/droom/groups/_action_menu.haml +11 -0
  175. data/app/views/droom/groups/_form.html.haml +10 -11
  176. data/app/views/droom/groups/_group.html.haml +9 -10
  177. data/app/views/droom/groups/_groups.html.haml +2 -3
  178. data/app/views/droom/groups/_search_result.html.haml +16 -0
  179. data/app/views/droom/groups/_suggested.html.haml +7 -0
  180. data/app/views/droom/groups/edit.html.haml +7 -1
  181. data/app/views/droom/groups/index.html.haml +6 -3
  182. data/app/views/droom/groups/new.html.haml +7 -0
  183. data/app/views/droom/groups/show.html.haml +1 -1
  184. data/app/views/droom/invitations/_created.html.haml +1 -1
  185. data/app/views/droom/invitations/_form.html.haml +9 -5
  186. data/app/views/droom/invitations/_invitation.html.haml +9 -0
  187. data/app/views/droom/invitations/_invitations.html.haml +8 -0
  188. data/app/views/droom/invitations/new.html.haml +6 -1
  189. data/app/views/droom/memberships/_member.html.haml +1 -1
  190. data/app/views/droom/memberships/_membership_toggle.html.haml +10 -0
  191. data/app/views/droom/memberships/new.html.haml +10 -0
  192. data/app/views/droom/organisations/_action_menu.html.haml +7 -0
  193. data/app/views/droom/organisations/_form.html.haml +25 -0
  194. data/app/views/droom/organisations/_organisation.html.haml +23 -0
  195. data/app/views/droom/organisations/_organisations.html.haml +2 -0
  196. data/app/views/droom/organisations/_suggested.html.haml +7 -0
  197. data/app/views/droom/organisations/edit.html.haml +6 -0
  198. data/app/views/droom/organisations/index.html.haml +20 -0
  199. data/app/views/droom/organisations/new.html.haml +6 -0
  200. data/app/views/droom/organisations/show.html.haml +1 -0
  201. data/app/views/droom/pages/_full_page.html.haml +1 -1
  202. data/app/views/droom/pages/index.html.haml +1 -1
  203. data/app/views/droom/panels/_account.html.haml +16 -0
  204. data/app/views/droom/panels/_admin.html.haml +23 -0
  205. data/app/views/droom/panels/_devices.html.haml +19 -0
  206. data/app/views/droom/panels/_dropbox.html.haml +17 -0
  207. data/app/views/droom/panels/_email.html.haml +16 -0
  208. data/app/views/droom/panels/_keywords.html.haml +3 -0
  209. data/app/views/droom/panels/_networks.html.haml +3 -0
  210. data/app/views/droom/panels/_readers.html.haml +18 -0
  211. data/app/views/droom/panels/_rss.html.haml +10 -0
  212. data/app/views/droom/panels/_search.html.haml +16 -0
  213. data/app/views/droom/panels/_vcal.html.haml +3 -0
  214. data/app/views/droom/people/_action_menu.html.haml +22 -0
  215. data/app/views/droom/people/_form.html.haml +69 -39
  216. data/app/views/droom/people/_listing.html.haml +19 -0
  217. data/app/views/droom/people/_memberships.html.haml +24 -0
  218. data/app/views/droom/people/_people.html.haml +5 -29
  219. data/app/views/droom/people/_person.html.haml +30 -32
  220. data/app/views/droom/people/_search_result.html.haml +14 -0
  221. data/app/views/droom/people/_suggested.html.haml +10 -5
  222. data/app/views/droom/people/edit.html.haml +9 -1
  223. data/app/views/droom/people/index.html.haml +6 -9
  224. data/app/views/droom/people/new.html.haml +6 -1
  225. data/app/views/droom/people/show.html.haml +1 -1
  226. data/app/views/droom/preferences/_checkbox.html.haml +7 -0
  227. data/app/views/droom/preferences/_radio_set.html.haml +9 -0
  228. data/app/views/droom/scraps/_action_menu.html.haml +9 -0
  229. data/app/views/droom/scraps/_caption.html.haml +9 -0
  230. data/app/views/droom/scraps/_credit.html.haml +10 -0
  231. data/app/views/droom/scraps/_form.html.haml +77 -0
  232. data/app/views/droom/scraps/_heading.html.haml +16 -0
  233. data/app/views/droom/scraps/_scrap.html.haml +17 -0
  234. data/app/views/droom/scraps/_search_result.html.haml +5 -0
  235. data/app/views/droom/scraps/_stream.html.haml +4 -0
  236. data/app/views/droom/scraps/_suggested.html.haml +5 -0
  237. data/app/views/droom/scraps/_thumb.html.haml +5 -0
  238. data/app/views/droom/scraps/edit.html.haml +2 -0
  239. data/app/views/droom/scraps/full/_document.html.haml +6 -0
  240. data/app/views/droom/scraps/full/_event.html.haml +20 -0
  241. data/app/views/droom/scraps/full/_image.html.haml +4 -0
  242. data/app/views/droom/scraps/full/_link.html.haml +5 -0
  243. data/app/views/droom/scraps/full/_quote.html.haml +8 -0
  244. data/app/views/droom/scraps/full/_text.html.haml +4 -0
  245. data/app/views/droom/scraps/full/_video.html.haml +4 -0
  246. data/app/views/droom/scraps/index.atom.builder +26 -0
  247. data/app/views/droom/scraps/index.html.haml +15 -0
  248. data/app/views/droom/scraps/new.html.haml +2 -0
  249. data/app/views/droom/scraps/show.html.haml +4 -0
  250. data/app/views/droom/scraps/thumbs/_document.html.haml +9 -0
  251. data/app/views/droom/scraps/thumbs/_event.html.haml +17 -0
  252. data/app/views/droom/scraps/thumbs/_image.html.haml +6 -0
  253. data/app/views/droom/scraps/thumbs/_link.html.haml +10 -0
  254. data/app/views/droom/scraps/thumbs/_quote.html.haml +8 -0
  255. data/app/views/droom/scraps/thumbs/_text.html.haml +8 -0
  256. data/app/views/droom/scraps/thumbs/_video.html.haml +6 -0
  257. data/app/views/droom/shared/_controls.html.haml +5 -3
  258. data/app/views/droom/shared/_excerpt.html.haml +2 -0
  259. data/app/views/droom/shared/_navigation.html.haml +4 -4
  260. data/app/views/droom/shared/_panels.html.haml +4 -0
  261. data/app/views/droom/shared/_quicklinks.html.haml +5 -0
  262. data/app/views/droom/shared/_search_form.html.haml +2 -1
  263. data/app/views/droom/shared/_search_results.html.haml +9 -0
  264. data/app/views/droom/shared/_suggestions.html.haml +13 -9
  265. data/app/views/droom/shared/_title_excerpt.haml +2 -0
  266. data/app/views/droom/shared/search.html.haml +18 -0
  267. data/app/views/droom/users/_confirmation.html.haml +2 -0
  268. data/app/views/droom/users/_dropbox_status.html.haml +2 -0
  269. data/app/views/droom/users/_form.html.haml +34 -0
  270. data/app/views/droom/users/_user.html.haml +2 -0
  271. data/app/views/droom/users/_user_or_person.html.haml +63 -0
  272. data/app/views/droom/users/_users_table.html.haml +17 -0
  273. data/app/views/droom/users/edit.html.haml +10 -0
  274. data/app/views/droom/users/index.html.haml +42 -0
  275. data/app/views/droom/users/unwelcome.en.html.haml +17 -0
  276. data/app/views/droom/venues/_search_result.html.haml +17 -0
  277. data/app/views/droom/youtube/show.html.haml +12 -0
  278. data/app/views/kaminari/_paginator.html.haml +16 -0
  279. data/app/views/layouts/droom/application.html.haml +17 -17
  280. data/app/views/layouts/droom/email.html.haml +59 -0
  281. data/config/cucumber.yml +8 -0
  282. data/config/initializers/devise.rb +240 -0
  283. data/config/locales/devise.en.yml +58 -0
  284. data/config/locales/en.yml +203 -32
  285. data/config/routes.rb +55 -16
  286. data/config/sunspot.yml +17 -0
  287. data/db/migrate/20121120115447_tags.rb +18 -0
  288. data/db/migrate/20130116155331_dropbox_tokens.rb +9 -0
  289. data/db/migrate/20130118103540_folders.rb +47 -0
  290. data/db/migrate/20130124113715_preferences.rb +10 -0
  291. data/db/migrate/20130125132427_users_in_droom.rb +58 -0
  292. data/db/migrate/20130129142307_mobile_phones.rb +7 -0
  293. data/db/migrate/20130130120124_folder_ancestry_to_parents.rb +7 -0
  294. data/db/migrate/20130131161430_mailing_lists.rb +37 -0
  295. data/db/migrate/20130207091903_preference_uuids.rb +5 -0
  296. data/db/migrate/20130207123614_stream.rb +13 -0
  297. data/db/migrate/20130208035113_access_token_secret.rb +5 -0
  298. data/db/migrate/20130214145014_person_image.rb +9 -0
  299. data/db/migrate/20130217152644_devise_confirmable.rb +13 -0
  300. data/db/migrate/20130225095328_create_droom_calendars.rb +20 -0
  301. data/db/migrate/20130226092944_give_scraps_document.rb +5 -0
  302. data/db/migrate/20130228083509_privateness.rb +9 -0
  303. data/db/migrate/20130228134143_store_metadata.rb +5 -0
  304. data/db/migrate/20130305150648_folders_nicely.rb +6 -0
  305. data/db/migrate/20130305151936_niceties.rb +7 -0
  306. data/db/migrate/20130308103807_create_droom_dropbox_documents.rb +11 -0
  307. data/db/migrate/20130308154552_dropbox_documents_changed.rb +5 -0
  308. data/db/migrate/20130326135738_user_titles.rb +5 -0
  309. data/lib/droom.rb +189 -22
  310. data/lib/droom/engine.rb +6 -1
  311. data/lib/droom/folders.rb +106 -0
  312. data/lib/droom/lazy_hash.rb +73 -0
  313. data/lib/droom/{helpers.rb → model_helpers.rb} +1 -1
  314. data/lib/droom/monkeys.rb +21 -2
  315. data/lib/droom/routing.rb +13 -0
  316. data/lib/droom/searchability.rb +25 -0
  317. data/lib/droom/taggability.rb +60 -0
  318. data/lib/droom/title_case.rb +101 -0
  319. data/lib/droom/user_config.rb +67 -0
  320. data/lib/droom/validators.rb +6 -0
  321. data/lib/droom/version.rb +1 -1
  322. data/lib/generators/droom/install/templates/droom_initializer.rb +0 -1
  323. data/lib/tasks/cucumber.rake +65 -0
  324. data/spec/datasets/calendar_events_dataset.rb +44 -0
  325. data/spec/datasets/calendar_pages_dataset.rb +8 -0
  326. data/spec/datasets/calendar_sites_dataset.rb +6 -0
  327. data/spec/datasets/calendars_dataset.rb +34 -0
  328. data/spec/datasets/documents_dataset.rb +28 -0
  329. data/spec/datasets/recurrence_dataset.rb +7 -0
  330. data/spec/dummy/README.rdoc +261 -0
  331. data/spec/dummy/Rakefile +7 -0
  332. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  333. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  334. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  335. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  336. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  337. data/spec/dummy/config.ru +4 -0
  338. data/spec/dummy/config/application.rb +65 -0
  339. data/spec/dummy/config/boot.rb +10 -0
  340. data/spec/dummy/config/database.yml +21 -0
  341. data/spec/dummy/config/environment.rb +5 -0
  342. data/spec/dummy/config/environments/development.rb +38 -0
  343. data/spec/dummy/config/environments/production.rb +67 -0
  344. data/spec/dummy/config/environments/test.rb +38 -0
  345. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  346. data/spec/dummy/config/initializers/inflections.rb +15 -0
  347. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  348. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  349. data/spec/dummy/config/initializers/session_store.rb +8 -0
  350. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  351. data/spec/dummy/config/locales/en.yml +7 -0
  352. data/spec/dummy/config/routes.rb +3 -0
  353. data/spec/dummy/config/sunspot.yml +17 -0
  354. data/spec/dummy/db/migrate/20120911070124_create_droom_data.droom.rb +135 -0
  355. data/spec/dummy/db/migrate/20120921094604_agenda_sections.droom.rb +14 -0
  356. data/spec/dummy/db/migrate/20120921094605_add_postal_address_to_people.droom.rb +11 -0
  357. data/spec/dummy/db/migrate/20121102064845_give_groups_descriptions.droom.rb +6 -0
  358. data/spec/dummy/db/migrate/20121102064846_more_names.droom.rb +6 -0
  359. data/spec/dummy/db/migrate/20121102064847_event_agenda_sections.droom.rb +14 -0
  360. data/spec/dummy/db/migrate/20121102064848_create_group_invitations.droom.rb +11 -0
  361. data/spec/dummy/db/migrate/20121102064849_give_people_positions.droom.rb +6 -0
  362. data/spec/dummy/db/migrate/20121102064850_help_pages.droom.rb +14 -0
  363. data/spec/dummy/db/migrate/20121102064851_category_slugs.droom.rb +6 -0
  364. data/spec/dummy/db/migrate/20121102064852_document_links.droom.rb +15 -0
  365. data/spec/dummy/db/migrate/20121102064853_people_visibility.droom.rb +8 -0
  366. data/spec/dummy/db/migrate/20121102094820_shy_people.droom.rb +6 -0
  367. data/spec/dummy/db/migrate/20121102095927_visibility_defaults.droom.rb +10 -0
  368. data/spec/dummy/db/migrate/20130121122352_tags.droom.rb +19 -0
  369. data/spec/dummy/db/migrate/20130121122353_dropbox.droom.rb +10 -0
  370. data/spec/dummy/db/migrate/20130121122354_folders.droom.rb +48 -0
  371. data/spec/dummy/db/migrate/20130128142902_memberships_expire.droom.rb +6 -0
  372. data/spec/dummy/db/migrate/20130128142903_give_documents_extracted_text.droom.rb +6 -0
  373. data/spec/dummy/db/migrate/20130128142904_preferences.droom.rb +11 -0
  374. data/spec/dummy/db/migrate/20130128142905_users_in_droom.droom.rb +59 -0
  375. data/spec/dummy/db/migrate/20130130120631_folder_ancestry_to_parents.droom.rb +8 -0
  376. data/spec/dummy/db/migrate/20130201103737_mobile_phones.droom.rb +8 -0
  377. data/spec/dummy/db/migrate/20130201103738_mailing_lists.droom.rb +38 -0
  378. data/spec/dummy/db/schema.rb +327 -0
  379. data/spec/dummy/log/sunspot-solr-test.log.1 +222 -0
  380. data/spec/dummy/public/404.html +26 -0
  381. data/spec/dummy/public/422.html +26 -0
  382. data/spec/dummy/public/500.html +25 -0
  383. data/spec/dummy/public/favicon.ico +0 -0
  384. data/spec/dummy/public/system/droom/documents/files/000/000/001/original/frog.png +0 -0
  385. data/spec/dummy/public/system/droom/documents/files/000/000/001/original/rat.png +0 -0
  386. data/spec/dummy/script/rails +6 -0
  387. data/spec/dummy/solr/conf/admin-extra.html +31 -0
  388. data/spec/dummy/solr/conf/elevate.xml +36 -0
  389. data/spec/dummy/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  390. data/spec/dummy/solr/conf/protwords.txt +21 -0
  391. data/spec/dummy/solr/conf/schema.xml +238 -0
  392. data/spec/dummy/solr/conf/scripts.conf +24 -0
  393. data/spec/dummy/solr/conf/solrconfig.xml +934 -0
  394. data/spec/dummy/solr/conf/spellings.txt +2 -0
  395. data/spec/dummy/solr/conf/stopwords.txt +58 -0
  396. data/spec/dummy/solr/conf/synonyms.txt +31 -0
  397. data/spec/dummy/solr/data/development/index/segments.gen +0 -0
  398. data/spec/dummy/solr/data/development/index/segments_1 +0 -0
  399. data/spec/dummy/solr/data/development/spellchecker/segments.gen +0 -0
  400. data/spec/dummy/solr/data/development/spellchecker/segments_1 +0 -0
  401. data/spec/dummy/solr/data/test/index/segments.gen +0 -0
  402. data/spec/dummy/solr/data/test/index/segments_3nu +0 -0
  403. data/spec/dummy/solr/data/test/spellchecker/segments.gen +0 -0
  404. data/spec/dummy/solr/data/test/spellchecker/segments_1 +0 -0
  405. data/spec/dummy/webdav/1/group/rat.png +0 -0
  406. data/spec/dummy/webdav/1/unattached/rat.png +0 -0
  407. data/spec/dummy/webdav/group/rat.png +0 -0
  408. data/spec/dummy/webdav/unattached/rat.png +0 -0
  409. data/spec/dummy/webdav/unattached/rat_v1.png +0 -0
  410. data/spec/factories/agenda_categories.rb +5 -0
  411. data/spec/factories/categories.rb +5 -0
  412. data/spec/factories/documents.rb +16 -0
  413. data/spec/factories/events.rb +41 -0
  414. data/spec/factories/folders.rb +5 -0
  415. data/spec/factories/groups.rb +6 -0
  416. data/spec/factories/memberships.rb +5 -0
  417. data/spec/factories/people.rb +16 -0
  418. data/spec/factories/recurrence_rules.rb +25 -0
  419. data/spec/factories/user.rb +6 -0
  420. data/spec/fixtures/dummy.ics +59 -0
  421. data/spec/fixtures/images/frog.png +0 -0
  422. data/spec/fixtures/images/rat.png +0 -0
  423. data/spec/fixtures/ny.ics +36 -0
  424. data/spec/lib/droom/folders_spec.rb +46 -0
  425. data/spec/lib/droom/lazy_hash_spec.rb +33 -0
  426. data/spec/models/droom/agenda_category_spec.rb +15 -0
  427. data/spec/models/droom/document_spec.rb +76 -0
  428. data/spec/models/droom/event_spec.rb +154 -0
  429. data/spec/models/droom/folder_spec.rb +5 -0
  430. data/spec/models/droom/ical_spec.rb +62 -0
  431. data/spec/models/droom/mailing_list_membership_spec.rb +81 -0
  432. data/spec/models/droom/membership_spec.rb +22 -0
  433. data/spec/models/droom/person_spec.rb +72 -0
  434. data/spec/models/droom/recurrence_rule_spec.rb +81 -0
  435. data/spec/models/droom/user_spec.rb +27 -0
  436. data/spec/models/droom/visibility_spec.rb +6 -0
  437. data/spec/spec_helper.rb +119 -0
  438. data/spec/support/matchers/content_type_matcher.rb +17 -0
  439. metadata +591 -36
  440. data/app/assets/javascripts/droom/calendar.js.coffee +0 -121
  441. data/app/assets/javascripts/droom/drag_sort.js.coffee +0 -22
  442. data/app/assets/javascripts/droom/forms.js.coffee +0 -746
  443. data/app/assets/javascripts/droom/sort.js.coffee +0 -126
  444. data/app/assets/javascripts/droom/suggester.js.coffee +0 -230
  445. data/app/controllers/droom/document_attachments_controller.rb +0 -19
  446. data/app/models/droom/document_link.rb +0 -31
  447. data/app/models/droom/personal_document.rb +0 -98
  448. data/app/views/droom/dashboard/_marginalia.html.haml +0 -3
  449. data/app/views/droom/dashboard/_my_future_events.html.haml +0 -9
  450. data/app/views/droom/dashboard/_my_group_documents.html.haml +0 -6
  451. data/app/views/droom/dashboard/_my_past_events.haml +0 -6
  452. data/app/views/droom/documents/_event_document_form.html.haml +0 -15
  453. data/app/views/droom/errors/bang.html.haml +0 -12
  454. data/app/views/droom/errors/not_allowed.html.haml +0 -12
  455. data/app/views/droom/errors/not_found.html.haml +0 -12
  456. data/app/views/droom/events/_attachment.html.haml +0 -1
  457. data/app/views/droom/events/_attachment_list.html.haml +0 -4
  458. data/app/views/droom/invitations/_attending_people.html.haml +0 -8
  459. data/config/initializers/dav.rb +0 -2
@@ -6,22 +6,84 @@ module Droom
6
6
  belongs_to :group
7
7
  belongs_to :created_by, :class_name => "User"
8
8
 
9
- after_create :link_documents
10
- after_destroy :unlink_documents
9
+ has_one :mailing_list_membership, :dependent => :destroy
10
+
11
+ after_create :link_folder
12
+ after_create :make_mailing_list_membership
13
+ after_create :update_person_status
14
+ after_create :create_invitations
15
+ after_destroy :unlink_folder
16
+ after_destroy :update_person_status
17
+ after_destroy :destroy_invitations
18
+ after_destroy :destroy_similar
19
+
20
+ validates :person, :presence => true
21
+ validates :group, :presence => true
11
22
 
12
23
  scope :of_group, lambda { |group|
13
24
  where(["group_id = ?", group.id])
14
25
  }
26
+
27
+ scope :privileged, select('droom_memberships.*')
28
+ .joins('inner join droom_groups as dg on droom_memberships.group_id = dg.id')
29
+ .where('dg.privileged' => true)
30
+ .group('droom_memberships.id')
31
+
32
+ def current?
33
+ expires and expires > Time.now
34
+ end
35
+
36
+ def set_expiry(date)
37
+ unless expires and expires > date
38
+ self.expires = date
39
+ save!
40
+ end
41
+ end
42
+
43
+ # This is sometimes useful if a configuration change means we're looking at a different mailman table.
44
+ #
45
+ def self.repair_mailing_list_memberships
46
+ self.all.each { |m| m.send :make_mailing_list_membership }
47
+ end
15
48
 
16
49
  protected
17
-
18
- def link_documents
19
- person.document_attachments << group.document_attachments
50
+
51
+ def link_folder
52
+ person.add_personal_folders(group.folder)
20
53
  end
21
-
22
- def unlink_documents
23
- person.document_attachments -= group.document_attachments
54
+
55
+ def unlink_folder
56
+ person.remove_personal_folders(group.folder)
57
+ end
58
+
59
+ def unlink_folder
60
+ person.remove_personal_folders(group.folder)
61
+ end
62
+
63
+ def make_mailing_list_membership
64
+ self.mailing_list_membership = Droom::MailingListMembership.find_or_create_by_address_and_listname(person.email, group.mailing_list_name)
65
+ end
66
+
67
+ def update_person_status
68
+ person.send :update_status
69
+ end
70
+
71
+ def create_invitations
72
+ group.group_invitations.each do |gi|
73
+ gi.create_personal_invitation_for(person)
74
+ end
75
+ end
76
+
77
+ def destroy_invitations
78
+ group.group_invitations.each do |gi|
79
+ gi.invitations.for_person(person).destroy_all
80
+ end
81
+ end
82
+
83
+ # it's easy to end up with multiple similar membership objects.
84
+ def destroy_similar
85
+ group.memberships.where(:person_id => person.id).destroy_all
24
86
  end
25
87
 
26
88
  end
27
- end
89
+ end
@@ -0,0 +1,22 @@
1
+ module Droom
2
+ class Organisation < ActiveRecord::Base
3
+ attr_accessible :name, :description, :created_by, :owner, :url
4
+ has_many :people
5
+ belongs_to :owner, :class_name => 'Droom::Person'
6
+ belongs_to :created_by, :class_name => 'Droom::User'
7
+
8
+ def self.for_selection
9
+ organisations = self.order("name asc").map{|f| [f.name, f.id] }
10
+ organisations.unshift(['', ''])
11
+ organisations
12
+ end
13
+
14
+ def url_with_protocol
15
+ url =~ /^https?:\/\// ? url : "http://#{url}"
16
+ end
17
+
18
+ def url_without_protocol
19
+ url.sub(/^https?:\/\//, '')
20
+ end
21
+ end
22
+ end
@@ -5,7 +5,7 @@ module Droom
5
5
  class Page < ActiveRecord::Base
6
6
  attr_accessible :title, :slug, :summary, :body, :video_id
7
7
 
8
- before_validation :check_slug
8
+ before_validation :ensure_slug
9
9
  before_save :render_body
10
10
  validates :slug, :uniqueness => true, :presence => true
11
11
  validates :title, :presence => true
@@ -13,10 +13,10 @@ module Droom
13
13
 
14
14
  protected
15
15
 
16
- def check_slug
16
+ def ensure_slug
17
17
  ensure_presence_and_uniqueness_of(:slug, title.parameterize)
18
18
  end
19
-
19
+
20
20
  def render_body
21
21
  Rails.logger.warn ">>> rendering body: #{self.body.inspect}"
22
22
  markdown = RDiscount.new(self.body)
@@ -1,60 +1,164 @@
1
1
  # This has been pulled from the yearbook and simplified. Docs need updating to match.
2
2
  require 'vcard'
3
+
3
4
  module Droom
4
5
  class Person < ActiveRecord::Base
5
- attr_accessible :name, :forename, :email, :phone, :description, :user, :title, :invite_on_creation, :admin_user, :position
6
+ attr_accessible :name, :forename, :email, :phone, :description, :user, :user_id, :title, :invite_on_creation, :admin_user, :position, :post_line1, :post_line2, :post_city, :post_region, :post_code, :mobile, :dob, :organisation_id
6
7
  attr_accessor :invite_on_creation, :admin_user
7
8
  acts_as_list
8
- ### Associations
9
+
10
+ belongs_to :organisation
11
+ belongs_to :created_by, :class_name => "Droom::User"
12
+ has_many :organisations, :foreign_key => :owner_id
13
+
14
+ ### Group memberships
9
15
  #
10
16
  has_many :memberships, :dependent => :destroy
11
17
  has_many :groups, :through => :memberships
18
+ has_many :mailing_list_memberships, :through => :memberships
19
+
20
+ has_many :dropbox_documents
21
+
22
+ has_many :preferences, :dependent => :destroy, :foreign_key => :created_by_id
23
+ accepts_nested_attributes_for :preferences
12
24
 
25
+ # The data requirements are minimal, with the idea that the directory will be populated gradually.
26
+ validates :name, :presence => true
27
+
28
+ def admit_to(group)
29
+ memberships.find_or_create_by_group_id(group.id) if group
30
+ end
31
+
32
+ def expel_from(group)
33
+ memberships.of_group(group).destroy_all
34
+ end
35
+
36
+ def member_of?(group)
37
+ group && memberships.of_group(group).any?
38
+ end
39
+
40
+ ### Event invitations
41
+ #
13
42
  has_many :invitations, :dependent => :destroy
14
43
  has_many :events, :through => :invitations
15
44
 
16
- # document_links is an automatically maintained index that we use to make easier the task of retrieving
17
- # the documents this person is allowed to see.
18
- has_many :document_links, :dependent => :destroy
19
- has_many :document_attachments, :through => :document_links
20
- # is this association really needed? We always retrieve the document list using the visible_to scope, so as to get public docs too.
21
- has_many :documents, :through => :document_attachments, :uniq => true
45
+ def invite_to(event)
46
+ invitations.find_or_create_by_event_id(event.id) if event
47
+ end
22
48
 
23
- # personal documents are the document clones created when a user logs to her DAV folder.
24
- # they are spun off the document links
25
- has_many :personal_documents, :through => :document_links
49
+ def uninvite_from(event)
50
+ invitations.to_event(event).destroy_all
51
+ end
52
+
53
+ def invited_to?(event)
54
+ event && !!invitation_to(event)
55
+ end
56
+
57
+ def invitation_to(event)
58
+ invitations.to_event(event).first
59
+ end
26
60
 
61
+ ## Folder permissions
62
+ #
63
+ # To simplify the business of showing and listing documents, we have adopted the convention that all
64
+ # documents live in a folder. Person accounts have links to those folders through the very thin
65
+ # PersonalFolder joining class, and at the view level we only ever show folder and subfolder lists.
66
+ # The only place we ever need a list of all the documents visible to this person is when searching, and
67
+ # for that we use the Document.visible_to scope, usually by way of the #documents method defined below.
68
+ #
69
+ # Personal folders are created and destroyed along with invitations and memberships..
70
+ #
71
+ has_many :personal_folders
72
+ has_many :folders, :through => :personal_folders
73
+
74
+ def add_personal_folders(folders=[])
75
+ self.folders << folders if folders
76
+ end
77
+
78
+ def remove_personal_folders(folders=[])
79
+ self.folders.delete(folders) if folders
80
+ end
81
+
82
+ def documents
83
+ Document.visible_to(self)
84
+ end
85
+
86
+ ## User accounts
87
+ #
27
88
  # The `user` is this person's administrative account for logging in and out and forgetting her password.
28
89
  # A person can be listed without ever having a user, and a user account can exist (for an administrator)
29
90
  # without having a person.
30
- belongs_to :user, :class_name => Droom.user_class.to_s, :dependent => :destroy
31
-
91
+ belongs_to :user, :class_name => "Droom::User"
32
92
  before_save :update_user
33
- after_save :invite_if_instructed
34
93
 
35
- # The data requirements are minimal, with the idea that the directory will be populated gradually.
36
- validates :name, :presence => true
94
+ after_create :invite_if_instructed
95
+
96
+ scope :unusered, where("user_id IS NULL")
97
+ scope :usered, where("user_id IS NOT NULL")
98
+
99
+ # some magic glue to allow slightly indiscriminate use of user and person objects.
100
+
101
+ def person
102
+ self
103
+ end
104
+
105
+ def admin?
106
+ user && user.admin?
107
+ end
108
+
109
+ def has_admin_user?
110
+ user && user.admin?
111
+ end
112
+
113
+
114
+ ### Images
115
+ #
116
+ has_upload :image,
117
+ :geometry => "520x520#",
118
+ :styles => {
119
+ :icon => "32x32#",
120
+ :thumb => "120x120#",
121
+ :precrop => "1200x1200^"
122
+ }
123
+
124
+ ## Scopes
37
125
 
38
126
  default_scope order("droom_people.#{Droom.people_sort}")
39
127
 
40
- scope :all_private, where("shy = 1")
41
- scope :not_private, where("shy <> 1")
42
- scope :all_public, where("public = 1 AND shy <> 1")
43
- scope :not_public, where("public <> 1 OR shy = 1)")
128
+ scope :all_private, where("private = 1")
129
+ scope :not_private, where("private <> 1 OR private IS NULL")
130
+ scope :all_public, where("public = 1 AND private <> 1 OR private IS NULL")
131
+ scope :not_public, where("public <> 1 OR private = 1)")
132
+
133
+ searchable do
134
+ text :name, :boost => 10, :stored => true
135
+ text :forename, :boost => 10, :stored => true
136
+ text :description, :stored => true
137
+ end
138
+
139
+ handle_asynchronously :solr_index
44
140
 
45
- scope :name_matching, lambda { |fragment|
141
+ def self.highlight_fields
142
+ [:name, :forename, :description]
143
+ end
144
+
145
+ scope :matching, lambda { |fragment|
46
146
  fragment = "%#{fragment}%"
47
- where('droom_people.name LIKE :f OR droom_people.forename LIKE :f', :f => fragment)
147
+ where('droom_people.name LIKE :f OR droom_people.forename LIKE :f OR droom_people.email LIKE :f OR droom_people.phone LIKE :f OR CONCAT(droom_people.forename, " ", droom_people.name) LIKE :f', :f => fragment)
48
148
  }
49
149
 
50
150
  # warning! won't work in SQLite.
51
151
  scope :visible_to, lambda { |person|
52
152
  if person
53
- select('droom_people.*')
54
- .joins('LEFT OUTER JOIN droom_memberships as dm1 on droom_people.id = dm1.person_id')
55
- .joins('LEFT OUTER JOIN droom_memberships as dm2 on dm1.group_id = dm2.group_id')
56
- .where(['(droom_people.public = 1 OR dm2.person_id = ?) AND (droom_people.shy IS NULL OR droom_people.shy <> 1)', person.id])
57
- .group('droom_people.id')
153
+ if person.admin?
154
+ scoped({})
155
+ else
156
+ select('droom_people.*')
157
+ .joins('LEFT OUTER JOIN droom_memberships as dm1 on droom_people.id = dm1.person_id')
158
+ .joins('LEFT OUTER JOIN droom_memberships as dm2 on dm1.group_id = dm2.group_id')
159
+ .where(['(dm2.person_id = ?) OR (droom_people.private <> 1)', person.id])
160
+ .group('droom_people.id')
161
+ end
58
162
  else
59
163
  all_public
60
164
  end
@@ -64,24 +168,21 @@ module Droom
64
168
  joins('LEFT OUTER JOIN droom_invitations on droom_people.id = droom_invitations.person_id').where('droom_invitations.group_invitation_id is null AND droom_invitations.event_id = ?', event.id)
65
169
  }
66
170
 
67
- ### Images
68
- #
69
- # The treatment here is very basic compared to the yearbook's uploader, but we might bring that across
70
- # if this starts to look like a useful directory resource.
71
- #
72
- has_attached_file :image, {
73
- :styles => {:standard => "400x300#", :thumb => "100x100#"},
74
- :default_url => "/assets/person/nopicture_:style.png"
75
- }
76
-
77
- def image_url(style=:standard)
78
- image.url(style)
79
- end
80
-
81
- def identifier
82
- 'person'
171
+
172
+ def membership_of(group)
173
+ memberships.find_by_group_id(group.id)
83
174
  end
175
+
176
+
177
+
178
+
179
+
84
180
 
181
+
182
+ def full_name
183
+ [forename, name].compact.join(' ').strip
184
+ end
185
+
85
186
  def formal_name
86
187
  [title, forename, name].compact.join(' ').strip
87
188
  end
@@ -94,138 +195,21 @@ module Droom
94
195
  end
95
196
  end
96
197
 
97
- # I don't think we're using this anywhere at the moment, but a JSON API will grow here. Other classes already make more use of
98
- # JSON representation, eg institutions for mapping or tags for tagging.
99
- #
100
- def as_json(options={})
101
- {
102
- :id => id,
103
- :name => name,
104
- :title => title
105
- }
106
- end
107
-
108
198
  # *for_selection* returns a list of people in options_for_select format with which to populate a select box.
109
199
  #
110
200
  def self.for_selection
111
201
  self.published.map{|p| [p.name, p.id] }
112
202
  end
113
203
 
114
- # Document links function as a lookup table to speed up the process of working out what this person can see.
115
- # They are created when an attachment, invitation or membership confers access, and destroyed when a link in
116
- # that chain is removed.
117
- #
118
- # This will rebuild the document_link index for this person.
119
- #
120
- def repair_document_links
121
- # NB this will also destroy all our personal documents. Very much a last resort.
122
- self.document_links.destroy_all
123
- group_and_event_attachments.each do |da|
124
- document_links.create(:document_attachment => da)
125
- end
126
- end
127
-
128
- def group_and_event_attachments
129
- Droom::DocumentAttachment.to_groups(groups) + Droom::DocumentAttachment.to_events(events)
130
- end
131
204
 
132
- # We defer the creation and updating of personal documents until the person actually logs in over DAV. At that stage a call
133
- # goes to person.create_personal_documents and the copying begins. It's not really ideal from a responsiveness point of view
134
- # but it saves a great deal of update hassle (and storage space).
135
- #
136
- # NB this will not recreate deleted files: we only look as far as the PersonalDocument object, not the file
137
- # it would usually have. This is to allow people to delete files they don't want, without having them
138
- # constantly recreated.
139
- #
140
- def create_personal_documents
141
- create_and_update_dav_directories
142
- document_links.each { |dl| dl.ensure_personal_document }
143
- end
144
-
145
- def create_and_update_dav_directories
146
- document_links.each do |dl|
147
- p "-> creating DAV directory #{dl.slug}"
148
- create_dav_directory(dl.slug)
149
- end
150
- end
151
-
152
- def create_dav_directory(name)
153
- FileUtils.mkdir_p(Rails.root + "#{Droom.dav_root}/#{self.id}/#{name}")
154
- end
155
205
 
156
- # If a personal version exists, we will return that since it may contain annotations or amendments.
157
- #
158
- def personal_or_generic_version_of(document)
159
- personal_version_of(document) || document
160
- end
161
206
 
162
- # But if there has been no DAV login there can be no personal version.
163
- #
164
- def personal_version_of(document)
165
- personal_documents.derived_from(document).first
166
- end
167
207
 
168
- # group_documents returns all those documents that have been attached to a group of which this person is a member.
169
- # These documents will not show up in the calendar (since they are not attached to an event) so it's often a useful list.
170
- #
171
- def group_documents
172
- groups.any? ? Droom::Document.attached_to_these_groups(groups).by_date : []
173
- end
174
-
175
- # It is possible to give us a document by creating an attachment that has no attachee
176
- # but which links to this person.
177
- #
178
- def attach(doc)
179
- document_attachments.create(:document => doc)
180
- end
181
208
 
182
209
 
183
- def invite_to(event)
184
- invitations.find_or_create_by_event_id(event.id) if event
185
- end
186
-
187
- def uninvite_from(event)
188
- p "-> destroying invitations: #{invitations.to_event(event).inspect}"
189
- invitations.to_event(event).destroy_all
190
- end
191
-
192
- def admit_to(group)
193
- memberships.find_or_create_by_group_id(group.id) if group
194
- end
195
-
196
- def expel_from(group)
197
- memberships.of_group(group).destroy_all
198
- end
199
-
200
- def member_of?(group)
201
- group && memberships.of_group(group).any?
202
- end
203
210
 
204
- def invited_to?(event)
205
- group && invitations.to_event(event).any?
206
- end
207
-
208
- # some magic glue to allow slightly indiscriminate use of user and person objects.
209
-
210
- def person
211
- self
212
- end
213
-
214
- def admin?
215
- user && user.admin?
216
- end
217
-
218
- def has_active_user?
219
- user && user.activated?
220
- end
221
211
 
222
- def has_invited_user?
223
- user && user.invited?
224
- end
225
212
 
226
- def has_admin_user?
227
- user && user.admin?
228
- end
229
213
 
230
214
 
231
215
  # Snail is a library that abstracts away - as far as possible - the vagaries of international address formats. Here we map our data columns onto Snail's abstract representations so that they can be rendered into the correct format for their country.
@@ -245,7 +229,7 @@ module Droom
245
229
  end
246
230
 
247
231
  def to_vcf
248
- @vcard ||= Vpim::Vcard::Maker.make2 do |maker|
232
+ @vcard ||= Vcard::Vcard::Maker.make2 do |maker|
249
233
  maker.add_name do |n|
250
234
  n.given = name || ""
251
235
  end
@@ -268,8 +252,34 @@ module Droom
268
252
  people.map(&:vcf).join("\n")
269
253
  end
270
254
 
271
- protected
255
+ def as_suggestion
256
+ {
257
+ :type => 'person',
258
+ :prompt => formal_name,
259
+ :value => formal_name,
260
+ :id => id
261
+ }
262
+ end
263
+
264
+ def as_search_result
265
+ {
266
+ :type => 'person',
267
+ :prompt => name,
268
+ :value => name,
269
+ :id => id
270
+ }
271
+ end
272
+
273
+ def invitable?
274
+ name? && email?
275
+ end
272
276
 
277
+ def invite!
278
+ invite_user
279
+ end
280
+
281
+ protected
282
+
273
283
  def invite_if_instructed
274
284
  invite_user if invite_on_creation
275
285
  end
@@ -277,25 +287,29 @@ module Droom
277
287
  # ### Administration & callbacks
278
288
  #
279
289
  # At some point we may want to create a user to log in and look after this person.
280
- # This usually has the side effect of sending out a login invitation.
290
+ # This usually has the side effect of sending out a confirmation message.
281
291
  #
282
292
  def invite_user
283
293
  unless self.user
284
- if self.name? && self.email?
285
- self.create_user(:forename => forename, :name => name, :email => email, :phone => phone, :admin => admin_user)
294
+ if invitable?
295
+ user = self.create_user(:forename => forename, :name => name, :email => email)
286
296
  self.save
287
297
  end
288
298
  end
299
+ self.user
289
300
  end
290
301
 
291
302
  def update_user
292
303
  if self.user && self.user.persisted?
293
304
  self.user.update_column(:email, self.email) if email_changed?
294
- self.user.update_column(:phone, self.phone) if phone_changed?
295
305
  self.user.update_column(:name, self.name) if name_changed?
296
306
  self.user.update_column(:forename, self.forename) if forename_changed?
297
307
  end
298
308
  end
309
+
310
+ def update_status
311
+ update_column(:privileged, memberships.privileged.any?)
312
+ end
299
313
 
300
314
  end
301
315
  end