introspective_grape 0.0.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.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +35 -0
  4. data/Gemfile +15 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +103 -0
  7. data/Rakefile +26 -0
  8. data/app/assets/images/introspective_grape/.keep +0 -0
  9. data/app/assets/stylesheets/introspective_grape/.keep +0 -0
  10. data/app/controllers/.keep +0 -0
  11. data/app/helpers/.keep +0 -0
  12. data/app/mailers/.keep +0 -0
  13. data/app/models/.keep +0 -0
  14. data/app/views/.keep +0 -0
  15. data/bin/rails +12 -0
  16. data/introspective_grape.gemspec +49 -0
  17. data/lib/introspective_grape/api.rb +445 -0
  18. data/lib/introspective_grape/camel_snake.rb +71 -0
  19. data/lib/introspective_grape/version.rb +3 -0
  20. data/lib/introspective_grape.rb +4 -0
  21. data/lib/tasks/introspective_grape_tasks.rake +4 -0
  22. data/spec/dummy/Gemfile +4 -0
  23. data/spec/dummy/README.rdoc +28 -0
  24. data/spec/dummy/Rakefile +6 -0
  25. data/spec/dummy/app/api/active_record_helpers.rb +17 -0
  26. data/spec/dummy/app/api/api_helpers.rb +36 -0
  27. data/spec/dummy/app/api/dummy/chat_api.rb +108 -0
  28. data/spec/dummy/app/api/dummy/company_api.rb +8 -0
  29. data/spec/dummy/app/api/dummy/entities.rb +25 -0
  30. data/spec/dummy/app/api/dummy/location_api.rb +37 -0
  31. data/spec/dummy/app/api/dummy/project_api.rb +51 -0
  32. data/spec/dummy/app/api/dummy/role_api.rb +7 -0
  33. data/spec/dummy/app/api/dummy/sessions.rb +55 -0
  34. data/spec/dummy/app/api/dummy/user_api.rb +32 -0
  35. data/spec/dummy/app/api/dummy_api.rb +57 -0
  36. data/spec/dummy/app/api/error_handlers.rb +28 -0
  37. data/spec/dummy/app/api/permissions_helper.rb +7 -0
  38. data/spec/dummy/app/assets/images/.keep +0 -0
  39. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  40. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  41. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  42. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  43. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  44. data/spec/dummy/app/mailers/.keep +0 -0
  45. data/spec/dummy/app/models/.keep +0 -0
  46. data/spec/dummy/app/models/abstract_adapter.rb +13 -0
  47. data/spec/dummy/app/models/admin_user.rb +6 -0
  48. data/spec/dummy/app/models/chat.rb +18 -0
  49. data/spec/dummy/app/models/chat_message.rb +34 -0
  50. data/spec/dummy/app/models/chat_message_user.rb +17 -0
  51. data/spec/dummy/app/models/chat_user.rb +16 -0
  52. data/spec/dummy/app/models/company.rb +14 -0
  53. data/spec/dummy/app/models/concerns/.keep +0 -0
  54. data/spec/dummy/app/models/image.rb +21 -0
  55. data/spec/dummy/app/models/job.rb +10 -0
  56. data/spec/dummy/app/models/locatable.rb +6 -0
  57. data/spec/dummy/app/models/location.rb +26 -0
  58. data/spec/dummy/app/models/location_beacon.rb +16 -0
  59. data/spec/dummy/app/models/location_gps.rb +14 -0
  60. data/spec/dummy/app/models/project.rb +20 -0
  61. data/spec/dummy/app/models/project_job.rb +7 -0
  62. data/spec/dummy/app/models/role.rb +30 -0
  63. data/spec/dummy/app/models/super_user.rb +11 -0
  64. data/spec/dummy/app/models/team.rb +9 -0
  65. data/spec/dummy/app/models/team_user.rb +13 -0
  66. data/spec/dummy/app/models/user/chatter.rb +79 -0
  67. data/spec/dummy/app/models/user.rb +84 -0
  68. data/spec/dummy/app/models/user_location.rb +28 -0
  69. data/spec/dummy/app/models/user_project_job.rb +16 -0
  70. data/spec/dummy/app/policies/application_policy.rb +47 -0
  71. data/spec/dummy/app/policies/chat_policy.rb +22 -0
  72. data/spec/dummy/app/policies/company_policy.rb +32 -0
  73. data/spec/dummy/app/policies/location_policy.rb +29 -0
  74. data/spec/dummy/app/policies/project_policy.rb +42 -0
  75. data/spec/dummy/app/policies/role_policy.rb +33 -0
  76. data/spec/dummy/app/policies/user_location_policy.rb +12 -0
  77. data/spec/dummy/app/policies/user_policy.rb +8 -0
  78. data/spec/dummy/app/views/layouts/application.html.erb +13 -0
  79. data/spec/dummy/bin/bundle +3 -0
  80. data/spec/dummy/bin/rails +4 -0
  81. data/spec/dummy/bin/rake +4 -0
  82. data/spec/dummy/bin/setup +29 -0
  83. data/spec/dummy/config/application.rb +38 -0
  84. data/spec/dummy/config/boot.rb +6 -0
  85. data/spec/dummy/config/database.yml +23 -0
  86. data/spec/dummy/config/environment.rb +11 -0
  87. data/spec/dummy/config/environments/development.rb +41 -0
  88. data/spec/dummy/config/environments/production.rb +79 -0
  89. data/spec/dummy/config/environments/test.rb +43 -0
  90. data/spec/dummy/config/initializers/assets.rb +11 -0
  91. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  92. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  93. data/spec/dummy/config/initializers/devise.rb +262 -0
  94. data/spec/dummy/config/initializers/devise_async.rb +2 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/spec/dummy/config/initializers/inflections.rb +16 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  98. data/spec/dummy/config/initializers/paperclip.rb +13 -0
  99. data/spec/dummy/config/initializers/paperclip_adapter.rb +13 -0
  100. data/spec/dummy/config/initializers/session_store.rb +3 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  102. data/spec/dummy/config/locales/devise.en.yml +60 -0
  103. data/spec/dummy/config/locales/en.yml +23 -0
  104. data/spec/dummy/config/routes.rb +8 -0
  105. data/spec/dummy/config/secrets.yml +22 -0
  106. data/spec/dummy/config.ru +4 -0
  107. data/spec/dummy/db/migrate/20141002205024_devise_create_users.rb +42 -0
  108. data/spec/dummy/db/migrate/20141002211055_devise_create_admin_users.rb +48 -0
  109. data/spec/dummy/db/migrate/20141002211057_create_active_admin_comments.rb +19 -0
  110. data/spec/dummy/db/migrate/20141002220722_add_lockable_to_users.rb +8 -0
  111. data/spec/dummy/db/migrate/20150406213646_create_companies.rb +11 -0
  112. data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +11 -0
  113. data/spec/dummy/db/migrate/20150415222005_create_roles.rb +12 -0
  114. data/spec/dummy/db/migrate/20150505181635_create_chats.rb +9 -0
  115. data/spec/dummy/db/migrate/20150505181636_create_chat_users.rb +11 -0
  116. data/spec/dummy/db/migrate/20150505181640_create_chat_messages.rb +11 -0
  117. data/spec/dummy/db/migrate/20150507191529_create_chat_message_users.rb +11 -0
  118. data/spec/dummy/db/migrate/20150601200526_create_locations.rb +12 -0
  119. data/spec/dummy/db/migrate/20150601200533_create_locatables.rb +10 -0
  120. data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +15 -0
  121. data/spec/dummy/db/migrate/20150601213542_create_location_gps.rb +12 -0
  122. data/spec/dummy/db/migrate/20150609201823_create_user_locations.rb +14 -0
  123. data/spec/dummy/db/migrate/20150616205336_add_role_user_constraint.rb +9 -0
  124. data/spec/dummy/db/migrate/20150617232519_create_projects.rb +10 -0
  125. data/spec/dummy/db/migrate/20150617232521_create_jobs.rb +9 -0
  126. data/spec/dummy/db/migrate/20150617232522_create_project_jobs.rb +11 -0
  127. data/spec/dummy/db/migrate/20150623170133_create_user_project_jobs.rb +12 -0
  128. data/spec/dummy/db/migrate/20150701234929_create_teams.rb +11 -0
  129. data/spec/dummy/db/migrate/20150701234930_create_team_users.rb +11 -0
  130. data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +11 -0
  131. data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +6 -0
  132. data/spec/dummy/db/migrate/20150824215701_create_images.rb +15 -0
  133. data/spec/dummy/db/migrate/20150909225019_add_password_to_project.rb +5 -0
  134. data/spec/dummy/db/schema.rb +278 -0
  135. data/spec/dummy/lib/assets/.keep +0 -0
  136. data/spec/dummy/log/.keep +0 -0
  137. data/spec/dummy/public/404.html +67 -0
  138. data/spec/dummy/public/422.html +67 -0
  139. data/spec/dummy/public/500.html +66 -0
  140. data/spec/dummy/public/favicon.ico +0 -0
  141. data/spec/fixtures/images/avatar.jpeg +0 -0
  142. data/spec/fixtures/images/exif.jpeg +0 -0
  143. data/spec/models/chat_spec.rb +32 -0
  144. data/spec/models/image_spec.rb +14 -0
  145. data/spec/models/locatable_spec.rb +10 -0
  146. data/spec/models/project_spec.rb +17 -0
  147. data/spec/models/role_spec.rb +63 -0
  148. data/spec/models/team_spec.rb +17 -0
  149. data/spec/models/team_user_spec.rb +20 -0
  150. data/spec/models/user_location_spec.rb +35 -0
  151. data/spec/models/user_project_job_spec.rb +30 -0
  152. data/spec/models/user_spec.rb +125 -0
  153. data/spec/rails_helper.rb +23 -0
  154. data/spec/requests/chat_api_spec.rb +174 -0
  155. data/spec/requests/company_api_spec.rb +61 -0
  156. data/spec/requests/location_api_spec.rb +96 -0
  157. data/spec/requests/project_api_spec.rb +151 -0
  158. data/spec/requests/role_api_spec.rb +37 -0
  159. data/spec/requests/sessions_api_spec.rb +55 -0
  160. data/spec/requests/user_api_spec.rb +191 -0
  161. data/spec/support/blueprints.rb +103 -0
  162. data/spec/support/location_helper.rb +56 -0
  163. data/spec/support/pundit_helpers.rb +13 -0
  164. data/spec/support/request_helpers.rb +22 -0
  165. metadata +562 -0
@@ -0,0 +1,26 @@
1
+ class Location < AbstractAdapter
2
+ has_many :locatables, dependent: :destroy
3
+ has_many :companies, through: :locatables, source: :locatable, source_type: 'Company'
4
+
5
+ has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
6
+ has_one :gps, class_name: 'LocationGps', dependent: :destroy
7
+ delegate :lat,:lng,:alt, to: :gps
8
+
9
+ belongs_to :parent_location, foreign_key: :parent_location_id, class_name: 'Location', inverse_of: :child_locations
10
+ has_many :child_locations, foreign_key: :parent_location_id, class_name: 'Location', dependent: :destroy, inverse_of: :parent_location
11
+
12
+ has_many :user_locations, dependent: :destroy
13
+
14
+ # isn't this list going to be kinda long? are there any reasonable constraints to put
15
+ # on this random bit of metadata?
16
+ validates_inclusion_of :kind, in: %w(airport terminal gate plane)
17
+
18
+ accepts_nested_attributes_for :child_locations, allow_destroy: true
19
+ accepts_nested_attributes_for :gps, allow_destroy: true
20
+ accepts_nested_attributes_for :beacons, allow_destroy: true
21
+
22
+ def coords
23
+ [gps.lat, gps.lng, gps.alt]
24
+ end
25
+
26
+ end
@@ -0,0 +1,16 @@
1
+ class LocationBeacon < AbstractAdapter
2
+ belongs_to :location
3
+ has_many :gps, through: :location
4
+ belongs_to :company
5
+
6
+ # B9407F30-F5F8-466E-AFF9-25556B57FE6D
7
+ validates_format_of :uuid, with: /[0-9a-fA-F]{32}/ # 32 digit hexadecimal UUID
8
+ validates_format_of :mac_address, with: /[0-9a-fA-F]{12}/ # 16 digit hexadecimal bluetooth MAC address
9
+
10
+ before_validation :massage_ids
11
+ def massage_ids
12
+ self.uuid = (uuid||'').gsub(/[^0-9a-fA-F]+/,'').upcase
13
+ self.mac_address = (mac_address||'').gsub(/[^0-9a-fA-F]+/,'').upcase
14
+ end
15
+
16
+ end
@@ -0,0 +1,14 @@
1
+ class LocationGps < AbstractAdapter
2
+ belongs_to :location
3
+ has_many :beacons, through: :location
4
+
5
+ # lat and lng in degrees altitude in meters
6
+ validates_numericality_of :lat, greater_than_or_equal_to: -90.0, less_than_or_equal_to: 90.0
7
+ validates_numericality_of :lng, greater_than_or_equal_to: -180.0, less_than_or_equal_to: 180.0
8
+ validates_numericality_of :alt
9
+
10
+ def distance_from(lat,lng) # calc distance between this location and the passed coords
11
+ Haversine.distance(self.lat,self.lng, lat,lng).to_meters
12
+ end
13
+
14
+ end
@@ -0,0 +1,20 @@
1
+ class Project < AbstractAdapter
2
+ belongs_to :owner, foreign_key: :owner_id, class_name: 'Company'
3
+
4
+ has_many :roles, as: :ownable
5
+ has_many :admins, through: :roles, source: :user
6
+ accepts_nested_attributes_for :roles, allow_destroy: true
7
+
8
+ has_many :project_jobs, dependent: :destroy, inverse_of: :project
9
+ has_many :jobs, through: :project_jobs
10
+ accepts_nested_attributes_for :project_jobs, allow_destroy: true
11
+
12
+ has_many :user_project_jobs, dependent: :destroy, inverse_of: :project
13
+ has_many :users, through: :user_project_jobs, inverse_of: :projects
14
+ accepts_nested_attributes_for :user_project_jobs, allow_destroy: true
15
+
16
+ has_many :teams, dependent: :destroy, inverse_of: :project
17
+ accepts_nested_attributes_for :teams, allow_destroy: true
18
+
19
+
20
+ end
@@ -0,0 +1,7 @@
1
+ class ProjectJob < AbstractAdapter
2
+ belongs_to :project
3
+ belongs_to :job
4
+
5
+ delegate :title, to: :job
6
+
7
+ end
@@ -0,0 +1,30 @@
1
+ class Role < AbstractAdapter
2
+ belongs_to :user
3
+ belongs_to :ownable, polymorphic: true
4
+
5
+ validates_uniqueness_of :user_id, scope: [:ownable_type,:ownable_id], unless: "user_id.nil?", message: "user has already been assigned that role"
6
+ validates_inclusion_of :ownable_type, in: ['SuperUser', 'Company', 'Project']
7
+
8
+ delegate :email, to: :user, allow_nil: true
9
+ def attributes
10
+ super.merge(email: email)
11
+ end
12
+
13
+ def ownable
14
+ # return the SuperUser null object
15
+ ownable_type == 'SuperUser' ? SuperUser.new : super
16
+ end
17
+
18
+ def self.ownable_assign_options(model=nil)
19
+ ([SuperUser.new] + Company.all + Project.all).map { |i| [ "#{i.class}: #{i.name}", "#{i.class}-#{i.id}"] }
20
+ end
21
+
22
+ def ownable_assign
23
+ ownable.present? ? "#{ownable_type}-#{ownable_id}" : nil
24
+ end
25
+
26
+ def ownable_assign=(value)
27
+ self.ownable_type,self.ownable_id = value.split('-')
28
+ end
29
+
30
+ end
@@ -0,0 +1,11 @@
1
+ #require 'activerecord-tableless'
2
+ class SuperUser < AbstractAdapter
3
+ # An empty ActiveRecord association for the polymorphic identity on Role.
4
+ # We could also just create a SuperUser table with one record to do this...
5
+ has_no_table :database => :pretend_success
6
+
7
+ def name
8
+ 'Admin'
9
+ end
10
+
11
+ end
@@ -0,0 +1,9 @@
1
+ class Team < AbstractAdapter
2
+ belongs_to :project
3
+ belongs_to :creator, class_name: 'User'
4
+
5
+ has_many :team_users, inverse_of: :team
6
+ has_many :users, through: :team_users
7
+ accepts_nested_attributes_for :team_users, allow_destroy: true
8
+
9
+ end
@@ -0,0 +1,13 @@
1
+ class TeamUser < AbstractAdapter
2
+ belongs_to :user
3
+ belongs_to :team
4
+
5
+ validate :user_on_project
6
+
7
+ def user_on_project
8
+ unless user && team && user.projects.include?(team.project)
9
+ errors.add(:user, "#{user.try(:name)} is not on the #{team.try(:project).try(:name)} project")
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,79 @@
1
+ module User::Chatter
2
+
3
+ def message_query(chat_id, new = true)
4
+ messages.joins(:chat_message_users)
5
+ .where('chat_message_users.user_id'=> id)
6
+ .where(new ? {'chat_message_users.read_at'=>nil} : '')
7
+ .where(chat_id ? {'chat_messages.chat_id'=> chat_id} : '')
8
+ .order('') # or it will add an order by id clause that breaks the count query.
9
+ end
10
+
11
+ def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
12
+ chat_id = chat.kind_of?(Chat) ? chat.id : chat
13
+ new = message_query(chat_id, new = true)
14
+ .select("chat_messages.chat_id, count(chat_messages.id) as count")
15
+ .group('chat_id')
16
+
17
+ chat ? { chat_id => new.first.try(:count)||0 } : Hash[new.map {|c| [c.chat_id, c.count]} ]
18
+ end
19
+
20
+ def read_messages(chat= nil, mark_as_read= false, new= true)
21
+ chat_id = chat.kind_of?(Chat) ? chat.id : chat
22
+ new = message_query(chat_id, new).order('chat_messages.created_at').includes(:author) # :chat?
23
+ new.map(&:chat).uniq.each {|chat| mark_as_read(chat) } if mark_as_read
24
+ new
25
+ end
26
+
27
+ def chat(users, message)
28
+ users = [users].flatten
29
+ users = users.first.kind_of?(User) ? users : User.where(id: users)
30
+ chat = Chat.create(creator: self)
31
+ chat.users.push users
32
+ chat.messages.build(message: message, author: self)
33
+ chat.save!
34
+ chat
35
+ end
36
+
37
+ def reply(chat, message)
38
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
39
+ mark_as_read(chat) # a reply implies that the thread has been read
40
+ chat.messages.build(message: message, author: self)
41
+ chat.save!
42
+ chat
43
+ end
44
+
45
+ def add_chatters(chat, users)
46
+ users = [users].flatten
47
+ users = users.first.kind_of?(User) ? users : User.where(id: users)
48
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
49
+
50
+ if chat.active_users.include?(self) # only current participants can add new users
51
+ chat.users.push users
52
+ chat.messages.build(chat: chat, author: self, message: "#{self.name} [[ADDED_USER_MESSAGE]] #{users.map(&:name).join(',')}")
53
+ chat.save!
54
+ else
55
+ chat.errors[:base] << "Only current chat participants can add users."
56
+ raise ActiveRecord::RecordInvalid.new(chat)
57
+ end
58
+ end
59
+
60
+ def leave_chat(chat)
61
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
62
+
63
+ if chat.active_users.include?(self)
64
+ reply(chat, "#{name} [[DEPARTS_MESSAGE]]")
65
+ chat.chat_users.detect {|cu| cu.user_id == self.id}.update_attributes(departed_at: Time.now)
66
+ else
67
+ true
68
+ end
69
+ end
70
+
71
+ def mark_as_read(chat)
72
+ ChatMessageUser.joins(:chat_message).where('read_at IS NULL AND chat_messages.chat_id = ? AND user_id = ?', chat.id, id).update_all(read_at: Time.now)
73
+ end
74
+
75
+ def mark_messages_as_read(messages)
76
+ chat_message_users.where("chat_message_id in (?) and read_at IS NULL", messages.map(&:id)).update_all(read_at: Time.now)
77
+ end
78
+
79
+ end
@@ -0,0 +1,84 @@
1
+ #require 'devise/async'
2
+ class User < AbstractAdapter
3
+ # Include default devise modules. Others available are:
4
+ # :confirmable, :lockable, :timeoutable and :omniauthable
5
+ devise :database_authenticatable, :registerable, :async, :confirmable,
6
+ :recoverable, :rememberable, :trackable, :validatable, :lockable
7
+
8
+ scope :active, -> { where(:locked_at => nil) }
9
+ scope :inactive, -> { where('locked_at is not null') }
10
+
11
+ has_many :user_locations, dependent: :destroy
12
+
13
+ has_many :user_project_jobs, dependent: :destroy, inverse_of: :user
14
+ has_many :jobs, through: :user_project_jobs, inverse_of: :users
15
+ has_many :projects, through: :user_project_jobs, inverse_of: :users
16
+ accepts_nested_attributes_for :user_project_jobs
17
+
18
+ before_validation :set_default_password_from_project, on: :create
19
+
20
+ has_many :team_users
21
+ has_many :teams, through: :team_users
22
+
23
+ has_one :avatar, class_name: 'Image', as: :imageable
24
+ accepts_nested_attributes_for :avatar, allow_destroy: true
25
+
26
+
27
+ has_many :own_chats, foreign_key: :creator_id, class_name: 'Chat'
28
+ has_many :chat_users
29
+ has_many :chats, through: :chat_users
30
+ has_many :chat_message_users
31
+ has_many :messages, ->{ where('chat_messages.created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR chat_messages.created_at <= chat_users.departed_at)') }, through: :chats
32
+ include User::Chatter
33
+
34
+ has_many :roles, dependent: :destroy, inverse_of: :user
35
+ accepts_nested_attributes_for :roles, allow_destroy: true
36
+ has_many :admin_companies, through: :roles, source: :ownable, source_type: Company
37
+ has_many :admin_projects, through: :roles, source: :ownable, source_type: Project
38
+
39
+ def all_admin_projects # aggregate companies' projects with project admin roles
40
+ (admin_companies.map(&:projects)+admin_projects).flatten
41
+ end
42
+
43
+ def superuser?
44
+ roles && roles.detect{|r| r.ownable_type == 'SuperUser' }.present?
45
+ end
46
+
47
+ def admin?(record)
48
+ superuser? || roles.detect{|r| r.ownable == record }.present?
49
+ end
50
+
51
+ def company_admin? # an admin of any company
52
+ superuser? || roles.detect{|r| r.ownable_type == 'Company' }.present?
53
+ end
54
+
55
+ def project_admin? # an admin of any project
56
+ superuser? || company_admin? || roles.detect{|r| r.ownable_type == 'Project' }.present?
57
+ end
58
+
59
+
60
+ def set_default_password_from_project
61
+ self.password = user_project_jobs.first.try(:project).try(:default_password) if password.blank?
62
+ end
63
+
64
+ def name
65
+ [first_name,last_name].delete_if(&:blank?).join(' ')
66
+ end
67
+
68
+ def avatar_url(size='medium')
69
+ avatar.try(:file).try(:url,size)
70
+ end
71
+
72
+ def self.attribute_param_types
73
+ { "skip_confirmation_email" => Virtus::Attribute::Boolean }
74
+ end
75
+
76
+ def skip_confirmation_email=(s)
77
+ return unless s.to_s == "true"
78
+ # skip_confirmation! does not work with update_attributes, a work-around:
79
+ self.update_column(:email, email) && self.reload if self.valid? && self.id
80
+ # devise: confirm the user without requiring a confirmation email
81
+ self.skip_confirmation!
82
+ end
83
+
84
+ end
@@ -0,0 +1,28 @@
1
+ class UserLocation < AbstractAdapter
2
+ belongs_to :user
3
+ belongs_to :location
4
+ belongs_to :detectable, polymorphic: true
5
+
6
+ validates_inclusion_of :detectable_type, in: %w(LocationBeacon LocationGps)
7
+
8
+ default_scope { includes(:detectable).order("created_at desc") }
9
+
10
+ def coords=(c) # convenience method to set coordinates by an array of [lat,lng,alt]
11
+ self.lat = c[0]
12
+ self.lng = c[1]
13
+ self.alt = c[2]
14
+ end
15
+
16
+ def beacon
17
+ detectable.is_a?(LocationBeacon) ? detectable : {}
18
+ end
19
+
20
+ def distance
21
+ if location.gps && lat && lng
22
+ location.gps.distance_from(lat,lng)
23
+ else
24
+ nil
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,16 @@
1
+ class UserProjectJob < AbstractAdapter
2
+ belongs_to :user, inverse_of: :user_project_jobs
3
+ belongs_to :project, inverse_of: :user_project_jobs
4
+ belongs_to :job, inverse_of: :user_project_jobs
5
+
6
+ validates_inclusion_of :job, in: proc {|r| r.project.try(:jobs) || [] }
7
+
8
+ delegate :email, :avatar_url, to: :user
9
+ delegate :title, to: :job
10
+ delegate :name, to: :project
11
+
12
+ def self.options_for_job(project=nil)
13
+ project.jobs
14
+ end
15
+
16
+ end
@@ -0,0 +1,47 @@
1
+ class ApplicationPolicy
2
+ attr_reader :user, :record
3
+
4
+ def initialize(user, record)
5
+ @user = user
6
+ @record = record
7
+ end
8
+
9
+ def index?
10
+ @user.superuser?
11
+ end
12
+
13
+ def show?
14
+ @user.superuser? || scope.where(:id => record.id).exists?
15
+ end
16
+
17
+ def create?
18
+ @user.superuser?
19
+ end
20
+
21
+ def update?
22
+ @user.superuser?
23
+ end
24
+
25
+ def destroy?
26
+ @user.superuser?
27
+ end
28
+
29
+ def scope
30
+ Pundit.policy_scope!(user, record.class)
31
+ end
32
+
33
+ class Scope
34
+ attr_reader :user, :scope
35
+
36
+ def initialize(user, scope)
37
+ @user = user
38
+ @scope = scope
39
+ end
40
+
41
+ def resolve
42
+ scope.all
43
+ end
44
+ end
45
+
46
+ end
47
+
@@ -0,0 +1,22 @@
1
+ class ChatPolicy
2
+ attr_reader :user, :record
3
+
4
+ def initialize(user, record)
5
+ @user = user
6
+ @record = record
7
+ end
8
+
9
+ def index?
10
+ @user
11
+ end
12
+
13
+ def show?
14
+ @user
15
+ end
16
+
17
+ def create?
18
+ @user
19
+ end
20
+
21
+ end
22
+
@@ -0,0 +1,32 @@
1
+ class CompanyPolicy < ApplicationPolicy
2
+ def index?
3
+ @user
4
+ end
5
+
6
+ def show?
7
+ @user && @user.admin?(record)
8
+ end
9
+
10
+ def update?
11
+ @user && @user.admin?(record)
12
+ end
13
+
14
+ def create?
15
+ @user && @user.admin?(record)
16
+ end
17
+
18
+ def destroy?
19
+ false
20
+ end
21
+
22
+ class Scope < ApplicationPolicy::Scope
23
+ def resolve
24
+ if user.superuser?
25
+ scope.all
26
+ else
27
+ scope.find( user.companies.map{|c| c.id} )
28
+ end
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,29 @@
1
+ class LocationPolicy < ApplicationPolicy
2
+ def index?
3
+ @user
4
+ end
5
+
6
+ def show?
7
+ @user
8
+ end
9
+
10
+ def update?
11
+ @user && @user.superuser?
12
+ end
13
+
14
+ def create?
15
+ @user && @user.superuser?
16
+ end
17
+
18
+ def destroy?
19
+ @user && @user.superuser?
20
+ end
21
+
22
+ class Scope < ApplicationPolicy::Scope
23
+ def resolve
24
+ scope.where(parent_location_id: nil)
25
+ end
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,42 @@
1
+ class ProjectPolicy < ApplicationPolicy
2
+ def index?
3
+ @user
4
+ end
5
+
6
+ def project_user?
7
+ project_manager? || record.users.include?(@user)
8
+ end
9
+
10
+ def project_manager?
11
+ @user.superuser? || @user.all_admin_projects.include?(record)
12
+ end
13
+
14
+ def show?
15
+ @user && project_user?
16
+ end
17
+
18
+ def update?
19
+ @user && project_manager?
20
+ end
21
+
22
+ def create?
23
+ @user && project_manager?
24
+ end
25
+
26
+ def destroy?
27
+ @user && project_manager?
28
+ end
29
+
30
+ class Scope < ApplicationPolicy::Scope
31
+ def resolve
32
+ if user.superuser?
33
+ scope.all
34
+ elsif user.project_admin?
35
+ scope.find( (user.all_admin_projects+user.projects).map(&:id) )
36
+ else
37
+ scope.find( user.projects )
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,33 @@
1
+ class RolePolicy < ApplicationPolicy
2
+
3
+ def index?
4
+ @user
5
+ end
6
+
7
+ def show?
8
+ @user.admin?(record.ownable)
9
+ end
10
+
11
+ def update?
12
+ @user.admin?(record.ownable)
13
+ end
14
+
15
+ def create?
16
+ @user.admin?(record.ownable)
17
+ end
18
+
19
+ def destroy?
20
+ @user.admin?(record.ownable)
21
+ end
22
+
23
+ class Scope < ApplicationPolicy::Scope
24
+ def resolve
25
+ if user.superuser?
26
+ scope.all
27
+ else
28
+ scope.where(ownable: user.admin_companies )
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,12 @@
1
+ class UserLocationPolicy < ApplicationPolicy
2
+ def index?
3
+ # This will need further specifications once the user-location relationship via
4
+ # their companies is defined via project etc.
5
+ @user && @user.company_admin?
6
+ end
7
+
8
+ def create?
9
+ @user
10
+ end
11
+ end
12
+
@@ -0,0 +1,8 @@
1
+ class UserPolicy < ApplicationPolicy
2
+
3
+ def sessions?
4
+ true
5
+ end
6
+
7
+ end
8
+
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all' %>
6
+ <%= csrf_meta_tags %>
7
+ </head>
8
+ <body>
9
+
10
+ <%= yield %>
11
+
12
+ </body>
13
+ </html>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end