From 51824ad84b398a8c1f5094427f40ab4b68ad33ed Mon Sep 17 00:00:00 2001 From: Ahmad Farhat Date: Tue, 26 May 2020 17:37:23 -0400 Subject: [PATCH] Merge v2.6-alpha (#1672) * GRN2-xx: Switch the relation between users and roles to make queries cleaner and faster (#1299) * First steps * Fixes in account creation flow * Fixed most testcases * more test fixes * Fixed more test cases * Passing tests and rubocop * Added rake task to remove rooms * Adding translation (#1510) * Update _account.html.erb * Update en.yml * Fix "for" attribute for label elements (#1488) Co-authored-by: Ahmad Farhat * Fix some issues reported by LGTM (#1478) * Declare local JavaScript variables (reported by LGTM) Signed-off-by: Stefan Weil * Remove unused local JavaScript variable (reported by LGTM) Signed-off-by: Stefan Weil * Puma Worker Configuration (#1332) We noticed that the current default settings perform very poorly under load. We managed to literally take down Greenlight during a larger event when people where accessing the landing page for rooms and when doing some tests, I was more or less able to DoS Greenlight on my own. This patch adds a default worker configuration which significantly improves the situation. The small, 4 core machine I was testing on could handle about thrice the amount of requests. While the new default configuration should be reasonably well suited for most deployments, this patch further allows users to easily configure the worker pool on their own in the environment file. * Made name and email readonly for no greenlight accounts (#1534) * Fixed hardcoded string (#1532) * fixed spelling error that was bugging me :) - sep a rat e (#1535) Co-authored-by: Dave Lane * Improve Server Rooms View (#1524) * Order rooms by status * Cleaned up order function * Now displays Started/Created/Ended * Added participant count to rooms list * Fix rake task user:create so that users can be created when terms are present (#1565) * Changed user create task to always accept terms * clean up * More secure room ID (#1451) * Legal and privpolicy link (#1421) * add customizable Links to Imprint and Privacy Policy * fix copy&paste error in spec * replace "imprint" with "legal" since that is the correct term * remove german translation of new strings, transifex will take care of them later * GRN2-295:Refactored update profile and update password (#1591) * Refactored update profile and update password * Relowered rubocop settings * Fixed email sending when not supposed to (#1592) * Design changes for small screens (#1580) * now rap for pagination * Update _subtitle.html.erb * Update _rooms.html.erb * Update _recordings.html.erb * Update _rooms.html.erb * Update _users.html.erb * Update cant_create_rooms.html.erb * Update room.js * Update edit.html.erb * Update new.html.erb * Update cant_create_rooms.html.erb * Update _sessions.html.erb * Update _account.html.erb * Make Greenlight work with Ruby 2.7 (#1560) Greenlight's failure to start up with Ruby 2.7 seems to be caused by [an issue in bootsnap](https://github.com/Shopify/bootsnap/issues/258). Updating that library makes Greenlight work again. However, there are still a lot of deprecation warnings. But that's something to deal with separately. This fixes #1558 * use email input for sign in (#1199) * use email input for sign in * use email input for registration * use email input for invitation * use email input for account settings Co-authored-by: Ahmad Farhat * Fix Gemfile (#1593) * Fixed invalid token for password reset (#1632) * HELP_URL env variable now works as expected (#1636) * #1372 Fix for long Text in Table + Remove invalid HTML Tag (#1403) * removed invalid HTML Tag * removed invalid HTML Tag * Update _public_recording_row.html.erb * Update _recording_row.html.erb * Update _server_recording_row.html.erb form-inline replaced by own css * Update _server_room_row.html.erb * Update _public_recording_row.html.erb * Update _recording_row.html.erb * Update _public_recording_row.html.erb * Update _recordings.html.erb * Update _rooms.html.erb * Update main.scss fix for long text * Update main.scss * Update _public_recording_row.html.erb * Added more validation on profile image (#1644) * Users who can't create rooms but have shared rooms now have a different view (#1649) * Revert "Puma Worker Configuration (#1332)" (#1667) This reverts commit 78ed8d74601b613af3fd96ccf75a6bada24deddd. * Removed html safe from all flash messages (#1668) * Remove hardcoded guest=true if require mod approval is set (#1669) * Change random generation for room uid (#1670) * GRN2-290: Update gems and update to Rails 5.2.4.3 (#1671) * Update gems and update to Rails 5.2.4.3 * remove gemfile error Co-authored-by: MrKeksi Co-authored-by: Florian Weber Co-authored-by: Stefan Weil Co-authored-by: Lars Kiesow Co-authored-by: Dave Lane Co-authored-by: Dave Lane Co-authored-by: Henning Co-authored-by: Marcel Waldvogel Co-authored-by: Christian Marg Co-authored-by: Klaus --- .rubocop.yml | 44 +++- Gemfile | 4 +- Gemfile.lock | 247 +++++++++--------- app/assets/javascripts/admins.js | 18 +- app/assets/javascripts/room.js | 8 +- app/assets/javascripts/user_edit.js | 66 +---- app/assets/stylesheets/main.scss | 7 + app/controllers/admins_controller.rb | 20 +- app/controllers/application_controller.rb | 4 +- app/controllers/concerns/authenticator.rb | 4 +- app/controllers/concerns/bbb_server.rb | 1 - app/controllers/concerns/emailer.rb | 11 +- app/controllers/concerns/populator.rb | 36 +-- app/controllers/concerns/rolify.rb | 63 +---- app/controllers/password_resets_controller.rb | 2 + app/controllers/recordings_controller.rb | 4 +- app/controllers/rooms_controller.rb | 31 ++- app/controllers/sessions_controller.rb | 8 +- app/controllers/users_controller.rb | 91 ++++--- app/helpers/admins_helper.rb | 7 +- app/helpers/application_helper.rb | 29 +- app/helpers/theming_helper.rb | 10 + app/helpers/users_helper.rb | 9 +- app/models/ability.rb | 2 +- app/models/concerns/auth_values.rb | 2 +- app/models/role.rb | 6 +- app/models/room.rb | 35 ++- app/models/setting.rb | 4 + app/models/user.rb | 87 ++---- .../admins/components/_menu_buttons.html.erb | 2 +- .../admins/components/_recordings.html.erb | 6 +- app/views/admins/components/_roles.html.erb | 4 +- app/views/admins/components/_rooms.html.erb | 9 +- .../components/_server_recording_row.html.erb | 6 +- .../components/_server_room_row.html.erb | 19 +- .../admins/components/_settings.html.erb | 28 ++ app/views/admins/components/_users.html.erb | 28 +- app/views/errors/bigbluebutton_error.html.erb | 2 +- app/views/main/components/_features.html.erb | 2 +- app/views/password_resets/edit.html.erb | 6 +- app/views/password_resets/new.html.erb | 4 +- app/views/rooms/cant_create_rooms.html.erb | 28 +- app/views/rooms/show.html.erb | 16 +- app/views/sessions/new.html.erb | 10 +- app/views/sessions/signin.html.erb | 2 +- app/views/shared/_flash_messages.html.erb | 8 +- app/views/shared/_footer.html.erb | 3 +- app/views/shared/_header.html.erb | 26 +- app/views/shared/_sessions.html.erb | 2 +- .../components/_public_recording_row.html.erb | 6 +- .../shared/components/_recording_row.html.erb | 6 +- .../shared/components/_subtitle.html.erb | 6 +- .../shared/modals/_invite_user_modal.html.erb | 2 +- app/views/users/components/_account.html.erb | 67 +++-- app/views/users/components/_password.html.erb | 2 +- config/application.rb | 2 +- config/locales/en.yml | 23 +- config/puma.rb | 3 + config/routes.rb | 8 +- .../20190314152108_rolify_create_roles.rb | 2 +- .../20200413150518_add_role_id_to_users.rb | 29 ++ db/schema.rb | 4 +- lib/assets/_primary_themes.scss | 3 +- lib/tasks/room.rake | 27 ++ lib/tasks/user.rake | 6 +- .../account_activations_controller_spec.rb | 3 +- spec/controllers/admins_controller_spec.rb | 62 ++++- .../application_controller_spec.rb | 4 +- .../password_resets_controller_spec.rb | 7 +- spec/controllers/rooms_controller_spec.rb | 70 +++-- spec/controllers/sessions_controller_spec.rb | 12 +- spec/controllers/users_controller_spec.rb | 161 +++++++----- spec/factories.rb | 3 +- spec/models/user_spec.rb | 45 +--- spec/rails_helper.rb | 2 +- spec/spec_helper.rb | 2 + 76 files changed, 903 insertions(+), 735 deletions(-) create mode 100644 db/migrate/20200413150518_add_role_id_to_users.rb create mode 100644 lib/tasks/room.rake diff --git a/.rubocop.yml b/.rubocop.yml index 98794836..0e7a2d4f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -73,11 +73,11 @@ Style/RescueStandardError: Enabled: false # Align the elements of a hash literal if they span more than one line. -Layout/AlignHash: +Layout/HashAlignment: Enabled: false # Align the parameters of a method definition if they span more than one line. -Layout/AlignParameters: +Layout/ParameterAlignment: Enabled: false # Align ends corresponding to defs correctly. @@ -93,7 +93,7 @@ Layout/EmptyLineAfterGuardClause: Enabled: false # Align the arguments of a method call if they span more than one line. -Layout/AlignArguments: +Layout/ArgumentAlignment: Enabled: false # @@ -120,7 +120,7 @@ Metrics/ClassLength: Enabled: false # Limit lines to 80 characters. -Metrics/LineLength: +Layout/LineLength: Max: 130 # Avoid methods longer than 10 lines of code. @@ -141,5 +141,39 @@ Metrics/CyclomaticComplexity: Max: 17 # Checks for method parameter names that contain capital letters, end in numbers, or do not meet a minimal length. -Naming/UncommunicativeMethodParamName: +Naming/MethodParameterName: Enabled: false + +Lint/LiteralInInterpolation: + Enabled: false + +Layout/EmptyLinesAroundAttributeAccessor: + Enabled: true + +Layout/SpaceAroundMethodCallOperator: + Enabled: true + +Lint/DeprecatedOpenSSLConstant: + Enabled: true + +Lint/RaiseException: + Enabled: true + +Lint/StructNewOverride: + Enabled: true + +Style/ExponentialNotation: + Enabled: true + +Style/HashEachMethods: + Enabled: true + +Style/HashTransformKeys: + Enabled: true + +Style/HashTransformValues: + Enabled: true + +Style/SlicingWithRange: + Enabled: true + \ No newline at end of file diff --git a/Gemfile b/Gemfile index 49b6882c..0b17c716 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ git_source(:github) do |repo_name| end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 5.2.3' +gem 'rails', '~> 5.2.4.3' # Use Puma as the app server gem 'puma', '~> 3.12' @@ -44,6 +44,8 @@ gem 'bcrypt', '~> 3.1.7' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false +gem 'sprockets', '< 4.0.0' + # Authentication. gem 'omniauth' gem 'omniauth-twitter' diff --git a/Gemfile.lock b/Gemfile.lock index 6f131109..97ab3ab0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,54 +9,54 @@ GIT GEM remote: https://rubygems.org/ specs: - action-cable-testing (0.5.0) + action-cable-testing (0.6.1) actioncable (>= 5.0) - actioncable (5.2.3) - actionpack (= 5.2.3) + actioncable (5.2.4.3) + actionpack (= 5.2.4.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.3) - actionpack (= 5.2.3) - actionview (= 5.2.3) - activejob (= 5.2.3) + actionmailer (5.2.4.3) + actionpack (= 5.2.4.3) + actionview (= 5.2.4.3) + activejob (= 5.2.4.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.3) - actionview (= 5.2.3) - activesupport (= 5.2.3) - rack (~> 2.0) + actionpack (5.2.4.3) + actionview (= 5.2.4.3) + activesupport (= 5.2.4.3) + rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.3) - activesupport (= 5.2.3) + actionview (5.2.4.3) + activesupport (= 5.2.4.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.3) - activesupport (= 5.2.3) + activejob (5.2.4.3) + activesupport (= 5.2.4.3) globalid (>= 0.3.6) - activemodel (5.2.3) - activesupport (= 5.2.3) - activerecord (5.2.3) - activemodel (= 5.2.3) - activesupport (= 5.2.3) + activemodel (5.2.4.3) + activesupport (= 5.2.4.3) + activerecord (5.2.4.3) + activemodel (= 5.2.4.3) + activesupport (= 5.2.4.3) arel (>= 9.0) - activestorage (5.2.3) - actionpack (= 5.2.3) - activerecord (= 5.2.3) + activestorage (5.2.4.3) + actionpack (= 5.2.4.3) + activerecord (= 5.2.4.3) marcel (~> 0.3.1) - activesupport (5.2.3) + activesupport (5.2.4.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.6.0) - public_suffix (>= 2.0.2, < 4.0) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) arel (9.0.0) ast (2.4.0) - autoprefixer-rails (9.6.1) + autoprefixer-rails (9.7.6) execjs bcrypt (3.1.13) bigbluebutton-api-ruby (1.7.0) @@ -64,14 +64,14 @@ GEM bindex (0.8.1) bn-ldap-authentication (0.1.2) net-ldap (~> 0) - bootsnap (1.4.4) + bootsnap (1.4.6) msgpack (~> 1.0) bootstrap (4.3.1) autoprefixer-rails (>= 9.1.0) popper_js (>= 1.14.3, < 2) sassc-rails (>= 2.0.0) - builder (3.2.3) - byebug (11.0.1) + builder (3.2.4) + byebug (11.1.3) cancancan (2.3.0) coffee-rails (4.2.2) coffee-script (>= 2.2.0) @@ -80,7 +80,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.5) + concurrent-ruby (1.1.6) coveralls (0.8.23) json (>= 1.8, < 3) simplecov (~> 0.16.1) @@ -89,46 +89,45 @@ GEM tins (~> 1.6) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.5) + crass (1.0.6) diff-lcs (1.3) docile (1.3.2) - dotenv (2.7.4) - dotenv-rails (2.7.4) - dotenv (= 2.7.4) + dotenv (2.7.5) + dotenv-rails (2.7.5) + dotenv (= 2.7.5) railties (>= 3.2, < 6.1) - erubi (1.8.0) + erubi (1.9.0) execjs (2.7.0) - factory_bot (5.0.2) + factory_bot (5.2.0) activesupport (>= 4.2.0) - factory_bot_rails (5.0.2) - factory_bot (~> 5.0.2) + factory_bot_rails (5.2.0) + factory_bot (~> 5.2.0) railties (>= 4.2.0) - faker (1.9.6) - i18n (>= 0.7) - faraday (0.15.4) + faker (2.11.0) + i18n (>= 1.6, < 2) + faraday (1.0.1) multipart-post (>= 1.2, < 3) - ffi (1.11.1) + ffi (1.12.2) font-awesome-sass (5.9.0) sassc (>= 1.11) globalid (0.4.2) activesupport (>= 4.2.0) - hashdiff (0.4.0) - hashie (3.6.0) + hashdiff (1.0.1) + hashie (4.1.0) hiredis (0.6.3) http_accept_language (2.1.1) - i18n (1.6.0) + i18n (1.8.2) concurrent-ruby (~> 1.0) - i18n-language-mapping (0.1.1) - jaro_winkler (1.5.3) - jbuilder (2.9.1) - activesupport (>= 4.2.0) + i18n-language-mapping (0.1.2) + jbuilder (2.10.0) + activesupport (>= 5.0.0) jquery-rails (4.3.5) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) jquery-ui-rails (6.0.1) railties (>= 3.2.16) - json (2.2.0) + json (2.3.0) jwt (2.2.1) listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) @@ -138,35 +137,35 @@ GEM activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.3.1) + loofah (2.5.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) marcel (0.3.3) mimemagic (~> 0.3.2) - method_source (0.9.2) - mimemagic (0.3.3) + method_source (1.0.0) + mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.4.0) - minitest (5.11.3) - msgpack (1.3.0) - multi_json (1.13.1) + minitest (5.14.1) + msgpack (1.3.3) + multi_json (1.14.1) multi_xml (0.6.0) multipart-post (2.1.1) - net-ldap (0.16.1) - nio4r (2.4.0) + net-ldap (0.16.2) + nio4r (2.5.2) nokogiri (1.10.9) mini_portile2 (~> 2.4.0) oauth (0.5.4) - oauth2 (1.4.1) - faraday (>= 0.8, < 0.16.0) + oauth2 (1.4.4) + faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (1.9.0) - hashie (>= 3.4.6, < 3.7.0) + omniauth (1.9.1) + hashie (>= 3.4.6) rack (>= 1.6.2, < 3) omniauth-bn-launcher (0.1.3) omniauth (~> 1.3, >= 1.3.2) @@ -187,29 +186,29 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - pagy (3.3.2) - parallel (1.17.0) - parser (2.6.3.0) + pagy (3.8.1) + parallel (1.19.1) + parser (2.7.1.3) ast (~> 2.4.0) pg (0.21.0) - popper_js (1.14.5) - public_suffix (3.1.1) - puma (3.12.4) + popper_js (1.16.0) + public_suffix (4.0.5) + puma (3.12.6) rack (2.2.2) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.3) - actioncable (= 5.2.3) - actionmailer (= 5.2.3) - actionpack (= 5.2.3) - actionview (= 5.2.3) - activejob (= 5.2.3) - activemodel (= 5.2.3) - activerecord (= 5.2.3) - activestorage (= 5.2.3) - activesupport (= 5.2.3) + rails (5.2.4.3) + actioncable (= 5.2.4.3) + actionmailer (= 5.2.4.3) + actionpack (= 5.2.4.3) + actionview (= 5.2.4.3) + activejob (= 5.2.4.3) + activemodel (= 5.2.4.3) + activerecord (= 5.2.4.3) + activestorage (= 5.2.4.3) + activesupport (= 5.2.4.3) bundler (>= 1.3.0) - railties (= 5.2.3) + railties (= 5.2.4.3) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.4) actionpack (>= 5.0.1.x) @@ -218,64 +217,67 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) - railties (5.2.3) - actionpack (= 5.2.3) - activesupport (= 5.2.3) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.2.4.3) + actionpack (= 5.2.4.3) + activesupport (= 5.2.4.3) method_source rake (>= 0.8.7) thor (>= 0.19.0, < 2.0) rainbow (3.0.0) rake (13.0.1) random_password (0.1.1) - rb-fsevent (0.10.3) - rb-inotify (0.10.0) + rb-fsevent (0.10.4) + rb-inotify (0.10.1) ffi (~> 1.0) - recaptcha (5.0.0) + recaptcha (5.5.0) json - redcarpet (3.4.0) - redis (4.1.2) + redcarpet (3.5.0) + redis (4.1.4) remote_syslog_logger (1.0.4) syslog_protocol - request_store (1.4.1) + request_store (1.5.0) rack (>= 1.4) - rspec-core (3.8.2) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.4) + rexml (3.2.4) + rspec-core (3.9.2) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.1) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-rails (3.8.2) + rspec-support (~> 3.9.0) + rspec-rails (3.9.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.2) - rubocop (0.72.0) - jaro_winkler (~> 1.5.1) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.3) + rubocop (0.84.0) parallel (~> 1.10) - parser (>= 2.6) + parser (>= 2.7.0.1) rainbow (>= 2.2.2, < 4.0) + rexml + rubocop-ast (>= 0.0.3) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) + unicode-display_width (>= 1.4.0, < 2.0) + rubocop-ast (0.0.3) + parser (>= 2.7.0.1) ruby-progressbar (1.10.1) safe_yaml (1.0.5) - sassc (2.0.1) + sassc (2.3.0) ffi (~> 1.9) - rake sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) sprockets (> 3.0) sprockets-rails tilt - sequel (5.29.0) + sequel (5.32.0) shoulda-matchers (3.1.3) activesupport (>= 4.0.0) simplecov (0.16.1) @@ -295,33 +297,35 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.3.13) + sync (0.5.0) syslog_protocol (0.9.2) term-ansicolor (1.7.1) tins (~> 1.0) - thor (0.20.3) + thor (1.0.1) thread_safe (0.3.6) - tilt (2.0.9) - tins (1.21.0) - turbolinks (5.2.0) + tilt (2.0.10) + tins (1.25.0) + sync + turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - tzinfo (1.2.5) + tzinfo (1.2.7) thread_safe (~> 0.1) - tzinfo-data (1.2019.3) + tzinfo-data (1.2020.1) tzinfo (>= 1.0.0) - uglifier (4.1.20) + uglifier (4.2.0) execjs (>= 0.3.0, < 3) - unicode-display_width (1.6.0) + unicode-display_width (1.7.0) web-console (3.7.0) actionview (>= 5.0) activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) - webmock (3.6.0) + webmock (3.8.3) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - websocket-driver (0.7.1) + websocket-driver (0.7.2) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.4) xml-simple (1.1.5) @@ -361,7 +365,7 @@ DEPENDENCIES pagy pg (~> 0.18) puma (~> 3.12) - rails (~> 5.2.3) + rails (~> 5.2.4.3) rails-controller-testing random_password recaptcha @@ -375,6 +379,7 @@ DEPENDENCIES shoulda-matchers (~> 3.1) spring spring-watcher-listen (~> 2.0.0) + sprockets (< 4.0.0) sqlite3 (~> 1.3.6) tabler-rubygem! turbolinks (~> 5) diff --git a/app/assets/javascripts/admins.js b/app/assets/javascripts/admins.js index 53fcfb57..f2db3fe8 100644 --- a/app/assets/javascripts/admins.js +++ b/app/assets/javascripts/admins.js @@ -80,7 +80,7 @@ $(document).on('turbolinks:load', function(){ // Get the uid of the selected user let user = $(".selectpicker").selectpicker('val') if (user != "") { - userInfo = JSON.parse(user) + let userInfo = JSON.parse(user) $("#merge-from").html("" + userInfo.name + "" + "" + userInfo.email + "" + "" + userInfo.uid + "") } }) @@ -95,7 +95,7 @@ $(document).on('turbolinks:load', function(){ }) // Updates the colour picker to the correct colour - role_colour = $("#role-colorinput-regular").data("colour") + let role_colour = $("#role-colorinput-regular").data("colour") $("#role-colorinput-regular").css("background-color", role_colour); $("#role-colorinput-regular").css("border-color", role_colour); @@ -122,6 +122,18 @@ function changeBrandingImage(path) { $.post(path, {value: url}) } +// Change the Legal URL to the one provided +function changeLegalURL(path) { + var url = $("#legal-url").val() + $.post(path, {value: url}) +} + +// Change the Privacy Policy URL to the one provided +function changePrivacyPolicyURL(path) { + var url = $("#privpolicy-url").val() + $.post(path, {value: url}) +} + function mergeUsers() { let userToMerge = $("#from-uid").text() $.post($("#merge-save-access").data("path"), {merge: userToMerge}) @@ -263,4 +275,4 @@ function loadRoleColourSelector(role_colour, disabled) { $("#role-colour").val(color.toHEXA().toString()); }); } -} \ No newline at end of file +} diff --git a/app/assets/javascripts/room.js b/app/assets/javascripts/room.js index 6186aaca..8137d0c6 100644 --- a/app/assets/javascripts/room.js +++ b/app/assets/javascripts/room.js @@ -44,11 +44,6 @@ $(document).on('turbolinks:load', function(){ } }); - // Forces the wrapper to take the entire screen height if the user can't create rooms - if ($("#cant-create-room-wrapper").length){ - $(".wrapper").css('height', '100%').css('height', '-=130px'); - } - // Display and update all fields related to creating a room in the createRoomModal $("#create-room-block").click(function(){ showCreateRoom(this) @@ -138,7 +133,6 @@ $(document).on('turbolinks:load', function(){ }); function showCreateRoom(target) { - var modal = $(target) $("#create-room-name").val("") $("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder")) $("#room_access_code").val(null) @@ -269,4 +263,4 @@ function removeSharedUser(target) { parentLI.removeChild(target) parentLI.classList.add("remove-shared") } -} \ No newline at end of file +} diff --git a/app/assets/javascripts/user_edit.js b/app/assets/javascripts/user_edit.js index e1dee271..eca04cb2 100644 --- a/app/assets/javascripts/user_edit.js +++ b/app/assets/javascripts/user_edit.js @@ -18,61 +18,19 @@ $(document).on('turbolinks:load', function(){ var controller = $("body").data('controller'); var action = $("body").data('action'); if ((controller == "admins" && action == "edit_user") || (controller == "users" && action == "edit")) { - // Clear the role when the user clicks the x - $(".clear-role").click(clearRole) + // Hack to make it play nice with turbolinks + if ($("#role-dropdown:visible").length == 0){ + $(window).trigger('load.bs.select.data-api') + } - // When the user selects an item in the dropdown add the role to the user - $("#role-select-dropdown").change(function(data){ - var dropdown = $("#role-select-dropdown"); - var select_role_id = dropdown.val(); + // Check to see if the role dropdown was set up + if ($("#role-dropdown").length != 0){ + $("#role-dropdown").selectpicker('val', $("#user_role_id").val()) + } - if(select_role_id){ - // Disable the role in the dropdown - var selected_role = dropdown.find('[value=\"' + select_role_id + '\"]'); - selected_role.prop("disabled", true) - - // Add the role tag - var tag_container = $("#role-tag-container"); - tag_container.append("" + - selected_role.text() + ""); - - // Update the role ids input that gets submited on user update - var role_ids = $("#user_role_ids").val() - role_ids += " " + select_role_id - $("#user_role_ids").val(role_ids) - - // Add the clear role function to the tag - $("#user-role-tag_" + select_role_id).click(clearRole); - - // Reset the dropdown - dropdown.val(null) - } + // Update hidden field with new value + $("#role-dropdown").on("changed.bs.select", function(){ + $("#user_role_id").val($("#role-dropdown").selectpicker('val')) }) } -}) - -// This function removes the specfied role from a user -function clearRole(data){ - // Get the role id - var role_id = $(data.target).data("role-id"); - var role_tag = $("#user-role-tag_" + role_id); - - // Remove the role tag - $(role_tag).remove() - - // Update the role ids input - var role_ids = $("#user_role_ids").val() - var parsed_ids = role_ids.split(' ') - - var index = parsed_ids.indexOf(role_id.toString()); - - if (index > -1) { - parsed_ids.splice(index, 1); - } - - $("#user_role_ids").val(parsed_ids.join(' ')) - - // Enable the role in the role select dropdown - var selected_role = $("#role-select-dropdown").find('[value=\"' + role_id + '\"]'); - selected_role.prop("disabled", false) -} \ No newline at end of file +}) \ No newline at end of file diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 8809beb0..15cce700 100755 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -158,3 +158,10 @@ .signin-button { font-size: 16px; } + +.table-responsive tbody td:first-child > *:first-child { + max-height: 3em; + overflow: hidden; + max-width: 200px; + display: flex; +} diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb index be8e8090..63db04b5 100644 --- a/app/controllers/admins_controller.rb +++ b/app/controllers/admins_controller.rb @@ -63,10 +63,16 @@ class AdminsController < ApplicationController # GET /admins/rooms def server_rooms @search = params[:search] || "" - @order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at" + @order_column = params[:column] && params[:direction] != "none" ? params[:column] : "status" @order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC" - @running_room_bbb_ids = all_running_meetings[:meetings].pluck(:meetingID) + meetings = all_running_meetings[:meetings] + @running_room_bbb_ids = meetings.pluck(:meetingID) + + @participants_count = {} + meetings.each do |meet| + @participants_count[meet[:meetingID]] = meet[:participantCount] + end @user_list = shared_user_list if shared_access_allowed @@ -86,23 +92,21 @@ class AdminsController < ApplicationController # POST /admins/ban/:user_uid def ban_user - @user.roles = [] - @user.add_role :denied + @user.set_role :denied redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.banned") } end # POST /admins/unban/:user_uid def unban_user - @user.remove_role :denied - @user.add_role :user + @user.set_role :user redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.unbanned") } end # POST /admins/approve/:user_uid def approve - @user.remove_role :pending + @user.set_role :user send_user_approved_email(@user) @@ -298,7 +302,7 @@ class AdminsController < ApplicationController flash[:alert] = I18n.t("administrator.roles.role_has_users", user_count: role.users.count) return redirect_to admin_roles_path(selected_role: role.id) elsif Role::RESERVED_ROLE_NAMES.include?(role) || role.provider != @user_domain || - role.priority <= current_user.highest_priority_role.priority + role.priority <= current_user.role.priority return redirect_to admin_roles_path(selected_role: role.id) else role.role_permissions.delete_all diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d59a64b9..e9e78cfd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,7 +27,7 @@ class ApplicationController < ActionController::Base # Retrieves the current user. def current_user - @current_user ||= User.includes(:roles, :main_room).find_by(id: session[:user_id]) + @current_user ||= User.includes(:role, :main_room).find_by(id: session[:user_id]) if Rails.configuration.loadbalanced_configuration if @current_user && !@current_user.has_role?(:super_admin) && @@ -119,7 +119,7 @@ class ApplicationController < ActionController::Base current_user&.greenlight_account? && current_user&.authenticate(Rails.configuration.admin_password_default) flash.now[:alert] = I18n.t("default_admin", - edit_link: edit_user_path(user_uid: current_user.uid) + "?setting=password").html_safe + edit_link: change_password_path(user_uid: current_user.uid)).html_safe end end diff --git a/app/controllers/concerns/authenticator.rb b/app/controllers/concerns/authenticator.rb index f935d6b4..b2802da7 100644 --- a/app/controllers/concerns/authenticator.rb +++ b/app/controllers/concerns/authenticator.rb @@ -46,8 +46,10 @@ module Authenticator internal_error_url, not_found_url] url = if cookies[:return_to] && !dont_redirect_to.include?(cookies[:return_to]) cookies[:return_to] - else + elsif user.role.get_permission("can_create_rooms") user.main_room + else + cant_create_rooms_path end # Delete the cookie if it exists diff --git a/app/controllers/concerns/bbb_server.rb b/app/controllers/concerns/bbb_server.rb index ee70ed7c..f8a99a56 100644 --- a/app/controllers/concerns/bbb_server.rb +++ b/app/controllers/concerns/bbb_server.rb @@ -54,7 +54,6 @@ module BbbServer join_opts = {} join_opts[:userID] = uid if uid join_opts[:join_via_html5] = true - join_opts[:guest] = true if options[:require_moderator_approval] && !options[:user_is_moderator] bbb_server.join_meeting_url(room.bbb_id, name, password, join_opts) end diff --git a/app/controllers/concerns/emailer.rb b/app/controllers/concerns/emailer.rb index 59540023..aeb48b1d 100644 --- a/app/controllers/concerns/emailer.rb +++ b/app/controllers/concerns/emailer.rb @@ -99,7 +99,6 @@ module Emailer def send_approval_user_signup_email(user) begin return unless Rails.configuration.enable_email_verification - admin_emails = admin_emails() UserMailer.approval_user_signup(user, admins_url(tab: "pending"), admin_emails, @settings).deliver_now unless admin_emails.empty? @@ -129,12 +128,12 @@ module Emailer end def admin_emails - admins = User.all_users_with_roles.where(roles: { role_permissions: { name: "can_manage_users", value: "true" } }) + roles = Role.where(provider: @user_domain, role_permissions: { name: "can_manage_users", value: "true" }) + .pluck(:name) - if Rails.configuration.loadbalanced_configuration - admins = admins.without_role(:super_admin) - .where(provider: @user_domain) - end + admins = User.with_role(roles - ["super_admin"]) + + admins = admins.where(provider: @user_domain) if Rails.configuration.loadbalanced_configuration admins.collect(&:email).join(",") end diff --git a/app/controllers/concerns/populator.rb b/app/controllers/concerns/populator.rb index 771fa25e..79b72724 100644 --- a/app/controllers/concerns/populator.rb +++ b/app/controllers/concerns/populator.rb @@ -25,29 +25,22 @@ module Populator initial_user = case @tab when "active" - User.includes(:roles).without_role(:pending).without_role(:denied) + User.without_role([:pending, :denied]) when "deleted" - User.includes(:roles).deleted + User.deleted else - User.includes(:roles) + User.all end current_role = Role.find_by(name: @tab, provider: @user_domain) if @tab == "pending" || @tab == "denied" - initial_list = if current_user.has_role? :super_admin - initial_user.where.not(id: current_user.id) - else - initial_user.without_role(:super_admin).where.not(id: current_user.id) - end + initial_list = initial_user.without_role(:super_admin) unless current_user.has_role? :super_admin - if Rails.configuration.loadbalanced_configuration - initial_list.where(provider: @user_domain) - .admins_search(@search, current_role) - .admins_order(@order_column, @order_direction) - else - initial_list.admins_search(@search, current_role) - .admins_order(@order_column, @order_direction) - end + initial_list = initial_list.where(provider: @user_domain) if Rails.configuration.loadbalanced_configuration + + initial_list.where.not(id: current_user.id) + .admins_search(@search, current_role) + .admins_order(@order_column, @order_direction) end # Returns a list of rooms that are in the same context of the current user @@ -55,9 +48,9 @@ module Populator if Rails.configuration.loadbalanced_configuration Room.includes(:owner).where(users: { provider: @user_domain }) .admins_search(@search) - .admins_order(@order_column, @order_direction) + .admins_order(@order_column, @order_direction, @running_room_bbb_ids) else - Room.includes(:owner).all.admins_search(@search).admins_order(@order_column, @order_direction) + Room.includes(:owner).admins_search(@search).admins_order(@order_column, @order_direction, @running_room_bbb_ids) end end @@ -77,10 +70,7 @@ module Populator roles_can_appear << role.name if role.get_permission("can_appear_in_share_list") && role.priority >= 0 end - initial_list = User.where.not(uid: current_user.uid) - .without_role(:pending) - .without_role(:denied) - .with_highest_priority_role(roles_can_appear) + initial_list = User.where.not(uid: current_user.uid).with_role(roles_can_appear) return initial_list unless Rails.configuration.loadbalanced_configuration initial_list.where(provider: @user_domain) @@ -88,7 +78,7 @@ module Populator # Returns a list of users that can merged into another user def merge_user_list - initial_list = User.where.not(uid: current_user.uid).without_role(:super_admin) + initial_list = User.without_role(:super_admin).where.not(uid: current_user.uid) return initial_list unless Rails.configuration.loadbalanced_configuration initial_list.where(provider: @user_domain) diff --git a/app/controllers/concerns/rolify.rb b/app/controllers/concerns/rolify.rb index 0dfff428..63eca96e 100644 --- a/app/controllers/concerns/rolify.rb +++ b/app/controllers/concerns/rolify.rb @@ -46,60 +46,23 @@ module Rolify end # Updates a user's roles - def update_roles(roles) - # Check that the user can manage users - return true unless current_user.highest_priority_role.get_permission("can_manage_users") + def update_roles(role_id) + return true if role_id.blank? + # Check to make sure user can edit roles + return false unless current_user.role.get_permission("can_manage_users") - new_roles = roles.split(' ').map(&:to_i) - old_roles = @user.roles.pluck(:id).uniq + return true if @user.role_id == role_id.to_i - added_role_ids = new_roles - old_roles - removed_role_ids = old_roles - new_roles + new_role = Role.find_by(id: role_id, provider: @user_domain) + # Return false if new role doesn't exist + return false if new_role.nil? - added_roles = [] - removed_roles = [] - current_user_role = current_user.highest_priority_role - - # Check that the user has the permissions to add all the new roles - added_role_ids.each do |id| - role = Role.find(id) - - # Admins are able to add the admin role to other users. All other roles may only - # add roles with a higher priority - if (role.priority > current_user_role.priority || current_user_role.name == "admin") && - role.provider == @user_domain - added_roles << role - else - return false - end - end - - # Check that the user has the permissions to remove all the deleted roles - removed_role_ids.each do |id| - role = Role.find(id) - - # Admins are able to remove the admin role from other users. All other roles may only - # remove roles with a higher priority - if (role.priority > current_user_role.priority || current_user_role.name == "admin") && - role.provider == @user_domain - removed_roles << role - else - return false - end - end + return false if new_role.priority < current_user.role.priority # Send promoted/demoted emails - added_roles.each { |role| send_user_promoted_email(@user, role) if role.get_permission("send_promoted_email") } - removed_roles.each { |role| send_user_demoted_email(@user, role) if role.get_permission("send_demoted_email") } + send_user_promoted_email(@user, new_role) if new_role.get_permission("send_promoted_email") - # Update the roles - @user.roles.delete(removed_roles) - @user.roles << added_roles - - # Make sure each user always has at least the user role - @user.roles = [Role.find_by(name: "user", provider: @user_domain)] if @user.roles.count.zero? - - @user.save! + @user.update_attribute(:role_id, role_id) end # Updates a roles priority @@ -107,7 +70,7 @@ module Rolify user_role = Role.find_by(name: "user", provider: @user_domain) admin_role = Role.find_by(name: "admin", provider: @user_domain) - current_user_role = current_user.highest_priority_role + current_user_role = current_user.role # Users aren't allowed to update the priority of the admin or user roles return false if role_to_update.include?(user_role.id.to_s) || role_to_update.include?(admin_role.id.to_s) @@ -149,7 +112,7 @@ module Rolify # Update Permissions def update_permissions(role) - current_user_role = current_user.highest_priority_role + current_user_role = current_user.role # Checks that it is valid for the provider to update the role return false if role.priority <= current_user_role.priority || role.provider != @user_domain diff --git a/app/controllers/password_resets_controller.rb b/app/controllers/password_resets_controller.rb index 36a84c83..73ea364a 100644 --- a/app/controllers/password_resets_controller.rb +++ b/app/controllers/password_resets_controller.rb @@ -67,6 +67,8 @@ class PasswordResetsController < ApplicationController def find_user @user = User.find_by(reset_digest: User.hash_token(params[:id]), provider: @user_domain) + + return redirect_to new_password_reset_url, alert: I18n.t("reset_password.invalid_token") unless @user end def user_params diff --git a/app/controllers/recordings_controller.rb b/app/controllers/recordings_controller.rb index fc82470e..93912b46 100644 --- a/app/controllers/recordings_controller.rb +++ b/app/controllers/recordings_controller.rb @@ -57,8 +57,6 @@ class RecordingsController < ApplicationController # Ensure the user is logged into the room they are accessing. def verify_room_ownership - if !@room.owned_by?(current_user) && !current_user&.highest_priority_role&.get_permission("can_manage_rooms_recordings") - redirect_to root_path - end + redirect_to root_path if !@room.owned_by?(current_user) && !current_user&.role&.get_permission("can_manage_rooms_recordings") end end diff --git a/app/controllers/rooms_controller.rb b/app/controllers/rooms_controller.rb index 7d2d048b..c9ef6417 100644 --- a/app/controllers/rooms_controller.rb +++ b/app/controllers/rooms_controller.rb @@ -25,7 +25,7 @@ class RoomsController < ApplicationController before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms } before_action :validate_verified_email, except: [:show, :join], unless: -> { !Rails.configuration.enable_email_verification } - before_action :find_room, except: [:create, :join_specific_room] + before_action :find_room, except: [:create, :join_specific_room, :cant_create_rooms] before_action :verify_room_ownership_or_admin_or_shared, only: [:start, :shared_access] before_action :verify_room_ownership_or_admin, only: [:update_settings, :destroy] before_action :verify_room_ownership_or_shared, only: [:remove_shared_access] @@ -69,19 +69,13 @@ class RoomsController < ApplicationController # If its the current user's room if current_user && (@room.owned_by?(current_user) || @shared_room) - if current_user.highest_priority_role.get_permission("can_create_rooms") - # User is allowed to have rooms - @search, @order_column, @order_direction, recs = - recordings(@room.bbb_id, params.permit(:search, :column, :direction), true) + # User is allowed to have rooms + @search, @order_column, @order_direction, recs = + recordings(@room.bbb_id, params.permit(:search, :column, :direction), true) - @user_list = shared_user_list if shared_access_allowed + @user_list = shared_user_list if shared_access_allowed - @pagy, @recordings = pagy_array(recs) - else - # Render view for users that cant create rooms - @recent_rooms = Room.where(id: cookies.encrypted["#{current_user.uid}_recently_joined_rooms"]) - render :cant_create_rooms - end + @pagy, @recordings = pagy_array(recs) else return redirect_to root_path, flash: { alert: I18n.t("room.invalid_provider") } if incorrect_user_domain @@ -89,6 +83,19 @@ class RoomsController < ApplicationController end end + # GET /rooms + def cant_create_rooms + shared_rooms = current_user.shared_rooms + + if current_user.shared_rooms.empty? + # Render view for users that cant create rooms + @recent_rooms = Room.where(id: cookies.encrypted["#{current_user.uid}_recently_joined_rooms"]) + render :cant_create_rooms + else + redirect_to shared_rooms[0] + end + end + # POST /:room_uid def join return redirect_to root_path, diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index d16b520b..b2e21e0d 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -39,7 +39,7 @@ class SessionsController < ApplicationController "#{Rails.configuration.relative_url_root}/auth/#{@providers.first}" end - return redirect_to provider_path + redirect_to provider_path end end @@ -94,7 +94,7 @@ class SessionsController < ApplicationController login(user) end - # GET /users/logout + # POST /users/logout def destroy logout redirect_to root_path @@ -218,7 +218,7 @@ class SessionsController < ApplicationController # Add pending role if approval method and is a new user if approval_registration && !@user_exists - user.add_role :pending + user.set_role :pending # Inform admins that a user signed up if emails are turned on send_approval_user_signup_email(user) @@ -228,6 +228,8 @@ class SessionsController < ApplicationController send_invite_user_signup_email(user) if invite_registration && !@user_exists + user.set_role :user unless @user_exists + login(user) if @auth['provider'] == "twitter" diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 9ce870bb..a061f246 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -24,7 +24,7 @@ class UsersController < ApplicationController include Recorder include Rolify - before_action :find_user, only: [:edit, :change_password, :delete_account, :update] + before_action :find_user, only: [:edit, :change_password, :delete_account, :update, :update_password] before_action :ensure_unauthenticated_except_twitter, only: [:create] before_action :check_user_signup_allowed, only: [:create] before_action :check_admin_of, only: [:edit, :change_password, :delete_account] @@ -47,7 +47,7 @@ class UsersController < ApplicationController # Set user to pending and redirect if Approval Registration is set if approval_registration - @user.add_role :pending + @user.set_role :pending return redirect_to root_path, flash: { success: I18n.t("registration.approval.signup") } unless Rails.configuration.enable_email_verification @@ -56,7 +56,11 @@ class UsersController < ApplicationController send_registration_email # Sign in automatically if email verification is disabled or if user is already verified. - login(@user) && return if !Rails.configuration.enable_email_verification || @user.email_verified + if !Rails.configuration.enable_email_verification || @user.email_verified + @user.set_role :user + + login(@user) && return + end send_activation_email(@user, @user.create_activation_token) @@ -77,9 +81,8 @@ class UsersController < ApplicationController def delete_account end - # PATCH /u/:user_uid/edit + # POST /u/:user_uid/edit def update - profile = params[:setting] == "password" ? change_password_path(@user) : edit_user_path(@user) if session[:prev_url].present? path = session[:prev_url] session.delete(:prev_url) @@ -87,44 +90,50 @@ class UsersController < ApplicationController path = admins_path end - redirect_path = current_user.admin_of?(@user, "can_manage_users") ? path : profile + redirect_path = current_user.admin_of?(@user, "can_manage_users") ? path : edit_user_path(@user) - if params[:setting] == "password" - # Update the users password. - - if @user.authenticate(user_params[:password]) - # Verify that the new passwords match. - if user_params[:new_password] == user_params[:password_confirmation] - @user.password = user_params[:new_password] - else - # New passwords don't match. - @user.errors.add(:password_confirmation, "doesn't match") - end - else - # Original password is incorrect, can't update. - @user.errors.add(:password, "is incorrect") - end - - # Notify the user that their account has been updated. - return redirect_to redirect_path, - flash: { success: I18n.t("info_update_success") } if @user.errors.empty? && @user.save - - render :change_password - else - if @user.update_attributes(user_params) - @user.update_attributes(email_verified: false) if user_params[:email] != @user.email - - user_locale(@user) - - if update_roles(params[:user][:role_ids]) - return redirect_to redirect_path, flash: { success: I18n.t("info_update_success") } - else - flash[:alert] = I18n.t("administrator.roles.invalid_assignment") - end - end - - render :edit + unless @user.greenlight_account? + params[:user][:name] = @user.name + params[:user][:email] = @user.email end + + if @user.update_attributes(user_params) + @user.update_attributes(email_verified: false) if user_params[:email] != @user.email + + user_locale(@user) + + if update_roles(params[:user][:role_id]) + return redirect_to redirect_path, flash: { success: I18n.t("info_update_success") } + else + flash[:alert] = I18n.t("administrator.roles.invalid_assignment") + end + end + + render :edit + end + + # POST /u/:user_uid/change_password + def update_password + # Update the users password. + if @user.authenticate(user_params[:password]) + # Verify that the new passwords match. + if user_params[:new_password] == user_params[:password_confirmation] + @user.password = user_params[:new_password] + else + # New passwords don't match. + @user.errors.add(:password_confirmation, "doesn't match") + end + else + # Original password is incorrect, can't update. + @user.errors.add(:password, "is incorrect") + end + + # Notify the user that their account has been updated. + return redirect_to change_password_path, + flash: { success: I18n.t("info_update_success") } if @user.errors.empty? && @user.save + + # redirect_to change_password_path + render :change_password end # DELETE /u/:user_uid diff --git a/app/helpers/admins_helper.rb b/app/helpers/admins_helper.rb index 6976a66b..cd420d8b 100644 --- a/app/helpers/admins_helper.rb +++ b/app/helpers/admins_helper.rb @@ -31,6 +31,11 @@ module AdminsHelper @running_room_bbb_ids.include?(id) end + # Returns a more friendly/readable date time object + def friendly_time(date) + I18n.l date, format: "%B %d, %Y %H:%M UTC" + end + # Site Settings def admin_invite_registration @@ -110,6 +115,6 @@ module AdminsHelper # Roles def edit_disabled - @edit_disabled ||= @selected_role.priority <= current_user.highest_priority_role.priority + @edit_disabled ||= @selected_role.priority <= current_user.role.priority end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index eaf90a23..7b4e914b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -58,7 +58,16 @@ module ApplicationHelper # Returns the page that the logo redirects to when clicked on def home_page return admins_path if current_user.has_role? :super_admin - current_user.main_room + return current_user.main_room if current_user.role.get_permission("can_create_rooms") + cant_create_rooms_path + end + + # Returns 'active' if the current page is the users home page (used to style header) + def active_home + home_actions = %w[show cant_create_rooms] + return "active" if params[:controller] == "admins" && params[:action] == "index" && current_user.has_role?(:super_admin) + return "active" if params[:controller] == "rooms" && home_actions.include?(params[:action]) + "" end # Returns the action method of the current page @@ -97,10 +106,22 @@ module ApplicationHelper "https://www.googletagmanager.com/gtag/js?id=#{ENV['GOOGLE_ANALYTICS_TRACKING_ID']}" end + # Checks to make sure the image url returns 200 and is of type image def valid_url?(input) - uri = URI.parse(input) - !uri.host.nil? - rescue URI::InvalidURIError + url = URI.parse(input) + + # Don't allow reference to own site + return false if url.host == request.host + + # Make a GET request and validate content type + http = Net::HTTP.new(url.host, url.port) + http.use_ssl = (url.scheme == "https") + + http.start do |web| + response = web.head(url.request_uri) + return response.code == "200" && response['Content-Type'].start_with?('image') + end + rescue false end end diff --git a/app/helpers/theming_helper.rb b/app/helpers/theming_helper.rb index bb725f12..527dd260 100644 --- a/app/helpers/theming_helper.rb +++ b/app/helpers/theming_helper.rb @@ -22,6 +22,16 @@ module ThemingHelper @settings.get_value("Branding Image") || Rails.configuration.branding_image_default end + # Returns the legal URL based on user's provider + def legal_url + @settings.get_value("Legal URL") || "" + end + + # Returns the logo based on user's provider + def privpolicy_url + @settings.get_value("Privacy Policy URL") || "" + end + # Returns the primary color based on user's provider def user_color @settings.get_value("Primary Color") || Rails.configuration.primary_color_default diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index c92ce09b..6e49a9a9 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -26,7 +26,7 @@ module UsersHelper end def disabled_roles(user) - current_user_role = current_user.highest_priority_role + current_user_role = current_user.role # Admins are able to remove the admin role from other admins # For all other roles they can only add/remove roles with a higher priority @@ -38,7 +38,7 @@ module UsersHelper .pluck(:id) end - user.roles.by_priority.pluck(:id) | disallowed_roles + [user.role.id] + disallowed_roles end # Returns language selection options for user edit @@ -52,6 +52,11 @@ module UsersHelper language_opts.sort end + # Returns a list of roles that the user can have + def role_options + Role.editable_roles(@user_domain).where("priority >= ?", current_user.role.priority) + end + # Parses markdown for rendering. def markdown(text) markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, diff --git a/app/models/ability.rb b/app/models/ability.rb index 559d69f5..be439105 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -25,7 +25,7 @@ class Ability elsif user.has_role? :super_admin can :manage, :all else - highest_role = user.highest_priority_role + highest_role = user.role if highest_role.get_permission("can_edit_site_settings") can [:site_settings, :room_configuration, :update_settings, :update_room_configuration, :coloring, :registration_method], :admin diff --git a/app/models/concerns/auth_values.rb b/app/models/concerns/auth_values.rb index 0201959c..a3f719db 100644 --- a/app/models/concerns/auth_values.rb +++ b/app/models/concerns/auth_values.rb @@ -63,7 +63,7 @@ module AuthValues role_provider = auth['provider'] == "bn_launcher" ? auth['info']['customer'] : "greenlight" roles.each do |role_name| role = Role.find_by(provider: role_provider, name: role_name) - user.roles << role if !role.nil? && !user.has_role?(role_name) + user.role = role if !role.nil? && !user.has_role?(role_name) end end end diff --git a/app/models/role.rb b/app/models/role.rb index 124bcd8e..41c54bcf 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -17,10 +17,12 @@ # with BigBlueButton; if not, see . class Role < ApplicationRecord - has_and_belongs_to_many :users, join_table: :users_roles + has_and_belongs_to_many :users, join_table: :users_roles # Obsolete -- not used anymore has_many :role_permissions - default_scope { includes(:role_permissions).order(:priority) } + has_many :users + + default_scope { includes(:role_permissions).distinct.order(:priority) } scope :by_priority, -> { order(:priority) } scope :editable_roles, ->(provider) { where(provider: provider).where.not(name: %w[super_admin denied pending]) } diff --git a/app/models/room.rb b/app/models/room.rb index e657fd12..02d0b7cc 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -45,10 +45,13 @@ class Room < ApplicationRecord where(search_query, search: search_param) end - def self.admins_order(column, direction) + def self.admins_order(column, direction, running_ids) # Include the owner of the table table = joins(:owner) + # Rely on manual ordering if trying to sort by status + return order_by_status(table, running_ids) if column == "status" + return table.order(Arel.sql("rooms.#{column} #{direction}")) if table.column_names.include?(column) return table.order(Arel.sql("#{column} #{direction}")) if column == "users.name" @@ -80,6 +83,21 @@ class Room < ApplicationRecord ActionCable.server.broadcast("#{uid}_waiting_channel", action: "started") end + # Return table with the running rooms first + def self.order_by_status(table, ids) + return table if ids.blank? + + order_string = "CASE bbb_id " + + ids.each_with_index do |id, index| + order_string += "WHEN '#{id}' THEN #{index} " + end + + order_string += "ELSE #{ids.length} END" + + table.order(Arel.sql(order_string)) + end + private # Generates a uid for the room and BigBlueButton. @@ -90,21 +108,18 @@ class Room < ApplicationRecord self.attendee_pw = RandomPassword.generate(length: 12) end - # Generates a three character uid chunk. - def uid_chunk - charset = ("a".."z").to_a - %w(b i l o s) + ("2".."9").to_a - %w(5 8) - (0...3).map { charset.to_a[rand(charset.size)] }.join - end - - # Generates a random room uid that uses the users name. + # Generates a fully random room uid. def random_room_uid - [owner.name_chunk, uid_chunk, uid_chunk].join('-').downcase + # 6 character long random string of chars from a..z and 0..9 + full_chunk = SecureRandom.alphanumeric(6).downcase + + [owner.name_chunk, full_chunk[0..2], full_chunk[3..5]].join("-") end # Generates a unique bbb_id based on uuid. def unique_bbb_id loop do - bbb_id = SecureRandom.hex(20) + bbb_id = SecureRandom.alphanumeric(40).downcase break bbb_id unless Room.exists?(bbb_id: bbb_id) end end diff --git a/app/models/setting.rb b/app/models/setting.rb index e38ee036..38b0a9b4 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -48,6 +48,10 @@ class Setting < ApplicationRecord case name when "Branding Image" Rails.configuration.branding_image_default + when "Legal URL" + nil + when "Privacy Policy URL" + nil when "Primary Color" Rails.configuration.primary_color_default when "Registration Method" diff --git a/app/models/user.rb b/app/models/user.rb index bdc25fa0..fd02bc97 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,7 +31,9 @@ class User < ApplicationRecord has_many :shared_access belongs_to :main_room, class_name: 'Room', foreign_key: :room_id, required: false - has_and_belongs_to_many :roles, join_table: :users_roles + has_and_belongs_to_many :roles, join_table: :users_roles # obsolete + + belongs_to :role, required: false validates :name, length: { maximum: 256 }, presence: true validates :provider, presence: true @@ -92,14 +94,12 @@ class User < ApplicationRecord end search_param = "%#{string}%" - joins("LEFT OUTER JOIN users_roles ON users_roles.user_id = users.id LEFT OUTER JOIN roles " \ - "ON roles.id = users_roles.role_id").distinct - .where(search_query, search: search_param, roles_search: role_search_param) + where(search_query, search: search_param, roles_search: role_search_param) end def self.admins_order(column, direction) # Arel.sql to avoid sql injection - order(Arel.sql("#{column} #{direction}")) + order(Arel.sql("users.#{column} #{direction}")) end # Returns a list of rooms ordered by last session (with nil rooms last) @@ -109,6 +109,7 @@ class User < ApplicationRecord # Activates an account and initialize a users main room def activate + set_role :user if role_id.nil? update_attributes(email_verified: true, activated_at: Time.zone.now, activation_digest: nil) end @@ -162,7 +163,7 @@ class User < ApplicationRecord end def admin_of?(user, permission) - has_correct_permission = highest_priority_role.get_permission(permission) && id != user.id + has_correct_permission = role.get_permission(permission) && id != user.id return has_correct_permission unless Rails.configuration.loadbalanced_configuration return id != user.id if has_role? :super_admin @@ -170,70 +171,31 @@ class User < ApplicationRecord end # role functions - def highest_priority_role - roles.min_by(&:priority) - end + def set_role(role) # rubocop:disable Naming/AccessorMethodName + return if has_role?(role) - def add_role(role) - unless has_role?(role) - role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight" + new_role = Role.find_by(name: role, provider: role_provider) - new_role = Role.find_by(name: role, provider: role_provider) + return if new_role.nil? - if new_role.nil? - return if Role.duplicate_name(role, role_provider) || role.strip.empty? + create_home_room if main_room.nil? && new_role.get_permission("can_create_rooms") - new_role = Role.create_new_role(role, role_provider) - end + update_attribute(:role, new_role) - roles << new_role - - save! - end - end - - def remove_role(role) - if has_role?(role) - role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight" - - roles.delete(Role.find_by(name: role, provider: role_provider)) - save! - end + new_role end # This rule is disabled as the function name must be has_role? - # rubocop:disable Naming/PredicateName - def has_role?(role) - # rubocop:enable Naming/PredicateName - roles.each do |single_role| - return true if single_role.name.eql? role.to_s - end - - false + def has_role?(role_name) # rubocop:disable Naming/PredicateName + role&.name == role_name.to_s end def self.with_role(role) - User.all_users_with_roles.where(roles: { name: role }) + User.includes(:role).where(roles: { name: role }) end def self.without_role(role) - User.where.not(id: with_role(role).pluck(:id)) - end - - def self.with_highest_priority_role(role) - User.all_users_highest_priority_role.where(roles: { name: role }) - end - - def self.all_users_with_roles - User.joins("INNER JOIN users_roles ON users_roles.user_id = users.id INNER JOIN roles " \ - "ON roles.id = users_roles.role_id INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct - end - - def self.all_users_highest_priority_role - User.joins("INNER JOIN (SELECT user_id, min(roles.priority) as role_priority FROM users_roles " \ - "INNER JOIN roles ON users_roles.role_id = roles.id GROUP BY user_id) as a ON " \ - "a.user_id = users.id INNER JOIN roles ON roles.priority = a.role_priority " \ - " INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct + User.includes(:role).where.not(roles: { name: role }) end private @@ -246,15 +208,13 @@ class User < ApplicationRecord def setup_user # Initializes a room for the user and assign a BigBlueButton user id. id = "gl-#{(0...12).map { rand(65..90).chr }.join.downcase}" - room = Room.create!(owner: self, name: I18n.t("home_room")) - update_attributes(uid: id, main_room: room) + update_attributes(uid: id) # Initialize the user to use the default user role role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight" Role.create_default_roles(role_provider) if Role.where(provider: role_provider).count.zero? - add_role(:user) if roles.blank? end def check_if_email_can_be_blank @@ -266,4 +226,13 @@ class User < ApplicationRecord end end end + + def create_home_room + room = Room.create!(owner: self, name: I18n.t("home_room")) + update_attributes(main_room: room) + end + + def role_provider + Rails.configuration.loadbalanced_configuration ? provider : "greenlight" + end end diff --git a/app/views/admins/components/_menu_buttons.html.erb b/app/views/admins/components/_menu_buttons.html.erb index af8f3f12..858a1bf7 100644 --- a/app/views/admins/components/_menu_buttons.html.erb +++ b/app/views/admins/components/_menu_buttons.html.erb @@ -14,7 +14,7 @@ %>
- <% highest_role = current_user.highest_priority_role %> + <% highest_role = current_user.role %> <% highest_role.name %> <% if highest_role.get_permission("can_manage_users") || highest_role.name == "super_admin" %> <%= link_to admins_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "index"}" do %> diff --git a/app/views/admins/components/_recordings.html.erb b/app/views/admins/components/_recordings.html.erb index 76e8ed17..8d890fef 100644 --- a/app/views/admins/components/_recordings.html.erb +++ b/app/views/admins/components/_recordings.html.erb @@ -16,7 +16,7 @@
- +
"> @@ -94,10 +94,10 @@
<% if !@recordings.empty?%> -
+
<%== pagy_bootstrap_nav(@pagy) %>
<% end %>
-
\ No newline at end of file +
diff --git a/app/views/admins/components/_roles.html.erb b/app/views/admins/components/_roles.html.erb index 77a316e1..a622bff6 100644 --- a/app/views/admins/components/_roles.html.erb +++ b/app/views/admins/components/_roles.html.erb @@ -15,7 +15,7 @@
- <% current_role = current_user.highest_priority_role%> + <% current_role = current_user.role%>
@@ -34,7 +34,7 @@
"> <%= form_with model: @selected_role, url: admin_update_role_path(@selected_role.id), method: :post do |f| %> - <%= f.label t('administrator.roles.name'), class: "form-label" %> + <%= f.label :name, t('administrator.roles.name'), class: "form-label" %> <%= f.text_field :name, class: 'form-control mb-3', value: translated_role_name(@selected_role), readonly: edit_disabled || @selected_role.name == "user" || @selected_role.name == "admin", required: true %> <%= f.hidden_field :colour, id: "role-colour", value: role_colour(@selected_role) %> diff --git a/app/views/admins/components/_rooms.html.erb b/app/views/admins/components/_rooms.html.erb index cfb95a22..39259229 100644 --- a/app/views/admins/components/_rooms.html.erb +++ b/app/views/admins/components/_rooms.html.erb @@ -16,7 +16,7 @@
- +
+ @@ -56,10 +59,10 @@
"> @@ -43,6 +43,9 @@ ↑ <% end %> + <%= t("administrator.rooms.table.participants") %> + <%= t("administrator.rooms.table.status") %>
<% if !@rooms.empty?%> -
+
<%== pagy_bootstrap_nav(@pagy) %>
<% end %>
-
\ No newline at end of file +
diff --git a/app/views/admins/components/_server_recording_row.html.erb b/app/views/admins/components/_server_recording_row.html.erb index bde89c80..c9c0c31c 100644 --- a/app/views/admins/components/_server_recording_row.html.erb +++ b/app/views/admins/components/_server_recording_row.html.erb @@ -15,14 +15,14 @@ -
- +
+ <% if recording[:metadata][:name] %> <%= recording[:metadata][:name] %> <% else %> <%= recording[:name] %> <% end %> - +
diff --git a/app/views/admins/components/_server_room_row.html.erb b/app/views/admins/components/_server_room_row.html.erb index f874452e..6a37ba55 100644 --- a/app/views/admins/components/_server_room_row.html.erb +++ b/app/views/admins/components/_server_room_row.html.erb @@ -15,16 +15,23 @@ data-room-access-code="<%= room.access_code %>"> -
+
<% if room.id == room.owner.room_id %> <% end %> - + <%= room.name %> - +
- <%= [t("administrator.users.table.created"), ": ", room.created_at].join %> + <% running = room_is_running(room.bbb_id) %> + <% if running %> + <%= t("administrator.rooms.table.started", session: friendly_time(room.last_session)) %> + <% elsif room.last_session.present? %> + <%= t("administrator.rooms.table.ended", session: friendly_time(room.last_session)) %> + <% else %> + <%= [t("administrator.users.table.created"), ": ", friendly_time(room.created_at)].join %> + <% end %>
@@ -33,8 +40,10 @@ <%= room.uid %> + + <%= @participants_count[room.bbb_id].presence || "-" %> + - <% running = room_is_running(room.bbb_id) %> <% if running %> <%= t("administrator.rooms.table.running") %> <% else %> diff --git a/app/views/admins/components/_settings.html.erb b/app/views/admins/components/_settings.html.erb index 4dcb0f73..17c6e8a6 100644 --- a/app/views/admins/components/_settings.html.erb +++ b/app/views/admins/components/_settings.html.erb @@ -28,6 +28,34 @@
+
+
+
+ + +
+ + + + +
+
+
+
+
+
+
+ + +
+ + + + +
+
+
+
diff --git a/app/views/admins/components/_users.html.erb b/app/views/admins/components/_users.html.erb index 8d46812e..c58adb3e 100644 --- a/app/views/admins/components/_users.html.erb +++ b/app/views/admins/components/_users.html.erb @@ -13,21 +13,6 @@ # with BigBlueButton; if not, see . %> -<% -# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. -# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below). -# This program is free software; you can redistribute it and/or modify it under the -# terms of the GNU Lesser General Public License as published by the Free Software -# Foundation; either version 3.0 of the License, or (at your option) any later -# version. -# -# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. -# You should have received a copy of the GNU Lesser General Public License along -# with BigBlueButton; if not, see . -%> - <% if @role.nil? %> <%= render "admins/components/manage_users_tags" %> <% else %> @@ -89,11 +74,10 @@ <%= user.email && user.email != "" ? user.email : user.username%> <%= user.provider %> - <% roles = user.roles().pluck(:name) %> - <%= render "admins/components/admins_role", role: user.highest_priority_role %> + <%= render "admins/components/admins_role", role: user.role %> - <% if !roles.include?("super_admin") %> + <% if !user.has_role?("super_admin") %>