Skip to content

Commit

Permalink
Merge pull request #45145 from code-dot-org/launch-code-docs-dcdo
Browse files Browse the repository at this point in the history
Update routes for code docs launch, using a dcdo flag
  • Loading branch information
bethanyaconnor committed Mar 31, 2022
2 parents 074fc0c + 9a02677 commit 42d98de
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 52 deletions.
71 changes: 48 additions & 23 deletions dashboard/app/controllers/programming_environments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
class ProgrammingEnvironmentsController < ApplicationController
include ProxyHelper
EXPIRY_TIME = 30.minutes

before_action :require_levelbuilder_mode_or_test_env, except: [:index, :show]
before_action :set_programming_environment, except: [:index, :new, :create]
before_action :set_programming_environment, except: [:index, :docs_index, :new, :create, :docs_show]
authorize_resource

def index
@programming_environments = ProgrammingEnvironment.where(published: true).order(:name).map(&:summarize_for_index)
end

def docs_index
if DCDO.get('use-studio-code-docs', false)
@programming_environments = ProgrammingEnvironment.all.order(:name).map(&:summarize_for_index)
render :index
else
render_proxied_url(
'https://curriculum.code.org/docs/',
allowed_content_types: nil,
allowed_hostname_suffixes: %w(curriculum.code.org),
expiry_time: EXPIRY_TIME,
infer_content_type: true
)
end
end

def new
end

Expand All @@ -21,56 +39,62 @@ def create
end

def edit
@programming_environment = ProgrammingEnvironment.find_by_name(params[:name])
return render :not_found unless @programming_environment
end

def update
programming_environment = ProgrammingEnvironment.find_by_name(params[:name])
unless programming_environment
render :not_found
return
end
programming_environment.assign_attributes(programming_environment_params.except(:categories))
@programming_environment.assign_attributes(programming_environment_params.except(:categories))
begin
if programming_environment_params[:categories]
programming_environment.categories =
@programming_environment.categories =
programming_environment_params[:categories].each_with_index.map do |category, i|
if category['id'].blank?
ProgrammingEnvironmentCategory.create!(category.merge(programming_environment_id: programming_environment.id, position: i))
ProgrammingEnvironmentCategory.create!(category.merge(programming_environment_id: @programming_environment.id, position: i))
else
existing_category = programming_environment.categories.find(category['id'])
existing_category = @programming_environment.categories.find(category['id'])
existing_category.assign_attributes(category.except('id'))
existing_category.position = i
existing_category.save! if existing_category.changed?
existing_category
end
end
end
programming_environment.save! if programming_environment.changed?
programming_environment.write_serialization
render json: programming_environment.summarize_for_edit.to_json
@programming_environment.save! if @programming_environment.changed?
@programming_environment.write_serialization
render json: @programming_environment.summarize_for_edit.to_json
rescue ActiveRecord::RecordInvalid => e
render(status: :not_acceptable, plain: e.message)
end
end

def show
return render :not_found unless @programming_environment
return head :forbidden unless can?(:read, @programming_environment)
@programming_environment_categories = @programming_environment.categories.select {|c| c.programming_expressions.count > 0}.map(&:summarize_for_environment_show)
end

def destroy
return render :not_found unless @programming_environment
begin
@programming_environment.destroy!
render(status: 200, plain: "Destroyed #{@programming_environment.name}")
rescue => e
render(status: :not_acceptable, plain: e.message)
def docs_show
if DCDO.get('use-studio-code-docs', false)
@programming_environment = ProgrammingEnvironment.find_by_name(params[:programming_environment_name])
return render :not_found unless @programming_environment
@programming_environment_categories = @programming_environment.categories.select {|c| c.programming_expressions.count > 0}.map(&:summarize_for_environment_show)
render :show
else
render_proxied_url(
"https://curriculum.code.org/docs/#{params[:programming_environment_name]}/",
allowed_content_types: nil,
allowed_hostname_suffixes: %w(curriculum.code.org),
expiry_time: EXPIRY_TIME,
infer_content_type: true
)
end
end

def destroy
@programming_environment.destroy!
render(status: 200, plain: "Destroyed #{@programming_environment.name}")
rescue => e
render(status: :not_acceptable, plain: e.message)
end

private

def programming_environment_params
Expand All @@ -90,5 +114,6 @@ def programming_environment_params

def set_programming_environment
@programming_environment = ProgrammingEnvironment.find_by_name(params[:name])
raise ActiveRecord::RecordNotFound unless @programming_environment
end
end
29 changes: 24 additions & 5 deletions dashboard/app/controllers/programming_expressions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
class ProgrammingExpressionsController < ApplicationController
include Rails.application.routes.url_helpers

load_and_authorize_resource
include ProxyHelper
EXPIRY_TIME = 30.minutes

before_action :require_levelbuilder_mode_or_test_env, except: [:search, :show, :show_by_keys]
before_action :set_expression_by_keys, only: [:show_by_keys, :docs_show]
load_and_authorize_resource

# GET /programming_expressions/get_filtered_expressions
# Possible filters:
Expand Down Expand Up @@ -93,10 +95,8 @@ def show
end

def show_by_keys
return render :not_found unless @programming_expression
if params[:programming_environment_name] && params[:programming_expression_key]
@programming_expression = ProgrammingEnvironment.find_by_name(params[:programming_environment_name])&.programming_expressions&.find_by_key(params[:programming_expression_key])
return render :not_found unless @programming_expression
return head :forbidden unless can?(:read, @programming_expression)
@programming_environment_categories = @programming_expression.programming_environment.categories.select {|c| c.programming_expressions.count > 0}.map(&:summarize_for_environment_show)
return render :show
end
Expand Down Expand Up @@ -125,6 +125,21 @@ def clone
end
end

def docs_show
if DCDO.get('use-studio-code-docs', false)
return render :not_found unless @programming_expression
@programming_environment_categories = @programming_expression.programming_environment.categories.select {|c| c.programming_expressions.count > 0}.map(&:summarize_for_environment_show)
return render :show
end
render_proxied_url(
"https://curriculum.code.org/docs/#{params[:programming_environment_name]}/#{params[:programming_expression_key]}/",
allowed_content_types: nil,
allowed_hostname_suffixes: %w(curriculum.code.org),
expiry_time: EXPIRY_TIME,
infer_content_type: true
)
end

private

def programming_expression_params
Expand All @@ -146,4 +161,8 @@ def programming_expression_params
)
transformed_params
end

def set_expression_by_keys
@programming_expression = ProgrammingEnvironment.find_by_name(params[:programming_environment_name])&.programming_expressions&.find_by_key(params[:programming_expression_key])
end
end
6 changes: 5 additions & 1 deletion dashboard/app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ def initialize(user)
environment.published || user.permission?(UserPermission::LEVELBUILDER)
end

can [:read, :show_by_keys], ProgrammingExpression do |expression|
can [:read, :show_by_keys, :docs_show], ProgrammingExpression do |expression|
can? :read, expression.programming_environment
end

can [:docs_index, :docs_show], ProgrammingEnvironment do |environment|
can? :read, environment
end

if user.persisted?
can :manage, user

Expand Down
10 changes: 9 additions & 1 deletion dashboard/app/models/programming_environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ def remove_serialization
File.delete(file_path) if File.exist?(file_path)
end

def studio_documentation_path
if DCDO.get('use-studio-code-docs', false) && ['applab', 'gamelab', 'spritelab', 'weblab'].include?(name)
"/docs/#{name}"
else
programming_environment_path(name)
end
end

def summarize_for_lesson_edit
{id: id, name: name}
end
Expand Down Expand Up @@ -119,7 +127,7 @@ def summarize_for_index
title: title,
imageUrl: image_url,
description: description,
showPath: programming_environment_path(name)
showPath: studio_documentation_path
}
end
end
6 changes: 5 additions & 1 deletion dashboard/app/models/programming_expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ def documentation_path
end

def studio_documentation_path
programming_environment_programming_expression_path(programming_environment.name, key)
if DCDO.get('use-studio-code-docs', false)
documentation_path
else
programming_environment_programming_expression_path(programming_environment.name, key)
end
end

def summarize_for_lesson_edit
Expand Down
2 changes: 2 additions & 0 deletions dashboard/app/views/programming_expressions/show.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//%script{src: webpack_asset_path('js/googleblockly.js')}
- content_for(:head) do
= tag 'meta', name: 'description', content: @programming_expression.syntax
%script{src: webpack_asset_path('js/blockly.js')}
%script{src: webpack_asset_path("js/#{js_locale}/blockly_locale.js")}
%script{src: webpack_asset_path('js/programming_expressions/show.js'),
Expand Down
11 changes: 10 additions & 1 deletion dashboard/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,16 @@

get 'redirected_url', to: 'redirect_proxy#get', format: false

get 'docs/', to: 'curriculum_proxy#get_doc_landing'
# We moved code docs off of curriculum builder in spring 2022.
# In that move, we wanted to preserve the previous /docs routes for these
# pages. However, there are a lot of other /docs URLs that did not move over
# so we're allow-listing the four IDEs that lived on curriculum builder to be
# served by ProgrammingEnvironmentsController and ProgrammingExpressionsController,
# with the rest falling back to the old proxying logic.
get 'docs/', to: 'programming_environments#docs_index'
get 'docs/:programming_environment_name', to: 'programming_environments#docs_show', constraints: {programming_environment_name: /(applab|gamelab|spritelab|weblab)/}
get 'docs/:programming_environment_name/:programming_expression_key', constraints: {programming_environment_name: /(applab|gamelab|spritelab|weblab)/, programming_expression_key: /#{CurriculumHelper::KEY_CHAR_RE}+/}, to: 'programming_expressions#docs_show'
get 'docs/:programming_environment_name/:programming_expression_key/index.html', constraints: {programming_environment_name: /(applab|gamelab|spritelab|weblab)/, programming_expression_key: /#{CurriculumHelper::KEY_CHAR_RE}+/}, to: 'programming_expressions#docs_show'
get 'docs/*path', to: 'curriculum_proxy#get_doc'
get 'curriculum/*path', to: 'curriculum_proxy#get_curriculum'

Expand Down
2 changes: 1 addition & 1 deletion dashboard/config/scripts/levels/allthethings_map.level
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"user_id": 556,
"properties": {
"instructions_important": "false",
"reference": "/docs/applab/checkbox/index.html"
"reference": "/docs/concepts/app-lab/the-counter-pattern/index.html"
},
"published": true,
"notes": ""
Expand Down
10 changes: 0 additions & 10 deletions dashboard/test/controllers/curriculum_proxy_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@
require 'test_helper'

class CurriculumProxyControllerTest < ActionController::TestCase
test "should redirect from studio.code.org/docs to curriculum.code.org/docs" do
stub_request(:get, "https://curriculum.code.org/docs/").
to_return(body: 'curriculum.code.org/docs content', headers: {})

request.host = "studio.code.org"
get :get_doc_landing
assert_response :success
assert_equal response.body, 'curriculum.code.org/docs content'
end

test "should redirect from studio.code.org/docs path to curriculum.code.org/docs path" do
stub_request(:get, "https://curriculum.code.org/docs/concepts/game-lab/drawing-shapes/").
to_return(body: 'curriculum.code.org content', headers: {})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'webmock/minitest'
WebMock.disable_net_connect!(allow_localhost: true)
require 'test_helper'

class ProgrammingEnvironmentsControllerTest < ActionController::TestCase
Expand Down Expand Up @@ -39,13 +41,77 @@ class ProgrammingEnvironmentsControllerTest < ActionController::TestCase
assert_equal 1, JSON.parse(nav_data).length
end

test 'data is passed down to docs show page if using studio code docs' do
DCDO.expects(:get).at_least_once
DCDO.expects(:get).with('use-studio-code-docs', false).returns(true).at_least_once

programming_environment = create :programming_environment, name: 'weblab'
category = create :programming_environment_category, programming_environment: programming_environment
create :programming_environment_category, programming_environment: programming_environment
create :programming_expression, programming_environment: programming_environment, programming_environment_category: category

get :docs_show, params: {programming_environment_name: programming_environment.name}
assert_response :ok

show_data = css_select('script[data-programmingenvironment]').first.attribute('data-programmingenvironment').to_s
assert_equal programming_environment.summarize_for_show.to_json, show_data

nav_data = css_select('script[data-categoriesfornavigation]').first.attribute('data-categoriesfornavigation').to_s
assert_equal 1, JSON.parse(nav_data).length
end

test 'page is proxied to docs show page if not using studio code docs' do
DCDO.expects(:get).with('use-studio-code-docs', false).returns(false).at_least_once

programming_environment = create :programming_environment, name: 'weblab'
category = create :programming_environment_category, programming_environment: programming_environment
create :programming_environment_category, programming_environment: programming_environment
create :programming_expression, programming_environment: programming_environment, programming_environment_category: category

stub_request(:get, "https://curriculum.code.org/docs/#{programming_environment.name}/").
to_return(body: 'curriculum.code.org/docs content', headers: {})

request.host = "studio.code.org"
get :docs_show, params: {programming_environment_name: programming_environment.name}
assert_response :ok
assert_equal @response.body, 'curriculum.code.org/docs content'
end

test 'page is not proxied to docs index if using studio code docs' do
DCDO.expects(:get).at_least_once
DCDO.expects(:get).with('use-studio-code-docs', false).returns(true).at_least_once

create :programming_environment
stubbed_request = stub_request(:get, "https://curriculum.code.org/docs/").
to_return(body: 'curriculum.code.org/docs content', headers: {})

get :docs_index
assert_response :ok
assert_not_requested stubbed_request
end

test 'page is proxied to docs index page if not using studio code docs' do
DCDO.expects(:get).with('use-studio-code-docs', false).returns(false).at_least_once
create :programming_environment

stubbed_request = stub_request(:get, "https://curriculum.code.org/docs/").
to_return(body: 'curriculum.code.org/docs content', headers: {})

request.host = "studio.code.org"
get :docs_index
assert_response :ok
assert_equal @response.body, 'curriculum.code.org/docs content'
assert_requested stubbed_request
end

test 'returns not_found if editing a non-existant programming environment' do
sign_in @levelbuilder

post :edit, params: {
name: 'fake_name'
}
assert_response :not_found
assert_raises(ActiveRecord::RecordNotFound) do
post :edit, params: {
name: 'fake_name'
}
end
end

test 'can update programming expression from params' do
Expand Down Expand Up @@ -97,11 +163,12 @@ class ProgrammingEnvironmentsControllerTest < ActionController::TestCase
test 'returns not_found if updating a non-existant programming environment' do
sign_in @levelbuilder

post :update, params: {
name: 'fake_name',
title: 'title'
}
assert_response :not_found
assert_raises(ActiveRecord::RecordNotFound) do
post :update, params: {
name: 'fake_name',
title: 'title'
}
end
end

test 'can create a new programming environment' do
Expand Down

0 comments on commit 42d98de

Please sign in to comment.