codidact / qpixel

Q&A-based community knowledge-sharing software
https://codidact.com
GNU Affero General Public License v3.0
388 stars 68 forks source link

Docker (Compose) deployment options? #70

Closed iBug closed 4 years ago

iBug commented 4 years ago

Not much detail needed, I believe :)

Wrapping this software up in a Docker container will surely make development, testing and deployment easier. At first glance, three containers are required: a Redis, a MySQL, and the last one for this app itself.

The Dockerfile would be pretty straightforward: Install necessary software from APT repository and RubyGems, then ENTRYPOINT /usr/src/app/bin/rails. A custom script to initialize the application by reading environment variables and generating the configuration files at the first start is also in need.

With all those stuff ready, a docker-compose.yml should be easy to work out.

The Dockerfile file from Charcoal-SE/metasmoke would be a good point to start at, although it's missing some best-practices for Docker.

Ideas?

ArtOfCode- commented 4 years ago

Eh... I don't like Docker, personally, so I'd still deploy the manual way, meaning unless someone else was using it, the Dockerfile would end up being outdated and unmaintained. If others would find it useful then we might want to do this, but if nobody's going to use it there's probably little point.

vsoch commented 4 years ago

I want to add :heavy_plus_sign: for support for Docker, it's the bread and butter to quick deployment on the cloud these days. It's also hugely useful to quickly bring up a development environment without mucking around with your host.

cellio commented 4 years ago

Given the previous comment, I don't see the harm in reopening this and waiting for someone who wants to work on it. It doesn't constrain the codidact.com deployment; it's just an option, right?

vsoch commented 4 years ago

Exactly! +1 for re-opening, and if no one grabs this quickly, I can definitely do it. For some background of my use case (and interest) my group had tried creating a Stack Exchange and didn't make it through the final rounds. We ported to Discourse, but it's not really intended to be akin to a Stack Exchange (even with the voting plugin). Glancing over the deployments here, this seems closer to what my group had in mind to either, so I'm definitely eager to try it out (and in the process, Dockerize).

ArtOfCode- commented 4 years ago

Works for me. All yours if you want it, @vsoch :)

vsoch commented 4 years ago

heyo! I made good progress today, I'm hoping I can ask for a bit of your expertise.

I made sure to create the community that corresponds to where I'm running the rails server

# here is running the server
rails server -b 0.0.0.0

And creating the community via rails runner

    rails runner "Community.create(name: \"$COMMUNITY_NAME\", host: '0.0.0.0:3000')"

I can also confirm that it exists running the same command with rails console:

# rails console
Running via Spring preloader in process 67
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Community.create(name: 'Dinosaur Community', host: '0.0.0.0:3000')
   (0.5ms)  SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.2ms)  BEGIN
  Community Exists (0.5ms)  SELECT  1 AS one FROM `communities` WHERE `communities`.`host` = BINARY '0.0.0.0:3000' LIMIT 1
   (0.3ms)  ROLLBACK
=> #<Community id: nil, name: "Dinosaur Community", host: "0.0.0.0:3000", created_at: nil, updated_at: nil>

but when I visit the portal, it indicates that it doesn't exist:

image

Looking at the code, it looks like it's looking in some kind of rails cache here?

def setup_request_context
    RequestContext.clear!

    host_name = request.raw_host_with_port # include port to support multiple localhost instances
    RequestContext.community = @community = Rails.cache.fetch("#{host_name}/community", expires_in: 1.hour) do
      Community.find_by(host: host_name)
    end

    Rails.logger.info "  Host #{host_name}, community ##{RequestContext.community_id} " \
                      "(#{RequestContext.community&.name})"
    unless RequestContext.community.present?
      render status: 422, plain: "No community record matching Host='#{host_name}'"
      return false
    end

I also tried different variations of the host name, in case it was expecting different:

Running via Spring preloader in process 34
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Community.create(name: 'Dinosaur Community', host: '127.0.0.1:3000')
   (1.3ms)  SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.8ms)  BEGIN
  Community Exists (10.9ms)  SELECT  1 AS one FROM `communities` WHERE `communities`.`host` = BINARY '127.0.0.1:3000' LIMIT 1
  Community Create (0.5ms)  INSERT INTO `communities` (`name`, `host`, `created_at`, `updated_at`) VALUES ('Dinosaur Community', '127.0.0.1:3000', '2020-08-22 22:06:24', '2020-08-22 22:06:24')
   (1.7ms)  COMMIT
=> #<Community id: 2, name: "Dinosaur Community", host: "127.0.0.1:3000", created_at: "2020-08-22 22:06:24", updated_at: "2020-08-22 22:06:24">
irb(main):002:0> Community.create(name: 'Dinosaur Community', host: 'localhost:3000')
   (0.8ms)  BEGIN
  Community Exists (1.1ms)  SELECT  1 AS one FROM `communities` WHERE `communities`.`host` = BINARY 'localhost:3000' LIMIT 1
  Community Create (1.0ms)  INSERT INTO `communities` (`name`, `host`, `created_at`, `updated_at`) VALUES ('Dinosaur Community', 'localhost:3000', '2020-08-22 22:06:30', '2020-08-22 22:06:30')
   (38.6ms)  COMMIT
=> #<Community id: 3, name: "Dinosaur Community", host: "localhost:3000", created_at: "2020-08-22 22:06:30", updated_at: "2020-08-22 22:06:30">
irb(main):003:0> Community.create(name: 'Dinosaur Community', host: 'localhost')
   (0.9ms)  BEGIN
  Community Exists (1.3ms)  SELECT  1 AS one FROM `communities` WHERE `communities`.`host` = BINARY 'localhost' LIMIT 1
  Community Create (1.1ms)  INSERT INTO `communities` (`name`, `host`, `created_at`, `updated_at`) VALUES ('Dinosaur Community', 'localhost', '2020-08-22 22:06:48', '2020-08-22 22:06:48')
   (13.1ms)  COMMIT
=> #<Community id: 4, name: "Dinosaur Community", host: "localhost", created_at: "2020-08-22 22:06:48", updated_at: "2020-08-22 22:06:48">
irb(main):004:0> Community.create(name: 'Dinosaur Community', host: '0.0.0.0')
   (0.8ms)  BEGIN
  Community Exists (1.2ms)  SELECT  1 AS one FROM `communities` WHERE `communities`.`host` = BINARY '0.0.0.0' LIMIT 1
  Community Create (1.1ms)  INSERT INTO `communities` (`name`, `host`, `created_at`, `updated_at`) VALUES ('Dinosaur Community', '0.0.0.0', '2020-08-22 22:06:52', '2020-08-22 22:06:52')
   (11.2ms)  COMMIT
=> #<Community id: 5, name: "Dinosaur Community", host: "0.0.0.0", created_at: "2020-08-22 22:06:52", updated_at: "2020-08-22 22:06:52">

Perhaps a good question to start our debugging - how does this cache get populated (and where?).

vsoch commented 4 years ago

Ah just found something, I think I need to add the docker host as an allowed network?

uwsgi_1  | Started GET "/" for 172.19.0.1 at 2020-08-22 22:08:14 +0000
uwsgi_1  | Cannot render console from 172.19.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
uwsgi_1  | Processing by CategoriesController#homepage as HTML
uwsgi_1  |   Host 0.0.0.0:3000, community # ()
uwsgi_1  |   Rendering text template
uwsgi_1  |   Rendered text template (0.0ms)
uwsgi_1  | Filter chain halted as :set_globals rendered or redirected
uwsgi_1  | Completed 422 Unprocessable Entity in 2ms (Views: 0.4ms | ActiveRecord: 0.0ms)
uwsgi_1  | 
uwsgi_1  | 
ArtOfCode- commented 4 years ago

Yep, site associations are cached - if you've hit it once and failed, and then corrected it and tried again, you'll need to clear the cache before it'll work - run Rails.cache.clear in a Rails console.

Cannot render console from 172.19.0.1!

That's an error from web_console - it's a problem only if you want the terminal-in-webpage thingy that Rails provides. It's separate from getting the right community record.

vsoch commented 4 years ago

Ok, I was able to add the docker container hostname, now I'm not seeing any obvious error:

uwsgi_1  | 
uwsgi_1  | 
uwsgi_1  | Started GET "/" for 172.19.0.1 at 2020-08-22 22:27:07 +0000
uwsgi_1  | Processing by CategoriesController#homepage as HTML
uwsgi_1  |   Host 0.0.0.0:3000, community # ()
uwsgi_1  |   Rendering text template
uwsgi_1  |   Rendered text template (0.0ms)
uwsgi_1  | Filter chain halted as :set_globals rendered or redirected
uwsgi_1  | Completed 422 Unprocessable Entity in 1ms (Views: 0.3ms | ActiveRecord: 0.0ms)
uwsgi_1  | 
uwsgi_1  | 

I cleared the cache

irb(main):002:0> Rails.cache.clear
=> ["/code/tmp/cache/C62", "/code/tmp/cache/317", "/code/tmp/cache/E0A", "/code/tmp/cache/3E0", "/code/tmp/cache/C39", "/code/tmp/cache/D9F", "/code/tmp/cache/292", "/code/tmp/cache/BFD"]

I'm seeing something now!

image

Progress, haha.

vsoch commented 4 years ago

Is there a way to programatically create an admin user? I don't think the container has the plumbing to send email.

ArtOfCode- commented 4 years ago

User.create(username: 'xyz', password: 'xyz', email: 'xyz', is_global_admin: true) should do it

vsoch commented 4 years ago

Awesome! I seemed to fix the 500 error (not sure how but I'll try to reproduce it)

image

vsoch commented 4 years ago

I'm not sure the create user command worked? I can't log in with the email / password I chose, and the query seems to return empty?

User.second
  User Load (1.4ms)  SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 OFFSET 1
=> nil

Note that User.first seems to be an anonymous system account.

vsoch commented 4 years ago

Do I need to provide a hash? That at least seems to do something:

User.create(username: "username", password:  Digest::SHA1.hexdigest("username"), email: "admin@domain.com", is_global_admin: true, is_global_moderator: true, staff: true)

But then I hit an error for sending a welcome email. Is there a setting to disable email sending?

  (0.6ms)  ROLLBACK
Traceback (most recent call last):
        4: from (irb):2
        3: from (irb):2:in `rescue in irb_binding'
        2: from app/models/user.rb:195:in `send_welcome_tour_message'
        1: from app/models/user.rb:195:in `+'
TypeError (no implicit conversion of nil into String)
irb(main):003:0> 

Anyhoo, I'm probably stopping for today, thanks for helping me on the weekend! And definitely thanks for helping me learn a little more about Ruby on Rails.

vsoch commented 4 years ago

Here is the branch if you want to take a look! https://github.com/researchapps/qpixel/tree/add/docker-compose Let me know if it would be easier for me to open a draft PR, definitely can do that.

ArtOfCode- commented 4 years ago

What did the User.create call return? That might help tell you something. The usual way of doing this is to create an account with the web interface, then upgrade it from the console, so I'm not well versed in the best way to do it all from a console.

vsoch commented 4 years ago

It's the error I showed above about sending the email - here is the full command and result so you can see it. It looks like that error rolls it back?

 User.create(username: "naa", password:"naa", email: "naa@a.com", is_global_admin: true, is_global_moderator: true, staff: true)
   (1.5ms)  SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.2ms)  BEGIN
  User Exists (11.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'naa@a.com' LIMIT 1
  SiteSetting Load (1.2ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'AdminBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  SiteSetting Load (0.8ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'ModBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
   (0.1ms)  ROLLBACK
   (0.1ms)  BEGIN
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'naa@a.com' LIMIT 1
  SiteSetting Load (0.4ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'AdminBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  SiteSetting Load (0.4ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'ModBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
   (0.2ms)  ROLLBACK
=> #<User id: nil, email: "naa@a.com", created_at: nil, updated_at: nil, is_global_moderator: true, is_global_admin: true, username: "naa", profile: nil, website: nil, twitter: nil, profile_markdown: nil, se_acct_id: nil, transferred_content: false, trust_level: 6, login_token: nil, login_token_expires_at: nil, two_factor_token: nil, enabled_2fa: false, two_factor_method: nil, staff: true

Sorry updated because I gave a call when it already existed!

vsoch commented 4 years ago

The user is supposedly created but it's id is nil.

ArtOfCode- commented 4 years ago

Sorry I haven't got back to this sooner, the last couple days have been super busy.

If you call create and the result has id: nil, there were validation or SQL errors while creating it - try running u = User.create(...), then u.errors.full_messages - that should reveal any validation errors.

vsoch commented 4 years ago

It was the weekend! Totally no worries. And ha, this message!

irb(main):002:0> u.errors.full_messages
=> ["Password is too short (minimum is 6 characters)"]

Now when I address that and make it >6 characters, I see that rollback error again, because the welcome email cannot be sent.

u = User.create(username: "noo", password:"naaaaaa", email: "noo@a.com", is_global_admin: true, is_global_moderator: true, staff: true)
   (0.2ms)  BEGIN
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'noo@a.com' LIMIT 1
  SiteSetting Load (0.2ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'AdminBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  SiteSetting Load (0.2ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'ModBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  User Create (0.2ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `is_global_moderator`, `is_global_admin`, `username`, `confirmation_token`, `confirmation_sent_at`, `staff`) VALUES ('noo@a.com', '$2a$11$RDkeuIvW4Izez8KkQKenV.LkeiPWlXgLXQyjI49N17T2PFw60u3/O', '2020-08-25 18:05:04', '2020-08-25 18:05:04', TRUE, TRUE, 'noo', '1xySKS-uiccs39qQfzf3', '2020-08-25 18:05:04', TRUE)
  SiteSetting Load (0.2ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'SiteName' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
   (1.0ms)  ROLLBACK
Traceback (most recent call last):
        3: from (irb):5
        2: from app/models/user.rb:195:in `send_welcome_tour_message'
        1: from app/models/user.rb:195:in `+'
TypeError (no implicit conversion of nil into String)

There isn't any new insight to look at the errors again because we don't return a new user object. Is there a way to either fix this welcome message functionality, or disable it?

vsoch commented 4 years ago

Where are the SiteSettings defined? I think the issue might be that one of them is nil.

vsoch commented 4 years ago

The error is about converting nil to a string, but the string in question isn't related to the user, I think it's a SiteSetting? Here is the error:

uwsgi_1  | /code/app/models/user.rb:195:in `+': no implicit conversion of nil into String (TypeError)
uwsgi_1  |  from /code/app/models/user.rb:195:in `send_welcome_tour_message'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:426:in `block in make_lambda'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:236:in `block in halting_and_conditional'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:517:in `block in invoke_after'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:517:in `each'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:517:in `invoke_after'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:133:in `run_callbacks'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:816:in `_run_create_callbacks'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/callbacks.rb:346:in `_create_record'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/timestamp.rb:102:in `_create_record'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/persistence.rb:705:in `create_or_update'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/callbacks.rb:342:in `block in create_or_update'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:132:in `run_callbacks'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/callbacks.rb:816:in `_run_save_callbacks'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/callbacks.rb:342:in `create_or_update'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/persistence.rb:275:in `save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/validations.rb:46:in `save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:310:in `block (2 levels) in save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:387:in `block in with_transaction_returning_status'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/connection_adapters/abstract/database_statements.rb:267:in `block in transaction'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/connection_adapters/abstract/transaction.rb:239:in `block in within_new_transaction'
uwsgi_1  |  from /usr/local/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/connection_adapters/abstract/transaction.rb:236:in `within_new_transaction'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/connection_adapters/abstract/database_statements.rb:267:in `transaction'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:212:in `transaction'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:385:in `with_transaction_returning_status'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:310:in `block in save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:325:in `rollback_active_record_state!'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/transactions.rb:309:in `save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/suppressor.rb:44:in `save'
uwsgi_1  |  from /usr/local/bundle/gems/activerecord-5.2.4.3/lib/active_record/persistence.rb:36:in `create'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/commands/runner/runner_command.rb:41:in `<main>'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/commands/runner/runner_command.rb:41:in `eval'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/commands/runner/runner_command.rb:41:in `perform'
uwsgi_1  |  from /usr/local/bundle/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
uwsgi_1  |  from /usr/local/bundle/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
uwsgi_1  |  from /usr/local/bundle/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/command/base.rb:69:in `perform'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/command.rb:46:in `invoke'
uwsgi_1  |  from /usr/local/bundle/gems/railties-5.2.4.3/lib/rails/commands.rb:18:in `<top (required)>'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:291:in `require'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:291:in `block in require'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:257:in `load_dependency'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:291:in `require'
uwsgi_1  |  from /code/bin/rails:9:in `<top (required)>'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:285:in `load'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:285:in `block in load'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:257:in `load_dependency'
uwsgi_1  |  from /usr/local/bundle/gems/activesupport-5.2.4.3/lib/active_support/dependencies.rb:285:in `load'
uwsgi_1  |  from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
uwsgi_1  |  from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
uwsgi_1  |  from -e:1:in `<main>'

and here is the notification attempt:

  def send_welcome_tour_message
    return if id == -1

    create_notification('👋 Welcome to ' + SiteSetting['SiteName'] + '! Take our tour to find out ' \
                        'how this site works.', '/tour')
  end

So I wonder how SiteName is set?

luap42 commented 4 years ago

Nah. The issue is, that there is no community here, because you're not on a request. Try going to the mentioned function and replacing SiteSetting['SiteName'] with (SiteSetting['SiteName'] || 'Codidact').

vsoch commented 4 years ago

Gotcha! Cool that I caught the issue :)

vsoch commented 4 years ago

Making progress! Now we get through that bug, and there is another issue that the community doesn't have an id:

u = User.create(username: "...", password:"...", email: "...", is_global_admin: true, is_global_moderator: true, staff: true)
   (0.8ms)  SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.2ms)  BEGIN
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'pancakes@a.com' LIMIT 1
  SiteSetting Load (0.4ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'AdminBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  SiteSetting Load (0.2ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'ModBadgeCharacter' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  User Create (0.4ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `is_global_moderator`, `is_global_admin`, `username`, `confirmation_token`, `confirmation_sent_at`, `staff`) VALUES ('pancakes@a.com', '$2a$11$t0LCKRfKjjW1eGkweB3bdeV1A45RZGBGKBmHKXivgyRl3kFvbxZpm', '2020-08-25 18:14:58', '2020-08-25 18:14:58', TRUE, TRUE, 'vanessa', 'bYYgC87gZRQzB3e5VgxG', '2020-08-25 18:14:58', TRUE)
  SiteSetting Load (0.3ms)  SELECT  `site_settings`.* FROM `site_settings` WHERE `site_settings`.`community_id` IS NULL AND `site_settings`.`name` = 'SiteName' ORDER BY IF(site_settings.community_id IS NULL, 1, 0) LIMIT 1
  Notification Create (0.9ms)  INSERT INTO `notifications` (`content`, `link`, `created_at`, `updated_at`) VALUES ('👋 Welcome to Codidact! Take our tour to find out how this site works.', '/tour', '2020-08-25 18:14:58', '2020-08-25 18:14:58')
   (3.8ms)  ROLLBACK
Traceback (most recent call last):
        3: from (irb):1
        2: from app/models/user.rb:195:in `send_welcome_tour_message'
        1: from app/models/user.rb:70:in `create_notification'
ActiveRecord::NotNullViolation (Mysql2::Error: Field 'community_id' doesn't have a default value: INSERT INTO `notifications` (`content`, `link`, `created_at`, `updated_at`) VALUES ('👋 Welcome to Codidact! Take our tour to find out how this site works.', '/tour', '2020-08-25 18:14:58', '2020-08-25 18:14:58'))

and the function

  def create_notification(content, link)
    notification = Notification.create(content: content, link: link)
    notifications << notification
  end

Is Codadict designed to be connected to some larger community, and then get an id?

luap42 commented 4 years ago

Ah. Good that we ruled that option out. :D Okay. Revert the change and add || RequestContext.community.nil? to the end of the return-clause at the top. That could work. :)

vsoch commented 4 years ago

That worked! There was a tiny issue with wanting to send an email, but the user seems to have been created okay anyway :)

...
   (1.9ms)  COMMIT
Devise::Mailer#confirmation_instructions: processed outbound mail in 4.6ms
Traceback (most recent call last):
        1: from (irb):1
ArgumentError (No :access_key_id provided)

But I can at least get acknowledgement from the interface that my account exists!

image

It looks like you are using something called Devise, and there is @ArtOfCode- UK email address and a key (but still the error because no access key?) So I think we would either need to get that working, or to have an option to disable email confirmation (likely would be useful for more development / Docker setups).

vsoch commented 4 years ago

This might be promising

  # ==> Configuration for :confirmable
  # A period that the user is allowed to access the website even without
  # confirming their account. For instance, if set to 2.days, the user will be
  # able to access the website for two days without confirming their account,
  # access will be blocked just in the third day. Default is 0.days, meaning
  # the user cannot access the website without confirming their account.
  # config.allow_unconfirmed_access_for = 2.days
luap42 commented 4 years ago

Yeah. That issue is known and happens, because no email is configured. As we require validation, it's also IMO status-bydesign.

You can update the user by setting confirmed_at to the current time. Something like user.update confirmed_at: DateTime.now should work for the initial user setup. And you might want to set is_global_admin to true, too.

vsoch commented 4 years ago

Success!

image

So I'm logged in, and wondering what kinds of other actions an admin needs to do for setup? For example, when I try to create a post I get an error about tag sets not having a default value.

image

The function being called is this one in post.rb

  def update_tag_associations
    tags_cache.each do |tag_name|
      tag = Tag.find_or_create_by name: tag_name, tag_set: category.tag_set
      unless tags.include? tag
        tags << tag
      end
    end
    tags.each do |tag|
      unless tags_cache.include? tag.name
        tags.delete tag
      end
    end
  end

with parent in posts_controller.rb - seems like the error is on @post.save (line 29)

  def create
    @category = Category.find(params[:category_id])
    @post = Post.new(post_params.merge(category: @category, user: current_user,
                                       post_type_id: params[:post][:post_type_id] || params[:post_type_id],
                                       body: helpers.render_markdown(params[:post][:body_markdown])))

    if @category.min_trust_level.present? && @category.min_trust_level > current_user.trust_level
      @post.errors.add(:base, "You don't have a high enough trust level to post in the #{@category.name} category.")
      render :new, status: 403
      return
    end

    if @post.save
      redirect_to helpers.generic_show_link(@post)
    else
      render :new, status: 400
    end
  end
luap42 commented 4 years ago

Heh. I thought @ArtOfCode- had written something about that, but it was on a different post. :D

You need to go to the categories, edit them and choose a tag set (likely Main for Q&A and Meta for Meta). You might also want to go to /admin/setup to do some administrative setup stuff, including seeding tags.

vsoch commented 4 years ago

I probably just missed it! Let me give those areas a quick look.

vsoch commented 4 years ago

Yep that worked!

vsoch commented 4 years ago

okay things are looking good, I've tested it again from start to finish, and works! I'm going to open a PR to discuss changes. This version is done for development, so likely in the PR we'd want to discuss how the user can set an environment variable for the docker-compose that would signal production. But if we do that, we'd also want to make sure the emails will work. It would also be okay to have this first PR provide the container build for development only. I'll repeat this when I open the PR.

sbkg0002 commented 3 years ago

Is it me, or is this still an issue when https://github.com/codidact/qpixel/blob/develop/docker/README.md is followed? I still got this with Docker for Mac:

img

ArtOfCode- commented 3 years ago

@sbkg0002 You need to change the community record in the database to have a host field of 0.0.0.0:3000, then it'll work

mattjbrent commented 3 years ago

@sbkg0002 did you try using localhost instead of 0.0.0.0 meta address?

sbkg0002 commented 3 years ago

Thanks @artofcode-, but how?