diff --git a/.gitignore b/.gitignore index 4e7f1527..46060552 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /config/smtp.yml /config/docker.yml.erb /config/*.production.yml +/config/*.staging.yml /coverage /log /public/assets diff --git a/.travis.yml b/.travis.yml index 0dca2ec6..40c85850 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ language: ruby rvm: - 2.1.5 - 2.2.1 -script: bundle exec rspec --tag ~docker +script: bundle exec rspec diff --git a/app/assets/javascripts/editor_edit.js b/app/assets/javascripts/editor_edit.js new file mode 100644 index 00000000..b1251cf9 --- /dev/null +++ b/app/assets/javascripts/editor_edit.js @@ -0,0 +1,55 @@ +$(function() { + var ACE_FILES_PATH = '/assets/ace/'; + var THEME = 'ace/theme/textmate'; + + var configureEditors = function() { + _.each(['modePath', 'themePath', 'workerPath'], function(attribute) { + ace.config.set(attribute, ACE_FILES_PATH); + }); + }; + + var initializeEditors = function() { + $('.editor').each(function(index, element) { + var editor = ace.edit(element); + + var document = editor.getSession().getDocument(); + // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added + var file_id = $(element).data('file-id'); + var content = $('.editor-content[data-file-id=' + file_id + ']'); + + document.insertLines(0, content.text().split(/\n/)); + // remove last (empty) that is there by default line + document.removeLines(document.getLength() - 1, document.getLength() - 1); + editor.setReadOnly($(element).data('read-only') !== undefined); + editor.setShowPrintMargin(false); + editor.setTheme(THEME); + + var textarea = $('textarea[id="exercise_files_attributes_'+index+'_content"]'); + var content = textarea.val(); + + if (content != undefined) + { + editor.getSession().setValue(content); + editor.getSession().on('change', function(){ + textarea.val(editor.getSession().getValue()); + }); + } + + editor.commands.bindKey("ctrl+alt+0", null); + var session = editor.getSession(); + session.setMode($(element).data('mode')); + session.setTabSize($(element).data('indent-size')); + session.setUseSoftTabs(true); + session.setUseWrapMode(true); + + var file_id = $(element).data('id'); + } + )}; + + if ($('#editor-edit').isPresent()) { + configureEditors(); + initializeEditors(); + $('.frame').show(); + } +}); + diff --git a/app/views/exercises/_code_field.html.slim b/app/views/exercises/_code_field.html.slim index 3ad55f16..5273a693 100644 --- a/app/views/exercises/_code_field.html.slim +++ b/app/views/exercises/_code_field.html.slim @@ -2,5 +2,5 @@ = form.label(attribute, label) |   a.toggle-input data={text_initial: t('shared.upload_file'), text_toggled: t('shared.back')} href='#' = t('shared.upload_file') - = form.text_area(attribute, class: 'code-field form-control original-input', rows: 16) + = form.text_area(attribute, class: 'code-field form-control original-input', rows: 16, style: "display:none;") = form.file_field(attribute, class: 'alternative-input form-control', disabled: true) diff --git a/app/views/exercises/_editor_edit.html.slim b/app/views/exercises/_editor_edit.html.slim new file mode 100644 index 00000000..810653d2 --- /dev/null +++ b/app/views/exercises/_editor_edit.html.slim @@ -0,0 +1,5 @@ +#editor-edit.panel-group.row data-exercise-id=@exercise.id + #frames + .frame + .editor-content.hidden + .editor \ No newline at end of file diff --git a/app/views/exercises/_file_form.html.slim b/app/views/exercises/_file_form.html.slim index 7bb4cd27..796c6722 100644 --- a/app/views/exercises/_file_form.html.slim +++ b/app/views/exercises/_file_form.html.slim @@ -1,4 +1,5 @@ - id = f.object.id + li.panel.panel-default .panel-heading role="tab" id="heading" a.file-heading data-toggle="collapse" data-parent="#files" href="#collapse#{id}" @@ -37,3 +38,4 @@ li.panel.panel-default = f.label(:role, t('activerecord.attributes.file.weight')) = f.number_field(:weight, class: 'form-control', min: 1, step: 'any') = render('code_field', attribute: :content, form: f, label: t('activerecord.attributes.file.content')) + = render partial: 'editor_edit', locals: { exercise: @exercise } \ No newline at end of file diff --git a/app/views/exercises/_form.html.slim b/app/views/exercises/_form.html.slim index 0dc004cc..a640f0c2 100644 --- a/app/views/exercises/_form.html.slim +++ b/app/views/exercises/_form.html.slim @@ -9,7 +9,6 @@ .form-group = f.label(:description) = f.pagedown_editor :description - .form-group = f.label(:execution_environment_id) = f.collection_select(:execution_environment_id, @execution_environments, :id, :name, {}, class: 'form-control') @@ -33,7 +32,9 @@ ul#files.list-unstyled.panel-group = f.fields_for :files do |files_form| = render('file_form', f: files_form) + a#add-file.btn.btn-default.btn-sm.pull-right href='#' = t('.add_file') ul#dummies.hidden = f.fields_for(:files, CodeOcean::File.new, child_index: 'index') do |files_form| = render('file_form', f: files_form) - .actions = render('shared/submit_button', f: f, object: @exercise) + + .actions = render('shared/submit_button', f: f, object: @exercise) \ No newline at end of file diff --git a/config.ru b/config.ru index 5bc2a619..23973bc3 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,7 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -run Rails.application + +map CodeOcean::Application.config.relative_url_root || '/' do + run Rails.application +end diff --git a/config/application.rb b/config/application.rb index f180783b..10a8537d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -30,6 +30,8 @@ module CodeOcean config.autoload_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib') + config.assets.precompile += %w( markdown-buttons.png ) + case (RUBY_ENGINE) when 'ruby' # ... diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb new file mode 100644 index 00000000..4cdc5169 --- /dev/null +++ b/config/deploy/staging.rb @@ -0,0 +1,2 @@ +server '10.210.0.50', roles: [:app, :db, :puma_nginx, :web], user: 'debian' +set :rails_env, "staging" diff --git a/config/docker.yml.erb b/config/docker.yml.erb index 9f55d126..8fac75d0 100644 --- a/config/docker.yml.erb +++ b/config/docker.yml.erb @@ -34,6 +34,20 @@ production: ws_host: ws://localhost:4243 #url to connect rails server to docker host ws_client_protocol: wss:// #set the websocket protocol to be used by the client to connect to the rails server (ws on development, wss on production) +staging: + <<: *default + host: unix:///var/run/docker.sock + pool: + active: true + refill: + async: false + batch_size: 8 + interval: 15 + timeout: 60 + workspace_root: <%= Rails.root.join('tmp', 'files', Rails.env) %> + ws_host: ws://localhost:4243 #url to connect rails server to docker host + ws_client_protocol: wss:// #set the websocket protocol to be used by the client to connect to the rails server (ws on development, wss on production) + test: <<: *default host: tcp://192.168.59.104:2376 diff --git a/config/environments/staging.rb b/config/environments/staging.rb new file mode 100644 index 00000000..1cb098cb --- /dev/null +++ b/config/environments/staging.rb @@ -0,0 +1,87 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Enable Rack::Cache to put a simple HTTP cache in front of your application + # Add `rack-cache` to your Gemfile before enabling this. + # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. + # config.action_dispatch.rack_cache = true + + # Disable Rails's static asset server (Apache or nginx will already do this). + config.serve_static_assets = false + + # Compress JavaScripts and CSS. + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Generate digests for assets URLs. + config.assets.digest = true + + # Version of your assets, change this if you want to expire all your assets. + config.assets.version = '1.0' + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Set to :debug to see everything in the log. + config.log_level = :error + + # Prepend all log lines with the following tags. + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups. + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets. + # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. + # config.assets.precompile += %w( search.js ) + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Disable automatic flushing of the log to improve performance. + # config.autoflush_log = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Run on subfolder in production environment. + config.relative_url_root = '/co-staging' + +end diff --git a/config/nginx.conf b/config/nginx.conf deleted file mode 100644 index 32d4f34f..00000000 --- a/config/nginx.conf +++ /dev/null @@ -1,45 +0,0 @@ -upstream puma { - server unix:///var/www/app/shared/tmp/sockets/puma.sock; -} - -server { - listen 80 default deferred; - return 301 https://codeocean.openhpi.de$request_uri; - server_name codeocean.openhpi.de; -} - -server { - client_max_body_size 4G; - error_page 500 502 503 504 /500.html; - keepalive_timeout 10; - listen 443 ssl; - root /var/www/app/current/public; - server_name codeocean.openhpi.de; - try_files $uri @puma; - - ssl_certificate /etc/nginx/ssl/ssl-bundle.crt; - ssl_certificate_key /etc/nginx/ssl/server.key; - ssl_ciphers HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM; - ssl_prefer_server_ciphers on; - ssl_protocols SSLv3 TLSv1; - ssl_session_timeout 5m; - - location / { - access_log /var/www/app/current/log/nginx.access.log; - error_log /var/www/app/current/log/nginx.error.log; - proxy_http_version 1.1; - proxy_pass http://puma; - proxy_read_timeout 900; - proxy_redirect off; - proxy_set_header Connection ''; - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location ^~ /assets/ { - add_header Cache-Control public; - expires max; - gzip_static on; - } -} diff --git a/db/schema.rb b/db/schema.rb index 57ce32e7..b2c3b8a4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -74,6 +74,7 @@ ActiveRecord::Schema.define(version: 20160704143402) do t.integer "file_type_id" t.integer "memory_limit" t.boolean "network_enabled" + end create_table "exercises", force: true do |t|