diff --git a/.gitignore b/.gitignore index 1b95341e..e197be3c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ coverage/* public/upload* upload* .byebug_history +docker-compose.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..9193595c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM opensuse/leap:15.1 + +# This includes several packages (like WebKit, xvfb or liberation-fonts) +# That are only needed to run the automated tests and wouldn't be relevant +# in a production environment. +RUN zypper --gpg-auto-import-keys --non-interactive in --no-recommends \ + ruby ruby-devel ruby2.5-rubygem-bundler libxml2-devel libxslt-devel \ + postgresql-devel sqlite3-devel libmariadb-devel \ + libQt5WebKit5 libQt5WebKit5-devel libQt5WebKitWidgets5 libQt5WebKitWidgets-devel \ + xvfb-run which liberation-fonts gcc gcc-c++ make tar gzip patch timezone && \ + zypper clean -a + +RUN mkdir /app +WORKDIR /app +COPY . /app +ENV QMAKE=/usr/bin/qmake-qt5 +RUN bundle install + +CMD ["rails", "server", "-b", "0.0.0.0"] diff --git a/Gemfile b/Gemfile index 7f1d2bb9..14b5c468 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ gem 'responders', '~> 2.0' # Choose your weapon gem 'sqlite3', '~> 1.3.13' # gem 'pg', '~> 0.21' -# gem 'mysql2', '~> 0.3.13' +# gem 'mysql2', '~> 0.4.10' # Use SCSS for stylesheets gem 'sass-rails', '~> 4.0.0' diff --git a/README.md b/README.md index 7e4b01f0..e4ba0c01 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,17 @@ name). ## Requirements -* Ruby >= 1.9 +* Ruby >= 2.4 * Any Rails supported database system: PosgreSQL, SQLite3, MariaDB, MySQL... ## Installation Please refer to [INSTALL](doc/INSTALL.md) documentation file +## Development +To simplify the process of setting up a development environment, this repository +includes some `docker-compose` configuration examples. Check the +[DOCKER](doc/DOCKER.md) documentation file. + ## Contact Ancor González Sosa diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 36a07f2a..5ccdd90d 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -10,7 +10,8 @@ def participants { label: @event.name, url: event_path(@event) }, { label: 'participants' } ] - @requests = @event.travel_sponsorships.includes(:user).group(:user_id).accessible_by(current_ability) + @requests = @event.travel_sponsorships.eager_load(:user).order('lower(users.nickname)').accessible_by(current_ability) + @requests.uniq!(&:user_id) end protected diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index fd379392..bcfcaca3 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -14,7 +14,7 @@ def event_title_line(event) def users_for_event(state) requests = @event.travel_sponsorships.includes(:user).accessible_by(current_ability) requests = requests.where(state: state) if state != 'all' - requests.distinct.pluck('users.email') + requests.distinct.order('users.email').pluck('users.email') end def state_label(state) diff --git a/app/models/event_organizer.rb b/app/models/event_organizer.rb index 59d6cb5f..19a5df06 100644 --- a/app/models/event_organizer.rb +++ b/app/models/event_organizer.rb @@ -9,6 +9,6 @@ class EventOrganizer < ActiveRecord::Base validates :user_id, uniqueness: { scope: :event_id, message: 'Already an event organizer for this event' } def self.autocomplete_users(term) - User.order(:nickname).where('nickname like ? or email like ?', "%#{term}%", "%#{term}%").pluck(:nickname, :email) + User.order('lower(nickname)').where('nickname like ? or email like ?', "%#{term}%", "%#{term}%").pluck(:nickname, :email) end end diff --git a/doc/DOCKER.md b/doc/DOCKER.md new file mode 100644 index 00000000..3b8a5f33 --- /dev/null +++ b/doc/DOCKER.md @@ -0,0 +1,37 @@ +# Using Docker to Develop TSP + +This repository includes a `Dockerfile` and a set of `docker-compose` configuration examples in +order to simplify the process of setting up a development environment. + +Given that you have `docker` and `docker-compose` installed, the process should be pretty +straighforward. + +1. Select a `docker-compose` configuration file from the `docker/` directory and copy it as + `docker-compose.yml`. For instance, to run the application using a PostgreSQL database: + + cp docker/docker-compose.development.postgresql docker-compose.yml + +2. Uncomment the gem for your favorite database driver from the `Gemfile`. +3. Copy the database configuration from `docker/` for your database. For instance, + to use PostgreSQL: + + cp docker/database.postgresql.yml config/database.yml + +3. Build the image: + + docker-compose build + +4. Now you should be able to set up the database: + + docker-compose run --rm web rake db:setup + +5. (Optional) Run the testsuite to find out whether the application works. + + docker-compose run --rm web xvfb-run -a rake spec + +6. And, now, you can start the application: + + docker-compose up + +For now on, you will need to rebuild the image whenever you change the `Gemfile` or `Gemfile.lock` +files. diff --git a/docker/database.mysql.yml b/docker/database.mysql.yml new file mode 100644 index 00000000..b79177ad --- /dev/null +++ b/docker/database.mysql.yml @@ -0,0 +1,25 @@ +# Ensure the MySQL connector gem is defined in your Gemfile +# gem 'mysql2' + +# Warning: this proposes the usage of the root user with no password. +# That's done for simplicity because this docker manifest is only meant for +# development purposes and, for that, a user with privileges to create and +# destroy databases is very convenient. +# NEVER use such setup in a production system. + +development: + adapter: mysql2 + database: tsp_development + host: db + username: root + password: + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: mysql2 + database: tsp_test + host: db + username: root + password: diff --git a/docker/database.postgresql.yml b/docker/database.postgresql.yml new file mode 100644 index 00000000..f7261198 --- /dev/null +++ b/docker/database.postgresql.yml @@ -0,0 +1,29 @@ +# Ensure the PostgreSQL connector gem is defined in your Gemfile +# gem 'pg' + +# Warning: this proposes the usage of the postgres superuser with no password. +# That's done for simplicity because this docker manifest is only meant for +# development purposes and, for that, a user with privileges to create and +# destroy databases is very convenient. +# NEVER use such setup in a production system. + +development: + adapter: postgresql + encoding: unicode + database: tsp_development + pool: 5 + host: db + username: postgres + password: + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: postgresql + encoding: unicode + database: tsp_test + pool: 5 + host: db + username: postgres + password: diff --git a/docker/database.sqlite.yml b/docker/database.sqlite.yml new file mode 100644 index 00000000..1902f924 --- /dev/null +++ b/docker/database.sqlite.yml @@ -0,0 +1,19 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 diff --git a/docker/docker-compose.development.mysql.yml b/docker/docker-compose.development.mysql.yml new file mode 100644 index 00000000..c671df11 --- /dev/null +++ b/docker/docker-compose.development.mysql.yml @@ -0,0 +1,18 @@ +version: '3' +services: + web: + image: tsp:latest + build: . + volumes: + - .:/app + ports: + - "3000:3000" + depends_on: + - db + db: + image: mariadb:10.2 + restart: always + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + # MYSQL_ROOT_PASSWORD: "tsp:secret" + diff --git a/docker/docker-compose.development.postgresql.yml b/docker/docker-compose.development.postgresql.yml new file mode 100644 index 00000000..0d43b858 --- /dev/null +++ b/docker/docker-compose.development.postgresql.yml @@ -0,0 +1,14 @@ +version: '3' +services: + web: + image: tsp:latest + build: . + volumes: + - .:/app + ports: + - "3000:3000" + depends_on: + - db + db: + image: postgres:9.6 + restart: always diff --git a/docker/docker-compose.development.sqlite3.yml b/docker/docker-compose.development.sqlite3.yml new file mode 100644 index 00000000..a0cd8572 --- /dev/null +++ b/docker/docker-compose.development.sqlite3.yml @@ -0,0 +1,9 @@ +version: '3' +services: + web: + image: tsp:latest + build: . + volumes: + - .:/app + ports: + - "3000:3000" diff --git a/spec/features/event_emails_spec.rb b/spec/features/event_emails_spec.rb index 1873d955..f112f8ae 100644 --- a/spec/features/event_emails_spec.rb +++ b/spec/features/event_emails_spec.rb @@ -52,12 +52,12 @@ page.check('Submitted') page.check('Incomplete') - page.should have_field('To', with: 'gial.ackbar@rebel-alliance.org,luke.skywalker@rebel-alliance.org,evram.lajaie@rebel-alliance.org,'\ - 'c3po@droids.com,wedge.antilles@rebel-alliance.org') + mails = 'c3po@droids.com,evram.lajaie@rebel-alliance.org,gial.ackbar@rebel-alliance.org,' \ + 'luke.skywalker@rebel-alliance.org,wedge.antilles@rebel-alliance.org' + page.should have_field('To', with: mails) page.check('All') - page.should have_field('To', with: 'gial.ackbar@rebel-alliance.org,luke.skywalker@rebel-alliance.org,evram.lajaie@rebel-alliance.org,'\ - 'c3po@droids.com,wedge.antilles@rebel-alliance.org') + page.should have_field('To', with: mails) fill_in 'Subject', with: "Death Star's destruction celebration" fill_in 'event_email_body', with: "Event Death Star's destruction celebration to be conducted soon. Be ready." diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 2d97861f..0f97b62d 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -10,15 +10,19 @@ describe '#users_for_event' do it 'returns email of all the participants of the event' do - expect(users_for_event('all')).to eq(['gial.ackbar@rebel-alliance.org', 'luke.skywalker@rebel-alliance.org', 'wedge.antilles@rebel-alliance.org', - 'evram.lajaie@rebel-alliance.org', 'c3po@droids.com']) + expect(users_for_event('all')).to eq( + ['c3po@droids.com', 'evram.lajaie@rebel-alliance.org', 'gial.ackbar@rebel-alliance.org', + 'luke.skywalker@rebel-alliance.org', 'wedge.antilles@rebel-alliance.org'] + ) end it 'returns emails of participants with their request in submitted state' do expect(users_for_event('submitted')).to eq(['wedge.antilles@rebel-alliance.org']) end it 'returns emails of participants with their request in incomplete state' do - expect(users_for_event('incomplete')).to eq(['gial.ackbar@rebel-alliance.org', 'luke.skywalker@rebel-alliance.org', 'evram.lajaie@rebel-alliance.org', - 'c3po@droids.com']) + expect(users_for_event('incomplete')).to eq( + ['c3po@droids.com', 'evram.lajaie@rebel-alliance.org', + 'gial.ackbar@rebel-alliance.org', 'luke.skywalker@rebel-alliance.org'] + ) end it 'returns emails of participants with their request in canceled state' do expect(users_for_event('canceled')) .to eq([]) diff --git a/spec/models/event_organizer_spec.rb b/spec/models/event_organizer_spec.rb index 3043993a..f301f787 100644 --- a/spec/models/event_organizer_spec.rb +++ b/spec/models/event_organizer_spec.rb @@ -13,6 +13,6 @@ it 'nickname and email of the user' do expect(EventOrganizer.autocomplete_users('john')).to eq [['johnsnow', 'john.skywalker@rebel-alliance.org']] - expect(EventOrganizer.autocomplete_users('co')).to eq [['C3PO', 'c3po@droids.com'], ['DD-19.A1', 'dd-19.a1@droids.com'], ['commanderlajaier', 'evram.lajaie@rebel-alliance.org']] + expect(EventOrganizer.autocomplete_users('co')).to eq [['C3PO', 'c3po@droids.com'], ['commanderlajaier', 'evram.lajaie@rebel-alliance.org'], ['DD-19.A1', 'dd-19.a1@droids.com']] end end