droom 0.4.3 → 0.5.3
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.
- checksums.yaml +7 -0
- data/app/assets/images/droom/admin_menu.png +0 -0
- data/app/assets/images/droom/applications_menu.png +0 -0
- data/app/assets/images/droom/arrows_small.png +0 -0
- data/app/assets/images/droom/config_menu.png +0 -0
- data/app/assets/images/droom/dropdown.png +0 -0
- data/app/assets/images/droom/menu/asterisk.png +0 -0
- data/app/assets/images/droom/{smalladd.png → menu/smalladd.png} +0 -0
- data/app/assets/images/droom/{small_asterisk.png → menu/smallasterisk.png} +0 -0
- data/app/assets/images/droom/{smalldelete.png → menu/smalldelete.png} +0 -0
- data/app/assets/images/droom/{smalldownload.png → menu/smalldownload.png} +0 -0
- data/app/assets/images/droom/{smalledit.png → menu/smalledit.png} +0 -0
- data/app/assets/images/droom/message.png +0 -0
- data/app/assets/images/droom/missing/scrap.jpg +0 -0
- data/app/assets/images/droom/missing/scrap.png +0 -0
- data/app/assets/images/droom/missing/thumb.png +0 -0
- data/app/assets/images/droom/missing/user.png +0 -0
- data/app/assets/images/droom/object_icons.png +0 -0
- data/app/assets/images/droom/panel/add.png +0 -0
- data/app/assets/images/droom/panel/edit.png +0 -0
- data/app/assets/images/droom/panel/manage.png +0 -0
- data/app/assets/images/droom/pointer_upwards.png +0 -0
- data/app/assets/images/droom/search_menu.png +0 -0
- data/app/assets/images/droom/setter.png +0 -0
- data/app/assets/images/droom/small_icons.png +0 -0
- data/app/assets/images/droom/stream/closer.png +0 -0
- data/app/assets/images/droom/stream/next.png +0 -0
- data/app/assets/images/droom/stream/prev.png +0 -0
- data/app/assets/images/droom/stream/previous.png +0 -0
- data/app/assets/images/droom/subscribe.png +0 -0
- data/app/assets/javascripts/droom.js.coffee +23 -13
- data/app/assets/javascripts/droom/actions.js.coffee +104 -10
- data/app/assets/javascripts/droom/ajax.js.coffee +36 -24
- data/app/assets/javascripts/droom/extensions.js.coffee +13 -0
- data/app/assets/javascripts/droom/lib/jquery.datepicker.js +1026 -0
- data/app/assets/javascripts/droom/lib/jquery.deserialize.js +142 -0
- data/app/assets/javascripts/droom/lib/jquery_ujs.js +416 -0
- data/app/assets/javascripts/droom/lib/swipe.js +568 -0
- data/app/assets/javascripts/droom/lib/underscore.js +1276 -0
- data/app/assets/javascripts/droom/popups.js.coffee +98 -37
- data/app/assets/javascripts/droom/stream.js.coffee +119 -77
- data/app/assets/javascripts/droom/utilities.js.coffee +25 -3
- data/app/assets/javascripts/droom/widgets.js.coffee +318 -253
- data/app/assets/stylesheets/droom.css.sass +482 -955
- data/app/assets/stylesheets/droom/_mixins.css.sass +12 -42
- data/app/assets/stylesheets/droom/_popups.css.sass +28 -11
- data/app/assets/stylesheets/droom/_stream.css.sass +375 -0
- data/app/assets/stylesheets/droom/_toolbar.css.sass +0 -6
- data/app/assets/stylesheets/droom/_variables.css.sass +4 -2
- data/app/controllers/droom/agenda_categories_controller.rb +6 -14
- data/app/controllers/droom/api/api_controller.rb +56 -0
- data/app/controllers/droom/api/events_controller.rb +74 -0
- data/app/controllers/droom/api/users_controller.rb +92 -0
- data/app/controllers/droom/api/venues_controller.rb +71 -0
- data/app/controllers/droom/calendars_controller.rb +4 -10
- data/app/controllers/droom/{user_confirmations_controller.rb → confirmations_controller.rb} +8 -7
- data/app/controllers/droom/dashboard_controller.rb +2 -19
- data/app/controllers/droom/documents_controller.rb +12 -60
- data/app/controllers/droom/dropbox_tokens_controller.rb +3 -4
- data/app/controllers/droom/engine_controller.rb +39 -11
- data/app/controllers/droom/events_controller.rb +62 -84
- data/app/controllers/droom/folders_controller.rb +30 -40
- data/app/controllers/droom/group_invitations_controller.rb +6 -23
- data/app/controllers/droom/group_permissions_controller.rb +26 -0
- data/app/controllers/droom/groups_controller.rb +10 -14
- data/app/controllers/droom/invitations_controller.rb +7 -25
- data/app/controllers/droom/memberships_controller.rb +13 -18
- data/app/controllers/droom/organisations_controller.rb +6 -25
- data/app/controllers/droom/permissions_controller.rb +50 -0
- data/app/controllers/droom/preferences_controller.rb +9 -10
- data/app/controllers/droom/scraps_controller.rb +23 -26
- data/app/controllers/droom/services_controller.rb +50 -0
- data/app/controllers/droom/suggestions_controller.rb +6 -4
- data/app/controllers/droom/users/confirmations_controller.rb +24 -0
- data/app/controllers/droom/users/passwords_controller.rb +39 -0
- data/app/controllers/droom/users/sessions_controller.rb +7 -0
- data/app/controllers/droom/users_controller.rb +60 -38
- data/app/controllers/droom/venues_controller.rb +8 -15
- data/app/controllers/droom/youtube_controller.rb +1 -1
- data/app/helpers/droom/droom_helper.rb +22 -17
- data/app/models/droom/ability.rb +81 -0
- data/app/models/droom/agenda_category.rb +0 -1
- data/app/models/droom/calendar.rb +12 -7
- data/app/models/droom/category.rb +4 -10
- data/app/models/droom/concerns/slugged.rb +21 -0
- data/app/models/droom/document.rb +15 -17
- data/app/models/droom/dropbox_document.rb +3 -6
- data/app/models/droom/dropbox_token.rb +2 -3
- data/app/models/droom/event.rb +117 -163
- data/app/models/droom/event_type.rb +25 -0
- data/app/models/droom/folder.rb +36 -48
- data/app/models/droom/group.rb +35 -27
- data/app/models/droom/group_invitation.rb +7 -10
- data/app/models/droom/group_permission.rb +29 -0
- data/app/models/droom/invitation.rb +14 -23
- data/app/models/droom/mailing_list_membership.rb +0 -1
- data/app/models/droom/membership.rb +32 -31
- data/app/models/droom/organisation.rb +6 -3
- data/app/models/droom/permission.rb +19 -0
- data/app/models/droom/personal_folder.rb +9 -21
- data/app/models/droom/preference.rb +1 -2
- data/app/models/droom/scrap.rb +31 -26
- data/app/models/droom/service.rb +31 -0
- data/app/models/droom/tag.rb +10 -9
- data/app/models/droom/tagging.rb +1 -1
- data/app/models/droom/user.rb +453 -130
- data/app/models/droom/user_permission.rb +8 -0
- data/app/models/droom/venue.rb +21 -32
- data/app/serializers/droom/user_serializer.rb +45 -0
- data/app/serializers/droom/venue_serializer.rb +5 -0
- data/app/views/droom/dashboard/_documents.html.haml +1 -1
- data/app/views/droom/dashboard/_folders.html.haml +1 -1
- data/app/views/droom/dashboard/_future_events.html.haml +10 -8
- data/app/views/droom/dashboard/_groups.html.haml +1 -1
- data/app/views/droom/dashboard/_past_events.haml +19 -12
- data/app/views/droom/dashboard/_stream.html.haml +2 -2
- data/app/views/droom/{users/_extra_columns.html.haml → dashboard/_welcome.html.haml} +0 -0
- data/app/views/droom/dashboard/index.html.haml +3 -0
- data/app/views/droom/documents/_document.html.haml +0 -2
- data/app/views/droom/documents/_documents.html.haml +1 -1
- data/app/views/droom/documents/_documents_list.html.haml +1 -1
- data/app/views/droom/documents/_documents_table.html.haml +1 -1
- data/app/views/droom/documents/_form.html.haml +8 -5
- data/app/views/droom/documents/_listing.html.haml +4 -2
- data/app/views/droom/documents/index.html.haml +13 -7
- data/app/views/droom/documents/new.html.haml +1 -4
- data/app/views/droom/events/_action_menu.html.haml +2 -2
- data/app/views/droom/events/_attachments.html.haml +8 -0
- data/app/views/droom/events/_calendar.html.haml +4 -8
- data/app/views/droom/events/_event.html.haml +44 -63
- data/app/views/droom/events/_event_line.html.haml +1 -1
- data/app/views/droom/events/_events.html.haml +18 -2
- data/app/views/droom/events/_form.html.haml +26 -19
- data/app/views/droom/events/_invitations.html.haml +7 -3
- data/app/views/droom/events/_scrap_events.html.haml +8 -0
- data/app/views/droom/events/_suggested.html.haml +4 -1
- data/app/views/droom/events/calendar.html.haml +8 -0
- data/app/views/droom/events/index.html.haml +24 -26
- data/app/views/droom/events/show.html.haml +6 -6
- data/app/views/droom/folders/_contents.html.haml +34 -4
- data/app/views/droom/folders/_folder.html.haml +7 -2
- data/app/views/droom/folders/_form.html.haml +11 -8
- data/app/views/droom/folders/index.html.haml +19 -22
- data/app/views/droom/group_invitations/_attending_groups.html.haml +1 -1
- data/app/views/droom/group_permissions/_toggle.html.haml +18 -0
- data/app/views/droom/groups/_action_menu.haml +0 -2
- data/app/views/droom/groups/_created.html.haml +0 -1
- data/app/views/droom/groups/_form.html.haml +3 -0
- data/app/views/droom/groups/_group.html.haml +10 -8
- data/app/views/droom/groups/_groups.html.haml +1 -1
- data/app/views/droom/groups/_search_result.html.haml +1 -1
- data/app/views/droom/groups/_suggested.html.haml +1 -1
- data/app/views/droom/groups/index.html.haml +15 -16
- data/app/views/droom/invitations/_form.html.haml +1 -1
- data/app/views/droom/invitations/_invitation.html.haml +1 -1
- data/app/views/droom/invitations/_invitations.html.haml +4 -4
- data/app/views/droom/memberships/_button.html.haml +5 -5
- data/app/views/droom/memberships/_form.html.haml +26 -7
- data/app/views/droom/memberships/_member.html.haml +1 -1
- data/app/views/droom/memberships/{_membership_toggle.html.haml → _toggle.html.haml} +4 -4
- data/app/views/droom/memberships/index.html.haml +9 -0
- data/app/views/droom/organisations/_action_menu.html.haml +1 -1
- data/app/views/droom/organisations/_organisation.html.haml +2 -2
- data/app/views/droom/organisations/_suggested.html.haml +1 -1
- data/app/views/droom/organisations/index.html.haml +11 -11
- data/app/views/droom/panels/_admin.html.haml +2 -2
- data/app/views/droom/panels/_configuration.html.haml +28 -0
- data/app/views/droom/panels/_devices.html.haml +2 -4
- data/app/views/droom/panels/_search.html.haml +9 -0
- data/app/views/droom/permissions/_action_menu.html.haml +10 -0
- data/app/views/droom/permissions/_created.html.haml +3 -0
- data/app/views/droom/permissions/_form.html.haml +17 -0
- data/app/views/droom/permissions/edit.html.haml +7 -0
- data/app/views/droom/permissions/new.html.haml +8 -0
- data/app/views/droom/permissions/show.html.haml +4 -0
- data/app/views/droom/preferences/_checkbox.html.haml +4 -2
- data/app/views/droom/scraps/_caption.html.haml +0 -2
- data/app/views/droom/scraps/_credit.html.haml +1 -1
- data/app/views/droom/scraps/_form.html.haml +68 -69
- data/app/views/droom/scraps/_preload.html.haml +4 -0
- data/app/views/droom/scraps/_stream.html.haml +11 -3
- data/app/views/droom/scraps/_thumb.html.haml +33 -1
- data/app/views/droom/scraps/edit.html.haml +6 -1
- data/app/views/droom/scraps/full/_document.html.haml +4 -3
- data/app/views/droom/scraps/full/_event.html.haml +17 -16
- data/app/views/droom/scraps/full/_image.html.haml +1 -2
- data/app/views/droom/scraps/full/_link.html.haml +4 -3
- data/app/views/droom/scraps/full/_quote.html.haml +4 -7
- data/app/views/droom/scraps/full/_text.html.haml +3 -2
- data/app/views/droom/scraps/full/_video.html.haml +2 -2
- data/app/views/droom/scraps/new.html.haml +6 -1
- data/app/views/droom/scraps/show.html.haml +4 -3
- data/app/views/droom/services/_action_menu.html.haml +12 -0
- data/app/views/droom/services/_created.html.haml +3 -0
- data/app/views/droom/services/_form.html.haml +18 -0
- data/app/views/droom/services/_services.html.haml +44 -0
- data/app/views/droom/services/edit.html.haml +7 -0
- data/app/views/droom/services/index.html.haml +5 -0
- data/app/views/droom/{people → services}/new.html.haml +4 -3
- data/app/views/droom/services/show.html.haml +4 -0
- data/app/views/droom/shared/_controls.html.haml +2 -2
- data/app/views/droom/shared/_navigation.html.haml +2 -2
- data/app/views/droom/shared/_toolbar.html.haml +1 -1
- data/app/views/droom/suggestions/index.html.haml +1 -0
- data/app/views/droom/users/_action_menu.html.haml +21 -0
- data/app/views/droom/users/_suggested.html.haml +14 -0
- data/app/views/droom/users/_user.html.haml +2 -2
- data/app/views/droom/users/_users.html.haml +7 -0
- data/app/views/droom/users/_users_table.html.haml +21 -22
- data/app/views/droom/users/admin.html.haml +10 -0
- data/app/views/droom/users/confirmations/_after_confirmation.html.haml +2 -0
- data/app/views/droom/users/confirmations/_password_required.html.haml +30 -0
- data/app/views/droom/users/confirmations/failure.en.html.haml +22 -0
- data/app/views/droom/users/confirmations/show.html.haml +13 -0
- data/app/views/droom/users/edit.html.haml +2 -10
- data/app/views/droom/users/edit/_details.html.haml +13 -0
- data/app/views/droom/users/edit/_memberships.html.haml +13 -0
- data/app/views/droom/users/edit/_password_fields.html.haml +16 -0
- data/app/views/droom/users/edit/_preferences.html.haml +37 -0
- data/app/views/droom/users/edit/_profile.html.haml +26 -0
- data/app/views/droom/users/edit/_user_fields.html.haml +66 -0
- data/app/views/droom/users/index.html.haml +6 -32
- data/app/views/droom/users/new.html.haml +3 -0
- data/app/views/droom/users/passwords/completed.html.haml +13 -0
- data/app/views/{devise → droom/users}/passwords/edit.html.haml +10 -4
- data/app/views/{devise → droom/users}/passwords/new.html.haml +4 -3
- data/app/views/droom/users/passwords/show.html.haml +6 -0
- data/app/views/droom/users/show.html.haml +2 -0
- data/app/views/droom/users/show/_listed.html.haml +46 -0
- data/app/views/droom/users/show/_profile.html.haml +33 -0
- data/app/views/droom/users/show/_tabled.html.haml +28 -0
- data/config/initializers/chronic.rb +2 -0
- data/config/initializers/devise.rb +35 -2
- data/config/initializers/paperclip.rb +11 -6
- data/config/locales/devise.en.yml +1 -1
- data/config/locales/en.yml +198 -103
- data/config/routes.rb +37 -45
- data/db/migrate/20130207123614_stream.rb +5 -1
- data/db/migrate/20130225095328_create_droom_calendars.rb +0 -1
- data/db/migrate/20130627065459_permissions.rb +34 -0
- data/db/migrate/20130627071938_users_take_over.rb +38 -0
- data/db/migrate/20130627073759_user_properties.rb +34 -0
- data/db/migrate/20130627080021_no_more_people.rb +11 -0
- data/db/migrate/20130701122935_directory_groups.rb +8 -0
- data/db/migrate/20130701123152_remove_old_access_control.rb +16 -0
- data/db/migrate/20130729102857_more_scrap_data.rb +12 -0
- data/db/migrate/20130904080340_international_names.rb +17 -0
- data/db/migrate/20130904080341_honours.rb +5 -0
- data/db/migrate/20131124082222_simple_addresses.rb +25 -0
- data/db/migrate/20131201093351_event_time_zone.rb +5 -0
- data/db/migrate/20131217060311_session_revocable.rb +5 -0
- data/db/migrate/20131219180311_event_types.rb +15 -0
- data/lib/devise/strategies/cookie_authenticatable.rb +46 -0
- data/lib/droom.rb +48 -33
- data/lib/droom/auth_cookie.rb +82 -0
- data/lib/droom/cropper.rb +24 -0
- data/lib/droom/engine.rb +20 -2
- data/lib/droom/folders.rb +6 -6
- data/lib/droom/lazy_hash.rb +11 -1
- data/lib/droom/monkeys.rb +6 -6
- data/lib/droom/taggability.rb +1 -1
- data/lib/droom/validators.rb +1 -1
- data/lib/droom/version.rb +1 -1
- data/lib/generators/droom/install/templates/droom_initializer.rb +10 -2
- data/lib/paperclip/geometry_transformation.rb +80 -0
- data/lib/paperclip/validators/attachment_height_validator.rb +89 -0
- data/lib/paperclip/validators/attachment_width_validator.rb +89 -0
- data/lib/paperclip_processors/offset_thumbnail.rb +85 -0
- data/spec/dummy/config/application.rb +0 -7
- data/spec/dummy/config/environments/development.rb +1 -10
- data/spec/dummy/config/environments/production.rb +1 -0
- data/spec/dummy/config/environments/test.rb +2 -7
- data/spec/dummy/db/migrate/20130130120631_folder_ancestry_to_parents.droom.rb +1 -1
- data/spec/dummy/db/migrate/20130724124758_dropbox_tokens.droom.rb +10 -0
- data/spec/dummy/db/migrate/20130724124759_preference_uuids.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124760_stream.droom.rb +14 -0
- data/spec/dummy/db/migrate/20130724124761_access_token_secret.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124762_person_image.droom.rb +10 -0
- data/spec/dummy/db/migrate/20130724124763_devise_confirmable.droom.rb +14 -0
- data/spec/dummy/db/migrate/20130724124764_create_droom_calendars.droom.rb +20 -0
- data/spec/dummy/db/migrate/20130724124765_give_scraps_document.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124766_privateness.droom.rb +10 -0
- data/spec/dummy/db/migrate/20130724124767_store_metadata.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124768_folders_nicely.droom.rb +7 -0
- data/spec/dummy/db/migrate/20130724124769_niceties.droom.rb +8 -0
- data/spec/dummy/db/migrate/20130724124770_create_droom_dropbox_documents.droom.rb +12 -0
- data/spec/dummy/db/migrate/20130724124771_dropbox_documents_changed.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124772_user_titles.droom.rb +6 -0
- data/spec/dummy/db/migrate/20130724124773_permissions.droom.rb +35 -0
- data/spec/dummy/db/migrate/20130724124774_users_take_over.droom.rb +39 -0
- data/spec/dummy/db/migrate/20130724124775_user_properties.droom.rb +35 -0
- data/spec/dummy/db/migrate/20130724124776_no_more_people.droom.rb +12 -0
- data/spec/dummy/db/migrate/20130724124777_directory_groups.droom.rb +9 -0
- data/spec/dummy/db/migrate/20130724124778_remove_old_access_control.droom.rb +17 -0
- data/spec/dummy/db/schema.rb +217 -140
- data/spec/factories/documents.rb +0 -5
- data/spec/factories/events.rb +0 -9
- data/spec/factories/user.rb +4 -2
- data/spec/lib/droom/folders_spec.rb +8 -8
- data/spec/models/droom/document_spec.rb +6 -43
- data/spec/models/droom/event_spec.rb +0 -34
- data/spec/models/droom/mailing_list_membership_spec.rb +4 -4
- data/spec/models/droom/membership_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -10
- metadata +322 -282
- data/app/assets/images/droom/Untitled-1.png +0 -0
- data/app/assets/images/droom/asterisk.png +0 -0
- data/app/assets/images/droom/smallmanage.png +0 -0
- data/app/assets/javascripts/droom/lib/kalendae.js +0 -1692
- data/app/assets/stylesheets/lib/_kalendae.css.sass +0 -139
- data/app/controllers/droom/pages_controller.rb +0 -61
- data/app/controllers/droom/people_controller.rb +0 -111
- data/app/models/droom/document_attachment.rb +0 -37
- data/app/models/droom/page.rb +0 -26
- data/app/models/droom/person.rb +0 -309
- data/app/models/droom/recurrence_rule.rb +0 -82
- data/app/models/droom/user_action_observer.rb +0 -12
- data/app/views/devise/confirmations/failure.en.html.haml +0 -20
- data/app/views/devise/confirmations/show.html.haml +0 -19
- data/app/views/droom/confirmations/show.html.haml +0 -40
- data/app/views/droom/documents/_document_line.html.haml +0 -2
- data/app/views/droom/events/_created.html.haml +0 -2
- data/app/views/droom/folders/_attachments.html.haml +0 -3
- data/app/views/droom/pages/_contents.html.haml +0 -10
- data/app/views/droom/pages/_form.html.haml +0 -36
- data/app/views/droom/pages/_full_page.html.haml +0 -17
- data/app/views/droom/pages/_page.html.haml +0 -5
- data/app/views/droom/pages/_pages.html.haml +0 -2
- data/app/views/droom/pages/admin.html.haml +0 -24
- data/app/views/droom/pages/edit.html.haml +0 -1
- data/app/views/droom/pages/index.html.haml +0 -10
- data/app/views/droom/pages/new.html.haml +0 -4
- data/app/views/droom/pages/show.html.haml +0 -5
- data/app/views/droom/panels/_account.html.haml +0 -16
- data/app/views/droom/panels/_readers.html.haml +0 -18
- data/app/views/droom/panels/_suggestions.html.haml +0 -15
- data/app/views/droom/people/_action_menu.html.haml +0 -22
- data/app/views/droom/people/_created.html.haml +0 -6
- data/app/views/droom/people/_form.html.haml +0 -66
- data/app/views/droom/people/_listing.html.haml +0 -19
- data/app/views/droom/people/_memberships.html.haml +0 -24
- data/app/views/droom/people/_people.html.haml +0 -5
- data/app/views/droom/people/_person.html.haml +0 -32
- data/app/views/droom/people/_search_result.html.haml +0 -14
- data/app/views/droom/people/_suggested.html.haml +0 -14
- data/app/views/droom/people/edit.html.haml +0 -9
- data/app/views/droom/people/index.html.haml +0 -8
- data/app/views/droom/people/show.html.haml +0 -31
- data/app/views/droom/scraps/_heading.html.haml +0 -16
- data/app/views/droom/scraps/thumbs/_document.html.haml +0 -9
- data/app/views/droom/scraps/thumbs/_event.html.haml +0 -17
- data/app/views/droom/scraps/thumbs/_image.html.haml +0 -6
- data/app/views/droom/scraps/thumbs/_link.html.haml +0 -10
- data/app/views/droom/scraps/thumbs/_quote.html.haml +0 -8
- data/app/views/droom/scraps/thumbs/_text.html.haml +0 -8
- data/app/views/droom/scraps/thumbs/_video.html.haml +0 -6
- data/app/views/droom/users/_extra_columns_header.html.haml +0 -0
- data/app/views/droom/users/_extra_columns_note.html.haml +0 -0
- data/app/views/droom/users/_form.html.haml +0 -14
- data/app/views/droom/users/_password_fields.html.haml +0 -15
- data/app/views/droom/users/_user_or_person.html.haml +0 -72
- data/app/views/kaminari/_paginator.html.haml +0 -16
- data/lib/droom/dav_resource.rb +0 -36
- data/lib/droom/model_helpers.rb +0 -25
- data/lib/droom/routing.rb +0 -13
- data/spec/datasets/calendar_events_dataset.rb +0 -44
- data/spec/datasets/calendar_pages_dataset.rb +0 -8
- data/spec/datasets/calendar_sites_dataset.rb +0 -6
- data/spec/datasets/calendars_dataset.rb +0 -34
- data/spec/datasets/documents_dataset.rb +0 -28
- data/spec/datasets/recurrence_dataset.rb +0 -7
- data/spec/dummy/config/sunspot.yml +0 -17
- data/spec/dummy/log/dav.log +0 -1
- data/spec/dummy/log/development.log +0 -2
- data/spec/dummy/log/test.log +0 -1
- data/spec/dummy/solr/conf/admin-extra.html +0 -31
- data/spec/dummy/solr/conf/elevate.xml +0 -36
- data/spec/dummy/solr/conf/mapping-ISOLatin1Accent.txt +0 -246
- data/spec/dummy/solr/conf/protwords.txt +0 -21
- data/spec/dummy/solr/conf/schema.xml +0 -238
- data/spec/dummy/solr/conf/scripts.conf +0 -24
- data/spec/dummy/solr/conf/solrconfig.xml +0 -934
- data/spec/dummy/solr/conf/spellings.txt +0 -2
- data/spec/dummy/solr/conf/stopwords.txt +0 -58
- data/spec/dummy/solr/conf/synonyms.txt +0 -31
- data/spec/dummy/solr/data/development/index/segments.gen +0 -0
- data/spec/dummy/solr/data/development/index/segments_1 +0 -0
- data/spec/dummy/solr/data/development/spellchecker/segments.gen +0 -0
- data/spec/dummy/solr/data/development/spellchecker/segments_1 +0 -0
- data/spec/dummy/solr/data/test/index/segments.gen +0 -0
- data/spec/dummy/solr/data/test/index/segments_3nu +0 -0
- data/spec/dummy/solr/data/test/spellchecker/segments.gen +0 -0
- data/spec/dummy/solr/data/test/spellchecker/segments_1 +0 -0
- data/spec/factories/recurrence_rules.rb +0 -25
- data/spec/models/droom/person_spec.rb +0 -72
- data/spec/models/droom/recurrence_rule_spec.rb +0 -81
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
module Droom
|
|
2
2
|
class Organisation < ActiveRecord::Base
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
belongs_to :owner, :class_name => 'Droom::Person'
|
|
3
|
+
has_many :users
|
|
4
|
+
belongs_to :owner, :class_name => 'Droom::User'
|
|
6
5
|
belongs_to :created_by, :class_name => 'Droom::User'
|
|
6
|
+
|
|
7
|
+
scope :added_since, -> date { where("created_at > ?", date)}
|
|
8
|
+
|
|
9
|
+
default_scope -> {order("name ASC")}
|
|
7
10
|
|
|
8
11
|
def self.for_selection
|
|
9
12
|
organisations = self.order("name asc").map{|f| [f.name, f.id] }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'acts_as_list'
|
|
2
|
+
|
|
3
|
+
module Droom
|
|
4
|
+
class Permission < ActiveRecord::Base
|
|
5
|
+
belongs_to :service
|
|
6
|
+
has_many :group_permissions, :dependent => :destroy
|
|
7
|
+
has_many :user_permissions, :dependent => :destroy
|
|
8
|
+
acts_as_list :scope => :service_id
|
|
9
|
+
before_save :set_slug
|
|
10
|
+
|
|
11
|
+
validates :slug, :uniqueness => true
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def set_slug
|
|
16
|
+
self.slug = [service.slug, self.name].join('.')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
module Droom
|
|
2
2
|
class PersonalFolder < ActiveRecord::Base
|
|
3
|
-
belongs_to :
|
|
3
|
+
belongs_to :user
|
|
4
4
|
belongs_to :folder
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
scope :of_folder, -> folder {
|
|
7
|
+
where(["folder_id = ?", folder.id])
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
scope :for_user, -> user {
|
|
11
|
+
where(["user_id = ?", user.id])
|
|
12
|
+
}
|
|
9
13
|
|
|
10
|
-
def
|
|
14
|
+
def copy_to_dropbox
|
|
11
15
|
|
|
12
16
|
end
|
|
13
17
|
|
|
14
|
-
#todo: lifted from Person and awaiting translation
|
|
15
|
-
#
|
|
16
|
-
# def create_and_update_dav_directories
|
|
17
|
-
# document_links.each do |dl|
|
|
18
|
-
# p "-> creating DAV directory #{dl.slug}"
|
|
19
|
-
# create_dav_directory(dl.slug)
|
|
20
|
-
# end
|
|
21
|
-
# end
|
|
22
|
-
#
|
|
23
|
-
# def create_dav_directory(name)
|
|
24
|
-
# FileUtils.mkdir_p(Rails.root + "#{Droom.dav_root}/#{self.id}/#{name}")
|
|
25
|
-
# end
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
# association helpers give us more readable logic elsewhere.
|
|
29
|
-
|
|
30
18
|
end
|
|
31
19
|
end
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Droom
|
|
4
4
|
class Preference < ActiveRecord::Base
|
|
5
|
-
attr_accessible :key, :value, :uuid
|
|
6
5
|
belongs_to :created_by, :class_name => "Droom::User"
|
|
7
|
-
validates :key, :presence => true, :uniqueness =>
|
|
6
|
+
validates :key, :presence => true, :uniqueness => {:scope => :created_by_id}
|
|
8
7
|
|
|
9
8
|
def set(value)
|
|
10
9
|
if boolean?
|
data/app/models/droom/scrap.rb
CHANGED
|
@@ -1,47 +1,48 @@
|
|
|
1
1
|
module Droom
|
|
2
2
|
class Scrap < ActiveRecord::Base
|
|
3
3
|
belongs_to :created_by, :class_name => "Droom::User"
|
|
4
|
-
belongs_to :event, :class_name => "Droom::Event"
|
|
5
|
-
accepts_nested_attributes_for :event
|
|
6
4
|
|
|
5
|
+
belongs_to :event, :class_name => "Droom::Event", :dependent => :destroy
|
|
6
|
+
accepts_nested_attributes_for :event
|
|
7
7
|
belongs_to :document, :class_name => "Droom::Document", :dependent => :destroy
|
|
8
8
|
accepts_nested_attributes_for :document
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
has_attached_file :image,
|
|
11
|
+
:styles => {
|
|
12
|
+
:stream => "1280x1280>",
|
|
13
|
+
:popup => "1280x1280>",
|
|
14
|
+
:icon => "32x32#",
|
|
15
|
+
:thumb => "130x73#"
|
|
16
|
+
}
|
|
17
17
|
|
|
18
|
-
attr_accessible :name, :body, :image, :description, :scraptype, :note, :created_by, :event, :event_attributes, :document, :document_attributes
|
|
19
18
|
before_save :get_youtube_thumbnail
|
|
19
|
+
before_validation :name_associates
|
|
20
20
|
|
|
21
|
-
scope :by_date, order("droom_scraps.created_at DESC")
|
|
21
|
+
scope :by_date, -> { order("droom_scraps.created_at DESC") }
|
|
22
22
|
|
|
23
|
-
scope :later_than,
|
|
24
|
-
where(["created_at > ?", scrap.created_at]).order("droom_scraps.created_at ASC")
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
scope :earlier_than, lambda { |scrap|
|
|
28
|
-
where(["created_at < ?", scrap.created_at]).order("droom_scraps.created_at DESC")
|
|
29
|
-
}
|
|
23
|
+
scope :later_than, -> scrap { where(["created_at > ?", scrap.created_at]).order("droom_scraps.created_at ASC") }
|
|
30
24
|
|
|
31
|
-
scope :
|
|
25
|
+
scope :earlier_than, -> scrap { where(["created_at < ?", scrap.created_at]).order("droom_scraps.created_at DESC") }
|
|
26
|
+
|
|
27
|
+
scope :matching, -> fragment {
|
|
32
28
|
fragment = "%#{fragment}%"
|
|
33
29
|
where('droom_scraps.name LIKE :f OR droom_scraps.body LIKE :f OR droom_scraps.note LIKE :f', :f => fragment)
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
scope :visible_to,
|
|
37
|
-
|
|
32
|
+
scope :visible_to, -> user { where("1=1") }
|
|
33
|
+
|
|
34
|
+
scope :with_future_or_current_event, -> {
|
|
35
|
+
joins(:event)
|
|
36
|
+
.where(["droom_scraps.scraptype = 'event' AND (droom_events.finish > :now) OR (droom_events.finish IS NULL AND droom_events.start > :now)", :now => Time.zone.now])
|
|
37
|
+
.order('droom_events.start ASC')
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
Droom.scrap_types.each do |t|
|
|
41
|
-
|
|
42
|
-
scope t.pluralize.to_sym, where(["scraptype == ?", t])
|
|
41
|
+
scope t.pluralize.to_sym, -> { where(:scraptype => t.to_s) }
|
|
43
42
|
end
|
|
44
43
|
|
|
44
|
+
default_scope -> { includes(:event, :document) }
|
|
45
|
+
|
|
45
46
|
def wordiness
|
|
46
47
|
if body.length < 48
|
|
47
48
|
'word'
|
|
@@ -90,11 +91,15 @@ module Droom
|
|
|
90
91
|
protected
|
|
91
92
|
|
|
92
93
|
def get_youtube_thumbnail
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.image = URI("http://img.youtube.com/vi/#{body}/0.jpg")
|
|
94
|
+
if scraptype == "video" && youtube_id?
|
|
95
|
+
self.image = URI("http://img.youtube.com/vi/#{youtube_id}/0.jpg")
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
def name_associates
|
|
100
|
+
event.name = name if event
|
|
101
|
+
document.name = name if document
|
|
102
|
+
end
|
|
103
|
+
|
|
99
104
|
end
|
|
100
105
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Droom
|
|
2
|
+
class Service < ActiveRecord::Base
|
|
3
|
+
has_many :permissions, -> {order(:position)}, :dependent => :destroy
|
|
4
|
+
before_save :set_slug
|
|
5
|
+
after_create :create_basic_permissions
|
|
6
|
+
after_save :update_permissions
|
|
7
|
+
validates :slug, :uniqueness => true
|
|
8
|
+
|
|
9
|
+
def self.for_selection
|
|
10
|
+
self.order("name asc").map{|f| [f.name, f.id] }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def set_slug
|
|
16
|
+
self.slug ||= name.parameterize
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create_basic_permissions
|
|
20
|
+
permissions.create(:name => 'login')
|
|
21
|
+
permissions.create(:name => 'admin')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update_permissions
|
|
25
|
+
permissions.all.each do |p|
|
|
26
|
+
p.send :set_slug
|
|
27
|
+
p.save
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/app/models/droom/tag.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Tags are simple one-word descriptors. There is no hierarchy or other structure among them.
|
|
2
|
-
# They are strictly catalogue data, used to locate people but not treated as part of the
|
|
2
|
+
# They are strictly catalogue data, used to locate people but not treated as part of the user record.
|
|
3
3
|
|
|
4
4
|
module Droom
|
|
5
5
|
class Tag < ActiveRecord::Base
|
|
6
|
-
# They are attached to people through many-to-many taggings.
|
|
6
|
+
# They are attached to people and other things through many-to-many taggings.
|
|
7
7
|
#
|
|
8
8
|
has_many :taggings
|
|
9
9
|
has_many :taggees, :through => :taggings
|
|
@@ -14,24 +14,25 @@ module Droom
|
|
|
14
14
|
# There is a tag-suggesting mechanism in the front end to encourage tag reuse and consistency.
|
|
15
15
|
# It rests on this simple scope, which returns all tags matching a given string fragment.
|
|
16
16
|
#
|
|
17
|
-
scope :matching,
|
|
17
|
+
scope :matching, -> fragment {
|
|
18
18
|
fragment = "%#{fragment}%"
|
|
19
19
|
where('tags.name like ?', fragment)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
# The public-facing search engine is faceted and relies on a similar but broader suggestion mechanism
|
|
23
23
|
# that offers both tags and institutions. In that situation we only want to display tags that will give
|
|
24
|
-
# give results, so we limit the suggestions to only those tags that have been applied to a
|
|
24
|
+
# give results, so we limit the suggestions to only those tags that have been applied to a user.
|
|
25
25
|
#
|
|
26
|
-
scope :in_use,
|
|
26
|
+
scope :in_use, -> {
|
|
27
27
|
joins("INNER JOIN taggings ON taggings.tag_id = tags.id")
|
|
28
28
|
.group('tags.id')
|
|
29
29
|
.having('count(taggings.tag_id) > 0')
|
|
30
|
+
}
|
|
30
31
|
|
|
31
32
|
# This returns a list of all the tags attached to any of a given set of objects.
|
|
32
33
|
# In future it will support cloud-weighting.
|
|
33
34
|
#
|
|
34
|
-
scope :attached_to_any_of,
|
|
35
|
+
scope :attached_to_any_of, -> these {
|
|
35
36
|
these = [these].flatten
|
|
36
37
|
type = these.first.class.to_s
|
|
37
38
|
placeholders = these.map{"?"}.join(',')
|
|
@@ -72,9 +73,9 @@ module Droom
|
|
|
72
73
|
#
|
|
73
74
|
def self.for(name, or_create=true)
|
|
74
75
|
if or_create
|
|
75
|
-
|
|
76
|
+
where(name: name).first_or_create
|
|
76
77
|
else
|
|
77
|
-
|
|
78
|
+
find_by(name: name)
|
|
78
79
|
end
|
|
79
80
|
end
|
|
80
81
|
|
|
@@ -86,7 +87,7 @@ module Droom
|
|
|
86
87
|
# display logic can be found in the [application_helper](../controllers/application_helper.html).
|
|
87
88
|
#
|
|
88
89
|
attr_accessor :cloud_size
|
|
89
|
-
scope :with_usage_count,
|
|
90
|
+
scope :with_usage_count, -> limit {
|
|
90
91
|
select("tags.*, count(tt.id) AS weight").joins("INNER JOIN taggings as tt ON tt.tag_id = tags.id").group("tt.tag_id").order("weight DESC").limit(limit)
|
|
91
92
|
}
|
|
92
93
|
|
data/app/models/droom/tagging.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Taggings are the many to many links that associated tags with people. There isn't much to see here.
|
|
1
|
+
# Taggings are the many to many links that associated tags with people and other things. There isn't much to see here.
|
|
2
2
|
|
|
3
3
|
module Droom
|
|
4
4
|
class Tagging < ActiveRecord::Base
|
data/app/models/droom/user.rb
CHANGED
|
@@ -1,87 +1,108 @@
|
|
|
1
1
|
module Droom
|
|
2
2
|
class User < ActiveRecord::Base
|
|
3
|
+
validates :family_name, :presence => true
|
|
4
|
+
validates :given_name, :presence => true
|
|
5
|
+
validates :email, :uniqueness => true, :presence => true
|
|
6
|
+
validates :uid, :uniqueness => true, :presence => true
|
|
3
7
|
|
|
4
|
-
attr_accessible :name, :forename, :email, :password, :password_confirmation, :admin, :newly_activated, :update_person_email, :preferences_attributes, :confirm, :old_id, :remove_person
|
|
5
|
-
has_one :person
|
|
6
|
-
has_many :dropbox_tokens, :foreign_key => "created_by_id"
|
|
7
8
|
has_many :preferences, :foreign_key => "created_by_id"
|
|
8
9
|
accepts_nested_attributes_for :preferences, :allow_destroy => true
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
validates :name, :presence => true
|
|
13
|
-
# validates :password, :presence => true, :length => { :minimum => 6 }, :confirmation => true, :if => :password_required?
|
|
14
|
-
|
|
15
|
-
receives_messages# :groups => [:unconfirmed, :personed, :administrative]
|
|
16
|
-
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
#
|
|
17
13
|
devise :database_authenticatable,
|
|
18
|
-
:
|
|
14
|
+
:cookie_authenticatable,
|
|
19
15
|
:recoverable,
|
|
20
|
-
:rememberable,
|
|
21
16
|
:trackable,
|
|
22
17
|
:confirmable,
|
|
23
|
-
:
|
|
24
|
-
:
|
|
25
|
-
|
|
26
|
-
before_create :ensure_authentication_token # provided by devise
|
|
27
|
-
before_create :ensure_confirmation_token # provided by devise
|
|
28
|
-
|
|
29
|
-
attr_accessor :newly_activated, :update_person_email, :confirm, :remove_person
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
scope :unconfirmed, where("confirmed_at IS NULL")
|
|
33
|
-
scope :administrative, where(:admin => true)
|
|
34
|
-
|
|
35
|
-
scope :personed, select("droom_users.*")
|
|
36
|
-
.joins("INNER JOIN droom_people as dp ON dp.user_id = droom_users.id")
|
|
37
|
-
|
|
38
|
-
scope :unpersoned, select("droom_users.*")
|
|
39
|
-
.joins("LEFT OUTER JOIN droom_people as dp ON dp.user_id = droom_users.id")
|
|
40
|
-
.having("count(dp.id) = 0")
|
|
18
|
+
:rememberable,
|
|
19
|
+
:reconfirmable => false
|
|
41
20
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.joins("INNER JOIN droom_people as dp ON dp.user_id = droom_users.id")
|
|
46
|
-
.joins("INNER JOIN droom_memberships as dm ON dp.id = dm.person_id")
|
|
47
|
-
.where("dm.group_id" => group)
|
|
48
|
-
}
|
|
21
|
+
before_validation :ensure_uid!
|
|
22
|
+
before_save :ensure_authentication_token
|
|
23
|
+
after_save :send_confirmation_if_directed
|
|
49
24
|
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
Droom::Group.all.each do |group|
|
|
63
|
-
@messaging_groups[group.slug.to_sym] = lambda { Droom::User.with_person_in_group(group.id) }
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
@messaging_groups
|
|
25
|
+
# People are often invited into the system in batches or after offline contact.
|
|
26
|
+
# set user.defer_confirmation to a true or call user.defer_confirmation! +before saving+
|
|
27
|
+
# if you want to create a user account without sending out any messages yet.
|
|
28
|
+
#
|
|
29
|
+
# When you do want to invite that person, call user.resend_confirmation_token or
|
|
30
|
+
# set the send_confirmation flag on a save.
|
|
31
|
+
#
|
|
32
|
+
attr_accessor :defer_confirmation, :send_confirmation
|
|
33
|
+
|
|
34
|
+
def defer_confirmation!
|
|
35
|
+
self.defer_confirmation = true
|
|
67
36
|
end
|
|
68
37
|
|
|
69
|
-
def
|
|
70
|
-
|
|
38
|
+
def defer_confirmation?
|
|
39
|
+
!!self.defer_confirmation
|
|
71
40
|
end
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
41
|
+
|
|
42
|
+
# Called after save by our own late-confirmation mechanism.
|
|
43
|
+
# If the send_confirmation flag has been set, we confirm.
|
|
44
|
+
#
|
|
45
|
+
def send_confirmation?
|
|
46
|
+
!!self.send_confirmation
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Called on create by devise's immediate confirmation mechanism.
|
|
50
|
+
# If the defer_confirmation flag has been set, we postpone.
|
|
51
|
+
#
|
|
52
|
+
def send_confirmation_notification?
|
|
53
|
+
super && !defer_confirmation?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def active_for_authentication?
|
|
57
|
+
true
|
|
79
58
|
end
|
|
80
59
|
|
|
81
|
-
# Password is not required on creation, contrary to the devise defaults.
|
|
82
60
|
def password_required?
|
|
83
61
|
confirmed? && (!password.blank?)
|
|
84
62
|
end
|
|
63
|
+
|
|
64
|
+
def password_set?
|
|
65
|
+
encrypted_password?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
## Session ID
|
|
69
|
+
#
|
|
70
|
+
# Allows us to invalidate a session by remote control if someone signs out on a satellite site.
|
|
71
|
+
|
|
72
|
+
def reset_session_id!
|
|
73
|
+
token = generate_authentication_token
|
|
74
|
+
self.update_column(:session_id, token)
|
|
75
|
+
token
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def clear_session_id!
|
|
79
|
+
self.update_column(:session_id, "")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
## Auth tokens
|
|
83
|
+
#
|
|
84
|
+
# Are no longer native to devise but we use them for domain-cookie auth.
|
|
85
|
+
|
|
86
|
+
def authenticate_token(token)
|
|
87
|
+
Devise.secure_compare(self.authentication_token, token)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def reset_authentication_token!
|
|
91
|
+
$cache.delete "/api/authenticate/#{authentication_token}" if $cache && authentication_token
|
|
92
|
+
token = generate_authentication_token
|
|
93
|
+
self.update_column(:authentication_token, token)
|
|
94
|
+
token
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def ensure_authentication_token
|
|
98
|
+
if authentication_token.blank?
|
|
99
|
+
self.authentication_token = generate_authentication_token
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def confirmed=(value)
|
|
104
|
+
self.confirmed_at = Time.now if value.present? and value != "false"
|
|
105
|
+
end
|
|
85
106
|
|
|
86
107
|
def password_match?
|
|
87
108
|
self.errors[:password] << "can't be blank" if password.blank?
|
|
@@ -90,48 +111,155 @@ module Droom
|
|
|
90
111
|
password == password_confirmation && !password.blank?
|
|
91
112
|
end
|
|
92
113
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
114
|
+
# Our old user accounts store passwords as salted sha512 digests. Current best practice uses BCrypt
|
|
115
|
+
# so we migrate user accounts across in this rescue block whenever we hear BCrypt grumbling about the old hash.
|
|
116
|
+
|
|
117
|
+
def valid_password?(password)
|
|
118
|
+
begin
|
|
119
|
+
super(password)
|
|
120
|
+
rescue BCrypt::Errors::InvalidHash
|
|
121
|
+
Rails.logger.warn "...trying sha512 on password input"
|
|
122
|
+
stretches = 10
|
|
123
|
+
salt = self.password_salt
|
|
124
|
+
pepper = nil
|
|
125
|
+
old_digest = Devise::Encryptable::Encryptors::Sha512.digest(password, stretches, salt, pepper)
|
|
126
|
+
if old_digest == self.encrypted_password
|
|
127
|
+
self.password = password
|
|
128
|
+
self.save
|
|
129
|
+
return true
|
|
130
|
+
else
|
|
131
|
+
# Doesn't match the old format either: password is just wrong.
|
|
132
|
+
return false
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
scope :unconfirmed, -> { where("confirmed_at IS NULL") }
|
|
138
|
+
scope :administrative, -> { where(:admin => true) }
|
|
139
|
+
scope :this_month, -> { where("created_at > ?", Time.now - 1.month) }
|
|
140
|
+
scope :this_week, -> { where("created_at > ?", Time.now - 1.week) }
|
|
141
|
+
|
|
142
|
+
scope :in_name_order, -> {
|
|
143
|
+
order("family_name ASC, given_name ASC")
|
|
144
|
+
}
|
|
96
145
|
|
|
97
|
-
def
|
|
98
|
-
|
|
146
|
+
def as_json_for_coca(options={})
|
|
147
|
+
ensure_uid!
|
|
148
|
+
ensure_authentication_token
|
|
149
|
+
{
|
|
150
|
+
uid: uid,
|
|
151
|
+
authentication_token: authentication_token,
|
|
152
|
+
title: title,
|
|
153
|
+
given_name: given_name,
|
|
154
|
+
family_name: family_name,
|
|
155
|
+
chinese_name: chinese_name,
|
|
156
|
+
email: email,
|
|
157
|
+
permissions: permission_codes.join(','),
|
|
158
|
+
image: thumbnail
|
|
159
|
+
}
|
|
99
160
|
end
|
|
100
161
|
|
|
101
|
-
|
|
102
|
-
# such as the UserActionObserver that sets ownership before save.
|
|
162
|
+
## Organisation affiliation
|
|
103
163
|
#
|
|
104
|
-
|
|
105
|
-
|
|
164
|
+
belongs_to :organisation
|
|
165
|
+
has_many :organisations, :foreign_key => :owner_id
|
|
166
|
+
|
|
167
|
+
## Group memberships
|
|
168
|
+
#
|
|
169
|
+
has_many :memberships, :dependent => :destroy
|
|
170
|
+
has_many :groups, :through => :memberships
|
|
171
|
+
has_many :mailing_list_memberships, :through => :memberships
|
|
172
|
+
|
|
173
|
+
scope :in_any_directory_group, -> {
|
|
174
|
+
joins(:groups).where(droom_groups: {directory: true}).group("droom_users.id")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
def admit_to(groups)
|
|
178
|
+
groups = [groups].flatten
|
|
179
|
+
groups.each do |group|
|
|
180
|
+
memberships.where(group_id: group.id).first_or_create
|
|
181
|
+
end
|
|
106
182
|
end
|
|
107
|
-
|
|
108
|
-
|
|
183
|
+
|
|
184
|
+
def expel_from(group)
|
|
185
|
+
memberships.of_group(group).destroy_all
|
|
109
186
|
end
|
|
110
187
|
|
|
111
|
-
|
|
188
|
+
def member_of?(group)
|
|
189
|
+
group && memberships.of_group(group).any?
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def membership_of(group)
|
|
193
|
+
memberships.find_by(group_id: group.id)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
scope :in_group, -> group {
|
|
197
|
+
group = group.id if group.is_a? Droom::Group
|
|
198
|
+
select("droom_users.*")
|
|
199
|
+
.joins("INNER JOIN droom_memberships as dm ON droom_users.id = dm.user_id")
|
|
200
|
+
.where("dm.group_id" => group)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
## Event invitations
|
|
112
204
|
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
205
|
+
has_many :invitations, :dependent => :destroy
|
|
206
|
+
has_many :events, :through => :invitations
|
|
207
|
+
|
|
208
|
+
def invite_to(event)
|
|
209
|
+
invitations.where(event_id: event.id).first_or_create if event
|
|
117
210
|
end
|
|
118
|
-
|
|
119
|
-
def
|
|
120
|
-
|
|
211
|
+
|
|
212
|
+
def uninvite_from(event)
|
|
213
|
+
invitations.to_event(event).destroy_all
|
|
121
214
|
end
|
|
122
215
|
|
|
123
|
-
def
|
|
124
|
-
|
|
216
|
+
def invited_to?(event)
|
|
217
|
+
event && !!invitation_to(event)
|
|
125
218
|
end
|
|
126
219
|
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
forename
|
|
130
|
-
else
|
|
131
|
-
name
|
|
132
|
-
end
|
|
220
|
+
def invitation_to(event)
|
|
221
|
+
invitations.to_event(event).first
|
|
133
222
|
end
|
|
223
|
+
|
|
224
|
+
scope :personally_invited_to_event, -> event {
|
|
225
|
+
joins('LEFT OUTER JOIN droom_invitations on droom_users.id = droom_invitations.user_id').where('droom_invitations.group_invitation_id is null AND droom_invitations.event_id = ?', event.id)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
## Folder permissions
|
|
229
|
+
#
|
|
230
|
+
# To simplify the business of showing and listing documents, we have adopted the convention that all
|
|
231
|
+
# documents live in a folder. User accounts have links to those folders through the very thin
|
|
232
|
+
# PersonalFolder joining class, and at the view level we only ever show folder and subfolder lists.
|
|
233
|
+
# The only place we ever need a list of all the documents visible to this person is when searching, and
|
|
234
|
+
# for that we use the Document.visible_to scope, usually by way of the #documents method defined below.
|
|
235
|
+
#
|
|
236
|
+
# Personal folders are created and destroyed along with invitations and memberships.
|
|
237
|
+
#
|
|
238
|
+
has_many :personal_folders
|
|
239
|
+
has_many :folders, :through => :personal_folders
|
|
134
240
|
|
|
241
|
+
def add_personal_folders(folders=[])
|
|
242
|
+
self.folders << folders if folders
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def remove_personal_folders(folders=[])
|
|
246
|
+
self.folders.delete(folders) if folders
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def has_folder?(folder)
|
|
250
|
+
folder && personal_folders.of_folder(folder).any?
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def documents
|
|
254
|
+
Document.visible_to(self)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
## Dropbox links
|
|
259
|
+
#
|
|
260
|
+
has_many :dropbox_tokens, :foreign_key => "created_by_id"
|
|
261
|
+
has_many :dropbox_documents
|
|
262
|
+
|
|
135
263
|
def dropbox_token
|
|
136
264
|
unless @dropbox_token
|
|
137
265
|
@dropbox_token = dropbox_tokens.by_date.last || 'nope'
|
|
@@ -142,12 +270,188 @@ module Droom
|
|
|
142
270
|
def dropbox_client
|
|
143
271
|
dropbox_token.dropbox_client if dropbox_token
|
|
144
272
|
end
|
|
273
|
+
|
|
274
|
+
## Mugshot
|
|
275
|
+
#
|
|
276
|
+
has_attached_file :image,
|
|
277
|
+
:default_url => ActionController::Base.helpers.image_path("droom/missing/:style.png"),
|
|
278
|
+
:styles => {
|
|
279
|
+
:standard => "520x520#",
|
|
280
|
+
:icon => "32x32#",
|
|
281
|
+
:thumb => "130x130#"
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
do_not_validate_attachment_file_type :image
|
|
285
|
+
|
|
286
|
+
def thumbnail
|
|
287
|
+
image.url(:thumb) if image?
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def icon
|
|
291
|
+
image.url(:icon) if image?
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# For suggestion box
|
|
295
|
+
#
|
|
296
|
+
scope :matching, -> fragment {
|
|
297
|
+
where('droom_users.given_name LIKE :f OR droom_users.family_name LIKE :f OR droom_users.chinese_name LIKE :f OR droom_users.title LIKE :f OR droom_users.email LIKE :f OR droom_users.phone LIKE :f OR CONCAT(droom_users.given_name, " ", droom_users.family_name) LIKE :f OR CONCAT(droom_users.family_name, " ", droom_users.given_name) LIKE :f', :f => "%#{fragment}%")
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
scope :matching_in_col, -> col, fragment {
|
|
301
|
+
where("droom_users.#{col} LIKE :f", :f => "%#{fragment}%")
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
def as_suggestion
|
|
305
|
+
{
|
|
306
|
+
:type => 'person',
|
|
307
|
+
:prompt => formal_name,
|
|
308
|
+
:value => formal_name,
|
|
309
|
+
:id => id
|
|
310
|
+
}
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def as_search_result
|
|
314
|
+
{
|
|
315
|
+
:type => 'person',
|
|
316
|
+
:prompt => name,
|
|
317
|
+
:value => name,
|
|
318
|
+
:id => id
|
|
319
|
+
}
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
# For select box
|
|
324
|
+
#
|
|
325
|
+
def self.for_selection
|
|
326
|
+
self.published.map{|p| [p.name, p.id] }
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
## Names
|
|
331
|
+
#
|
|
332
|
+
# With Anglo-Chinese Hong Kong names it is difficult to be sure of the right presentation.
|
|
333
|
+
#
|
|
334
|
+
# We hold the name in three fields: title, given name and family name. People with both a Chinese and an
|
|
335
|
+
# English forename are encouraged to enter their given name in the form Tai Wan, Jimmy. The family_name
|
|
336
|
+
# should always be a single, usually Chinese, surname: Chan or Smith.
|
|
337
|
+
#
|
|
338
|
+
# When a comma is found in the given name, we assume that they have followed the chinese, english format.
|
|
339
|
+
# If not, we assume the whole name is Chinese.
|
|
340
|
+
#
|
|
341
|
+
# ### Polite informality
|
|
342
|
+
#
|
|
343
|
+
# People with an English forename would normally be addressed as Jimmy Chan. People with only a Chinese
|
|
344
|
+
# forename should be addressed as Chan Tai Wan.
|
|
345
|
+
#
|
|
346
|
+
def informal_name
|
|
347
|
+
# The standard form of the given name is Tai Wan, Ray
|
|
348
|
+
chinese, english = given_name.split(/,\s*/)
|
|
349
|
+
# But some people are known only as Ray.
|
|
350
|
+
# Here we can't tell the difference between people with one chinese given name and one anglo given name
|
|
351
|
+
# but the order of names is reversed in the latter case. For now we assume that the presence of a chinese
|
|
352
|
+
# name indicates that the chinese word ordering should be used.
|
|
353
|
+
unless chinese_name?
|
|
354
|
+
english ||= chinese.strip.split(/\s+/).first
|
|
355
|
+
end
|
|
356
|
+
if english
|
|
357
|
+
# People with an english name are called Ray Chan, by default
|
|
358
|
+
[english, family_name].join(' ')
|
|
359
|
+
else
|
|
360
|
+
# People without are called Chan Tai Wan
|
|
361
|
+
[family_name, chinese].join(' ')
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def name
|
|
366
|
+
chinese, english = given_name.split(/,\s*/)
|
|
367
|
+
unless chinese_name?
|
|
368
|
+
english ||= chinese.split(/\s+/).first
|
|
369
|
+
end
|
|
370
|
+
if english
|
|
371
|
+
[english, family_name].join(' ')
|
|
372
|
+
else
|
|
373
|
+
[family_name, chinese].join(' ')
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# ### Formality
|
|
378
|
+
#
|
|
379
|
+
# The family name is held separately becaose for most purposes we will address people using the relatively
|
|
380
|
+
# reliable 'Dr Chan' or 'Mr Smith'.
|
|
381
|
+
#
|
|
145
382
|
|
|
146
|
-
def
|
|
147
|
-
|
|
383
|
+
def title_ordinary?
|
|
384
|
+
['Mr', 'Ms', 'Mrs', '', nil].include?(title)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def title_if_it_matters
|
|
388
|
+
title unless title_ordinary?
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def title
|
|
392
|
+
title = read_attribute(:title)
|
|
393
|
+
if title.blank?
|
|
394
|
+
title = (gender == 'f') ? 'Ms' : 'Mr'
|
|
395
|
+
end
|
|
396
|
+
title
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# This shuold be a reasonable formal first-person form of address.
|
|
400
|
+
#
|
|
401
|
+
def formal_name
|
|
402
|
+
[title, family_name].join(' ')
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# This is our best shot at a representation of the usual third person form of this person's name. It combines
|
|
406
|
+
# the informal name (which includes some logic to show chinese, anglo and mixed names correctly) with the title,
|
|
407
|
+
# if the title is not ordinary.
|
|
408
|
+
#
|
|
409
|
+
def colloquial_name
|
|
410
|
+
[title_if_it_matters, informal_name, honours].compact.join(' ')
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# ### Completeness
|
|
414
|
+
#
|
|
415
|
+
# For record-keeping purposes we show the whole name: Chan Tai Wan, Jimmy.
|
|
416
|
+
#
|
|
417
|
+
def full_name
|
|
418
|
+
[family_name, given_name].compact.join(' ')
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# ### Compatibility
|
|
422
|
+
#
|
|
423
|
+
# An HKID card will normally show only the translitered Chinese name: Chan Tai Wan
|
|
424
|
+
#
|
|
425
|
+
def official_name
|
|
426
|
+
chinese, english = given_name.split(/,\s*/)
|
|
427
|
+
[family_name, chinese].join(' ')
|
|
148
428
|
end
|
|
149
429
|
|
|
430
|
+
def to_vcf
|
|
431
|
+
@vcard ||= Vcard::Vcard::Maker.make2 do |maker|
|
|
432
|
+
maker.add_name do |n|
|
|
433
|
+
n.given = name || ""
|
|
434
|
+
end
|
|
435
|
+
maker.add_addr {|a|
|
|
436
|
+
a.location = 'home' # until we do this properly with multiple contact sets
|
|
437
|
+
a.country = post_country || ""
|
|
438
|
+
a.region = post_region || ""
|
|
439
|
+
a.locality = post_city || ""
|
|
440
|
+
a.street = "#{post_line1}, #{post_line2}"
|
|
441
|
+
a.postalcode = post_code || ""
|
|
442
|
+
}
|
|
443
|
+
maker.add_tel phone { |t| t.location = 'home' } unless phone.blank?
|
|
444
|
+
maker.add_tel mobile { |t| t.location = 'cell' } unless mobile.blank?
|
|
445
|
+
maker.add_email email { |e| t.location = 'home' }
|
|
446
|
+
end
|
|
447
|
+
@vcard.to_s
|
|
448
|
+
end
|
|
150
449
|
|
|
450
|
+
def self.vcards_for(users=[])
|
|
451
|
+
users.map(&:vcf).join("\n")
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
|
|
151
455
|
## Preferences
|
|
152
456
|
#
|
|
153
457
|
# User settings are held as an association with Preference objects, which are simple key:value pairs.
|
|
@@ -166,13 +470,17 @@ module Droom
|
|
|
166
470
|
# = link_to "copy to dropbox", dropbox_folder_url(folder)
|
|
167
471
|
#
|
|
168
472
|
def pref(key)
|
|
169
|
-
if pref = preferences.
|
|
473
|
+
if pref = preferences.find_by(key: key)
|
|
170
474
|
pref.value
|
|
171
475
|
else
|
|
172
476
|
Droom.user_default(key)
|
|
173
477
|
end
|
|
174
478
|
end
|
|
175
|
-
|
|
479
|
+
|
|
480
|
+
def pref?(key)
|
|
481
|
+
!!pref(key)
|
|
482
|
+
end
|
|
483
|
+
|
|
176
484
|
# `User#preference(key)` always returns a preference object and is used to build control panels. If no preference
|
|
177
485
|
# is saved for the given key, we return a new (unsaved) one with that key and the default value.
|
|
178
486
|
#
|
|
@@ -181,7 +489,7 @@ module Droom
|
|
|
181
489
|
pref.value = Droom.user_default(key) unless pref.persisted?
|
|
182
490
|
pref
|
|
183
491
|
end
|
|
184
|
-
|
|
492
|
+
|
|
185
493
|
# Setting preferences is normally handled either by the PreferencesController or by nesting preferences
|
|
186
494
|
# in a user form. `User#set_pref` is a convenient console method but not otherwise used much.
|
|
187
495
|
#
|
|
@@ -190,46 +498,61 @@ module Droom
|
|
|
190
498
|
# user.set_pref("email:enabled", true)
|
|
191
499
|
#
|
|
192
500
|
def set_pref(key, value)
|
|
193
|
-
preferences.
|
|
501
|
+
preferences.where(key: key).first_or_create.set(value)
|
|
194
502
|
end
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
## Permissions
|
|
199
507
|
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
:confirmation_url => Droom::Engine.routes.url_helpers.welcome_url(:id => self.id, :confirmation_token => self.confirmation_token, :host => ActionMailer::Base.default_url_options[:host]),
|
|
209
|
-
:sign_in_url => Droom::Engine.routes.url_helpers.new_user_session_path(:host => ActionMailer::Base.default_url_options[:host]),
|
|
210
|
-
:password_reset_url => Droom::Engine.routes.url_helpers.edit_user_password_url(:reset_password_token => self.reset_password_token, :host => ActionMailer::Base.default_url_options[:host])
|
|
211
|
-
}
|
|
508
|
+
# Permissions are usually assigned by way of group membership, but the effect of this is to create a user-permission
|
|
509
|
+
# object. Additional user-permission objects can be created: all we need to do here is return that set.
|
|
510
|
+
|
|
511
|
+
has_many :user_permissions
|
|
512
|
+
has_many :permissions, :through => :user_permissions
|
|
513
|
+
|
|
514
|
+
def permission_codes
|
|
515
|
+
permissions.map(&:slug).compact.uniq
|
|
212
516
|
end
|
|
213
517
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
# a new local account.
|
|
518
|
+
def permission_codes=(codes)
|
|
519
|
+
#TODO
|
|
520
|
+
end
|
|
218
521
|
|
|
219
|
-
def
|
|
220
|
-
|
|
221
|
-
id: id,
|
|
222
|
-
title: title,
|
|
223
|
-
name: name,
|
|
224
|
-
forename: forename,
|
|
225
|
-
email: email,
|
|
226
|
-
admin: admin?,
|
|
227
|
-
image: thumbnail
|
|
228
|
-
}
|
|
522
|
+
def permitted?(key)
|
|
523
|
+
permission_codes.include?(key)
|
|
229
524
|
end
|
|
230
525
|
|
|
231
|
-
def
|
|
232
|
-
|
|
526
|
+
def permissions_elsewhere?
|
|
527
|
+
permission_codes.select{|pc| pc !~ /droom/}.any?
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def data_room_user?
|
|
531
|
+
admin? || permitted?('droom.login')
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
## Other ownership
|
|
535
|
+
#
|
|
536
|
+
has_many :scraps, :foreign_key => "created_by_id"
|
|
537
|
+
has_many :documents, :foreign_key => "created_by_id"
|
|
538
|
+
|
|
539
|
+
protected
|
|
540
|
+
|
|
541
|
+
def ensure_uid!
|
|
542
|
+
self.uid = SecureRandom.uuid unless self.uid?
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
def send_confirmation_if_directed
|
|
546
|
+
self.send_confirmation_instructions if send_confirmation?
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
private
|
|
550
|
+
|
|
551
|
+
def generate_authentication_token
|
|
552
|
+
loop do
|
|
553
|
+
token = Devise.friendly_token
|
|
554
|
+
break token unless User.where(authentication_token: token).first
|
|
555
|
+
end
|
|
233
556
|
end
|
|
234
557
|
|
|
235
558
|
end
|