socializer 0.1.13
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/.editorconfig +11 -0
- data/.gitignore +29 -0
- data/.rubocop.yml +42 -0
- data/.travis.yml +13 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +31 -0
- data/README.md +91 -0
- data/Rakefile +38 -0
- data/app/assets/images/socializer/.gitkeep +0 -0
- data/app/assets/images/socializer/auth_buttons/facebook_128.png +0 -0
- data/app/assets/images/socializer/auth_buttons/facebook_256.png +0 -0
- data/app/assets/images/socializer/auth_buttons/facebook_32.png +0 -0
- data/app/assets/images/socializer/auth_buttons/facebook_64.png +0 -0
- data/app/assets/images/socializer/auth_buttons/google_128.png +0 -0
- data/app/assets/images/socializer/auth_buttons/google_256.png +0 -0
- data/app/assets/images/socializer/auth_buttons/google_32.png +0 -0
- data/app/assets/images/socializer/auth_buttons/google_64.png +0 -0
- data/app/assets/images/socializer/auth_buttons/linkedin_128.png +0 -0
- data/app/assets/images/socializer/auth_buttons/linkedin_256.png +0 -0
- data/app/assets/images/socializer/auth_buttons/linkedin_32.png +0 -0
- data/app/assets/images/socializer/auth_buttons/linkedin_64.png +0 -0
- data/app/assets/images/socializer/auth_buttons/twitter_128.png +0 -0
- data/app/assets/images/socializer/auth_buttons/twitter_256.png +0 -0
- data/app/assets/images/socializer/auth_buttons/twitter_32.png +0 -0
- data/app/assets/images/socializer/auth_buttons/twitter_64.png +0 -0
- data/app/assets/images/socializer/auth_buttons/yahoo_128.png +0 -0
- data/app/assets/images/socializer/auth_buttons/yahoo_256.png +0 -0
- data/app/assets/images/socializer/auth_buttons/yahoo_32.png +0 -0
- data/app/assets/images/socializer/auth_buttons/yahoo_64.png +0 -0
- data/app/assets/images/socializer/close.png +0 -0
- data/app/assets/images/socializer/icons/Bell.png +0 -0
- data/app/assets/images/socializer/icons/Edit.png +0 -0
- data/app/assets/images/socializer/icons/Home.png +0 -0
- data/app/assets/images/socializer/icons/Power.png +0 -0
- data/app/assets/images/socializer/icons/Safe.png +0 -0
- data/app/assets/images/socializer/icons/User.png +0 -0
- data/app/assets/images/socializer/icons/Users.png +0 -0
- data/app/assets/images/socializer/icons/Web.png +0 -0
- data/app/assets/images/socializer/loading.gif +0 -0
- data/app/assets/images/socializer/next.png +0 -0
- data/app/assets/images/socializer/pause.png +0 -0
- data/app/assets/images/socializer/play.png +0 -0
- data/app/assets/images/socializer/previous.png +0 -0
- data/app/assets/javascripts/socializer/activities.js.coffee +47 -0
- data/app/assets/javascripts/socializer/application.js +24 -0
- data/app/assets/javascripts/socializer/circles.js.coffee +33 -0
- data/app/assets/javascripts/socializer/jquery.qtip.min.js +7 -0
- data/app/assets/javascripts/socializer/jquery.tokeninput.js +862 -0
- data/app/assets/javascripts/socializer/notes.js.coffee +38 -0
- data/app/assets/javascripts/socializer/people.js.coffee +7 -0
- data/app/assets/javascripts/socializer/shares.js.coffee +8 -0
- data/app/assets/stylesheets/socializer/activities.css +84 -0
- data/app/assets/stylesheets/socializer/application.css +409 -0
- data/app/assets/stylesheets/socializer/authentications.css +4 -0
- data/app/assets/stylesheets/socializer/circles.css +74 -0
- data/app/assets/stylesheets/socializer/comments.css +4 -0
- data/app/assets/stylesheets/socializer/groups.css +61 -0
- data/app/assets/stylesheets/socializer/jquery.qtip.min.css +2 -0
- data/app/assets/stylesheets/socializer/likes.css +4 -0
- data/app/assets/stylesheets/socializer/memberships.css +4 -0
- data/app/assets/stylesheets/socializer/notes.css +21 -0
- data/app/assets/stylesheets/socializer/notifications.css +46 -0
- data/app/assets/stylesheets/socializer/pages.css +4 -0
- data/app/assets/stylesheets/socializer/persons.css +25 -0
- data/app/assets/stylesheets/socializer/sessions.css +4 -0
- data/app/assets/stylesheets/socializer/shares.css.scss +3 -0
- data/app/assets/stylesheets/socializer/ties.css +4 -0
- data/app/assets/stylesheets/socializer/token-input.css +183 -0
- data/app/controllers/socializer/activities_controller.rb +84 -0
- data/app/controllers/socializer/application_controller.rb +37 -0
- data/app/controllers/socializer/audiences_controller.rb +30 -0
- data/app/controllers/socializer/authentications_controller.rb +13 -0
- data/app/controllers/socializer/circles_controller.rb +54 -0
- data/app/controllers/socializer/comments_controller.rb +37 -0
- data/app/controllers/socializer/groups_controller.rb +70 -0
- data/app/controllers/socializer/likes_controller.rb +50 -0
- data/app/controllers/socializer/memberships_controller.rb +46 -0
- data/app/controllers/socializer/notes_controller.rb +43 -0
- data/app/controllers/socializer/notifications_controller.rb +29 -0
- data/app/controllers/socializer/pages_controller.rb +7 -0
- data/app/controllers/socializer/people_controller.rb +37 -0
- data/app/controllers/socializer/person_addresses_controller.rb +27 -0
- data/app/controllers/socializer/person_contributions_controller.rb +27 -0
- data/app/controllers/socializer/person_educations_controller.rb +27 -0
- data/app/controllers/socializer/person_employments_controller.rb +27 -0
- data/app/controllers/socializer/person_links_controller.rb +27 -0
- data/app/controllers/socializer/person_phones_controller.rb +27 -0
- data/app/controllers/socializer/person_places_controller.rb +27 -0
- data/app/controllers/socializer/person_profiles_controller.rb +27 -0
- data/app/controllers/socializer/sessions_controller.rb +37 -0
- data/app/controllers/socializer/shares_controller.rb +54 -0
- data/app/controllers/socializer/ties_controller.rb +16 -0
- data/app/helpers/socializer/application_helper.rb +22 -0
- data/app/models/concerns/socializer/object_type_base.rb +58 -0
- data/app/models/socializer/activity.rb +162 -0
- data/app/models/socializer/activity_field.rb +10 -0
- data/app/models/socializer/activity_object.rb +118 -0
- data/app/models/socializer/audience.rb +19 -0
- data/app/models/socializer/authentication.rb +20 -0
- data/app/models/socializer/circle.rb +32 -0
- data/app/models/socializer/comment.rb +13 -0
- data/app/models/socializer/group.rb +100 -0
- data/app/models/socializer/group_category.rb +11 -0
- data/app/models/socializer/group_link.rb +12 -0
- data/app/models/socializer/identity.rb +9 -0
- data/app/models/socializer/membership.rb +24 -0
- data/app/models/socializer/note.rb +13 -0
- data/app/models/socializer/notification.rb +16 -0
- data/app/models/socializer/person.rb +129 -0
- data/app/models/socializer/person_address.rb +12 -0
- data/app/models/socializer/person_contribution.rb +12 -0
- data/app/models/socializer/person_education.rb +8 -0
- data/app/models/socializer/person_employment.rb +8 -0
- data/app/models/socializer/person_link.rb +12 -0
- data/app/models/socializer/person_phone.rb +16 -0
- data/app/models/socializer/person_place.rb +11 -0
- data/app/models/socializer/person_profile.rb +12 -0
- data/app/models/socializer/tie.rb +12 -0
- data/app/models/socializer/verb.rb +9 -0
- data/app/views/layouts/socializer/_header.html.erb +11 -0
- data/app/views/layouts/socializer/application.html.erb +60 -0
- data/app/views/socializer/activities/_activity.html.erb +23 -0
- data/app/views/socializer/activities/_activity_bottom.html.erb +55 -0
- data/app/views/socializer/activities/_activity_content.html.erb +19 -0
- data/app/views/socializer/activities/_activity_top.html.erb +22 -0
- data/app/views/socializer/activities/_stream_card.html.erb +6 -0
- data/app/views/socializer/activities/_stream_list.html.erb +16 -0
- data/app/views/socializer/activities/audience.html.erb +19 -0
- data/app/views/socializer/activities/destroy.js.erb +3 -0
- data/app/views/socializer/activities/edit.html.erb +0 -0
- data/app/views/socializer/activities/index.html.erb +15 -0
- data/app/views/socializer/authentications/_form.html.erb +0 -0
- data/app/views/socializer/authentications/_menu.html.erb +5 -0
- data/app/views/socializer/authentications/index.html.erb +8 -0
- data/app/views/socializer/authentications/new.html.erb +8 -0
- data/app/views/socializer/circles/_card.html.erb +7 -0
- data/app/views/socializer/circles/_circles.html.erb +6 -0
- data/app/views/socializer/circles/_form.html.erb +6 -0
- data/app/views/socializer/circles/_menu.html.erb +7 -0
- data/app/views/socializer/circles/contact_of.html.erb +7 -0
- data/app/views/socializer/circles/contacts.html.erb +7 -0
- data/app/views/socializer/circles/edit.html.erb +1 -0
- data/app/views/socializer/circles/find_people.html.erb +7 -0
- data/app/views/socializer/circles/index.html.erb +6 -0
- data/app/views/socializer/circles/new.html.erb +1 -0
- data/app/views/socializer/circles/show.html.erb +10 -0
- data/app/views/socializer/comments/_form.html.erb +8 -0
- data/app/views/socializer/comments/edit.html.erb +1 -0
- data/app/views/socializer/comments/new.html.erb +1 -0
- data/app/views/socializer/groups/_card.html.erb +6 -0
- data/app/views/socializer/groups/_form.html.erb +6 -0
- data/app/views/socializer/groups/_menu.html.erb +10 -0
- data/app/views/socializer/groups/edit.html.erb +1 -0
- data/app/views/socializer/groups/index.html.erb +0 -0
- data/app/views/socializer/groups/joinable.html.erb +16 -0
- data/app/views/socializer/groups/memberships.html.erb +19 -0
- data/app/views/socializer/groups/new.html.erb +1 -0
- data/app/views/socializer/groups/ownerships.html.erb +20 -0
- data/app/views/socializer/groups/pending_invites.html.erb +20 -0
- data/app/views/socializer/groups/public.html.erb +16 -0
- data/app/views/socializer/groups/restricted.html.erb +16 -0
- data/app/views/socializer/groups/show.html.erb +29 -0
- data/app/views/socializer/likes/create.js.erb +2 -0
- data/app/views/socializer/likes/destroy.js.erb +2 -0
- data/app/views/socializer/likes/index.html.erb +5 -0
- data/app/views/socializer/notes/_form.html.erb +7 -0
- data/app/views/socializer/notes/create.js.erb +10 -0
- data/app/views/socializer/notes/destroy.js.erb +3 -0
- data/app/views/socializer/notes/edit.html.erb +1 -0
- data/app/views/socializer/notes/new.html.erb +2 -0
- data/app/views/socializer/notifications/index.html.erb +35 -0
- data/app/views/socializer/pages/index.html.erb +2 -0
- data/app/views/socializer/people/_card.html.erb +15 -0
- data/app/views/socializer/people/_form.html.erb +30 -0
- data/app/views/socializer/people/_login.html.erb +14 -0
- data/app/views/socializer/people/_menu.html.erb +9 -0
- data/app/views/socializer/people/edit.html.erb +2 -0
- data/app/views/socializer/people/index.html.erb +5 -0
- data/app/views/socializer/people/likes.html.erb +6 -0
- data/app/views/socializer/people/message.html.erb +5 -0
- data/app/views/socializer/people/show.html.erb +122 -0
- data/app/views/socializer/person_addresses/_form.html.erb +12 -0
- data/app/views/socializer/person_contributions/_form.html.erb +7 -0
- data/app/views/socializer/person_educations/_form.html.erb +10 -0
- data/app/views/socializer/person_employments/_form.html.erb +10 -0
- data/app/views/socializer/person_links/_form.html.erb +6 -0
- data/app/views/socializer/person_phones/_form.html.erb +6 -0
- data/app/views/socializer/person_places/_form.html.erb +6 -0
- data/app/views/socializer/person_profiles/_form.html.erb +6 -0
- data/app/views/socializer/shares/_form.html.erb +19 -0
- data/app/views/socializer/shares/new.html.erb +1 -0
- data/config.ru +4 -0
- data/config/cucumber.yml +8 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/locales/en.yml +108 -0
- data/config/locales/fr.yml +329 -0
- data/config/rails_best_practices.yml +41 -0
- data/config/routes.rb +71 -0
- data/db/migrate/20110804175740_create_socializer_activity_objects.rb +14 -0
- data/db/migrate/20110804180557_create_socializer_people.rb +31 -0
- data/db/migrate/20110804184415_create_socializer_notes.rb +12 -0
- data/db/migrate/20110804192211_create_socializer_authentications.rb +12 -0
- data/db/migrate/20110805085417_create_socializer_circles.rb +14 -0
- data/db/migrate/20110805090617_create_socializer_activities.rb +17 -0
- data/db/migrate/20110805092635_create_socializer_audiences.rb +14 -0
- data/db/migrate/20110805094846_create_socializer_comments.rb +12 -0
- data/db/migrate/20110805121454_create_socializer_groups.rb +19 -0
- data/db/migrate/20110805121543_create_socializer_memberships.rb +14 -0
- data/db/migrate/20110805125606_create_socializer_ties.rb +13 -0
- data/db/migrate/20111207234435_create_socializer_identities.rb +12 -0
- data/db/migrate/20130524000429_create_socializer_verbs.rb +10 -0
- data/db/migrate/20130528143831_create_socializer_activity_fields.rb +10 -0
- data/db/migrate/20140128235250_create_socializer_notifications.rb +11 -0
- data/db/migrate/20140131065531_create_socializer_person_employments.rb +15 -0
- data/db/migrate/20140131065733_create_socializer_person_educations.rb +15 -0
- data/db/migrate/20140131065836_create_socializer_person_places.rb +11 -0
- data/db/migrate/20140131070051_create_socializer_person_contributions.rb +12 -0
- data/db/migrate/20140131070232_create_socializer_person_links.rb +11 -0
- data/db/migrate/20140131070259_create_socializer_person_profiles.rb +11 -0
- data/db/migrate/20140131070417_create_socializer_person_phones.rb +12 -0
- data/db/migrate/20140131070611_create_socializer_person_addresses.rb +17 -0
- data/db/migrate/20140131070839_create_socializer_group_links.rb +11 -0
- data/db/migrate/20140131070951_create_socializer_group_categories.rb +10 -0
- data/features/support/capybara.rb +14 -0
- data/features/support/env.rb +57 -0
- data/features/support/factory_girl.rb +1 -0
- data/lib/socializer.rb +4 -0
- data/lib/socializer/engine.rb +27 -0
- data/lib/socializer/version.rb +3 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/socializer_tasks.rake +4 -0
- data/script/cucumber +10 -0
- data/socializer.gemspec +49 -0
- data/spec/controllers/socializer/likes_controller_spec.rb +29 -0
- data/spec/controllers/socializer/shares_controller_spec.rb +22 -0
- data/spec/factories/socializer_activities.rb +11 -0
- data/spec/factories/socializer_activity_fields.rb +8 -0
- data/spec/factories/socializer_activity_objects.rb +7 -0
- data/spec/factories/socializer_audiences.rb +9 -0
- data/spec/factories/socializer_authentications.rb +6 -0
- data/spec/factories/socializer_circles.rb +9 -0
- data/spec/factories/socializer_comments.rb +6 -0
- data/spec/factories/socializer_group_categories.rb +8 -0
- data/spec/factories/socializer_group_links.rb +9 -0
- data/spec/factories/socializer_groups.rb +9 -0
- data/spec/factories/socializer_identities.rb +10 -0
- data/spec/factories/socializer_memberships.rb +6 -0
- data/spec/factories/socializer_notes.rb +7 -0
- data/spec/factories/socializer_notifications.rb +10 -0
- data/spec/factories/socializer_people.rb +7 -0
- data/spec/factories/socializer_person_addresses.rb +8 -0
- data/spec/factories/socializer_person_contributions.rb +9 -0
- data/spec/factories/socializer_person_educations.rb +7 -0
- data/spec/factories/socializer_person_employments.rb +7 -0
- data/spec/factories/socializer_person_links.rb +9 -0
- data/spec/factories/socializer_person_phones.rb +9 -0
- data/spec/factories/socializer_person_places.rb +8 -0
- data/spec/factories/socializer_person_profiles.rb +9 -0
- data/spec/factories/socializer_ties.rb +6 -0
- data/spec/factories/socializer_verbs.rb +7 -0
- data/spec/inflector_spec.rb +19 -0
- data/spec/models/socializer/activity_field_spec.rb +25 -0
- data/spec/models/socializer/activity_object_spec.rb +118 -0
- data/spec/models/socializer/activity_spec.rb +16 -0
- data/spec/models/socializer/audience_spec.rb +32 -0
- data/spec/models/socializer/authentication_spec.rb +29 -0
- data/spec/models/socializer/circle_spec.rb +53 -0
- data/spec/models/socializer/comment_spec.rb +19 -0
- data/spec/models/socializer/group_category_spec.rb +23 -0
- data/spec/models/socializer/group_link_spec.rb +25 -0
- data/spec/models/socializer/group_spec.rb +218 -0
- data/spec/models/socializer/identity_spec.rb +32 -0
- data/spec/models/socializer/membership_spec.rb +68 -0
- data/spec/models/socializer/note_spec.rb +19 -0
- data/spec/models/socializer/notification_spec.rb +28 -0
- data/spec/models/socializer/person_address_spec.rb +27 -0
- data/spec/models/socializer/person_contribution_spec.rb +27 -0
- data/spec/models/socializer/person_education_spec.rb +25 -0
- data/spec/models/socializer/person_employment_spec.rb +25 -0
- data/spec/models/socializer/person_link_spec.rb +26 -0
- data/spec/models/socializer/person_phone_spec.rb +28 -0
- data/spec/models/socializer/person_place_spec.rb +25 -0
- data/spec/models/socializer/person_profile_spec.rb +26 -0
- data/spec/models/socializer/person_spec.rb +105 -0
- data/spec/models/socializer/tie_spec.rb +24 -0
- data/spec/models/socializer/verb_spec.rb +24 -0
- data/spec/spec_helper.rb +84 -0
- data/vendor/assets/javascripts/moment/langs.js +5841 -0
- data/vendor/assets/javascripts/moment/moment.js +2400 -0
- metadata +754 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Activity < ActiveRecord::Base
|
|
3
|
+
include Socializer::ObjectTypeBase
|
|
4
|
+
|
|
5
|
+
default_scope { order(created_at: :desc) }
|
|
6
|
+
|
|
7
|
+
attr_accessible :verb, :circles, :actor_id, :activity_object_id, :target_id
|
|
8
|
+
|
|
9
|
+
belongs_to :parent, class_name: 'Activity', foreign_key: 'target_id'
|
|
10
|
+
belongs_to :activitable_actor, class_name: 'ActivityObject', foreign_key: 'actor_id'
|
|
11
|
+
belongs_to :activitable_object, class_name: 'ActivityObject', foreign_key: 'activity_object_id'
|
|
12
|
+
belongs_to :activitable_target, class_name: 'ActivityObject', foreign_key: 'target_id'
|
|
13
|
+
belongs_to :verb, inverse_of: :activities
|
|
14
|
+
|
|
15
|
+
has_one :activity_field, inverse_of: :activity
|
|
16
|
+
has_many :audiences # , dependent: :destroy
|
|
17
|
+
has_many :activity_objects, through: :audiences
|
|
18
|
+
has_many :children, class_name: 'Activity', foreign_key: 'target_id', dependent: :destroy
|
|
19
|
+
has_many :notifications
|
|
20
|
+
|
|
21
|
+
validates :verb, presence: true
|
|
22
|
+
|
|
23
|
+
def comments
|
|
24
|
+
@comments ||= children.joins(:activitable_object).where { activitable_object.activitable_type.eq('Socializer::Comment') }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def actor
|
|
28
|
+
@actor ||= activitable_actor.activitable
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def object
|
|
32
|
+
@object ||= activitable_object.activitable
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def target
|
|
36
|
+
@target ||= activitable_target.activitable
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Selects the activites that either the person made, that is public from a person in
|
|
40
|
+
# one of his circle, or that is shared to one of the circles he is part of.
|
|
41
|
+
#
|
|
42
|
+
# * <tt>options[:provider]</tt> - <tt>nil</tt>, <tt>activities</tt>, <tt>people</tt>, <tt>circles</tt>, <tt>groups</tt>
|
|
43
|
+
# * <tt>options[:actor_id]</tt> - unique identifier of the previously typed provider
|
|
44
|
+
# * <tt>options[:viewer_id]</tt> - who wants to see the activity stream
|
|
45
|
+
#
|
|
46
|
+
# Activity.stream(provider: nil, actor_id: current_user.id, viewer_id: current_user.id)
|
|
47
|
+
def self.stream(options = {})
|
|
48
|
+
options.assert_valid_keys(:provider, :actor_id, :viewer_id)
|
|
49
|
+
|
|
50
|
+
provider = options.delete(:provider)
|
|
51
|
+
actor_uid = options.delete(:actor_id)
|
|
52
|
+
viewer_id = options.delete(:viewer_id)
|
|
53
|
+
|
|
54
|
+
viewer_id = Person.find(viewer_id).guid
|
|
55
|
+
|
|
56
|
+
query = build_query(viewer_id)
|
|
57
|
+
|
|
58
|
+
case provider
|
|
59
|
+
when nil
|
|
60
|
+
# this is your dashboard. display everything about people in circles and yourself.
|
|
61
|
+
query.uniq
|
|
62
|
+
when 'activities'
|
|
63
|
+
# we only want to display a single activity. make sure the viewer is allowed to do so.
|
|
64
|
+
activity_id = actor_uid
|
|
65
|
+
query.where { id.eq(activity_id) }.uniq
|
|
66
|
+
when 'people'
|
|
67
|
+
# this is a user profile. display everything about him that you are allowed to see
|
|
68
|
+
person_id = Person.find(actor_uid).guid
|
|
69
|
+
query.where { actor_id.eq(person_id) }.uniq
|
|
70
|
+
when 'circles'
|
|
71
|
+
# FIXME: Should display notes even if circle has no members and the owner is viewing it.
|
|
72
|
+
# Notes still don't show after adding people to the circles.
|
|
73
|
+
|
|
74
|
+
circles_sql = Circle.select { id }.where { (id.eq actor_uid) & (author_id.eq viewer_id) }
|
|
75
|
+
followed_sql = Tie.select { contact_id }.where { circle_id.in(circles_sql) }
|
|
76
|
+
|
|
77
|
+
query.where { actor_id.in(followed_sql) }.uniq
|
|
78
|
+
when 'groups'
|
|
79
|
+
# this is a group. display everything that was posted to this group as audience
|
|
80
|
+
group_id = Group.find(actor_uid).guid
|
|
81
|
+
# query.where(audiences: {activity_object_id: group_id}).uniq
|
|
82
|
+
query.where { audiences.activity_object_id.eq(group_id) }.uniq
|
|
83
|
+
else
|
|
84
|
+
fail 'Unknown stream provider.'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def self.build_query(viewer_id)
|
|
91
|
+
fail 'viewer_id cannot be nil.' if viewer_id.nil?
|
|
92
|
+
|
|
93
|
+
# for an activity to be interesting, it must correspond to one of these verbs
|
|
94
|
+
verbs_of_interest = %w(post share)
|
|
95
|
+
verbs_of_interest = Verb.where { name.in(verbs_of_interest) }
|
|
96
|
+
|
|
97
|
+
# privacy_levels
|
|
98
|
+
privacy_public = Audience.privacy_level.find_value(:public).value
|
|
99
|
+
privacy_circles = Audience.privacy_level.find_value(:circles).value
|
|
100
|
+
privacy_limited = Audience.privacy_level.find_value(:limited).value
|
|
101
|
+
|
|
102
|
+
query = joins { audiences }.where { verb_id.in(verbs_of_interest) }.where { target_id.eq(nil) }
|
|
103
|
+
|
|
104
|
+
query.where { (audiences.privacy_level == privacy_public) |
|
|
105
|
+
((audiences.privacy_level == privacy_circles) & `#{viewer_id}`.in(my { build_circles_subquery })) |
|
|
106
|
+
((audiences.privacy_level == privacy_limited) & (
|
|
107
|
+
`#{viewer_id}`.in(my { build_limited_circle_subquery(viewer_id) }) |
|
|
108
|
+
audiences.activity_object_id.in(my { build_limited_group_subquery(viewer_id) }) |
|
|
109
|
+
audiences.activity_object_id.in(my { build_limited_viewer_subquery(viewer_id) })
|
|
110
|
+
)) |
|
|
111
|
+
(actor_id == viewer_id) }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Audience : CIRCLES
|
|
115
|
+
# Ensure the audience is CIRCLES and then make sure that the viewer is in those circles
|
|
116
|
+
def self.build_circles_subquery
|
|
117
|
+
# TODO: Convert this to squeel
|
|
118
|
+
|
|
119
|
+
# Retrieve the author's unique identifier
|
|
120
|
+
subquery = 'SELECT socializer_activity_objects.id ' \
|
|
121
|
+
'FROM socializer_activity_objects ' \
|
|
122
|
+
'INNER JOIN socializer_people ' \
|
|
123
|
+
'ON socializer_activity_objects.activitable_id = socializer_people.id ' \
|
|
124
|
+
'WHERE socializer_people.id = socializer_activities.actor_id'
|
|
125
|
+
|
|
126
|
+
Circle.select { id }.where { author_id.in(`#{subquery}`) }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Audience : LIMITED
|
|
130
|
+
# Ensure that the audience is LIMITED and then make sure that the viewer is either
|
|
131
|
+
# part of a circle that is the target audience, or that the viewer is part of
|
|
132
|
+
# a group that is the target audience, or that the viewer is the target audience.
|
|
133
|
+
def self.build_limited_circle_subquery(viewer_id)
|
|
134
|
+
# TODO: Convert this to squeel
|
|
135
|
+
|
|
136
|
+
# Retrieve the circle's unique identifier related to the audience (when the audience
|
|
137
|
+
# is not a circle, this query will simply return nothing)
|
|
138
|
+
limited_circle_id_sql = 'SELECT socializer_circles.id ' \
|
|
139
|
+
'FROM socializer_circles ' \
|
|
140
|
+
'INNER JOIN socializer_activity_objects ' \
|
|
141
|
+
'ON socializer_circles.id = socializer_activity_objects.activitable_id ' \
|
|
142
|
+
"AND socializer_activity_objects.activitable_type = 'Socializer::Circle' " \
|
|
143
|
+
'WHERE socializer_activity_objects.id = socializer_audiences.activity_object_id '
|
|
144
|
+
|
|
145
|
+
# Retrieve all the contacts (people) that are part of those circles
|
|
146
|
+
Tie.select { contact_id }.where { circle_id.in(`#{limited_circle_id_sql}`) }
|
|
147
|
+
|
|
148
|
+
# Ensure that the audience is LIMITED and then make sure that the viewer is either
|
|
149
|
+
# part of a circle that is the target audience, or that the viewer is part of
|
|
150
|
+
# a group that is the target audience, or that the viewer is the target audience.
|
|
151
|
+
# limited_sql = Audience.with_privacy_level(:limited).where{(`"#{viewer_id}"`.in(actor_circles_sql)) | (activity_object_id.in(limited_groups_sql)) | (activity_object_id.eq(viewer_id))}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.build_limited_group_subquery(viewer_id)
|
|
155
|
+
ActivityObject.select { id }.joins { activitable(Group).memberships }.where { socializer_memberships.member_id.eq(viewer_id) }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def self.build_limited_viewer_subquery(viewer_id)
|
|
159
|
+
"( #{viewer_id} )"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class ActivityObject < ActiveRecord::Base
|
|
3
|
+
attr_accessor :scope, :object_ids
|
|
4
|
+
attr_accessible :scope, :object_ids, :activitable_id, :activitable_type, :like_count, :unread_notifications_count
|
|
5
|
+
|
|
6
|
+
belongs_to :activitable, polymorphic: true
|
|
7
|
+
|
|
8
|
+
has_many :notifications
|
|
9
|
+
has_many :audiences # , dependent: :destroy
|
|
10
|
+
# FIXME: This shouldn't need source. See if it is fixed in Rails 4 RC2 or Final
|
|
11
|
+
has_many :activities, through: :audiences, source: :activity
|
|
12
|
+
|
|
13
|
+
has_many :actor_activities, class_name: 'Activity', foreign_key: 'actor_id', dependent: :destroy
|
|
14
|
+
has_many :object_activities, class_name: 'Activity', foreign_key: 'activity_object_id', dependent: :destroy
|
|
15
|
+
has_many :target_activities, class_name: 'Activity', foreign_key: 'target_id', dependent: :destroy
|
|
16
|
+
|
|
17
|
+
# when the embedded object is an actor (person/group)
|
|
18
|
+
# it can be the owner of certain objects.
|
|
19
|
+
has_many :notes, foreign_key: 'author_id'
|
|
20
|
+
has_many :comments, foreign_key: 'author_id'
|
|
21
|
+
has_many :groups, foreign_key: 'author_id'
|
|
22
|
+
has_many :circles, foreign_key: 'author_id'
|
|
23
|
+
|
|
24
|
+
has_many :ties, foreign_key: 'contact_id'
|
|
25
|
+
has_many :memberships, -> { where active: true }, foreign_key: 'member_id'
|
|
26
|
+
|
|
27
|
+
# define a class macro for setting comparaison with activitable_type
|
|
28
|
+
def self.attribute_type_of(*args)
|
|
29
|
+
args.each do |type|
|
|
30
|
+
define_method("#{type}?") { activitable_type == "Socializer::#{type.capitalize}" }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attribute_type_of :note, :activity, :comment, :person, :group, :circle
|
|
35
|
+
|
|
36
|
+
# REFACTOR: DRY this up. Reduce database calls
|
|
37
|
+
# TODO: Rename this method to liked_by
|
|
38
|
+
def likes
|
|
39
|
+
people = []
|
|
40
|
+
query = Activity.joins { verb }.where { activity_object_id.eq(my { id }) }
|
|
41
|
+
|
|
42
|
+
activities_likes = query.where { verb.name.eq('like') }
|
|
43
|
+
activities_likes.each do |activity|
|
|
44
|
+
people.push activity.actor
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
activities_unlikes = query.where { verb.name.eq('unlike') }
|
|
48
|
+
activities_unlikes.each do |activity|
|
|
49
|
+
people.delete_at people.index(activity.actor)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
people
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def like!(person)
|
|
56
|
+
activity = Activity.create! do |a|
|
|
57
|
+
a.actor_id = person.activity_object.id
|
|
58
|
+
a.activity_object_id = id
|
|
59
|
+
a.verb = Verb.find_or_create_by(name: 'like')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Audience.create!(privacy_level: :public, activity_id: activity.id)
|
|
63
|
+
|
|
64
|
+
increment_like_count
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def unlike!(person)
|
|
68
|
+
activity = Activity.create! do |a|
|
|
69
|
+
a.actor_id = person.activity_object.id
|
|
70
|
+
a.activity_object_id = id
|
|
71
|
+
a.verb = Verb.find_or_create_by(name: 'unlike')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Audience.create!(privacy_level: :public, activity_id: activity.id)
|
|
75
|
+
|
|
76
|
+
decrement_like_count
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def share!
|
|
80
|
+
public = Socializer::Audience.privacy_level.find_value(:public).value.to_s
|
|
81
|
+
circles = Socializer::Audience.privacy_level.find_value(:circles).value.to_s
|
|
82
|
+
|
|
83
|
+
activity = Activity.new do |a|
|
|
84
|
+
a.actor_id = actor_id
|
|
85
|
+
a.activity_object_id = id
|
|
86
|
+
a.verb = Verb.find_or_create_by(name: 'share')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# REFACTOR: remove duplication
|
|
90
|
+
if scope == public || scope == circles
|
|
91
|
+
activity.audiences.build(privacy_level: scope)
|
|
92
|
+
else
|
|
93
|
+
object_ids.each do |object_id|
|
|
94
|
+
activity.audiences.build do |a|
|
|
95
|
+
a.privacy_level = :limited
|
|
96
|
+
a.activity_object_id = object_id
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
activity.save!
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def increment_unread_notifications_count
|
|
105
|
+
increment!(:unread_notifications_count)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def increment_like_count
|
|
111
|
+
increment!(:like_count)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def decrement_like_count
|
|
115
|
+
decrement!(:like_count)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Audience < ActiveRecord::Base
|
|
3
|
+
extend Enumerize
|
|
4
|
+
|
|
5
|
+
enumerize :privacy_level, in: { public: 1, circles: 2, limited: 3 }, default: :public, predicates: true, scope: true
|
|
6
|
+
|
|
7
|
+
attr_accessible :activity_id, :privacy_level
|
|
8
|
+
|
|
9
|
+
belongs_to :activity
|
|
10
|
+
belongs_to :activity_object
|
|
11
|
+
|
|
12
|
+
validates :activity_id, presence: true, uniqueness: { scope: :activity_object_id }
|
|
13
|
+
validates :privacy_level, presence: true
|
|
14
|
+
|
|
15
|
+
def object
|
|
16
|
+
@object ||= activity_object.activitable
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Authentication < ActiveRecord::Base
|
|
3
|
+
attr_accessible :provider, :uid, :image_url
|
|
4
|
+
|
|
5
|
+
belongs_to :person
|
|
6
|
+
|
|
7
|
+
before_destroy :make_sure_its_not_the_last_one
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def make_sure_its_not_the_last_one
|
|
12
|
+
if person.authentications.count == 1
|
|
13
|
+
# FIXME: authentication - This is not be a good user experience.
|
|
14
|
+
# If the user clicks 'unbind' on their last authentication they will get an error.
|
|
15
|
+
# A flash notice should be set and the user should be able to continue on.
|
|
16
|
+
fail 'Cannot delete the last authentication available.'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Circle < ActiveRecord::Base
|
|
3
|
+
include Socializer::ObjectTypeBase
|
|
4
|
+
|
|
5
|
+
attr_accessible :name, :content
|
|
6
|
+
|
|
7
|
+
belongs_to :activity_author, class_name: 'ActivityObject', foreign_key: 'author_id'
|
|
8
|
+
|
|
9
|
+
has_many :ties
|
|
10
|
+
has_many :activity_contacts, through: :ties
|
|
11
|
+
|
|
12
|
+
validates :name, presence: true, uniqueness: { scope: :author_id }
|
|
13
|
+
|
|
14
|
+
def author
|
|
15
|
+
@author ||= activity_author.activitable
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def contacts
|
|
19
|
+
@contacts ||= activity_contacts.map { |ec| ec.activitable }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add_contact(contact_id)
|
|
23
|
+
@tie = ties.build(contact_id: contact_id)
|
|
24
|
+
@tie.save
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def remove_contact(contact_id)
|
|
28
|
+
@tie = ties.find_by(contact_id: contact_id)
|
|
29
|
+
@tie.destroy
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Comment < ActiveRecord::Base
|
|
3
|
+
include Socializer::ObjectTypeBase
|
|
4
|
+
|
|
5
|
+
attr_accessible :content
|
|
6
|
+
|
|
7
|
+
belongs_to :activity_author, class_name: 'ActivityObject', foreign_key: 'author_id'
|
|
8
|
+
|
|
9
|
+
def author
|
|
10
|
+
@author ||= activity_author.activitable
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module Socializer
|
|
2
|
+
class Group < ActiveRecord::Base
|
|
3
|
+
extend Enumerize
|
|
4
|
+
include Socializer::ObjectTypeBase
|
|
5
|
+
|
|
6
|
+
enumerize :privacy_level, in: { public: 1, restricted: 2, private: 3 }, default: :public, predicates: true, scope: true
|
|
7
|
+
|
|
8
|
+
attr_accessible :name, :privacy_level, :author_id
|
|
9
|
+
|
|
10
|
+
# Relationships
|
|
11
|
+
belongs_to :activity_author, class_name: 'ActivityObject', foreign_key: 'author_id'
|
|
12
|
+
|
|
13
|
+
has_many :memberships
|
|
14
|
+
has_many :activity_members, -> { where(socializer_memberships: { active: true }) }, through: :memberships
|
|
15
|
+
has_many :links, class_name: 'GroupLink', foreign_key: 'group_id', dependent: :destroy
|
|
16
|
+
has_many :categories, class_name: 'GroupCategory', foreign_key: 'group_id', dependent: :destroy
|
|
17
|
+
|
|
18
|
+
# Validations
|
|
19
|
+
validates :author_id, presence: true
|
|
20
|
+
validates :name, presence: true, uniqueness: { scope: :author_id }
|
|
21
|
+
validates :privacy_level, presence: true
|
|
22
|
+
|
|
23
|
+
# Callbacks
|
|
24
|
+
after_create :add_author_to_members
|
|
25
|
+
before_destroy :deny_delete_if_members
|
|
26
|
+
|
|
27
|
+
# Named Scopes
|
|
28
|
+
|
|
29
|
+
# Class Methods
|
|
30
|
+
def self.public
|
|
31
|
+
Group.with_privacy_level(:public)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.restricted
|
|
35
|
+
Group.with_privacy_level(:restricted)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.private
|
|
39
|
+
Group.with_privacy_level(:private)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.joinable
|
|
43
|
+
Group.with_privacy_level(:public, :restricted)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Instance Methods
|
|
47
|
+
def author
|
|
48
|
+
@author ||= activity_author.activitable
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def members
|
|
52
|
+
@members ||= activity_members.map { |em| em.activitable }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def join(person)
|
|
56
|
+
@membership = person.memberships.build(group_id: id)
|
|
57
|
+
|
|
58
|
+
if privacy_level.public?
|
|
59
|
+
@membership.active = true
|
|
60
|
+
elsif privacy_level.restricted?
|
|
61
|
+
@membership.active = false
|
|
62
|
+
else
|
|
63
|
+
fail 'Cannot self-join a private group, you need to be invited'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@membership.save
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def invite(person)
|
|
70
|
+
@membership = person.memberships.build(group_id: id)
|
|
71
|
+
|
|
72
|
+
@membership.active = false
|
|
73
|
+
@membership.save
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def leave(person)
|
|
77
|
+
@membership = person.memberships.find_by(group_id: id)
|
|
78
|
+
@membership.destroy
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def member?(person)
|
|
82
|
+
person.memberships.find_by(group_id: id).present?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def add_author_to_members
|
|
88
|
+
@membership = author.memberships.build(group_id: id)
|
|
89
|
+
|
|
90
|
+
@membership.active = true
|
|
91
|
+
@membership.save
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def deny_delete_if_members
|
|
95
|
+
if memberships.count > 0
|
|
96
|
+
fail 'Cannot delete a group that has members in it.'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|