droom 0.0.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.
- data/MIT-LICENSE +20 -0
- data/README.md +23 -0
- data/Rakefile +27 -0
- data/app/assets/images/droom/arrows.png +0 -0
- data/app/assets/images/droom/big_icons.png +0 -0
- data/app/assets/images/droom/blueblob.png +0 -0
- data/app/assets/images/droom/close.png +0 -0
- data/app/assets/images/droom/cross.png +0 -0
- data/app/assets/images/droom/download.png +0 -0
- data/app/assets/images/droom/greyblob.png +0 -0
- data/app/assets/images/droom/help/goodreader.jpg +0 -0
- data/app/assets/images/droom/ical.png +0 -0
- data/app/assets/images/droom/icons.png +0 -0
- data/app/assets/images/droom/medium_icons.png +0 -0
- data/app/assets/images/droom/medium_object_icons.png +0 -0
- data/app/assets/images/droom/minimonth.png +0 -0
- data/app/assets/images/droom/minisymbols.png +0 -0
- data/app/assets/images/droom/object_icons.png +0 -0
- data/app/assets/images/droom/pinkblob.png +0 -0
- data/app/assets/images/droom/place_busy.png +0 -0
- data/app/assets/images/droom/place_quiet.png +0 -0
- data/app/assets/images/droom/plus_bullet.png +0 -0
- data/app/assets/images/droom/search.png +0 -0
- data/app/assets/images/droom/setup.png +0 -0
- data/app/assets/images/droom/small_go.png +0 -0
- data/app/assets/images/droom/smallbullet.png +0 -0
- data/app/assets/images/droom/smallspinner.gif +0 -0
- data/app/assets/images/droom/spinner.gif +0 -0
- data/app/assets/images/droom/spr_toolbar_icons_r2.png +0 -0
- data/app/assets/images/droom/tablesort.png +0 -0
- data/app/assets/images/droom/tick.png +0 -0
- data/app/assets/images/droom/tinysymbols.png +0 -0
- data/app/assets/images/droom/twister.png +0 -0
- data/app/assets/images/droom/vcard.png +0 -0
- data/app/assets/images/droom/venue_bullet.png +0 -0
- data/app/assets/javascripts/droom.js.coffee +88 -0
- data/app/assets/javascripts/droom/calendar.js.coffee +121 -0
- data/app/assets/javascripts/droom/drag_sort.js.coffee +22 -0
- data/app/assets/javascripts/droom/forms.js.coffee +746 -0
- data/app/assets/javascripts/droom/lib/extensions.js.coffee +60 -0
- data/app/assets/javascripts/droom/lib/jquery.animate-colors.js +109 -0
- data/app/assets/javascripts/droom/lib/jquery.cookie.js +71 -0
- data/app/assets/javascripts/droom/lib/jquery.sortable.js +97 -0
- data/app/assets/javascripts/droom/lib/kalendae.js +1692 -0
- data/app/assets/javascripts/droom/lib/modernizr.js +4 -0
- data/app/assets/javascripts/droom/lib/parser_rules/advanced.js +553 -0
- data/app/assets/javascripts/droom/lib/parser_rules/simple.js +32 -0
- data/app/assets/javascripts/droom/lib/wysihtml5.js +9550 -0
- data/app/assets/javascripts/droom/map.js.coffee +123 -0
- data/app/assets/javascripts/droom/sort.js.coffee +126 -0
- data/app/assets/javascripts/droom/suggester.js.coffee +230 -0
- data/app/assets/stylesheets/droom.css.sass +1151 -0
- data/app/assets/stylesheets/lib/_kalendae.css.sass +142 -0
- data/app/assets/stylesheets/lib/_toolbar.css.sass +192 -0
- data/app/controllers/droom/dashboard_controller.rb +27 -0
- data/app/controllers/droom/document_attachments_controller.rb +19 -0
- data/app/controllers/droom/documents_controller.rb +116 -0
- data/app/controllers/droom/engine_controller.rb +43 -0
- data/app/controllers/droom/events_controller.rb +120 -0
- data/app/controllers/droom/group_invitations_controller.rb +47 -0
- data/app/controllers/droom/groups_controller.rb +67 -0
- data/app/controllers/droom/invitations_controller.rb +43 -0
- data/app/controllers/droom/memberships_controller.rb +47 -0
- data/app/controllers/droom/pages_controller.rb +61 -0
- data/app/controllers/droom/people_controller.rb +92 -0
- data/app/controllers/droom/suggestions_controller.rb +58 -0
- data/app/controllers/droom/venues_controller.rb +39 -0
- data/app/helpers/droom/droom_helper.rb +74 -0
- data/app/models/droom/agenda_category.rb +8 -0
- data/app/models/droom/category.rb +27 -0
- data/app/models/droom/document.rb +110 -0
- data/app/models/droom/document_attachment.rb +71 -0
- data/app/models/droom/document_link.rb +31 -0
- data/app/models/droom/event.rb +409 -0
- data/app/models/droom/event_set.rb +6 -0
- data/app/models/droom/group.rb +66 -0
- data/app/models/droom/group_invitation.rb +23 -0
- data/app/models/droom/invitation.rb +30 -0
- data/app/models/droom/membership.rb +27 -0
- data/app/models/droom/page.rb +26 -0
- data/app/models/droom/person.rb +302 -0
- data/app/models/droom/personal_document.rb +98 -0
- data/app/models/droom/recurrence_rule.rb +82 -0
- data/app/models/droom/venue.rb +125 -0
- data/app/views/droom/dashboard/_marginalia.html.haml +3 -0
- data/app/views/droom/dashboard/_my_future_events.html.haml +9 -0
- data/app/views/droom/dashboard/_my_group_documents.html.haml +6 -0
- data/app/views/droom/dashboard/_my_past_events.haml +6 -0
- data/app/views/droom/dashboard/index.html.haml +5 -0
- data/app/views/droom/documents/_created.html.haml +2 -0
- data/app/views/droom/documents/_document.html.haml +14 -0
- data/app/views/droom/documents/_document_line.html.haml +2 -0
- data/app/views/droom/documents/_documents_list.html.haml +31 -0
- data/app/views/droom/documents/_documents_table.html.haml +13 -0
- data/app/views/droom/documents/_event_document_form.html.haml +15 -0
- data/app/views/droom/documents/_form.html.haml +22 -0
- data/app/views/droom/documents/_listing.html.haml +8 -0
- data/app/views/droom/documents/_suggested.html.haml +9 -0
- data/app/views/droom/documents/_table_document.html.haml +31 -0
- data/app/views/droom/documents/edit.html.haml +1 -0
- data/app/views/droom/documents/index.html.haml +29 -0
- data/app/views/droom/documents/new.html.haml +1 -0
- data/app/views/droom/errors/bang.html.haml +12 -0
- data/app/views/droom/errors/not_allowed.html.haml +12 -0
- data/app/views/droom/errors/not_found.html.haml +12 -0
- data/app/views/droom/events/_attachment.html.haml +1 -0
- data/app/views/droom/events/_attachment_list.html.haml +4 -0
- data/app/views/droom/events/_calendar.html.haml +54 -0
- data/app/views/droom/events/_created.html.haml +2 -0
- data/app/views/droom/events/_event.html.haml +77 -0
- data/app/views/droom/events/_event_line.html.haml +13 -0
- data/app/views/droom/events/_events.html.haml +2 -0
- data/app/views/droom/events/_form.html.haml +35 -0
- data/app/views/droom/events/_invitations.html.haml +20 -0
- data/app/views/droom/events/_other_page_parts.html.haml +0 -0
- data/app/views/droom/events/_popup_event.html.haml +6 -0
- data/app/views/droom/events/_suggested.html.haml +12 -0
- data/app/views/droom/events/_views.html.haml +7 -0
- data/app/views/droom/events/edit.html.haml +1 -0
- data/app/views/droom/events/index.html.haml +12 -0
- data/app/views/droom/events/index.rss.builder +20 -0
- data/app/views/droom/events/new.html.haml +1 -0
- data/app/views/droom/events/show.html.haml +4 -0
- data/app/views/droom/group_invitations/_attending_groups.html.haml +8 -0
- data/app/views/droom/group_invitations/_created.html.haml +3 -0
- data/app/views/droom/group_invitations/_form.html.haml +4 -0
- data/app/views/droom/group_invitations/new.html.haml +1 -0
- data/app/views/droom/groups/_created.html.haml +3 -0
- data/app/views/droom/groups/_form.html.haml +12 -0
- data/app/views/droom/groups/_group.html.haml +11 -0
- data/app/views/droom/groups/_groups.html.haml +3 -0
- data/app/views/droom/groups/edit.html.haml +1 -0
- data/app/views/droom/groups/index.html.haml +7 -0
- data/app/views/droom/groups/show.html.haml +13 -0
- data/app/views/droom/invitations/_attending_people.html.haml +8 -0
- data/app/views/droom/invitations/_created.html.haml +3 -0
- data/app/views/droom/invitations/_form.html.haml +5 -0
- data/app/views/droom/invitations/new.html.haml +1 -0
- data/app/views/droom/memberships/_button.html.haml +11 -0
- data/app/views/droom/memberships/_created.html.haml +4 -0
- data/app/views/droom/memberships/_form.html.haml +7 -0
- data/app/views/droom/memberships/_member.html.haml +33 -0
- data/app/views/droom/memberships/_memberships.html.haml +4 -0
- data/app/views/droom/pages/_contents.html.haml +10 -0
- data/app/views/droom/pages/_form.html.haml +36 -0
- data/app/views/droom/pages/_full_page.html.haml +17 -0
- data/app/views/droom/pages/_page.html.haml +5 -0
- data/app/views/droom/pages/_pages.html.haml +2 -0
- data/app/views/droom/pages/admin.html.haml +24 -0
- data/app/views/droom/pages/edit.html.haml +1 -0
- data/app/views/droom/pages/index.html.haml +10 -0
- data/app/views/droom/pages/new.html.haml +4 -0
- data/app/views/droom/pages/show.html.haml +5 -0
- data/app/views/droom/people/_created.html.haml +6 -0
- data/app/views/droom/people/_form.html.haml +40 -0
- data/app/views/droom/people/_people.html.haml +29 -0
- data/app/views/droom/people/_person.html.haml +34 -0
- data/app/views/droom/people/_suggested.html.haml +9 -0
- data/app/views/droom/people/edit.html.haml +1 -0
- data/app/views/droom/people/index.html.haml +11 -0
- data/app/views/droom/people/new.html.haml +1 -0
- data/app/views/droom/people/show.html.haml +1 -0
- data/app/views/droom/shared/_calendar_and_search.html.haml +2 -0
- data/app/views/droom/shared/_calendar_holder.haml +3 -0
- data/app/views/droom/shared/_controls.html.haml +8 -0
- data/app/views/droom/shared/_navigation.html.haml +8 -0
- data/app/views/droom/shared/_search_form.html.haml +4 -0
- data/app/views/droom/shared/_suggestions.html.haml +11 -0
- data/app/views/droom/shared/_toolbar.html.haml +17 -0
- data/app/views/droom/venues/_suggested.html.haml +6 -0
- data/app/views/droom/venues/index.html.haml +6 -0
- data/app/views/droom/venues/show.html.haml +21 -0
- data/app/views/layouts/droom/application.html.haml +36 -0
- data/config/initializers/dav.rb +2 -0
- data/config/initializers/paperclip.rb +26 -0
- data/config/initializers/snail.rb +2 -0
- data/config/locales/en.yml +191 -0
- data/config/routes.rb +51 -0
- data/db/migrate/20120910075016_create_droom_data.rb +134 -0
- data/db/migrate/20120917095804_agenda_sections.rb +13 -0
- data/db/migrate/20120918121352_add_postal_address_to_people.rb +10 -0
- data/db/migrate/20121009075049_give_groups_descriptions.rb +5 -0
- data/db/migrate/20121009105244_more_names.rb +5 -0
- data/db/migrate/20121009145944_event_agenda_sections.rb +13 -0
- data/db/migrate/20121011091230_create_group_invitations.rb +10 -0
- data/db/migrate/20121012144720_give_people_positions.rb +5 -0
- data/db/migrate/20121012154558_help_pages.rb +13 -0
- data/db/migrate/20121012163201_category_slugs.rb +5 -0
- data/db/migrate/20121101160102_document_links.rb +14 -0
- data/db/migrate/20121101181247_people_visibility.rb +7 -0
- data/db/migrate/20121102094738_shy_people.rb +6 -0
- data/db/migrate/20121102095856_visibility_defaults.rb +8 -0
- data/lib/droom.rb +73 -0
- data/lib/droom/dav_resource.rb +36 -0
- data/lib/droom/engine.rb +8 -0
- data/lib/droom/helpers.rb +25 -0
- data/lib/droom/monkeys.rb +15 -0
- data/lib/droom/renderers.rb +13 -0
- data/lib/droom/validators.rb +5 -0
- data/lib/droom/version.rb +3 -0
- data/lib/generators/droom/dashboard/dashboard_generator.rb +16 -0
- data/lib/generators/droom/install/USAGE +9 -0
- data/lib/generators/droom/install/install_generator.rb +15 -0
- data/lib/generators/droom/install/templates/droom_initializer.rb +6 -0
- data/lib/generators/droom/views/views_generator.rb +9 -0
- data/lib/tasks/droom_tasks.rake +4 -0
- metadata +635 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Droom
|
|
2
|
+
class Group < ActiveRecord::Base
|
|
3
|
+
attr_accessible :name, :leader_id, :description
|
|
4
|
+
|
|
5
|
+
belongs_to :created_by, :class_name => 'User'
|
|
6
|
+
belongs_to :leader, :class_name => 'Person'
|
|
7
|
+
|
|
8
|
+
has_many :group_invitations, :dependent => :destroy, :uniq => true
|
|
9
|
+
has_many :events, :through => :group_invitations
|
|
10
|
+
|
|
11
|
+
has_many :memberships, :dependent => :destroy
|
|
12
|
+
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|
|
|
26
|
+
fragment = "%#{fragment}%"
|
|
27
|
+
where('droom_groups.name like ?', fragment)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
default_scope order("droom_groups.created_at ASC")
|
|
31
|
+
|
|
32
|
+
def identifier
|
|
33
|
+
'group'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def admit(person)
|
|
37
|
+
self.people << person
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def attach(doc)
|
|
41
|
+
self.documents << doc
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def membership_for(person)
|
|
45
|
+
self.memberships.for(person).first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def invite_to(event)
|
|
49
|
+
group_invitations.find_or_create_by_event_id(event.id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def uninvite_from(event)
|
|
53
|
+
group_invitation = group_invitations.find_by_event_id(event.id)
|
|
54
|
+
group_invitation.invitations.to_event(event).each do |invitation|
|
|
55
|
+
invitation.destroy!
|
|
56
|
+
end
|
|
57
|
+
group_invitation.destroy!
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
|
|
62
|
+
def check_slug
|
|
63
|
+
ensure_presence_and_uniqueness_of(:slug, name.parameterize)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Droom
|
|
2
|
+
class GroupInvitation < ActiveRecord::Base
|
|
3
|
+
attr_accessible :event_id, :group_id
|
|
4
|
+
|
|
5
|
+
belongs_to :created_by, :class_name => "User"
|
|
6
|
+
belongs_to :group
|
|
7
|
+
belongs_to :event
|
|
8
|
+
has_many :invitations, :dependent => :destroy
|
|
9
|
+
after_create :create_personal_invitations
|
|
10
|
+
validates_uniqueness_of :group_id, :scope => :event_id
|
|
11
|
+
|
|
12
|
+
scope :to_event, lambda { |event|
|
|
13
|
+
where("group_invitations.event_id = ?", event.id)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def create_personal_invitations
|
|
17
|
+
group.people.each do |person|
|
|
18
|
+
invitations.find_or_create_by_person_id_and_event_id(person.id, event.id)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Droom
|
|
2
|
+
class Invitation < ActiveRecord::Base
|
|
3
|
+
attr_accessible :event_id, :person_id
|
|
4
|
+
|
|
5
|
+
belongs_to :person
|
|
6
|
+
belongs_to :event
|
|
7
|
+
belongs_to :group_invitation
|
|
8
|
+
belongs_to :created_by, :class_name => "User"
|
|
9
|
+
|
|
10
|
+
after_create :link_documents
|
|
11
|
+
after_destroy :unlink_documents
|
|
12
|
+
|
|
13
|
+
validates_uniqueness_of :person_id, :scope => [:event_id, :group_invitation_id]
|
|
14
|
+
|
|
15
|
+
scope :to_event, lambda { |event|
|
|
16
|
+
where(["event_id = ?", event.id])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def link_documents
|
|
22
|
+
person.document_attachments << event.document_attachments
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def unlink_documents
|
|
26
|
+
person.document_attachments -= event.document_attachments
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Droom
|
|
2
|
+
class Membership < ActiveRecord::Base
|
|
3
|
+
attr_accessible :group_id, :person_id
|
|
4
|
+
|
|
5
|
+
belongs_to :person
|
|
6
|
+
belongs_to :group
|
|
7
|
+
belongs_to :created_by, :class_name => "User"
|
|
8
|
+
|
|
9
|
+
after_create :link_documents
|
|
10
|
+
after_destroy :unlink_documents
|
|
11
|
+
|
|
12
|
+
scope :of_group, lambda { |group|
|
|
13
|
+
where(["group_id = ?", group.id])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def link_documents
|
|
19
|
+
person.document_attachments << group.document_attachments
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def unlink_documents
|
|
23
|
+
person.document_attachments -= group.document_attachments
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Pages are currently just minimal text-holders. The text is entered in markdown,
|
|
2
|
+
# rendered on save and placed into the usual layout.
|
|
3
|
+
#
|
|
4
|
+
module Droom
|
|
5
|
+
class Page < ActiveRecord::Base
|
|
6
|
+
attr_accessible :title, :slug, :summary, :body, :video_id
|
|
7
|
+
|
|
8
|
+
before_validation :check_slug
|
|
9
|
+
before_save :render_body
|
|
10
|
+
validates :slug, :uniqueness => true, :presence => true
|
|
11
|
+
validates :title, :presence => true
|
|
12
|
+
default_scope order('title ASC')
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def check_slug
|
|
17
|
+
ensure_presence_and_uniqueness_of(:slug, title.parameterize)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render_body
|
|
21
|
+
Rails.logger.warn ">>> rendering body: #{self.body.inspect}"
|
|
22
|
+
markdown = RDiscount.new(self.body)
|
|
23
|
+
self.rendered_body = markdown.to_html
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# This has been pulled from the yearbook and simplified. Docs need updating to match.
|
|
2
|
+
require 'vcard'
|
|
3
|
+
module Droom
|
|
4
|
+
class Person < ActiveRecord::Base
|
|
5
|
+
attr_accessible :name, :forename, :email, :phone, :description, :user, :title, :invite_on_creation, :admin_user, :position
|
|
6
|
+
attr_accessor :invite_on_creation, :admin_user
|
|
7
|
+
acts_as_list
|
|
8
|
+
### Associations
|
|
9
|
+
#
|
|
10
|
+
has_many :memberships, :dependent => :destroy
|
|
11
|
+
has_many :groups, :through => :memberships
|
|
12
|
+
|
|
13
|
+
has_many :invitations, :dependent => :destroy
|
|
14
|
+
has_many :events, :through => :invitations
|
|
15
|
+
|
|
16
|
+
# document_links is an automatically maintained index that we use to make easier the task of retrieving
|
|
17
|
+
# the documents this person is allowed to see.
|
|
18
|
+
has_many :document_links, :dependent => :destroy
|
|
19
|
+
has_many :document_attachments, :through => :document_links
|
|
20
|
+
# is this association really needed? We always retrieve the document list using the visible_to scope, so as to get public docs too.
|
|
21
|
+
has_many :documents, :through => :document_attachments, :uniq => true
|
|
22
|
+
|
|
23
|
+
# personal documents are the document clones created when a user logs to her DAV folder.
|
|
24
|
+
# they are spun off the document links
|
|
25
|
+
has_many :personal_documents, :through => :document_links
|
|
26
|
+
|
|
27
|
+
# The `user` is this person's administrative account for logging in and out and forgetting her password.
|
|
28
|
+
# A person can be listed without ever having a user, and a user account can exist (for an administrator)
|
|
29
|
+
# without having a person.
|
|
30
|
+
belongs_to :user, :class_name => Droom.user_class.to_s, :dependent => :destroy
|
|
31
|
+
|
|
32
|
+
before_save :update_user
|
|
33
|
+
after_save :invite_if_instructed
|
|
34
|
+
|
|
35
|
+
# The data requirements are minimal, with the idea that the directory will be populated gradually.
|
|
36
|
+
validates :name, :presence => true
|
|
37
|
+
|
|
38
|
+
default_scope order("droom_people.#{Droom.people_sort}")
|
|
39
|
+
|
|
40
|
+
scope :all_private, where("shy = 1")
|
|
41
|
+
scope :not_private, where("shy <> 1")
|
|
42
|
+
scope :all_public, where("public = 1 AND shy <> 1")
|
|
43
|
+
scope :not_public, where("public <> 1 OR shy = 1)")
|
|
44
|
+
|
|
45
|
+
scope :name_matching, lambda { |fragment|
|
|
46
|
+
fragment = "%#{fragment}%"
|
|
47
|
+
where('droom_people.name LIKE :f OR droom_people.forename LIKE :f', :f => fragment)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# warning! won't work in SQLite.
|
|
51
|
+
scope :visible_to, lambda { |person|
|
|
52
|
+
if person
|
|
53
|
+
select('droom_people.*')
|
|
54
|
+
.joins('LEFT OUTER JOIN droom_memberships as dm1 on droom_people.id = dm1.person_id')
|
|
55
|
+
.joins('LEFT OUTER JOIN droom_memberships as dm2 on dm1.group_id = dm2.group_id')
|
|
56
|
+
.where(['(droom_people.public = 1 OR dm2.person_id = ?) AND (droom_people.shy IS NULL OR droom_people.shy <> 1)', person.id])
|
|
57
|
+
.group('droom_people.id')
|
|
58
|
+
else
|
|
59
|
+
all_public
|
|
60
|
+
end
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
scope :personally_invited_to_event, lambda { |event|
|
|
64
|
+
joins('LEFT OUTER JOIN droom_invitations on droom_people.id = droom_invitations.person_id').where('droom_invitations.group_invitation_id is null AND droom_invitations.event_id = ?', event.id)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
### Images
|
|
68
|
+
#
|
|
69
|
+
# The treatment here is very basic compared to the yearbook's uploader, but we might bring that across
|
|
70
|
+
# if this starts to look like a useful directory resource.
|
|
71
|
+
#
|
|
72
|
+
has_attached_file :image, {
|
|
73
|
+
:styles => {:standard => "400x300#", :thumb => "100x100#"},
|
|
74
|
+
:default_url => "/assets/person/nopicture_:style.png"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def image_url(style=:standard)
|
|
78
|
+
image.url(style)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def identifier
|
|
82
|
+
'person'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def formal_name
|
|
86
|
+
[title, forename, name].compact.join(' ').strip
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def informal_name
|
|
90
|
+
if Droom.use_forenames
|
|
91
|
+
forename
|
|
92
|
+
else
|
|
93
|
+
name
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# I don't think we're using this anywhere at the moment, but a JSON API will grow here. Other classes already make more use of
|
|
98
|
+
# JSON representation, eg institutions for mapping or tags for tagging.
|
|
99
|
+
#
|
|
100
|
+
def as_json(options={})
|
|
101
|
+
{
|
|
102
|
+
:id => id,
|
|
103
|
+
:name => name,
|
|
104
|
+
:title => title
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# *for_selection* returns a list of people in options_for_select format with which to populate a select box.
|
|
109
|
+
#
|
|
110
|
+
def self.for_selection
|
|
111
|
+
self.published.map{|p| [p.name, p.id] }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Document links function as a lookup table to speed up the process of working out what this person can see.
|
|
115
|
+
# They are created when an attachment, invitation or membership confers access, and destroyed when a link in
|
|
116
|
+
# that chain is removed.
|
|
117
|
+
#
|
|
118
|
+
# This will rebuild the document_link index for this person.
|
|
119
|
+
#
|
|
120
|
+
def repair_document_links
|
|
121
|
+
# NB this will also destroy all our personal documents. Very much a last resort.
|
|
122
|
+
self.document_links.destroy_all
|
|
123
|
+
group_and_event_attachments.each do |da|
|
|
124
|
+
document_links.create(:document_attachment => da)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def group_and_event_attachments
|
|
129
|
+
Droom::DocumentAttachment.to_groups(groups) + Droom::DocumentAttachment.to_events(events)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# We defer the creation and updating of personal documents until the person actually logs in over DAV. At that stage a call
|
|
133
|
+
# goes to person.create_personal_documents and the copying begins. It's not really ideal from a responsiveness point of view
|
|
134
|
+
# but it saves a great deal of update hassle (and storage space).
|
|
135
|
+
#
|
|
136
|
+
# NB this will not recreate deleted files: we only look as far as the PersonalDocument object, not the file
|
|
137
|
+
# it would usually have. This is to allow people to delete files they don't want, without having them
|
|
138
|
+
# constantly recreated.
|
|
139
|
+
#
|
|
140
|
+
def create_personal_documents
|
|
141
|
+
create_and_update_dav_directories
|
|
142
|
+
document_links.each { |dl| dl.ensure_personal_document }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def create_and_update_dav_directories
|
|
146
|
+
document_links.each do |dl|
|
|
147
|
+
p "-> creating DAV directory #{dl.slug}"
|
|
148
|
+
create_dav_directory(dl.slug)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def create_dav_directory(name)
|
|
153
|
+
FileUtils.mkdir_p(Rails.root + "#{Droom.dav_root}/#{self.id}/#{name}")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# If a personal version exists, we will return that since it may contain annotations or amendments.
|
|
157
|
+
#
|
|
158
|
+
def personal_or_generic_version_of(document)
|
|
159
|
+
personal_version_of(document) || document
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# But if there has been no DAV login there can be no personal version.
|
|
163
|
+
#
|
|
164
|
+
def personal_version_of(document)
|
|
165
|
+
personal_documents.derived_from(document).first
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# group_documents returns all those documents that have been attached to a group of which this person is a member.
|
|
169
|
+
# These documents will not show up in the calendar (since they are not attached to an event) so it's often a useful list.
|
|
170
|
+
#
|
|
171
|
+
def group_documents
|
|
172
|
+
groups.any? ? Droom::Document.attached_to_these_groups(groups).by_date : []
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# It is possible to give us a document by creating an attachment that has no attachee
|
|
176
|
+
# but which links to this person.
|
|
177
|
+
#
|
|
178
|
+
def attach(doc)
|
|
179
|
+
document_attachments.create(:document => doc)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def invite_to(event)
|
|
184
|
+
invitations.find_or_create_by_event_id(event.id) if event
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def uninvite_from(event)
|
|
188
|
+
p "-> destroying invitations: #{invitations.to_event(event).inspect}"
|
|
189
|
+
invitations.to_event(event).destroy_all
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def admit_to(group)
|
|
193
|
+
memberships.find_or_create_by_group_id(group.id) if group
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def expel_from(group)
|
|
197
|
+
memberships.of_group(group).destroy_all
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def member_of?(group)
|
|
201
|
+
group && memberships.of_group(group).any?
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def invited_to?(event)
|
|
205
|
+
group && invitations.to_event(event).any?
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# some magic glue to allow slightly indiscriminate use of user and person objects.
|
|
209
|
+
|
|
210
|
+
def person
|
|
211
|
+
self
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def admin?
|
|
215
|
+
user && user.admin?
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def has_active_user?
|
|
219
|
+
user && user.activated?
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def has_invited_user?
|
|
223
|
+
user && user.invited?
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def has_admin_user?
|
|
227
|
+
user && user.admin?
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# Snail is a library that abstracts away - as far as possible - the vagaries of international address formats. Here we map our data columns onto Snail's abstract representations so that they can be rendered into the correct format for their country.
|
|
232
|
+
def address
|
|
233
|
+
Snail.new(
|
|
234
|
+
:line_1 => post_line1,
|
|
235
|
+
:line_2 => post_line2,
|
|
236
|
+
:city => post_city,
|
|
237
|
+
:region => post_region,
|
|
238
|
+
:postal_code => post_code,
|
|
239
|
+
:country => post_country
|
|
240
|
+
)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def address?
|
|
244
|
+
post_line1? && post_city
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def to_vcf
|
|
248
|
+
@vcard ||= Vpim::Vcard::Maker.make2 do |maker|
|
|
249
|
+
maker.add_name do |n|
|
|
250
|
+
n.given = name || ""
|
|
251
|
+
end
|
|
252
|
+
maker.add_addr {|a|
|
|
253
|
+
a.location = 'home' # until we do this properly with multiple contact sets
|
|
254
|
+
a.country = post_country || ""
|
|
255
|
+
a.region = post_region || ""
|
|
256
|
+
a.locality = post_city || ""
|
|
257
|
+
a.street = "#{post_line1}, #{post_line2}"
|
|
258
|
+
a.postalcode = post_code || ""
|
|
259
|
+
}
|
|
260
|
+
maker.add_tel phone { |t| t.location = 'home' } unless phone.blank?
|
|
261
|
+
# maker.add_tel mobile { |t| t.location = 'cell' } unless mobile.blank?
|
|
262
|
+
maker.add_email email { |e| t.location = 'home' }
|
|
263
|
+
end
|
|
264
|
+
@vcard.to_s
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def self.vcards_for(people=[])
|
|
268
|
+
people.map(&:vcf).join("\n")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
protected
|
|
272
|
+
|
|
273
|
+
def invite_if_instructed
|
|
274
|
+
invite_user if invite_on_creation
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# ### Administration & callbacks
|
|
278
|
+
#
|
|
279
|
+
# At some point we may want to create a user to log in and look after this person.
|
|
280
|
+
# This usually has the side effect of sending out a login invitation.
|
|
281
|
+
#
|
|
282
|
+
def invite_user
|
|
283
|
+
unless self.user
|
|
284
|
+
if self.name? && self.email?
|
|
285
|
+
self.create_user(:forename => forename, :name => name, :email => email, :phone => phone, :admin => admin_user)
|
|
286
|
+
self.save
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def update_user
|
|
292
|
+
if self.user && self.user.persisted?
|
|
293
|
+
self.user.update_column(:email, self.email) if email_changed?
|
|
294
|
+
self.user.update_column(:phone, self.phone) if phone_changed?
|
|
295
|
+
self.user.update_column(:name, self.name) if name_changed?
|
|
296
|
+
self.user.update_column(:forename, self.forename) if forename_changed?
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|