Skip to content

Commit b54f450

Browse files
Add support for Scratch projects (#513)
This introduces the concept of projects of type "scratch" which we're going to need for the [Experience CS project](https://github.com/RaspberryPiFoundation/experience-cs). However, it goes to some pains to ensure that any existing clients of the API (e.g. `editor-standalone`, `editor-ui`, the admin dashboard in `editor-api`, etc) will not see a scratch project for now unless they specifically choose to by adding a `project_type=scratch` query string parameter. * [Add default scope to hide scratch projects](bdf8ccc) * [Add scratch-only option for project show endpoint](91e8466) * [Consistently use strings for Project#project_type](f442965) * [Extract string literals -> Project::Types constants](dfade60) --------- Co-authored-by: Chris Roos <[email protected]>
1 parent b6fc0b7 commit b54f450

File tree

17 files changed

+90
-30
lines changed

17 files changed

+90
-30
lines changed

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ GraphQL/ObjectDescription:
2020
- app/graphql/types/query_type.rb
2121

2222
RSpec/NestedGroups:
23-
Max: 4
23+
Max: 5
2424

2525
RSpec/DescribeClass:
2626
Exclude:

app/controllers/api/default_projects_controller.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class DefaultProjectsController < ApiController
55
before_action :authorize_user, only: %i[create]
66

77
def show
8-
data = if params[:type] == 'html'
8+
data = if params[:type] == Project::Types::HTML
99
html_project
1010
else
1111
python_project
@@ -23,7 +23,7 @@ def html
2323

2424
def create
2525
identifier = PhraseIdentifier.generate
26-
@project = Project.new(identifier:, project_type: 'python')
26+
@project = Project.new(identifier:, project_type: Project::Types::PYTHON)
2727
@project.components << Component.new(python_component)
2828
@project.save
2929

@@ -38,7 +38,7 @@ def python_component
3838

3939
def python_project
4040
{
41-
type: 'python',
41+
type: Project::Types::PYTHON,
4242
components: [
4343
{ lang: 'py', name: 'main',
4444
content: "import turtle\nt = turtle.Turtle()\nt.forward(100)\nprint(\"Oh yeah!\")" }
@@ -53,7 +53,7 @@ def html_project
5353
CON
5454

5555
{
56-
type: 'html',
56+
type: Project::Types::HTML,
5757
components: [
5858
{ lang: 'html', name: 'index', content: },
5959
{ lang: 'css', name: 'style', content: "h1 {\n color: blue;\n}" },

app/controllers/api/projects_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def verify_lesson_belongs_to_school
6464
def load_project
6565
project_loader = ProjectLoader.new(params[:id], [params[:locale]])
6666
@project = if action_name == 'show'
67-
project_loader.load(include_images: true)
67+
project_loader.load(include_images: true, only_scratch: params[:project_type] == Project::Types::SCRATCH)
6868
else
6969
project_loader.load
7070
end

app/models/filesystem_project.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def self.import_all!
1515
categorized_files = categorize_files(files, dir)
1616

1717
project_importer = ProjectImporter.new(name: proj_config['NAME'], identifier: proj_config['IDENTIFIER'],
18-
type: proj_config['TYPE'] || 'python',
18+
type: proj_config['TYPE'] || Project::Types::PYTHON,
1919
locale: proj_config['LOCALE'] || 'en', **categorized_files)
2020
project_importer.import!
2121
end

app/models/project.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# frozen_string_literal: true
22

33
class Project < ApplicationRecord
4+
module Types
5+
PYTHON = 'python'
6+
HTML = 'html'
7+
SCRATCH = 'scratch'
8+
end
9+
410
belongs_to :school, optional: true
511
belongs_to :lesson, optional: true
612
belongs_to :parent, optional: true, class_name: :Project, foreign_key: :remixed_from_id, inverse_of: :remixes
@@ -26,6 +32,8 @@ class Project < ApplicationRecord
2632
validate :project_with_school_id_has_school_project
2733
validate :school_project_school_matches_project_school
2834

35+
default_scope -> { where.not(project_type: Types::SCRATCH) }
36+
2937
scope :internal_projects, -> { where(user_id: nil) }
3038

3139
has_paper_trail(

lib/project_loader.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ def initialize(identifier, locales)
88
@locales = [*locales, 'en', nil]
99
end
1010

11-
def load(include_images: false)
12-
query = Project.where(identifier:, locale: @locales)
11+
def load(include_images: false, only_scratch: false)
12+
query = only_scratch ? Project.unscoped.where(project_type: Project::Types::SCRATCH) : Project
13+
query = query.where(identifier:, locale: @locales)
1314
query = query.includes(images_attachments: :blob) if include_images
1415
query.min_by { |project| @locales.find_index(project.locale) }
1516
end

lib/tasks/seeds_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def create_project(user_id, school, lesson, code = '')
9898
project.school = school
9999
project.lesson = lesson
100100
project.locale = 'en'
101-
project.project_type = 'python'
101+
project.project_type = Project::Types::PYTHON
102102
project.components << Component.new({ extension: 'py', name: 'main',
103103
content: code })
104104
end

spec/concepts/lesson/create_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
school_id: school.id,
1515
project_attributes: {
1616
name: 'Hello world project',
17-
project_type: 'python',
17+
project_type: Project::Types::PYTHON,
1818
components: [
1919
{ name: 'main.py', extension: 'py', content: 'print("Hello, world!")' }
2020
]
@@ -86,7 +86,7 @@
8686
{
8787
project_attributes: {
8888
name: 'Hello world project',
89-
project_type: 'python',
89+
project_type: Project::Types::PYTHON,
9090
components: [
9191
{ name: 'main.py', extension: 'py', content: 'print("Hello, world!")' }
9292
]

spec/concepts/project/create_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
let(:project_hash) do
2222
{
23-
project_type: 'python',
23+
project_type: Project::Types::PYTHON,
2424
components: [{
2525
name: 'main',
2626
extension: 'py',

spec/factories/project.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
user_id { SecureRandom.uuid }
66
name { Faker::Book.title }
77
identifier { "#{Faker::Verb.base}-#{Faker::Verb.base}-#{Faker::Verb.base}" }
8-
project_type { 'python' }
8+
project_type { Project::Types::PYTHON }
99
locale { %w[en es-LA fr-FR].sample }
1010

1111
transient do

0 commit comments

Comments
 (0)