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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +35 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +103 -0
- data/Rakefile +26 -0
- data/app/assets/images/introspective_grape/.keep +0 -0
- data/app/assets/stylesheets/introspective_grape/.keep +0 -0
- data/app/controllers/.keep +0 -0
- data/app/helpers/.keep +0 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/views/.keep +0 -0
- data/bin/rails +12 -0
- data/introspective_grape.gemspec +49 -0
- data/lib/introspective_grape/api.rb +445 -0
- data/lib/introspective_grape/camel_snake.rb +71 -0
- data/lib/introspective_grape/version.rb +3 -0
- data/lib/introspective_grape.rb +4 -0
- data/lib/tasks/introspective_grape_tasks.rake +4 -0
- data/spec/dummy/Gemfile +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/api/active_record_helpers.rb +17 -0
- data/spec/dummy/app/api/api_helpers.rb +36 -0
- data/spec/dummy/app/api/dummy/chat_api.rb +108 -0
- data/spec/dummy/app/api/dummy/company_api.rb +8 -0
- data/spec/dummy/app/api/dummy/entities.rb +25 -0
- data/spec/dummy/app/api/dummy/location_api.rb +37 -0
- data/spec/dummy/app/api/dummy/project_api.rb +51 -0
- data/spec/dummy/app/api/dummy/role_api.rb +7 -0
- data/spec/dummy/app/api/dummy/sessions.rb +55 -0
- data/spec/dummy/app/api/dummy/user_api.rb +32 -0
- data/spec/dummy/app/api/dummy_api.rb +57 -0
- data/spec/dummy/app/api/error_handlers.rb +28 -0
- data/spec/dummy/app/api/permissions_helper.rb +7 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/abstract_adapter.rb +13 -0
- data/spec/dummy/app/models/admin_user.rb +6 -0
- data/spec/dummy/app/models/chat.rb +18 -0
- data/spec/dummy/app/models/chat_message.rb +34 -0
- data/spec/dummy/app/models/chat_message_user.rb +17 -0
- data/spec/dummy/app/models/chat_user.rb +16 -0
- data/spec/dummy/app/models/company.rb +14 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/image.rb +21 -0
- data/spec/dummy/app/models/job.rb +10 -0
- data/spec/dummy/app/models/locatable.rb +6 -0
- data/spec/dummy/app/models/location.rb +26 -0
- data/spec/dummy/app/models/location_beacon.rb +16 -0
- data/spec/dummy/app/models/location_gps.rb +14 -0
- data/spec/dummy/app/models/project.rb +20 -0
- data/spec/dummy/app/models/project_job.rb +7 -0
- data/spec/dummy/app/models/role.rb +30 -0
- data/spec/dummy/app/models/super_user.rb +11 -0
- data/spec/dummy/app/models/team.rb +9 -0
- data/spec/dummy/app/models/team_user.rb +13 -0
- data/spec/dummy/app/models/user/chatter.rb +79 -0
- data/spec/dummy/app/models/user.rb +84 -0
- data/spec/dummy/app/models/user_location.rb +28 -0
- data/spec/dummy/app/models/user_project_job.rb +16 -0
- data/spec/dummy/app/policies/application_policy.rb +47 -0
- data/spec/dummy/app/policies/chat_policy.rb +22 -0
- data/spec/dummy/app/policies/company_policy.rb +32 -0
- data/spec/dummy/app/policies/location_policy.rb +29 -0
- data/spec/dummy/app/policies/project_policy.rb +42 -0
- data/spec/dummy/app/policies/role_policy.rb +33 -0
- data/spec/dummy/app/policies/user_location_policy.rb +12 -0
- data/spec/dummy/app/policies/user_policy.rb +8 -0
- data/spec/dummy/app/views/layouts/application.html.erb +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config/application.rb +38 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +23 -0
- data/spec/dummy/config/environment.rb +11 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +43 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/devise.rb +262 -0
- data/spec/dummy/config/initializers/devise_async.rb +2 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/paperclip.rb +13 -0
- data/spec/dummy/config/initializers/paperclip_adapter.rb +13 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/devise.en.yml +60 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20141002205024_devise_create_users.rb +42 -0
- data/spec/dummy/db/migrate/20141002211055_devise_create_admin_users.rb +48 -0
- data/spec/dummy/db/migrate/20141002211057_create_active_admin_comments.rb +19 -0
- data/spec/dummy/db/migrate/20141002220722_add_lockable_to_users.rb +8 -0
- data/spec/dummy/db/migrate/20150406213646_create_companies.rb +11 -0
- data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +11 -0
- data/spec/dummy/db/migrate/20150415222005_create_roles.rb +12 -0
- data/spec/dummy/db/migrate/20150505181635_create_chats.rb +9 -0
- data/spec/dummy/db/migrate/20150505181636_create_chat_users.rb +11 -0
- data/spec/dummy/db/migrate/20150505181640_create_chat_messages.rb +11 -0
- data/spec/dummy/db/migrate/20150507191529_create_chat_message_users.rb +11 -0
- data/spec/dummy/db/migrate/20150601200526_create_locations.rb +12 -0
- data/spec/dummy/db/migrate/20150601200533_create_locatables.rb +10 -0
- data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +15 -0
- data/spec/dummy/db/migrate/20150601213542_create_location_gps.rb +12 -0
- data/spec/dummy/db/migrate/20150609201823_create_user_locations.rb +14 -0
- data/spec/dummy/db/migrate/20150616205336_add_role_user_constraint.rb +9 -0
- data/spec/dummy/db/migrate/20150617232519_create_projects.rb +10 -0
- data/spec/dummy/db/migrate/20150617232521_create_jobs.rb +9 -0
- data/spec/dummy/db/migrate/20150617232522_create_project_jobs.rb +11 -0
- data/spec/dummy/db/migrate/20150623170133_create_user_project_jobs.rb +12 -0
- data/spec/dummy/db/migrate/20150701234929_create_teams.rb +11 -0
- data/spec/dummy/db/migrate/20150701234930_create_team_users.rb +11 -0
- data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +11 -0
- data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +6 -0
- data/spec/dummy/db/migrate/20150824215701_create_images.rb +15 -0
- data/spec/dummy/db/migrate/20150909225019_add_password_to_project.rb +5 -0
- data/spec/dummy/db/schema.rb +278 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fixtures/images/avatar.jpeg +0 -0
- data/spec/fixtures/images/exif.jpeg +0 -0
- data/spec/models/chat_spec.rb +32 -0
- data/spec/models/image_spec.rb +14 -0
- data/spec/models/locatable_spec.rb +10 -0
- data/spec/models/project_spec.rb +17 -0
- data/spec/models/role_spec.rb +63 -0
- data/spec/models/team_spec.rb +17 -0
- data/spec/models/team_user_spec.rb +20 -0
- data/spec/models/user_location_spec.rb +35 -0
- data/spec/models/user_project_job_spec.rb +30 -0
- data/spec/models/user_spec.rb +125 -0
- data/spec/rails_helper.rb +23 -0
- data/spec/requests/chat_api_spec.rb +174 -0
- data/spec/requests/company_api_spec.rb +61 -0
- data/spec/requests/location_api_spec.rb +96 -0
- data/spec/requests/project_api_spec.rb +151 -0
- data/spec/requests/role_api_spec.rb +37 -0
- data/spec/requests/sessions_api_spec.rb +55 -0
- data/spec/requests/user_api_spec.rb +191 -0
- data/spec/support/blueprints.rb +103 -0
- data/spec/support/location_helper.rb +56 -0
- data/spec/support/pundit_helpers.rb +13 -0
- data/spec/support/request_helpers.rb +22 -0
- 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,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,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,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
|
+
|
data/spec/dummy/bin/rake
ADDED
|
@@ -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
|