Refactor all server-side fetching calls, refactor solutionProblemView, minor changes to rest

This commit is contained in:
Josh Callebaut 2016-05-13 15:32:59 -07:00
parent 19e1c808d8
commit 38e97ab404
11 changed files with 216 additions and 234 deletions

View file

@ -6,10 +6,13 @@ module.exports = class LevelCollection extends CocoCollection
model: Level
fetchForClassroom: (classroomID, options={}) ->
options.url = "/db/classroom/#{classroomID}/levels"
options.url = '/db/classroom/#{classroomID}/levels'
@fetch(options)
fetchForClassroomAndCourse: (classroomID, courseID, options={}) ->
options.url = "/db/classroom/#{classroomID}/courses/#{courseID}/levels"
options.url = '/db/classroom/#{classroomID}/courses/#{courseID}/levels'
@fetch(options)
fetchForCampaign: (campaignSlug, options={}) ->
options.url = '/db/campaign/' + campaignSlug + '/levels'
@fetch(options)

View file

@ -1,5 +1,9 @@
#solution-problems-view
.problemType
width: 50%
width: 87.5%
.problemValue
width: 50%
width: 12.5%
.problemsTable
width: 100%

View file

@ -3,14 +3,14 @@ extends /templates/base
block content
img(src='/images/pages/user/artisan.png')
div
a(href='artisans/thang-tasks')
a(href='/artisans/thang-tasks')
|Thang Tasks
div
a(href="artisans/level-tasks")
a(href="/artisans/level-tasks")
|Level Tasks
div
a(href="artisans/solution-problems")
a(href="/artisans/solution-problems")
|Solution Problems
div
a(href="artisans/course-gear")
a(href="/artisans/course-gear")
|Course Gear Progression

View file

@ -3,8 +3,9 @@ extends /templates/base
block content
#level-tasks-view
div
a(href='./')
a(href='/artisans')
| < Artisans Home
br
input#nameSearch(placeholder='Filter: Level Name')
br
input#descSearch(placeholder='Filter: Task Description')
@ -20,15 +21,13 @@ block content
else
div ole?
mixin levelRow(level)
tr
td.taskOwner
a(href= 'level/' + level.slug)= level.name
td.tasks
table.table-condensed.table-striped.table-hover.tasksTable
for task in (level.tasks2 || [])
table.table-striped.table-hover.tasksTable
for task in (level.tasks || [])
if !task.complete
tr
td= task.name

View file

@ -1,15 +1,24 @@
extends /templates/base
block content
#solution-problems-view
div
a(href='/artisans')
| < Artisans Home
br
div Total number of problems: #{view.problemCount}
hr
table.table.table-striped#levelTable
tr
th Level Name
th Solution Problems
for level in (view.parsedLevels || [])
if (level.problems || []).length != 0
tr
td(style="width:10%")= level.level.get('slug')
td(style="width:10%")= level.level.get('name')
td
table.table-condensed.table-striped.table-hover
table.table-striped.table-hover.problemsTable
for problem in (level.problems || [])
tr(style="width:100%")
td.problemType= problem.type
td.problemValue= problem.value
td.problemType= problem.type

View file

@ -3,8 +3,9 @@ extends /templates/base
block content
#thang-tasks-view
div
a(href='./')
a(href='/artisans')
| < Artisans Home
br
input#nameSearch(placeholder='Filter: Thang Name')
br
input#descSearch(placeholder='Filter: Task Description')

View file

@ -1,57 +1,67 @@
RootView = require 'views/core/RootView'
template = require 'templates/artisans/level-tasks-view'
#ThangType = require 'models/ThangType'
Level = require 'models/Level'
Campaigns = require 'collections/Campaigns'
Campaign = require 'models/Campaign'
CocoCollection = require 'collections/CocoCollection'
module.exports = class LevelTasksView extends RootView
template: template
id: 'level-tasks-view'
events:
'input input': 'searchUpdate'
'change input': 'searchUpdate'
'input .searchInput': 'searchUpdate'
'change .searchInput': 'searchUpdate'
excludedCampaigns = [
"picoctf"
"auditions"
'picoctf', 'auditions'
]
constructor: (options) ->
super options
@campaigns = new CocoCollection([],
url: '/db/campaign?project=name,slug,tasks'
model: Campaign
)
@campaigns.fetch()
@listenTo(@campaigns, 'sync', @onCampaignsLoaded)
@supermodel.loadCollection(@campaigns, 'campaigns')
levels: {}
initialize: () ->
@searchUpdate = _.debounce(@searchUpdate, 250)
onCampaignsLoaded: ->
@campaigns = new Campaigns()
@listenTo(@campaigns, 'sync', @onCampaignsLoaded)
@supermodel.trackRequest(@campaigns.fetch(
data:
project: 'name,slug,levels,tasks'
))
onCampaignsLoaded: (campCollection) ->
@levels = {}
sum = 0
for campaign in @campaigns.models
continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1
levels = campaign.get('levels')
sum += Object.keys(levels).length
for campaign in campCollection.models
campaignSlug = campaign.get 'slug'
continue if campaignSlug in excludedCampaigns
levels = campaign.get 'levels'
for key, level of levels
continue unless ///#{$('#nameSearch')[0].value}///i.test level.name
levelSlug = level.slug
@levels[levelSlug] = level
@processedLevels = @levels
for key, level of @processedLevels
level.tasks2 = _.filter level.tasks, (_elem) ->
return ///#{$('#descSearch')[0].value}///i.test _elem.name
@processedLevels = {}
for key, level of @levels
filteredTasks = level.tasks.filter (elem) ->
return ///#{$('#descSearch')[0].value}///i.test elem.name
@processedLevels[key] = {
tasks: filteredTasks
name: level.name
}
@renderSelectors '#levelTable'
searchUpdate: ->
@onCampaignsLoaded(@campaigns)
###
if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update.
@campaigns.fetch()
#@campaigns.fetch()
@listenTo(@campaigns, 'sync', @onCampaignsLoaded)
@supermodel.loadCollection(@campaigns, 'campaigns')
@superModel.trackRequest()
#@supermodel.loadCollection(@campaigns, 'campaigns')
@lastLoad = (new Date()).getTime()
else
@onCampaignsLoaded()
###
destroy: ->
@searchUpdate.cancel()
super()
# Jade helper
hasIncompleteTasks: (level) ->
return level.tasks2 and level.tasks2.filter((_elem) -> return not _elem.complete).length > 0
return level.tasks and level.tasks.filter((_elem) -> return not _elem.complete).length > 0

View file

@ -1,206 +1,165 @@
RootView = require 'views/core/RootView'
template = require 'templates/artisans/solution-problems-view'
Level = require 'models/Level'
Campaign = require 'models/Campaign'
Level = require 'models/Level'
CocoCollection = require 'collections/CocoCollection'
Campaigns = require 'collections/Campaigns'
Levels = require 'collections/Levels'
module.exports = class SolutionProblemsView extends RootView
template: template
id: 'solution-problems-view'
excludedCampaigns = [
"picoctf"
"auditions"
# Misc. campaigns
'picoctf', 'auditions'
"dungeon"
"forest"
"desert"
#"mountain"
"glacier"
# Campaign-version campaigns
#'dungeon', 'forest', 'desert', 'mountain', 'glacier'
"dungeon-branching-test"
"forest-branching-test"
"desert-branching-test"
# Test campaigns
'dungeon-branching-test', 'forest-branching-test', 'desert-branching-test'
"intro"
"course-2"
"course-3"
"course-4"
"course-5"
"course-6"
# Course-version campaigns
#'intro', 'course-2', 'course-3', 'course-4', 'course-5', 'course-6'
]
excludedSimulationLevels = [
# Course Arenas
"wakka-maul"
"cross-bones"
'wakka-maul', 'cross-bones'
]
excludedSolutionLevels = [
# Multiplayer Levels
"cavern-survival"
"dueling-grounds"
"multiplayer-treasure-grove"
"harrowland"
"zero-sum"
"ace-of-coders"
"capture-their-flag"
'cavern-survival'
'dueling-grounds', 'multiplayer-treasure-grove'
'harrowland'
'zero-sum'
'ace-of-coders', 'capture-their-flag'
]
levelOffset: 0
isReady: 0
requiresSubs: 0
simulationRequirements = [
'seed'
'succeeds'
'heroConfig'
'frameCount'
'goals'
]
includedLanguages = [
'python', 'javascript', 'java', 'lua', 'coffeescript'
]
# TODO: Phase the following out:
excludedLanguages = [
#'java', 'lua', 'coffeescript'
]
rob: []
test2: []
constructor: (options) ->
super options
@campaigns = new CocoCollection([],
url: '/db/campaign?project=slug'
model: Campaign
)
@campaigns.fetch()
unloadedCampaigns: 0
campaignLevels: {}
loadedLevels: {}
parsedLevels: []
problemCount: 0
initialize: ->
@campaigns = new Campaigns([])
@listenTo(@campaigns, 'sync', @onCampaignsLoaded)
@supermodel.loadCollection(@campaigns, 'campaigns')
###
@levels = new CocoCollection([],
url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset
model: Level
)
@levels.fetch()
@listenTo(@levels, 'sync', @onLevelsLoaded)
@supermodel.loadCollection(@levels, 'levels')
###
@supermodel.trackRequest(@campaigns.fetch(
data:
project:'slug'
))
onCampaignsLoaded: ->
@levelSlugs = []
@test = {}
@loadedLevels = {}
count = 0
for campaign in @campaigns.models
onCampaignsLoaded: (campCollection) ->
for campaign in campCollection.models
campaignSlug = campaign.get('slug')
continue unless excludedCampaigns.indexOf(campaignSlug) is -1
count++
@test[campaignSlug] = new CocoCollection([],
url: '/db/campaign/' + campaignSlug + '/levels?project=thangs,slug,requiresSubscription,campaign'
model: Level
)
@test[campaignSlug].fetch()
@listenTo(@test[campaignSlug], 'sync', (e) ->
e.models.reverse()
for level in e.models
if not @loadedLevels[level.get('slug')]? and level.get('requiresSubscription')
@requiresSubs++
continue if campaignSlug in excludedCampaigns
@unloadedCampaigns++
@campaignLevels[campaignSlug] = new Levels()
@listenTo(@campaignLevels[campaignSlug], 'sync', @onLevelsLoaded)
@supermodel.trackRequest(@campaignLevels[campaignSlug].fetchForCampaign(campaignSlug,
data:
project: 'thangs,name,slug,campaign'
))
onLevelsLoaded: (lvlCollection) ->
for level in lvlCollection.models
@loadedLevels[level.get('slug')] = level
count--
if count is 0
@readyUp()
)
@supermodel.loadCollection(@test[campaignSlug], 'levels')
if --@unloadedCampaigns is 0
@onAllLevelsLoaded()
readyUp: ->
console.log("Count of levels: " + _.size(@loadedLevels))
console.log("Count requires sub: " + @requiresSubs)
@parsedLevels = []
@problemCount = 0
onAllLevelsLoaded: ->
for levelSlug, level of @loadedLevels
unless level?
console.error 'Level Slug doesn\'t have associated Level', levelSlug
continue
thangs = level.get('thangs')
continue if levelSlug in excludedSolutionLevels
thangs = level.get 'thangs'
component = null
thang = _.findWhere(thangs, (elem) ->
return elem.id is "Hero Placeholder" and _.findWhere(elem.components, (elem2) ->
if elem2.config?.programmableMethods?.plan?
thangs = _.filter(thangs, (elem) ->
return _.findWhere(elem.components, (elem2) ->
if elem2.config?.programmableMethods?
component = elem2
return true
)
)
thangs = _.filter(thangs, (elem) ->
return _.findWhere(elem.components, (elem2) ->
if elem2.config?.programmableMethods?
return true
)
)
if thangs.length > 1
console.log levelSlug + ":" + thangs.length + " " + thangs.map((elem) -> return elem.id)
unless thang? and component
console.log("Cannot find programmableMethods component in: " + levelSlug)
unless levelSlug in excludedSimulationLevels
console.warn 'Level has more than 1 programmableMethod Thangs', levelSlug
continue
unless component?.config?.programmableMethods?.plan?
console.log("Cannot find plannable method inside component: " + levelSlug)
unless component?
console.error 'Level doesn\'t have programmableMethod Thang', levelSlug
continue
plan = component.config.programmableMethods.plan
solutions = plan.solutions
solutions = plan.solutions or []
problems = []
if excludedSolutionLevels.indexOf(levelSlug) is -1
for lang in ["python", "javascript", "lua", "java", "coffeescript"]
if _.findWhere(solutions, (elem) -> return elem.language is lang)
#@rob.push language: lang, level: levelSlug
else if lang not in ["lua", "java", "coffeescript"]
problems.push {
"type":"Missing Solution Language",
"value":lang
}
@test2.push(levelSlug)
#break
@problemCount++
else
# monitor lua/java when we care about it here
for solutionIndex of solutions
solution = solutions[solutionIndex]
if excludedSimulationLevels.indexOf(levelSlug) is -1
isSimul = true
for req in ["seed", "succeeds", "heroConfig", 'frameCount', 'goals'] # Implement a fix for lastHash
unless solution[req]?
console.log levelSlug, req
problems.push {
"type":"Solution is not simulatable",
"value":solution.language
}
@problemCount++
isSimul = false
break
if isSimul
console.log level.get('campaign')
if @rob.indexOf(levelSlug) is -1
@rob.push(levelSlug)
if solution.source.search(/pass\n/i) isnt -1
problems.push {
"type":"Solution contains pass",
"value":solution.language
}
@problemCount++
if solution.source.indexOf('<%=') is -1
problems.push {
"type":"Solution is not i18n'd",
"value":solution.language
}
@problemCount++
if solution.language is 'javascript'
if solution.source is plan.source
problems.push {
"type":"Solution is identical to source",
"value":solution.language
}
@problemCount++
else
#console.log solution.source
#console.log plan.languages[solution.language]
if solution.source is plan.languages[solution.language]
problems.push {
"type":"Solution is identical to source",
"value":solution.language
}
@problemCount++
@parsedLevels.push {
problems = problems.concat(@findMissingSolutions solutions)
unless levelSlug in excludedSimulationLevels
for solution in solutions
problems = problems.concat(@findSimulationProblems solution)
problems = problems.concat(@findPass solution)
problems = problems.concat(@findIdenticalToSource solution, plan)
@problemCount += problems.length
@parsedLevels.push
level: level
problems: problems
}
@renderSelectors '#levelTable'
findMissingSolutions: (solutions) ->
problems = []
for lang in includedLanguages
if _.findWhere(solutions, (elem) -> return elem.language is lang)
# TODO: Phase the following out:
else if lang not in excludedLanguages
problems.push
type: 'Missing solution language'
value: lang
problems
findSimulationProblems: (solution) ->
problems = []
for req in simulationRequirements
unless solution[req]?
problems.push
type: 'Solution is not simulatable'
value: solution.language
break
problems
findPass: (solution) ->
problems = []
if solution.source.search(/pass\n/) isnt -1
problems.push
type: 'Solution contains pass'
value: solution.language
problems
findIdenticalToSource: (solution, plan) ->
problems = []
source = if solution.lang is 'javascript' then plan.source else plan.languages[solution.language]
if solution.source is source
problems.push
type: 'Solution matches sample code'
value: solution.language
problems

View file

@ -1,7 +1,9 @@
RootView = require 'views/core/RootView'
template = require 'templates/artisans/thang-tasks-view'
ThangType = require 'models/ThangType'
CocoCollection = require 'collections/CocoCollection'
ThangTypes = require 'collections/ThangTypes'
module.exports = class ThangTasksView extends RootView
template: template
@ -9,18 +11,13 @@ module.exports = class ThangTasksView extends RootView
events:
'input input': 'searchUpdate'
'change input': 'searchUpdate'
constructor: (options) ->
super options
@thangs = new CocoCollection([],
url: '/db/thang.type?project=name,tasks,slug'
model: ThangType
comparator: @sortThangs
)
@lastLoad = (new Date()).getTime()
initialize: () ->
@thangs = new ThangTypes()
@listenTo(@thangs, 'sync', @onThangsLoaded)
@supermodel.loadCollection(@thangs, 'thangs')
@supermodel.trackRequest(@thangs.fetch(
data:
project: 'name,tasks,slug'
))
searchUpdate: ->
if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update.
@thangs.fetch()