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
@@ -0,0 +1,134 @@
1
+ require 'zip/zip'
2
+ require 'open-uri'
3
+
4
+ module Droom
5
+ class Folder < ActiveRecord::Base
6
+ attr_accessible :name, :parent, :parent_id
7
+
8
+ belongs_to :created_by, :class_name => "Droom::User"
9
+ belongs_to :holder, :polymorphic => true
10
+ has_many :documents, :dependent => :destroy
11
+ has_many :personal_folders, :dependent => :destroy
12
+ acts_as_tree :order => "name ASC"
13
+
14
+ validates :slug, :presence => true, :uniqueness => { :scope => :parent_id }
15
+
16
+ before_validation :set_properties
17
+ before_validation :ensure_slug
18
+
19
+ default_scope includes(:documents)
20
+
21
+ scope :all_private, where("#{table_name}.private = 1")
22
+ scope :not_private, where("#{table_name}.private <> 1 OR #{table_name}.private IS NULL")
23
+ scope :all_public, where("#{table_name}.public = 1 AND #{table_name}.private <> 1 OR #{table_name}.private IS NULL")
24
+ scope :not_public, where("#{table_name}.public <> 1 OR #{table_name}.private = 1)")
25
+ scope :by_name, order("#{table_name}.name ASC")
26
+ scope :visible_to, lambda { |person|
27
+ # if person
28
+ # select('droom_folders.*')
29
+ # .joins('LEFT OUTER JOIN droom_personal_folders AS dpf ON droom_folders.id = dpf.folder_id')
30
+ # .where(["(droom_folders.public = 1 OR dpf.person_id = ?)", person.id])
31
+ # .group('droom_folders.id')
32
+ # else
33
+ # all_public
34
+ # end
35
+ not_private
36
+ }
37
+
38
+ def visible_to?(person)
39
+ true
40
+ end
41
+
42
+ # A root folders is created automatically for each class that has_folder,
43
+ # the first time something in that class asks for its folder.
44
+ # scope :roots, where('droom_folders.holder_type IS NULL AND droom_folders.parent_id IS NULL')
45
+
46
+ scope :loose, where('parent_id IS NULL')
47
+
48
+ scope :populated, select('droom_folders.*')
49
+ .joins('LEFT OUTER JOIN droom_documents AS dd ON droom_folders.id = dd.folder_id LEFT OUTER JOIN droom_folders AS df ON droom_folders.id = df.parent_id')
50
+ .having('count(dd.id) > 0 OR count(df.id) > 0')
51
+ .group('droom_folders.id')
52
+
53
+ scope :latest, lambda {|limit|
54
+ order("updated_at DESC, created_at DESC").limit(limit)
55
+ }
56
+
57
+ def path
58
+ "#{parent.path if parent}/#{slug}"
59
+ end
60
+
61
+ def documents_zipped
62
+ if self.documents.any?
63
+ tempfile = Tempfile.new("droom-temp-#{slug}-#{Time.now}.zip")
64
+ Zip::ZipOutputStream.open(tempfile.path) do |z|
65
+ self.documents.each do |doc|
66
+ z.add(doc.file_file_name, doc.original_file)
67
+ end
68
+ end
69
+ tempfile
70
+ end
71
+ end
72
+
73
+ def populated?
74
+ children.any? || documents.any?
75
+ end
76
+
77
+ def empty?
78
+ !populated?
79
+ end
80
+
81
+ def simple?
82
+ children.empty? && documents.count <= 2
83
+ end
84
+
85
+ # If we start to get deep folder trees we'll have to use ancestry instead of acts_as_tree.
86
+ def family
87
+ self_and_children
88
+ end
89
+
90
+ def loose?
91
+ !parent
92
+ end
93
+
94
+ def ancestor_of?(folder)
95
+ folder && folder.ancestors.include?(self)
96
+ end
97
+
98
+ def copy_to_dropbox(user)
99
+ Rails.logger.warn ">>> creating dropbox subfolder #{slug} for user #{user.name}"
100
+ documents.each { |doc| doc.copy_to_dropbox(user) }
101
+ end
102
+
103
+ def dropboxed_for?(user)
104
+ # user.person && dropbox_documents.for_person(person).any?
105
+ end
106
+
107
+ def copy_to_dav
108
+ Rails.logger.warn ">>> copy folder #{@folder.inspect} to DAV"
109
+ end
110
+
111
+ def get_name_from_holder
112
+ send :set_properties
113
+ self.save if self.changed?
114
+ end
115
+
116
+ protected
117
+
118
+ def set_properties
119
+ if holder
120
+ self.name ||= holder.name
121
+ self.slug ||= holder.slug
122
+ end
123
+ # folders originally only had slugs, so this happens from time to time
124
+ self.name ||= self.slug
125
+ self.public = !holder && (!parent || parent.public?)
126
+ true
127
+ end
128
+
129
+ def ensure_slug
130
+ ensure_presence_and_uniqueness_of(:slug, name.parameterize)
131
+ end
132
+
133
+ end
134
+ end
@@ -2,53 +2,77 @@ module Droom
2
2
  class Group < ActiveRecord::Base
3
3
  attr_accessible :name, :leader_id, :description
4
4
 
5
- belongs_to :created_by, :class_name => 'User'
5
+ belongs_to :created_by, :class_name => "Droom::User"
6
6
  belongs_to :leader, :class_name => 'Person'
7
7
 
8
+ has_folder
9
+
8
10
  has_many :group_invitations, :dependent => :destroy, :uniq => true
9
11
  has_many :events, :through => :group_invitations
10
12
 
11
13
  has_many :memberships, :dependent => :destroy
12
14
  has_many :people, :through => :memberships, :uniq => true
13
-
14
- has_many :document_attachments, :as => :attachee, :dependent => :destroy
15
- has_many :documents, :through => :document_attachments
16
-
17
- before_save :check_slug
18
-
19
- scope :with_documents,
20
- select("droom_groups.*")
21
- .joins("INNER JOIN droom_document_attachments ON droom_groups.id = droom_document_attachments.attachee_id AND droom_document_attachments.attachee_type = 'Droom::Group'")
22
- .group("droom_groups.id")
23
-
24
-
25
- scope :name_matching, lambda { |fragment|
15
+
16
+ before_validation :ensure_slug
17
+ before_validation :ensure_mailing_list_name
18
+
19
+ validates :slug, :uniqueness => true, :presence => true
20
+ validates :mailing_list_name, :uniqueness => true, :presence => true
21
+
22
+ searchable do
23
+ text :name, :boost => 10, :stored => true
24
+ text :description, :stored => true
25
+ end
26
+
27
+ handle_asynchronously :solr_index
28
+
29
+ def self.highlight_fields
30
+ [:name, :description]
31
+ end
32
+
33
+ scope :all_private, where("private = 1")
34
+ scope :not_private, where("private <> 1 OR private IS NULL")
35
+ scope :all_public, where("public = 1 AND private <> 1 OR private IS NULL")
36
+ scope :not_public, where("public <> 1 OR private = 1)")
37
+
38
+ scope :visible_to, lambda { |person|
39
+ if person
40
+ if person.admin?
41
+ scoped({})
42
+ else
43
+ select('droom_groups.*')
44
+ .joins('INNER JOIN droom_memberships as dm on droom_groups.id = dm.group_id')
45
+ .where(['dm.person_id = ?', person.id])
46
+ .group('droom_groups.id')
47
+ end
48
+ else
49
+ where("1=0")
50
+ end
51
+ }
52
+
53
+ scope :matching, lambda { |fragment|
26
54
  fragment = "%#{fragment}%"
27
55
  where('droom_groups.name like ?', fragment)
28
56
  }
29
-
57
+
30
58
  default_scope order("droom_groups.created_at ASC")
31
-
32
- def identifier
33
- 'group'
34
- end
35
-
59
+
36
60
  def admit(person)
37
61
  self.people << person
38
62
  end
39
-
63
+
40
64
  def attach(doc)
41
- self.documents << doc
65
+ # self.documents << doc
42
66
  end
43
67
 
44
68
  def membership_for(person)
45
69
  self.memberships.for(person).first
46
70
  end
47
-
71
+
48
72
  def invite_to(event)
49
73
  group_invitations.find_or_create_by_event_id(event.id)
50
74
  end
51
-
75
+
52
76
  def uninvite_from(event)
53
77
  group_invitation = group_invitations.find_by_event_id(event.id)
54
78
  group_invitation.invitations.to_event(event).each do |invitation|
@@ -57,10 +81,27 @@ module Droom
57
81
  group_invitation.destroy!
58
82
  end
59
83
 
84
+ def invited_to?(event)
85
+ group_invitations.to_event(event).any?
86
+ end
87
+
88
+ def as_suggestion
89
+ {
90
+ :type => 'group',
91
+ :prompt => name,
92
+ :value => name,
93
+ :id => id
94
+ }
95
+ end
96
+
60
97
  protected
61
-
62
- def check_slug
98
+
99
+ def ensure_slug
63
100
  ensure_presence_and_uniqueness_of(:slug, name.parameterize)
64
101
  end
102
+
103
+ def ensure_mailing_list_name
104
+ ensure_presence_and_uniqueness_of(:mailing_list_name, slug)
105
+ end
65
106
  end
66
- end
107
+ end
@@ -6,18 +6,27 @@ module Droom
6
6
  belongs_to :group
7
7
  belongs_to :event
8
8
  has_many :invitations, :dependent => :destroy
9
- after_create :create_personal_invitations
9
+ after_save :create_personal_invitations
10
10
  validates_uniqueness_of :group_id, :scope => :event_id
11
11
 
12
12
  scope :to_event, lambda { |event|
13
- where("group_invitations.event_id = ?", event.id)
13
+ where("droom_group_invitations.event_id = ?", event.id)
14
14
  }
15
15
 
16
+ scope :for_group, lambda { |group|
17
+ where("droom_group_invitations.group_id = ?", group.id)
18
+ }
19
+
20
+
16
21
  def create_personal_invitations
17
22
  group.people.each do |person|
18
- invitations.find_or_create_by_person_id_and_event_id(person.id, event.id)
23
+ create_personal_invitation_for(person)
19
24
  end
20
25
  end
26
+
27
+ def create_personal_invitation_for(person)
28
+ event.invitations.find_or_create_by_person_id(person.id) if person.member_of?(group)
29
+ end
21
30
 
22
31
  end
23
32
  end
@@ -7,24 +7,66 @@ module Droom
7
7
  belongs_to :group_invitation
8
8
  belongs_to :created_by, :class_name => "User"
9
9
 
10
- after_create :link_documents
11
- after_destroy :unlink_documents
10
+ after_create :link_folder
11
+ after_destroy :unlink_folder
12
+ # after_destroy :delete_similar
12
13
 
13
14
  validates_uniqueness_of :person_id, :scope => [:event_id, :group_invitation_id]
14
15
 
15
16
  scope :to_event, lambda { |event|
16
17
  where(["event_id = ?", event.id])
17
18
  }
18
-
19
- protected
19
+
20
+ scope :for_person, lambda { |person|
21
+ where("droom_invitations.person_id = ?", person.id)
22
+ }
23
+
24
+ scope :future, lambda {
25
+ select('droom_invitations.*')
26
+ .joins('inner join droom_events as de on droom_invitations.event_id = de.id')
27
+ .where(['de.start > :now', :now => Time.now])
28
+ .group('droom_invitations.id')
29
+ }
30
+
31
+ scope :refused, where("response < 1")
32
+ scope :accepted, where("response > 1")
33
+ scope :not_refused, where("response > 0")
34
+ scope :not_accepted, where("response < 2")
35
+ scope :responded, where("response <> 1")
36
+ scope :not_responded, where("response == 1")
20
37
 
21
- def link_documents
22
- person.document_attachments << event.document_attachments
38
+ def link_folder
39
+ person.add_personal_folders(event.folder)
40
+ end
41
+
42
+ def unlink_folder
43
+ person.remove_personal_folders(event.folder)
23
44
  end
24
45
 
25
- def unlink_documents
26
- person.document_attachments -= event.document_attachments
46
+ def status
47
+ if response < 1
48
+ "refused"
49
+ elsif response == 1
50
+ "maybe"
51
+ else
52
+ "accepted"
53
+ end
54
+ end
55
+
56
+ def accepted?
57
+ response && response > 1
27
58
  end
28
59
 
60
+ def refused?
61
+ response && response < 1
62
+ end
63
+
64
+ protected
65
+
66
+ def delete_similar
67
+ Droom::Invitation.for_person(person).to_event(event).delete_all
68
+ end
69
+
29
70
  end
71
+
30
72
  end
@@ -0,0 +1,128 @@
1
+ # This class has the awkward job of giving access to the mailing list membership records stored in
2
+ # legacy mailman mysql tables. They're likely to be held in another database, and they have an extremely
3
+ # un-rails-like schema, so our main job is to translate between their and our conventions.
4
+ #
5
+ # This whole mechanism and its configuration requirements can safely be ignored unless you want to
6
+ # use it, in which case you should set `Droom.enable_mailing_lists` to true in an initializer and read on.
7
+ #
8
+ # If you don't set `enable_mailing_lists` then some database activity will still go on, but with no
9
+ # consequence, and the mailing list interface controls will not appear.
10
+ #
11
+ ## Requirements
12
+ #
13
+ # The MailingListMembership class is able to interface directly with your existing mailman data, with
14
+ # the addition of a couple of columns to support activerecord associations. It's mostly just a case of
15
+ # configuring access to the old data.
16
+ #
17
+ # ### Mailman data held in MySQL tables with the 'flat' data structure
18
+ #
19
+ # There are two options here. Either you can use the standard table that has already been created here,
20
+ # or you can define a `mailman_[env]` connection in database.yml that points to an external mailman
21
+ # database. In that case see the notes below about adding a couple of columns.
22
+ #
23
+ # ### Mailman configured to use MySQL
24
+ #
25
+ # If you don't have an existing mailmanmysql setup, it takes a few steps to point your mailman installation
26
+ # at this database and table. It can be done either globally or on a per-list basis, so it is possible
27
+ # to keep your existing mailman installation but add a new database-backed mailing list.
28
+ #
29
+ # Mysql storage is considered modern and a bit racy in the mailman community, having only been available
30
+ # since the early 2000s. It's not officially supported until mailman 3 coalesces out of the ether but if
31
+ # you speak any python it's easy to make it work with 2.x. Two sets of dusty patches are available here:
32
+ #
33
+ # http://wiki.list.org/pages/viewpage.action?pageId=15564884
34
+ #
35
+ # and I've found the slightly less ancient version from rezo.net works well:
36
+ #
37
+ # http://trac.rezo.net/trac/rezo/browser/Mailman
38
+ #
39
+ # In order that we can store membership of different lists in the same table, please make sure that
40
+ # mailman is using the 'flat' data structure. If you want to enable mysql just for selected lists,
41
+ # put an `extend.py` in each list directory and leave the rest of your configuration as it is.
42
+ #
43
+ # It is currently a good idea to avoid reserved words in your mailing list names. They'll work in rails
44
+ # but not in python, where the quoting of some database queries seems to be less than perfect.
45
+ #
46
+ # ### Minor changes to the mailman table
47
+ #
48
+ # The local table is already set up in a way that should work equally well with rails and mailman.
49
+ # If you're using a remote mailman table, it will need a couple of small changes:
50
+ #
51
+ # **An id column as primary key.** Strictly speaking we should define a composite primary key based
52
+ # on address & listname, but it's much easier just to add an auto_incrementing id column and make
53
+ # that the primary key. Mailman doesn't care as long as its columns are there. You probably also want
54
+ # to create a unique index on address+listname so that mailman gets the benefit and sees the expected
55
+ # behaviour.
56
+ #
57
+ # **A membership_id column** We could (and used to) twist Activerecord out of shape by defining
58
+ # associations with address and listname primary keys between mailing list memberships and people
59
+ # and groups, but again it's much easier just to belong_to a group membership. For that we need a
60
+ # membership_id column. Again, you will want an index on that column.
61
+
62
+ module Droom
63
+ class MailingListMembership < ActiveRecord::Base
64
+ attr_accessible :address, :listname, :digest, :not_metoo, :nomail, :plain, :ack
65
+ #
66
+ ## Configuration
67
+ #
68
+ # A dedicated mailman database connection can be defined in the host app's config/database.yml as
69
+ # `mailman_development` or `mailman_production` if you want us to use an existing mailman database.
70
+ # We can only work with the 'flat' database structure, where all the list memberships are held in
71
+ # one table.
72
+ #
73
+ # If no such connection is defined, we will use the local `droom_mailing_list_memberships` table.
74
+ #
75
+ begin
76
+ establish_connection :"mailman_#{Rails.env}"
77
+ set_table_name Droom.mailman_table_name
78
+ rescue ActiveRecord::AdapterNotSpecified
79
+ Rails.logger.warn "Droom: No mailman connection configured. Using #{Rails.env} database."
80
+ end
81
+
82
+ ## Associations
83
+ #
84
+ # Giving membership of a group will create a mailing list membership automatically.
85
+ # The activity status of the created mlm depends on the `Droom.mailing_lists_active_by_default`
86
+ # setting, and its effect depends of course on your mailman setup.
87
+ #
88
+ belongs_to :membership
89
+ before_create :set_defaults
90
+
91
+ validates :address, :uniqueness => {:scope => :listname}
92
+
93
+ ## Translation
94
+ #
95
+ # Mailman's boolean columns are held as Y/N so we intervene to translate.
96
+ #
97
+ [:digest, :not_metoo, :nomail, :plain, :ack].each do |col|
98
+ define_method(col) do
99
+ read_attribute(col) == 'Y'
100
+ end
101
+ define_method("#{col}?") do
102
+ read_attribute(col) == 'Y'
103
+ end
104
+ define_method("#{col}=") do |value|
105
+ write_attribute(col, to_yesno(value))
106
+ end
107
+ define_method("#{col}_before_type_cast") do
108
+ read_attribute(col) == 'Y' ? 1 : 0
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def set_defaults
115
+ self.bi_lastnotice = 0
116
+ self.bi_date = 0
117
+ self.ack = true
118
+ self.nomail = !Droom.mailing_lists_active_by_default?
119
+ self.digest = Droom.mailing_lists_digest_by_default?
120
+ true
121
+ end
122
+
123
+ def to_yesno(value)
124
+ (value && value != 0 && value != "0" && value != "N") ? 'Y' : 'N'
125
+ end
126
+
127
+ end
128
+ end