diff --git a/.rubocop.yml b/.rubocop.yml
index 34d5b0bda..e0c98cdc4 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -26,6 +26,8 @@ Style/FrozenStringLiteralComment:
Enabled: false
Style/SymbolArray:
Enabled: false
+Style/OpenStructUse:
+ Enabled: false
Style/OptionalBooleanParameter:
Exclude:
- 'app/services/email_templates/db_resolver_service.rb'
@@ -68,14 +70,20 @@ Rails/ApplicationController:
- 'app/controllers/platform_controller.rb'
- 'app/controllers/public_controller.rb'
- 'app/controllers/survey/responses_controller.rb'
+Rails/CompactBlank:
+ Enabled: false
Rails/EnvironmentVariableAccess:
Enabled: false
Rails/TimeZoneAssignment:
Enabled: false
+Rails/RedundantPresenceValidationOnBelongsTo:
+ Enabled: false
Style/ClassAndModuleChildren:
EnforcedStyle: compact
Exclude:
- 'config/application.rb'
+Style/MapToHash:
+ Enabled: false
RSpec/NestedGroups:
Enabled: true
Max: 4
@@ -83,6 +91,8 @@ RSpec/MessageSpies:
Enabled: false
RSpec/StubbedMock:
Enabled: false
+RSpec/FactoryBot/SyntaxMethods:
+ Enabled: false
Naming/VariableNumber:
Enabled: false
Metrics/MethodLength:
@@ -119,6 +129,7 @@ Rails/ReversibleMigration:
- 'db/migrate/20191020085608_rename_old_tables.rb'
- 'db/migrate/20191126185833_update_user_invite_foreign_key.rb'
- 'db/migrate/20191130164019_add_template_type_to_messages.rb'
+ - 'db/migrate/20210513083044_remove_not_null_from_webhook_url_channel_api.rb'
Rails/BulkChangeTable:
Exclude:
- 'db/migrate/20161025070152_removechannelsfrommodels.rb'
diff --git a/Gemfile.lock b/Gemfile.lock
index 4df118291..5e2abbac6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,8 +56,8 @@ GEM
activerecord (6.1.4.6)
activemodel (= 6.1.4.6)
activesupport (= 6.1.4.6)
- activerecord-import (1.2.0)
- activerecord (>= 3.2)
+ activerecord-import (1.3.0)
+ activerecord (>= 4.2)
activestorage (6.1.4.6)
actionpack (= 6.1.4.6)
activejob (= 6.1.4.6)
@@ -71,11 +71,11 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
- acts-as-taggable-on (8.1.0)
- activerecord (>= 5.0, < 6.2)
+ acts-as-taggable-on (9.0.1)
+ activerecord (>= 6.0, < 7.1)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
- administrate (0.16.0)
+ administrate (0.17.0)
actionpack (>= 5.0)
actionview (>= 5.0)
activerecord (>= 5.0)
@@ -85,46 +85,46 @@ GEM
momentjs-rails (~> 2.8)
sassc-rails (~> 2.1)
selectize-rails (~> 0.6)
- annotate (3.1.1)
- activerecord (>= 3.2, < 7.0)
+ annotate (3.2.0)
+ activerecord (>= 3.2, < 8.0)
rake (>= 10.4, < 14.0)
ast (2.4.2)
- attr_extras (6.2.4)
+ attr_extras (6.2.5)
aws-eventstream (1.2.0)
- aws-partitions (1.513.0)
- aws-sdk-core (3.121.1)
+ aws-partitions (1.556.0)
+ aws-sdk-core (3.126.2)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.239.0)
+ aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
- aws-sdk-kms (1.49.0)
- aws-sdk-core (~> 3, >= 3.120.0)
+ aws-sdk-kms (1.54.0)
+ aws-sdk-core (~> 3, >= 3.126.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.103.0)
- aws-sdk-core (~> 3, >= 3.120.0)
+ aws-sdk-s3 (1.112.0)
+ aws-sdk-core (~> 3, >= 3.126.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
- azure-storage-blob (2.0.1)
+ azure-storage-blob (2.0.3)
azure-storage-common (~> 2.0)
- nokogiri (~> 1.11.0.rc2)
- azure-storage-common (2.0.2)
+ nokogiri (~> 1, >= 1.10.8)
+ azure-storage-common (2.0.4)
faraday (~> 1.0)
- faraday_middleware (~> 1.0.0.rc1)
+ faraday_middleware (~> 1.0, >= 1.0.0.rc1)
net-http-persistent (~> 4.0)
- nokogiri (~> 1.11.0.rc2)
+ nokogiri (~> 1, >= 1.10.8)
barnes (0.0.9)
multi_json (~> 1)
statsd-ruby (~> 1.1)
bcrypt (3.1.16)
bindex (0.8.1)
- bootsnap (1.9.1)
- msgpack (~> 1.0)
- brakeman (5.1.1)
+ bootsnap (1.10.3)
+ msgpack (~> 1.2)
+ brakeman (5.2.1)
browser (5.3.1)
builder (3.2.4)
- bullet (6.1.5)
+ bullet (7.0.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundle-audit (0.1.0)
@@ -141,7 +141,7 @@ GEM
crack (0.4.5)
rexml
crass (1.0.6)
- cypress-on-rails (1.11.0)
+ cypress-on-rails (1.12.1)
rack
database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0)
@@ -151,11 +151,12 @@ GEM
database_cleaner-core (2.0.1)
datetime_picker_rails (0.0.7)
momentjs-rails (>= 2.8.1)
- ddtrace (0.53.0)
- ffi (~> 1.0)
+ ddtrace (0.54.2)
+ debase-ruby_core_source (<= 0.10.14)
msgpack
+ debase-ruby_core_source (0.10.14)
declarative (0.0.20)
- devise (4.8.0)
+ devise (4.8.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@@ -165,7 +166,7 @@ GEM
bcrypt (~> 3.0)
devise (> 3.5.2, < 5)
rails (>= 4.2.0, < 6.2)
- diff-lcs (1.4.4)
+ diff-lcs (1.5.0)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
docile (1.4.0)
@@ -175,14 +176,14 @@ GEM
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
- down (5.2.4)
+ down (5.3.0)
addressable (~> 2.8)
- ecma-re-validator (0.3.0)
- regexp_parser (~> 2.0)
+ ecma-re-validator (0.4.0)
+ regexp_parser (~> 2.2)
email_reply_trimmer (0.1.13)
erubi (1.10.0)
erubis (2.7.0)
- et-orbi (1.2.5)
+ et-orbi (1.2.6)
tzinfo
execjs (2.8.1)
facebook-messenger (2.0.1)
@@ -197,11 +198,11 @@ GEM
i18n (>= 1.6, < 2)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
- faraday_middleware (1.0.0)
+ faraday_middleware (1.2.0)
faraday (~> 1.0)
- fcm (1.0.3)
+ fcm (1.0.5)
faraday (~> 1)
- ffi (1.15.4)
+ ffi (1.15.5)
flag_shih_tzu (0.3.23)
flay (2.12.1)
erubis (~> 2.7.0)
@@ -218,11 +219,11 @@ GEM
googleapis-common-protos-types (>= 1.0.4, < 2.0)
googleauth (~> 0.9)
grpc (~> 1.25)
- geocoder (1.7.0)
- gli (2.20.1)
+ geocoder (1.7.3)
+ gli (2.21.0)
globalid (1.0.0)
activesupport (>= 5.0)
- google-apis-core (0.4.1)
+ google-apis-core (0.4.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -231,9 +232,9 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
- google-apis-iamcredentials_v1 (0.7.0)
+ google-apis-iamcredentials_v1 (0.10.0)
google-apis-core (>= 0.4, < 2.a)
- google-apis-storage_v1 (0.8.0)
+ google-apis-storage_v1 (0.11.0)
google-apis-core (>= 0.4, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
@@ -247,22 +248,22 @@ GEM
google-cloud-env (1.5.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.2.0)
- google-cloud-storage (1.34.1)
- addressable (~> 2.5)
+ google-cloud-storage (1.36.1)
+ addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- google-protobuf (3.19.2)
- google-protobuf (3.19.2-x86_64-darwin)
- google-protobuf (3.19.2-x86_64-linux)
+ google-protobuf (3.19.4)
+ google-protobuf (3.19.4-x86_64-darwin)
+ google-protobuf (3.19.4-x86_64-linux)
googleapis-common-protos (1.3.12)
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
- googleapis-common-protos-types (1.2.0)
+ googleapis-common-protos-types (1.3.0)
google-protobuf (~> 3.14)
googleauth (0.17.1)
faraday (>= 0.17.3, < 2.0)
@@ -271,25 +272,25 @@ GEM
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.15)
- groupdate (5.2.2)
- activesupport (>= 5)
- grpc (1.41.0)
- google-protobuf (~> 3.17)
+ groupdate (6.0.1)
+ activesupport (>= 5.2)
+ grpc (1.43.1)
+ google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
- grpc (1.41.0-universal-darwin)
- google-protobuf (~> 3.17)
+ grpc (1.43.1-universal-darwin)
+ google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
- grpc (1.41.0-x86_64-linux)
- google-protobuf (~> 3.17)
+ grpc (1.43.1-x86_64-linux)
+ google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
haikunator (1.1.1)
- hairtrigger (0.2.24)
- activerecord (>= 5.0, < 7)
+ hairtrigger (0.2.25)
+ activerecord (>= 5.0, < 8)
ruby2ruby (~> 2.4)
ruby_parser (~> 3.10)
hana (1.3.7)
hashdiff (1.0.1)
- hashie (4.1.0)
+ hashie (5.0.0)
hkdf (0.3.0)
html2text (0.2.1)
nokogiri (~> 1.6)
@@ -300,50 +301,52 @@ GEM
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.9.1)
+ i18n (1.10.0)
concurrent-ruby (~> 1.0)
image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
- jbuilder (2.11.2)
+ jbuilder (2.11.5)
+ actionview (>= 5.0.0)
activesupport (>= 5.0.0)
- jmespath (1.4.0)
+ jmespath (1.6.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
- json (2.5.1)
- json_refs (0.1.6)
+ json (2.6.1)
+ json_refs (0.1.7)
hana
- json_schemer (0.2.18)
+ json_schemer (0.2.19)
ecma-re-validator (~> 0.3)
hana (~> 1.3)
regexp_parser (~> 2.0)
uri_template (~> 0.7)
jwt (2.3.0)
- kaminari (1.2.1)
+ kaminari (1.2.2)
activesupport (>= 4.1.0)
- kaminari-actionview (= 1.2.1)
- kaminari-activerecord (= 1.2.1)
- kaminari-core (= 1.2.1)
- kaminari-actionview (1.2.1)
+ kaminari-actionview (= 1.2.2)
+ kaminari-activerecord (= 1.2.2)
+ kaminari-core (= 1.2.2)
+ kaminari-actionview (1.2.2)
actionview
- kaminari-core (= 1.2.1)
- kaminari-activerecord (1.2.1)
+ kaminari-core (= 1.2.2)
+ kaminari-activerecord (1.2.2)
activerecord
- kaminari-core (= 1.2.1)
- kaminari-core (1.2.1)
- koala (3.0.0)
+ kaminari-core (= 1.2.2)
+ kaminari-core (1.2.2)
+ koala (3.1.0)
addressable
- faraday
+ faraday (< 2)
json (>= 1.8)
+ rexml
launchy (2.5.0)
addressable (~> 2.7)
letter_opener (1.7.0)
launchy (~> 2.2)
- line-bot-api (1.22.0)
+ line-bot-api (1.23.0)
liquid (5.1.0)
- listen (3.7.0)
+ listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.14.0)
@@ -355,43 +358,43 @@ GEM
maxminddb (0.1.22)
memoist (0.16.2)
method_source (1.0.0)
- mime-types (3.3.1)
+ mime-types (3.4.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2021.0901)
+ mime-types-data (3.2022.0105)
mini_magick (4.11.0)
mini_mime (1.1.2)
- mini_portile2 (2.5.3)
+ mini_portile2 (2.8.0)
minitest (5.15.0)
- mock_redis (0.29.0)
+ mock_redis (0.30.0)
ruby2_keywords
- momentjs-rails (2.20.1)
+ momentjs-rails (2.29.1.1)
railties (>= 3.1)
- msgpack (1.4.2)
+ msgpack (1.4.5)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.1.1)
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
netrc (0.11.0)
- newrelic_rpm (8.0.0)
+ newrelic_rpm (8.4.0)
nio4r (2.5.8)
- nokogiri (1.11.7)
- mini_portile2 (~> 2.5.0)
+ nokogiri (1.13.3)
+ mini_portile2 (~> 2.8.0)
racc (~> 1.4)
- nokogiri (1.11.7-arm64-darwin)
+ nokogiri (1.13.3-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.11.7-x86_64-darwin)
+ nokogiri (1.13.3-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.11.7-x86_64-linux)
+ nokogiri (1.13.3-x86_64-linux)
racc (~> 1.4)
- oauth (0.5.6)
+ oauth (0.5.8)
orm_adapter (0.5.0)
- os (1.1.1)
+ os (1.1.4)
parallel (1.21.0)
- parser (3.0.2.0)
+ parser (3.1.1.0)
ast (~> 2.4.1)
path_expander (1.1.0)
- pg (1.2.3)
+ pg (1.3.2)
procore-sift (0.16.0)
rails (> 4.2.0)
pry (0.14.1)
@@ -402,16 +405,16 @@ GEM
public_suffix (4.0.6)
puma (5.6.2)
nio4r (~> 2.0)
- pundit (2.1.1)
+ pundit (2.2.0)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.6.0)
rack (2.2.3)
- rack-attack (6.5.0)
+ rack-attack (6.6.0)
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
- rack-proxy (0.7.0)
+ rack-proxy (0.7.2)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
@@ -442,15 +445,15 @@ GEM
method_source
rake (>= 0.13)
thor (~> 1.0)
- rainbow (3.0.0)
+ rainbow (3.1.1)
rake (13.0.6)
- rb-fsevent (0.11.0)
+ rb-fsevent (0.11.1)
rb-inotify (0.10.1)
ffi (~> 1.0)
- redis (4.5.1)
+ redis (4.6.0)
redis-namespace (1.8.1)
redis (>= 3.0.4)
- regexp_parser (2.1.1)
+ regexp_parser (2.2.1)
representable (3.1.1)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -465,19 +468,19 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
- rspec (3.10.0)
- rspec-core (~> 3.10.0)
- rspec-expectations (~> 3.10.0)
- rspec-mocks (~> 3.10.0)
- rspec-core (3.10.1)
- rspec-support (~> 3.10.0)
- rspec-expectations (3.10.1)
+ rspec (3.11.0)
+ rspec-core (~> 3.11.0)
+ rspec-expectations (~> 3.11.0)
+ rspec-mocks (~> 3.11.0)
+ rspec-core (3.11.0)
+ rspec-support (~> 3.11.0)
+ rspec-expectations (3.11.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.10.0)
- rspec-mocks (3.10.2)
+ rspec-support (~> 3.11.0)
+ rspec-mocks (3.11.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.10.0)
- rspec-rails (5.0.2)
+ rspec-support (~> 3.11.0)
+ rspec-rails (5.0.3)
actionpack (>= 5.2)
activesupport (>= 5.2)
railties (>= 5.2)
@@ -485,36 +488,36 @@ GEM
rspec-expectations (~> 3.10)
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
- rspec-support (3.10.2)
- rubocop (1.22.1)
+ rspec-support (3.11.0)
+ rubocop (1.25.1)
parallel (~> 1.10)
- parser (>= 3.0.0.0)
+ parser (>= 3.1.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
- rubocop-ast (>= 1.12.0, < 2.0)
+ rubocop-ast (>= 1.15.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
- rubocop-ast (1.12.0)
- parser (>= 3.0.1.1)
- rubocop-performance (1.11.5)
+ rubocop-ast (1.16.0)
+ parser (>= 3.1.1.0)
+ rubocop-performance (1.13.2)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
- rubocop-rails (2.12.3)
+ rubocop-rails (2.13.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
- rubocop-rspec (2.5.0)
+ rubocop-rspec (2.8.0)
rubocop (~> 1.19)
ruby-progressbar (1.11.0)
- ruby-vips (2.1.3)
+ ruby-vips (2.1.4)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
ruby2ruby (2.4.4)
ruby_parser (~> 3.1)
sexp_processor (~> 4.6)
- ruby_parser (3.17.0)
- sexp_processor (~> 4.15, >= 4.15.1)
+ ruby_parser (3.18.1)
+ sexp_processor (~> 4.16)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
@@ -523,30 +526,28 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
- scout_apm (4.1.2)
+ scout_apm (5.1.1)
parser
seed_dump (3.3.1)
activerecord (>= 4)
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (3.0.0)
- sentry-rails (4.7.3)
+ sentry-rails (5.1.0)
railties (>= 5.0)
- sentry-ruby-core (~> 4.7.0)
- sentry-ruby (4.7.3)
+ sentry-ruby-core (~> 5.1.0)
+ sentry-ruby (5.1.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
- faraday (>= 1.0)
- sentry-ruby-core (= 4.7.3)
- sentry-ruby-core (4.7.3)
+ sentry-ruby-core (= 5.1.0)
+ sentry-ruby-core (5.1.0)
concurrent-ruby
- faraday
- sentry-sidekiq (4.7.3)
- sentry-ruby-core (~> 4.7.0)
+ sentry-sidekiq (5.1.0)
+ sentry-ruby-core (~> 5.1.0)
sidekiq (>= 3.0)
- sexp_processor (4.15.3)
- shoulda-matchers (5.0.0)
+ sexp_processor (4.16.0)
+ shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
- sidekiq (6.4.0)
+ sidekiq (6.4.1)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
@@ -563,7 +564,7 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
- slack-ruby-client (0.17.0)
+ slack-ruby-client (1.0.0)
faraday (>= 1.0)
faraday_middleware
gli
@@ -582,13 +583,13 @@ GEM
sprockets (>= 3.0.0)
squasher (0.6.2)
statsd-ruby (1.5.0)
- telephone_number (1.4.12)
+ telephone_number (1.4.13)
thor (1.2.1)
tilt (2.0.10)
time_diff (0.3.0)
activesupport
i18n
- trailblazer-option (0.1.1)
+ trailblazer-option (0.1.2)
twilio-ruby (5.32.0)
faraday (~> 1.0.0)
jwt (>= 1.5, <= 2.5)
@@ -597,7 +598,7 @@ GEM
oauth
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
- tzinfo-data (1.2021.3)
+ tzinfo-data (1.2021.5)
tzinfo (>= 1.0.0)
uber (0.1.0)
uglifier (4.2.0)
@@ -608,12 +609,12 @@ GEM
unicode-display_width (2.1.0)
uniform_notifier (1.14.2)
uri_template (0.7.0)
- valid_email2 (4.0.0)
+ valid_email2 (4.0.3)
activemodel (>= 3.2)
mail (~> 2.5)
warden (1.2.9)
rack (>= 2.0.9)
- web-console (4.1.0)
+ web-console (4.2.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
diff --git a/app/builders/v2/report_builder.rb b/app/builders/v2/report_builder.rb
index c2900c7e6..7f0dd470c 100644
--- a/app/builders/v2/report_builder.rb
+++ b/app/builders/v2/report_builder.rb
@@ -7,6 +7,9 @@ class V2::ReportBuilder
def initialize(account, params)
@account = account
@params = params
+
+ timezone_offset = (params[:timezone_offset] || 0).to_f
+ @timezone = ActiveSupport::TimeZone[timezone_offset]&.name
end
def timeseries
@@ -64,60 +67,58 @@ class V2::ReportBuilder
@team ||= account.teams.find(params[:id])
end
+ def get_grouped_values(object_scope)
+ object_scope.group_by_period(
+ params[:group_by] || DEFAULT_GROUP_BY,
+ :created_at,
+ default_value: 0,
+ range: range,
+ permit: %w[day week month year],
+ time_zone: @timezone
+ )
+ end
+
def conversations_count
- scope.conversations
- .group_by_period(params[:group_by] || DEFAULT_GROUP_BY,
- :created_at, range: range, default_value: 0, permit: %w[day week month year])
- .count
+ (get_grouped_values scope.conversations).count
end
def incoming_messages_count
- scope.messages.incoming.unscope(:order)
- .group_by_period(params[:group_by] || DEFAULT_GROUP_BY,
- :created_at, range: range, default_value: 0, permit: %w[day week month year])
- .count
+ (get_grouped_values scope.messages.incoming.unscope(:order)).count
end
def outgoing_messages_count
- scope.messages.outgoing.unscope(:order)
- .group_by_period(params[:group_by] || DEFAULT_GROUP_BY,
- :created_at, range: range, default_value: 0, permit: %w[day week month year])
- .count
+ (get_grouped_values scope.messages.outgoing.unscope(:order)).count
end
def resolutions_count
- scope.conversations
- .resolved
- .group_by_period(params[:group_by] || DEFAULT_GROUP_BY,
- :created_at, range: range, default_value: 0, permit: %w[day week month year])
- .count
+ (get_grouped_values scope.conversations.resolved).count
end
def avg_first_response_time
- scope.events
- .where(name: 'first_response')
- .group_by_day(:created_at, range: range, default_value: 0)
- .average(:value)
+ (get_grouped_values scope.events.where(name: 'first_response')).average(:value)
end
def avg_resolution_time
- scope.events.where(name: 'conversation_resolved')
- .group_by_day(:created_at, range: range, default_value: 0)
- .average(:value)
+ (get_grouped_values scope.events.where(name: 'conversation_resolved')).average(:value)
end
- # Taking average of average is not too accurate
- # https://en.wikipedia.org/wiki/Simpson's_paradox
- # TODO: Will optimize this later
def avg_resolution_time_summary
- return 0 if avg_resolution_time.values.empty?
+ avg_rt = scope.events
+ .where(name: 'conversation_resolved', created_at: range)
+ .average(:value)
- (avg_resolution_time.values.sum / avg_resolution_time.values.length)
+ return 0 if avg_rt.blank?
+
+ avg_rt
end
def avg_first_response_time_summary
- return 0 if avg_first_response_time.values.empty?
+ avg_frt = scope.events
+ .where(name: 'first_response', created_at: range)
+ .average(:value)
- (avg_first_response_time.values.sum / avg_first_response_time.values.length)
+ return 0 if avg_frt.blank?
+
+ avg_frt
end
end
diff --git a/app/controllers/api/v1/accounts/bulk_actions_controller.rb b/app/controllers/api/v1/accounts/bulk_actions_controller.rb
new file mode 100644
index 000000000..832f5a49b
--- /dev/null
+++ b/app/controllers/api/v1/accounts/bulk_actions_controller.rb
@@ -0,0 +1,26 @@
+class Api::V1::Accounts::BulkActionsController < Api::V1::Accounts::BaseController
+ before_action :type_matches?
+
+ def create
+ if type_matches?
+ ::BulkActionsJob.perform_later(
+ account: @current_account,
+ user: current_user,
+ params: permitted_params
+ )
+ head :ok
+ else
+ render json: { success: false }, status: :unprocessable_entity
+ end
+ end
+
+ private
+
+ def type_matches?
+ ['Conversation'].include?(params[:type])
+ end
+
+ def permitted_params
+ params.permit(:type, ids: [], fields: [:status, :assignee_id, :team_id], labels: [add: [], remove: []])
+ end
+end
diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb
index e0c963d25..2bda5c07a 100644
--- a/app/controllers/api/v1/accounts/inboxes_controller.rb
+++ b/app/controllers/api/v1/accounts/inboxes_controller.rb
@@ -138,7 +138,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
end
def get_channel_attributes(channel_type)
- if channel_type.constantize.const_defined?('EDITABLE_ATTRS')
+ if channel_type.constantize.const_defined?(:EDITABLE_ATTRS)
channel_type.constantize::EDITABLE_ATTRS.presence
else
[]
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index f1755b921..e75d3f852 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -4,6 +4,7 @@ class Api::V1::AccountsController < Api::BaseController
skip_before_action :authenticate_user!, :set_current_user, :handle_with_exception,
only: [:create], raise: false
before_action :check_signup_enabled, only: [:create]
+ before_action :validate_captcha, only: [:create]
before_action :fetch_account, except: [:create]
before_action :check_authorization, except: [:create]
@@ -58,6 +59,10 @@ class Api::V1::AccountsController < Api::BaseController
raise ActionController::RoutingError, 'Not Found' if GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false') == 'false'
end
+ def validate_captcha
+ raise ActionController::InvalidAuthenticityToken, 'Invalid Captcha' unless ChatwootCaptcha.new(params[:h_captcha_client_response]).valid?
+ end
+
def pundit_user
{
user: current_user,
diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb
index 9801d760d..a83611676 100644
--- a/app/controllers/api/v2/accounts/reports_controller.rb
+++ b/app/controllers/api/v2/accounts/reports_controller.rb
@@ -58,7 +58,8 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
since: params[:since],
until: params[:until],
id: params[:id],
- group_by: params[:group_by]
+ group_by: params[:group_by],
+ timezone_offset: params[:timezone_offset]
}
end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 52c6c87af..2bb8e9847 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -26,7 +26,10 @@ class DashboardController < ActionController::Base
'API_CHANNEL_THUMBNAIL',
'ANALYTICS_TOKEN',
'ANALYTICS_HOST',
- 'DIRECT_UPLOADS_ENABLED'
+ 'DIRECT_UPLOADS_ENABLED',
+ 'HCAPTCHA_SITE_KEY',
+ 'LOGOUT_REDIRECT_LINK',
+ 'DISABLE_USER_PROFILE_UPDATE'
).merge(app_config)
end
diff --git a/app/controllers/widget_tests_controller.rb b/app/controllers/widget_tests_controller.rb
index 22a8c0da8..fff47d907 100644
--- a/app/controllers/widget_tests_controller.rb
+++ b/app/controllers/widget_tests_controller.rb
@@ -1,5 +1,8 @@
class WidgetTestsController < ActionController::Base
- before_action :set_web_widget
+ before_action :ensure_web_widget
+ before_action :ensure_widget_position
+ before_action :ensure_widget_type
+ before_action :ensure_widget_style
def index
render
@@ -7,7 +10,24 @@ class WidgetTestsController < ActionController::Base
private
- def set_web_widget
- @web_widget = Channel::WebWidget.first
+ def ensure_widget_style
+ @widget_style = params[:widget_style] || 'standard'
+ end
+
+ def ensure_widget_position
+ @widget_position = params[:position] || 'left'
+ end
+
+ def ensure_widget_type
+ @widget_type = params[:type] || 'expanded_bubble'
+ end
+
+ def inbox_id
+ @inbox_id ||= params[:inbox_id] || Channel::WebWidget.first.inbox.id
+ end
+
+ def ensure_web_widget
+ @inbox = Inbox.find(inbox_id)
+ @web_widget = @inbox.channel
end
end
diff --git a/app/javascript/dashboard/api/auth.js b/app/javascript/dashboard/api/auth.js
index 7079614c1..18ec9e811 100644
--- a/app/javascript/dashboard/api/auth.js
+++ b/app/javascript/dashboard/api/auth.js
@@ -30,6 +30,7 @@ export default {
user_full_name: creds.fullName.trim(),
email: creds.email,
password: creds.password,
+ h_captcha_client_response: creds.hCaptchaClientResponse,
})
.then(response => {
setAuthCredentials(response);
diff --git a/app/javascript/dashboard/api/reports.js b/app/javascript/dashboard/api/reports.js
index dbb2bf08d..90f8b34ea 100644
--- a/app/javascript/dashboard/api/reports.js
+++ b/app/javascript/dashboard/api/reports.js
@@ -1,6 +1,8 @@
/* global axios */
import ApiClient from './ApiClient';
+const getTimeOffset = () => -new Date().getTimezoneOffset() / 60;
+
class ReportsAPI extends ApiClient {
constructor() {
super('reports', { accountScoped: true, apiVersion: 'v2' });
@@ -8,13 +10,27 @@ class ReportsAPI extends ApiClient {
getReports(metric, since, until, type = 'account', id, group_by) {
return axios.get(`${this.url}`, {
- params: { metric, since, until, type, id, group_by },
+ params: {
+ metric,
+ since,
+ until,
+ type,
+ id,
+ group_by,
+ timezone_offset: getTimeOffset(),
+ },
});
}
getSummary(since, until, type = 'account', id, group_by) {
return axios.get(`${this.url}/summary`, {
- params: { since, until, type, id, group_by },
+ params: {
+ since,
+ until,
+ type,
+ id,
+ group_by,
+ },
});
}
diff --git a/app/javascript/dashboard/api/specs/reports.spec.js b/app/javascript/dashboard/api/specs/reports.spec.js
index f3b66996a..efde84fe4 100644
--- a/app/javascript/dashboard/api/specs/reports.spec.js
+++ b/app/javascript/dashboard/api/specs/reports.spec.js
@@ -27,6 +27,7 @@ describe('#Reports API', () => {
since: 1621103400,
until: 1621621800,
type: 'account',
+ timezone_offset: -0,
},
});
});
diff --git a/app/javascript/dashboard/assets/scss/_utility-helpers.scss b/app/javascript/dashboard/assets/scss/_utility-helpers.scss
index 7b528d1c2..8a85dc6a5 100644
--- a/app/javascript/dashboard/assets/scss/_utility-helpers.scss
+++ b/app/javascript/dashboard/assets/scss/_utility-helpers.scss
@@ -54,3 +54,9 @@
.text-y-800 {
color: var(--y-800);
}
+
+.text-ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue
index 4173ed438..deb0276bf 100644
--- a/app/javascript/dashboard/components/ChatList.vue
+++ b/app/javascript/dashboard/components/ChatList.vue
@@ -219,7 +219,7 @@ export default {
folders: 'customViews/getCustomViews',
}),
hasAppliedFilters() {
- return this.appliedFilters.length;
+ return this.appliedFilters.length !== 0;
},
hasActiveFolders() {
return this.activeFolder && this.foldersId !== 0;
@@ -460,7 +460,8 @@ export default {
if (this.hasActiveFolders) {
const payload = this.activeFolder.query;
this.fetchSavedFilteredConversations(payload);
- } else {
+ }
+ if (this.hasAppliedFilters) {
this.fetchFilteredConversations(this.appliedFilters);
}
},
diff --git a/app/javascript/dashboard/components/NetworkNotification.vue b/app/javascript/dashboard/components/NetworkNotification.vue
index deb5931c4..c716731d5 100644
--- a/app/javascript/dashboard/components/NetworkNotification.vue
+++ b/app/javascript/dashboard/components/NetworkNotification.vue
@@ -30,6 +30,7 @@
+
diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
index da14cf295..6222490e4 100644
--- a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
+++ b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
@@ -1,5 +1,6 @@