diff --git a/Dockerfile b/Dockerfile index 075337301..d2f9211ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,43 +1,49 @@ FROM ruby:2.4 -ENV HELPY_VERSION=master \ - RAILS_ENV=production \ +ENV RAILS_ENV=production \ HELPY_HOME=/helpy \ HELPY_USER=helpyuser \ - HELPY_SLACK_INTEGRATION_ENABLED=true + HELPY_SLACK_INTEGRATION_ENABLED=true \ + BUNDLE_PATH=/opt/helpy-bundle RUN apt-get update \ && apt-get upgrade -y \ && apt-get install -y nodejs postgresql-client imagemagick --no-install-recommends \ - && rm -rf /var/lib/apt/lists/* \ - && useradd --no-create-home $HELPY_USER \ - && mkdir -p $HELPY_HOME \ - && chown -R $HELPY_USER:$HELPY_USER $HELPY_HOME /usr/local/lib/ruby /usr/local/bundle + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd --no-create-home $HELPY_USER \ + && mkdir -p $HELPY_HOME $BUNDLE_PATH \ + && chown -R $HELPY_USER:$HELPY_USER $HELPY_HOME $BUNDLE_PATH WORKDIR $HELPY_HOME +COPY Gemfile Gemfile.lock $HELPY_HOME/ +COPY vendor $HELPY_HOME/vendor +RUN chown -R $HELPY_USER $HELPY_HOME + USER $HELPY_USER -RUN git clone --branch $HELPY_VERSION --depth=1 https://github.com/helpyio/helpy.git . # add the slack integration gem to the Gemfile if the HELPY_SLACK_INTEGRATION_ENABLED is true # use `test` for sh compatibility, also use only one `=`. also for sh compatibility -RUN test "$HELPY_SLACK_INTEGRATION_ENABLED" = "true" && sed -i '128i\gem "helpy_slack", git: "https://github.com/helpyio/helpy_slack.git", branch: "master"' $HELPY_HOME/Gemfile +RUN test "$HELPY_SLACK_INTEGRATION_ENABLED" = "true" \ + && sed -i '128i\gem "helpy_slack", git: "https://github.com/helpyio/helpy_slack.git", branch: "master"' $HELPY_HOME/Gemfile RUN bundle install -RUN touch /helpy/log/production.log && chmod 0664 /helpy/log/production.log - -# Due to a weird issue with one of the gems, execute this permissions change: -RUN chmod +r /usr/local/bundle/gems/griddler-mandrill-1.1.4/lib/griddler/mandrill/adapter.rb - # manually create the /helpy/public/assets folder and give the helpy user rights to it # this ensures that helpy can write precompiled assets to it -RUN mkdir -p $HELPY_HOME/public/assets && chown $HELPY_USER $HELPY_HOME/public/assets +RUN mkdir -p $HELPY_HOME/public/assets \ + && chown $HELPY_USER $HELPY_HOME/public/assets VOLUME $HELPY_HOME/public +USER root +COPY . $HELPY_HOME/ +RUN chown -R $HELPY_USER $HELPY_HOME +USER $HELPY_USER + COPY docker/database.yml $HELPY_HOME/config/database.yml -COPY docker/run.sh $HELPY_HOME/run.sh -CMD ["./run.sh"] +CMD ["/bin/bash", "/helpy/docker/run.sh"] diff --git a/Gemfile b/Gemfile index ff1e4fb46..c0d481053 100644 --- a/Gemfile +++ b/Gemfile @@ -96,6 +96,8 @@ gem 'cloudinary', '1.1.7' gem 'attachinary' gem 'carrierwave', '~> 1.3.1' +gem 'fog' +gem 'fog-aws' gem "jquery-fileupload-rails" gem 'mini_magick' diff --git a/Gemfile.lock b/Gemfile.lock index 5b89b0a1d..1b3eedb24 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,6 +19,7 @@ PATH GEM remote: https://rubygems.org/ specs: + CFPropertyList (2.3.6) actionmailer (4.2.11) actionpack (= 4.2.11) actionview (= 4.2.11) @@ -156,6 +157,8 @@ GEM addressable daemons (1.3.1) debug_inspector (0.0.3) + declarative (0.0.10) + declarative-option (0.1.0) deep_merge (1.0.1) deface (1.3.2) nokogiri (>= 1.6) @@ -180,9 +183,11 @@ GEM docile (1.3.1) domain_name (0.5.20180417) unf (>= 0.0.5, < 1.0.0) + dry-inflector (0.1.2) equalizer (0.0.11) erubi (1.8.0) erubis (2.7.0) + excon (0.62.0) execjs (2.7.0) factory_bot (4.11.1) activesupport (>= 3.0.0) @@ -194,8 +199,166 @@ GEM faraday (0.15.4) multipart-post (>= 1.2, < 3) ffi (1.9.25) + fission (0.5.0) + CFPropertyList (~> 2.2) + fog (2.1.0) + fog-aliyun (>= 0.1.0) + fog-atmos + fog-aws (>= 0.6.0) + fog-brightbox (~> 0.4) + fog-cloudatcost (~> 0.1.0) + fog-core (~> 1.45) + fog-digitalocean (>= 0.3.0) + fog-dnsimple (~> 1.0) + fog-dynect (~> 0.0.2) + fog-ecloud (~> 0.1) + fog-google (~> 1.0) + fog-internet-archive + fog-joyent + fog-json + fog-local + fog-openstack + fog-ovirt + fog-powerdns (>= 0.1.1) + fog-profitbricks + fog-rackspace + fog-radosgw (>= 0.0.2) + fog-riakcs + fog-sakuracloud (>= 0.0.4) + fog-serverlove + fog-softlayer + fog-storm_on_demand + fog-terremark + fog-vmfusion + fog-voxel + fog-vsphere (>= 0.4.0) + fog-xenserver + fog-xml (~> 0.1.1) + ipaddress (~> 0.5) + json (~> 2.0) + fog-aliyun (0.3.2) + fog-core + fog-json + ipaddress (~> 0.8) + xml-simple (~> 1.1) + fog-atmos (0.1.0) + fog-core + fog-xml + fog-aws (2.0.1) + fog-core (~> 1.38) + fog-json (~> 1.0) + fog-xml (~> 0.1) + ipaddress (~> 0.8) + fog-brightbox (0.16.1) + dry-inflector + fog-core + fog-json + mime-types + fog-cloudatcost (0.1.2) + fog-core (~> 1.36) + fog-json (~> 1.0) + fog-xml (~> 0.1) + ipaddress (~> 0.8) + fog-core (1.45.0) + builder + excon (~> 0.58) + formatador (~> 0.2) + fog-digitalocean (0.4.0) + fog-core + fog-json + fog-xml + ipaddress (>= 0.5) + fog-dnsimple (1.0.0) + fog-core (~> 1.38) + fog-json (~> 1.0) + fog-dynect (0.0.3) + fog-core + fog-json + fog-xml + fog-ecloud (0.3.0) + fog-core + fog-xml + fog-google (1.8.1) + fog-core (<= 2.1.0) + fog-json (~> 1.2.0) + fog-xml (~> 0.1.0) + google-api-client (~> 0.23.0) + fog-internet-archive (0.0.1) + fog-core + fog-json + fog-xml + fog-joyent (0.0.1) + fog-core (~> 1.42) + fog-json (>= 1.0) + fog-json (1.2.0) + fog-core + multi_json (~> 1.10) + fog-local (0.6.0) + fog-core (>= 1.27, < 3.0) + fog-openstack (0.3.9) + fog-core (>= 1.45, <= 2.1.0) + fog-json (>= 1.0) + ipaddress (>= 0.8) + fog-ovirt (1.1.4) + fog-core + fog-json + fog-xml + ovirt-engine-sdk (>= 4.1.3) + rbovirt (~> 0.1.5) + fog-powerdns (0.2.0) + fog-core + fog-json + fog-xml + fog-profitbricks (4.1.1) + fog-core (~> 1.42) + fog-json (~> 1.0) + fog-rackspace (0.1.6) + fog-core (>= 1.35) + fog-json (>= 1.0) + fog-xml (>= 0.1) + ipaddress (>= 0.8) + fog-radosgw (0.0.5) + fog-core (>= 1.21.0) + fog-json + fog-xml (>= 0.0.1) + fog-riakcs (0.1.0) + fog-core + fog-json + fog-xml + fog-sakuracloud (1.7.5) + fog-core + fog-json + fog-serverlove (0.1.2) + fog-core + fog-json + fog-softlayer (1.1.4) + fog-core + fog-json + fog-storm_on_demand (0.1.1) + fog-core + fog-json + fog-terremark (0.1.0) + fog-core + fog-xml + fog-vmfusion (0.1.0) + fission + fog-core + fog-voxel (0.1.0) + fog-core + fog-xml + fog-vsphere (2.5.0) + fog-core + rbvmomi (~> 1.9) + fog-xenserver (1.0.0) + fog-core + fog-xml + xmlrpc + fog-xml (0.1.3) + fog-core + nokogiri (>= 1.5.11, < 2.0.0) font-awesome-sass (5.6.1) sassc (>= 1.11) + formatador (0.2.5) foundation_emails (2.2.1.0) gemoji (3.0.0) globalid (0.4.1) @@ -210,6 +373,21 @@ GEM activerecord (>= 3.2.0, < 5) globalize (>= 3.0.4, < 6) paper_trail (>= 3.0.0, < 5) + google-api-client (0.23.9) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.5, < 0.7.0) + httpclient (>= 2.8.1, < 3.0) + mime-types (~> 3.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.9) + googleauth (0.6.7) + faraday (~> 0.12) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.7) grape (1.2.1) activesupport builder @@ -256,6 +434,7 @@ GEM http-cookie (1.0.3) domain_name (~> 0.5) http_accept_language (2.1.1) + httpclient (2.8.3) i18n (0.9.5) concurrent-ruby (~> 1.0) i18n-country-translations (1.3.0) @@ -266,6 +445,7 @@ GEM foundation_emails (~> 2) nokogiri io-like (0.3.0) + ipaddress (0.8.3) jaro_winkler (1.5.1) jbuilder (2.8.0) activesupport (>= 4.2.0) @@ -334,6 +514,7 @@ GEM listen (~> 2.2) mail (>= 2.0.3) maildir (>= 0.5.0) + memoist (0.16.0) method_source (0.9.2) mime-types (3.2.2) mime-types-data (~> 3.2015) @@ -385,6 +566,9 @@ GEM omniauth-oauth (~> 1.1) rack orm_adapter (0.5.0) + os (1.0.0) + ovirt-engine-sdk (4.2.5) + json (>= 1, < 3) paper_trail (4.2.0) activerecord (>= 3.0, < 6.0) activesupport (>= 3.0, < 6.0) @@ -461,11 +645,23 @@ GEM rb-fsevent (0.10.3) rb-inotify (0.10.0) ffi (~> 1.0) + rbovirt (0.1.7) + nokogiri + rest-client (> 1.7.0) + rbvmomi (1.13.0) + builder (~> 3.0) + json (>= 1.8) + nokogiri (~> 1.5) + trollop (~> 2.1) rdiscount (2.2.0.1) rdoc (6.0.4) recaptcha (2.3.0) json regexp_parser (0.5.0) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) request_store (1.4.1) rack (>= 1.4) responders (2.4.0) @@ -475,6 +671,7 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) + retriable (3.1.2) roo (2.7.1) nokogiri (~> 1) rubyzip (~> 1.1, < 2.0.0) @@ -516,6 +713,11 @@ GEM shoulda-context (1.2.2) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) + signet (0.11.0) + addressable (~> 2.3) + faraday (~> 0.9) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) simple_form (3.5.1) actionpack (> 4, < 5.2) activemodel (> 4, < 5.2) @@ -548,6 +750,7 @@ GEM timecop (0.9.1) timers (4.0.4) hitimes + trollop (2.9.9) turbolinks (2.5.4) coffee-rails twitter-bootstrap-rails (3.2.2) @@ -558,6 +761,7 @@ GEM twitter-bootstrap-rails-confirm (2.0.0) tzinfo (1.2.5) thread_safe (~> 0.1) + uber (0.1.0) uglifier (4.1.20) execjs (>= 0.3.0, < 3) unf (0.1.4) @@ -579,6 +783,8 @@ GEM activemodel (>= 4.2) debug_inspector railties (>= 4.2) + xml-simple (1.1.5) + xmlrpc (0.3.0) xpath (3.2.0) nokogiri (~> 1.8) @@ -619,6 +825,8 @@ DEPENDENCIES devise_invitable (< 1.7) factory_bot_rails faker + fog + fog-aws font-awesome-sass gemoji globalize (= 5.0.1) diff --git a/README.md b/README.md index 6329efe8e..06f8d6fb5 100644 --- a/README.md +++ b/README.md @@ -113,12 +113,10 @@ Although not required, installing locally is highly recommended and will make it Docker is the recommended way to quickly test or run Helpy in production. 1) Install [Docker](https://get.docker.com/) and docker-compose -2) Edit the `docker/.env` file with the neccessary information and passwords +2) Create config file from template `cp docker/.env.sample docker/.env` and edit `docker/.env` to match your needs 3) Edit `docker/Caddyfile` to include your URL or turn on SSL -4) Run `docker-compose up -d` to start all of the services - -_Other notes_ -You can modify `docker/run.sh` and set `DO_NOT_PREPARE` to true, which will skip compiling the assets when the docker container loads. While this makes the container start faster, it is not reccommended because this is also the step where database migrations are run. If there's an update and the migrations don't run it could lead to issues with the website throwing a lot of errors. +4) Build Helpy from local git checkout `docker-compose build` +5) Run `docker-compose up -d` to start all of the services **Configure Basic Settings** diff --git a/app/mailers/post_mailer.rb b/app/mailers/post_mailer.rb index 11181675f..3253c99a6 100644 --- a/app/mailers/post_mailer.rb +++ b/app/mailers/post_mailer.rb @@ -26,7 +26,7 @@ def new_post(post_id) email_with_name = %("#{@topic.user_name}" <#{@topic.user.email}>) @post.attachments.each do |att| - attachments[att.file.filename] = File.read(att.file.file) + attachments[att.file.filename] = ENV["REMOTE_STORAGE"]=="true" ? open(att.url).read : File.read(att.file.file) end mail( to: email_with_name, diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 42b8a1db8..31d308085 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -5,8 +5,15 @@ class AttachmentUploader < CarrierWave::Uploader::Base # include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: - storage :file - # storage :fog + def self.set_storage + if ENV['REMOTE_STORAGE'] == "true" + :fog + else + :file + end + end + + storage set_storage # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb index 267bb8a25..85f840939 100644 --- a/app/uploaders/image_uploader.rb +++ b/app/uploaders/image_uploader.rb @@ -5,8 +5,15 @@ class ImageUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: - storage :file - # storage :fog + def self.set_storage + if ENV['REMOTE_STORAGE'] == "true" + :fog + else + :file + end + end + + storage set_storage # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: diff --git a/app/uploaders/logo_uploader.rb b/app/uploaders/logo_uploader.rb index d83e37fc5..ccba17064 100644 --- a/app/uploaders/logo_uploader.rb +++ b/app/uploaders/logo_uploader.rb @@ -5,8 +5,15 @@ class LogoUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: - storage :file - # storage :fog + def self.set_storage + if ENV['REMOTE_STORAGE'] == "true" + :fog + else + :file + end + end + + storage set_storage # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: diff --git a/app/uploaders/profile_image_uploader.rb b/app/uploaders/profile_image_uploader.rb index b09e19e0a..db6ee25bb 100644 --- a/app/uploaders/profile_image_uploader.rb +++ b/app/uploaders/profile_image_uploader.rb @@ -5,8 +5,15 @@ class ProfileImageUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: - storage :file - # storage :fog + def self.set_storage + if ENV['REMOTE_STORAGE'] == "true" + :fog + else + :file + end + end + + storage set_storage # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: diff --git a/config/initializers/fog-aws.rb b/config/initializers/fog-aws.rb new file mode 100644 index 000000000..3d5828c9f --- /dev/null +++ b/config/initializers/fog-aws.rb @@ -0,0 +1,28 @@ +CarrierWave.configure do |config| + config.fog_provider = 'fog/aws' + if Rails.env == 'test' + config.fog_credentials = { + provider: 'AWS', + aws_access_key_id: 'secretkeyid', + aws_secret_access_key: 'secretaccesskey', + region: 'abc', + endpoint: 'ayz' + } + config.fog_directory = 'testbucket' + + else + if ENV['REMOTE_STORAGE'] == "true" + config.fog_credentials = { + provider: 'AWS', + aws_access_key_id: ENV['S3_KEY'], + aws_secret_access_key: ENV['S3_SECRET'], + region: ENV['S3_REGION'], + # host: 's3.example.com', + endpoint: ENV['S3_ENDPOINT'] + } + config.fog_directory = ENV['S3_BUCKET_NAME'] + config.fog_public = true + config.fog_attributes = { cache_control: "public, max-age=#{365.day.to_i}" } + end + end +end diff --git a/docker-compose.yml b/docker-compose.yml index c4901648b..8e84aa4a8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: depends_on: - helpy helpy: - image: helpy/helpy + build: . restart: always networks: - front @@ -25,8 +25,6 @@ services: volumes: - rails-assets:/helpy/public env_file: docker/.env - #environment: - # - DO_NOT_PREPARE=true depends_on: - postgres postgres: diff --git a/docker/.env.sample b/docker/.env.sample index b774382e1..ac7106b99 100644 --- a/docker/.env.sample +++ b/docker/.env.sample @@ -1,4 +1,25 @@ +# Database +POSTGRES_HOST=postgres +POSTGRES_PORT=5432 POSTGRES_DB=helpy_production POSTGRES_USER=helpy POSTGRES_PASSWORD=some_secure_pg_password_change_in_production + +# Rails Secret SECRET_KEY_BASE=some_secret_key_base_change_in_production + +# File storage +REMOTE_STORAGE=false +# S3_KEY=change_key +# S3_SECRET=change_secret +# S3_REGION=change_region +# S3_ENDPOINT=change_endpoint +# S3_BUCKET_NAME=change_bucket_name + +# If you set `DO_NOT_PREPARE` to true, we will skip compiling +# the assets when the docker container loads. While this makes +# the container start faster, it is not reccommended because +# this is also the step where database migrations are run. +# If there's an update and the migrations don't run it could +# lead to issues with the website throwing a lot of errors. +#DO_NOT_PREPARE=true diff --git a/docker/database.yml b/docker/database.yml index bf19964d6..478634975 100644 --- a/docker/database.yml +++ b/docker/database.yml @@ -17,7 +17,8 @@ test: production: <<: *default - host: postgres + host: <%= ENV['POSTGRES_HOST'] %> + port: <%= ENV['POSTGRES_PORT'] %> database: <%= ENV['POSTGRES_DB'] %> username: <%= ENV['POSTGRES_USER'] %> password: <%= ENV['POSTGRES_PASSWORD'] %> diff --git a/docker/run.sh b/docker/run.sh index 8fc452814..a2ebcccc2 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -30,5 +30,7 @@ if [[ "$RUN_PREPARE" = "false" ]] fi echo "starting unicorn" +mkdir -p log +touch log/production.log exec bundle exec unicorn -E production -c config/unicorn.rb