add profile pics to mastery gradebook and outcome result api
fixes CNVS-10295 test plan - regression on mastery gradebook - ensure student profile pics appear next to the student name on the mastery gradebook when profile pics are enabled - ensure that profile pics do not appear if profile pics are disabled Change-Id: I24ccb21990402a76fe1c79ea39a752d1f73e8d5f Reviewed-on: https://gerrit.instructure.com/28561 Reviewed-by: Braden Anderson <banderson@instructure.com> QA-Review: Braden Anderson <banderson@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Joel Hough <joel@instructure.com>
This commit is contained in:
parent
c126c17f5b
commit
e209ba649d
|
@ -115,7 +115,7 @@ define [
|
|||
# Returns an object.
|
||||
_toRow: (rollup, section) ->
|
||||
return null unless Grid.Util.sectionFilter(section, rollup)
|
||||
row = { student: rollup.name, section: rollup.links.section }
|
||||
row = { student: Grid.Util.lookupStudent(rollup.links.user), section: rollup.links.section }
|
||||
_.each rollup.scores, (score) ->
|
||||
row["outcome_#{score.links.outcome}"] = score.score
|
||||
row
|
||||
|
@ -149,6 +149,25 @@ define [
|
|||
lookupOutcome: (name) ->
|
||||
Grid.outcomes[name]
|
||||
|
||||
# Public: Parse and store a list of students from the outcome rollups API.
|
||||
#
|
||||
# students - An array of student objects.
|
||||
#
|
||||
# Returns nothing.
|
||||
saveStudents: (students) ->
|
||||
Grid.students = _.reduce(students, (result, student) ->
|
||||
result[student.id] = student
|
||||
result
|
||||
, {})
|
||||
|
||||
# Public: Look up a student in the current student list.
|
||||
#
|
||||
# name - The id for the student to look for.
|
||||
#
|
||||
# Returns an student or null.
|
||||
lookupStudent: (id) ->
|
||||
Grid.students[id]
|
||||
|
||||
Math:
|
||||
mean: (values, round = false) ->
|
||||
total = _.reduce(values, ((a, b) -> a + b), 0)
|
||||
|
@ -197,7 +216,7 @@ define [
|
|||
cellTemplate(score: value, className: className, masteryScore: outcome.mastery_points)
|
||||
|
||||
studentCell: (row, cell, value, columnDef, dataContext) ->
|
||||
studentCellTemplate(name: value)
|
||||
studentCellTemplate(value)
|
||||
|
||||
# Public: Create a string class name for the given score.
|
||||
#
|
||||
|
|
|
@ -81,6 +81,7 @@ define [
|
|||
# Returns nothing.
|
||||
renderGrid: (response) =>
|
||||
Grid.Util.saveOutcomes(response.linked.outcomes)
|
||||
Grid.Util.saveStudents(response.linked.users)
|
||||
[columns, rows] = Grid.Util.toGrid(response, column: { formatter: Grid.View.cell }, row: { section: @menu.currentSection })
|
||||
@grid = new Slick.Grid(
|
||||
'.outcome-gradebook-wrapper',
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#
|
||||
# "links": {
|
||||
# // The id of the related outcome
|
||||
# "outcome": 42
|
||||
# "outcome": "42"
|
||||
# }
|
||||
# }
|
||||
#
|
||||
|
@ -39,15 +39,21 @@
|
|||
# // an array of OutcomeRollupScore objects
|
||||
# "scores": ["OutcomeRollupScore"],
|
||||
#
|
||||
# // The id of the resource for this rollup. For example, the user id.
|
||||
# "id": 42,
|
||||
#
|
||||
# // The name of the resource for this rollup. For example, the user name.
|
||||
# "name": "John Doe",
|
||||
#
|
||||
# "links": {
|
||||
# // (Optional) The id of the section this resource is in
|
||||
# "section": 57
|
||||
# // If an aggregate result was requested, the course field will be present
|
||||
# // Otherwise, the user and section field will be present
|
||||
#
|
||||
# // (Optional) The id of the course that this rollup applies to
|
||||
# "course": "42",
|
||||
#
|
||||
# // (Optional) The id of the user that this rollup applies to
|
||||
# "user": "42",
|
||||
#
|
||||
# // (Optional) The id of the section the user is in
|
||||
# "section": "57"
|
||||
# }
|
||||
# }
|
||||
#
|
||||
|
@ -88,7 +94,13 @@ class OutcomeResultsController < ApplicationController
|
|||
# {
|
||||
# "rollups": [OutcomeRollup],
|
||||
# "linked": {
|
||||
# "outcomes": [Outcome]
|
||||
# "outcomes": [Outcome],
|
||||
#
|
||||
# // (Optional) Included if aggregate is not set
|
||||
# "users": [User],
|
||||
#
|
||||
# // (Optional) Included if aggregate is 'course'
|
||||
# "courses": [Course]
|
||||
# }
|
||||
# }
|
||||
def rollups
|
||||
|
@ -106,7 +118,20 @@ class OutcomeResultsController < ApplicationController
|
|||
@users = Api.paginate(@users, self, api_v1_course_outcome_rollups_url(@context))
|
||||
@results = find_outcome_results(users: @users, context: @context, outcomes: @outcomes)
|
||||
rollups = outcome_results_rollups(@results, @users)
|
||||
json = outcome_results_rollups_json(rollups, @outcomes)
|
||||
json = outcome_results_rollups_json(rollups)
|
||||
json[:linked] = {
|
||||
outcomes: Api.recursively_stringify_json_ids(outcomes_json(@outcomes, @current_user, session)),
|
||||
users: @users.map do |u|
|
||||
hash = {
|
||||
id: u.id.to_s,
|
||||
name: u.name,
|
||||
display_name: u.short_name,
|
||||
sortable_name: u.sortable_name
|
||||
}
|
||||
hash[:avatar_image_url] = avatar_url_for_user(u, blank_fallback) if service_enabled?(:avatars)
|
||||
hash
|
||||
end
|
||||
}
|
||||
json[:meta] = Api.jsonapi_meta(@users, self, api_v1_course_outcome_rollups_url(@context))
|
||||
render json: json
|
||||
end
|
||||
|
@ -119,7 +144,11 @@ class OutcomeResultsController < ApplicationController
|
|||
# rollup, so don't paginate users in ths method.
|
||||
@results = find_outcome_results(users: @users, context: @context, outcomes: @outcomes)
|
||||
aggregate_rollups = [aggregate_outcome_results_rollup(@results, @context)]
|
||||
json = aggregate_outcome_results_rollups_json(aggregate_rollups, @outcomes)
|
||||
json = aggregate_outcome_results_rollups_json(aggregate_rollups)
|
||||
json[:linked] = {
|
||||
outcomes: Api.recursively_stringify_json_ids(outcomes_json(@outcomes, @current_user, session)),
|
||||
courses: [{id: @context.id.to_s, name: @context.name}]
|
||||
}
|
||||
# no pagination, so no meta field
|
||||
render json: json
|
||||
end
|
||||
|
|
|
@ -241,16 +241,21 @@ $page-dark: #ebeff2;
|
|||
width: 228px;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
.avatar-circle {
|
||||
border: 1px solid $border-light;
|
||||
border-radius: 25px;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
float: left;
|
||||
height: 25px;
|
||||
margin: 5px 8px 0 4px;
|
||||
margin: 5px 8px 0 -4px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
.outcome-student-cell-content {
|
||||
padding-left: 8px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.outcome-cell-wrapper {
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
<div class="avatar-placeholder"></div>
|
||||
{{name}}
|
||||
<div class="outcome-student-cell-content">
|
||||
{{#if avatar_image_url}}
|
||||
<img class="avatar-circle" src="{{avatar_image_url}}" alt="{{display_name}}">
|
||||
{{/if}}
|
||||
{{display_name}}
|
||||
</div>
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
module Api::V1::Outcome
|
||||
include Api::V1::Json
|
||||
|
||||
# style can be :full or :abbrev; anything unrecognized defaults to :full.
|
||||
# abbreviated includes only id, title, url, subgroups_url, outcomes_url, and can_edit. full expands on
|
||||
# that by adding import_url, parent_outcome_group (if any),
|
||||
# context id and type, and description.
|
||||
def outcomes_json(outcomes, user, session, style=:full)
|
||||
outcomes.map { |o| outcome_json(o, user, session, style) }
|
||||
end
|
||||
|
||||
# style can be :full or :abbrev; anything unrecognized defaults to :full.
|
||||
# abbreviated includes only id, title, context id and type, url, and
|
||||
# can_edit. full expands on that by adding description and criterion values
|
||||
|
|
|
@ -24,41 +24,31 @@ module Api::V1::OutcomeResults
|
|||
# rollups - The rollups from Outcomes::ResultAnalytics to seralize
|
||||
#
|
||||
# Returns a hash that can be converted into json.
|
||||
def outcome_results_rollups_json(rollups, outcomes)
|
||||
def outcome_results_rollups_json(rollups)
|
||||
{
|
||||
rollups: serialize_user_rollups(rollups),
|
||||
linked: serialize_linked_outcomes(outcomes),
|
||||
rollups: serialize_user_rollups(rollups)
|
||||
}
|
||||
end
|
||||
|
||||
# Public: Serializes the aggregate rollup. Uses the specified context for the
|
||||
# id and name fields.
|
||||
def aggregate_outcome_results_rollups_json(rollups, outcomes)
|
||||
def aggregate_outcome_results_rollups_json(rollups)
|
||||
{
|
||||
rollups: serialize_rollups(rollups),
|
||||
linked: serialize_linked_outcomes(outcomes),
|
||||
}
|
||||
end
|
||||
|
||||
# Internal: Returns a hash for linked of serialized outcomes
|
||||
def serialize_linked_outcomes(outcomes)
|
||||
{
|
||||
outcomes: outcomes.map { |o| Api.recursively_stringify_json_ids(outcome_json(o, @current_user, session)) },
|
||||
rollups: serialize_rollups(rollups, :course)
|
||||
}
|
||||
end
|
||||
|
||||
# Internal: Returns an Array of serialized rollups.
|
||||
def serialize_rollups(rollups)
|
||||
rollups.map { |rollup| serialize_rollup(rollup) }
|
||||
def serialize_rollups(rollups, context_key)
|
||||
rollups.map { |rollup| serialize_rollup(rollup, context_key) }
|
||||
end
|
||||
|
||||
# Internal: Returns a suitable output hash for the rollup.
|
||||
def serialize_rollup(rollup)
|
||||
def serialize_rollup(rollup, context_key)
|
||||
# both Course and User have a name method, so this works for both.
|
||||
{
|
||||
id: rollup.context.id.to_s,
|
||||
name: rollup.context.name,
|
||||
scores: serialize_rollup_scores(rollup.scores),
|
||||
links: {context_key => rollup.context.id.to_s}
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -66,7 +56,7 @@ module Api::V1::OutcomeResults
|
|||
# section information.
|
||||
def serialize_user_rollups(rollups)
|
||||
serialized_rollup_pairs = rollups.map do |rollup|
|
||||
[rollup, serialize_rollup(rollup)]
|
||||
[rollup, serialize_rollup(rollup, :user)]
|
||||
end
|
||||
|
||||
serialized_rollups_with_section_duplicates = serialized_rollup_pairs.map do |rollup, serialized_rollup|
|
||||
|
@ -89,7 +79,7 @@ module Api::V1::OutcomeResults
|
|||
# is in multiple sections, they will have multiple rollup results. pagination is
|
||||
# still by user, so the counts won't match up. again, this is a very rare thing
|
||||
(@section ? [@section] : rollup.context.sections_for_course(@context)).map do |section|
|
||||
serialized_rollup.merge(links: {section: section.id.to_s})
|
||||
serialized_rollup.deep_merge(links: {section: section.id.to_s})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -219,25 +219,28 @@ describe "Outcome Results API", :type => :integration do
|
|||
json.keys.sort.should == %w(linked meta rollups)
|
||||
json['rollups'].size.should == 1
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id links name scores)
|
||||
rollup['links'].keys.should == %w(section)
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links'].keys.sort.should == %w(section user)
|
||||
rollup['links']['section'].should == @course.course_sections.first.id.to_s
|
||||
rollup['links']['user'].should == outcome_student.id.to_s
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
score['score'].should == first_outcome_rating[:points]
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
score['links']['outcome'].should == outcome_object.id.to_s
|
||||
end
|
||||
end
|
||||
json['linked'].keys.should == %w(outcomes)
|
||||
json['linked'].keys.sort.should == %w(outcomes users)
|
||||
json['linked']['outcomes'].size.should == 1
|
||||
json['linked']['users'].size.should == 1
|
||||
end
|
||||
|
||||
describe "user_ids parameter" do
|
||||
it "restricts results to specified users" do
|
||||
outcome_students
|
||||
student_id_str = outcome_students[0..1].map(&:id).join(',')
|
||||
student_ids = outcome_students[0..1].map(&:id).map(&:to_s)
|
||||
student_id_str = student_ids.join(',')
|
||||
course_with_teacher_logged_in(course: outcome_course, active_all: true)
|
||||
api_call(:get, outcome_rollups_url(outcome_course, user_ids: student_id_str),
|
||||
controller: 'outcome_results', action: 'rollups', format: 'json', course_id: outcome_course.id.to_s, user_ids: student_id_str)
|
||||
|
@ -245,19 +248,21 @@ describe "Outcome Results API", :type => :integration do
|
|||
json.keys.sort.should == %w(linked meta rollups)
|
||||
json['rollups'].size.should == 2
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id links name scores)
|
||||
rollup['links'].keys.should == %w(section)
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links'].keys.sort.should == %w(section user)
|
||||
rollup['links']['section'].should == @course.course_sections.first.id.to_s
|
||||
student_ids.should be_include(rollup['links']['user'])
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
[0,1].should be_include(score['score'])
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
score['links']['outcome'].should == outcome_object.id.to_s
|
||||
end
|
||||
end
|
||||
json['linked'].keys.should == %w(outcomes)
|
||||
json['linked'].keys.sort.should == %w(outcomes users)
|
||||
json['linked']['outcomes'].size.should == 1
|
||||
json['linked']['users'].size.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -271,19 +276,21 @@ describe "Outcome Results API", :type => :integration do
|
|||
json.keys.sort.should == %w(linked meta rollups)
|
||||
json['rollups'].size.should == 2
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id links name scores)
|
||||
rollup['links'].keys.should == %w(section)
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links'].keys.sort.should == %w(section user)
|
||||
rollup['links']['section'].should == outcome_course_sections[0].id.to_s
|
||||
outcome_course_sections[0].student_ids.map(&:to_s).should be_include(rollup['links']['user'])
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
[0,2].should be_include(score['score'])
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
score['links']['outcome'].should == outcome_object.id.to_s
|
||||
end
|
||||
end
|
||||
json['linked'].keys.should == %w(outcomes)
|
||||
json['linked'].keys.sort.should == %w(outcomes users)
|
||||
json['linked']['outcomes'].size.should == 1
|
||||
json['linked']['users'].size.should == outcome_course_sections[0].students.count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -347,18 +354,18 @@ describe "Outcome Results API", :type => :integration do
|
|||
json.keys.sort.should == %w(linked rollups)
|
||||
json['rollups'].size.should == 1
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id name scores)
|
||||
rollup['id'].should == @course.id.to_s
|
||||
rollup['name'].should == @course.name
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links']['course'] == @course.id.to_s
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
score['score'].should == first_outcome_rating[:points]
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
end
|
||||
end
|
||||
json['linked'].keys.should == %w(outcomes)
|
||||
json['linked'].keys.sort.should == %w(courses outcomes)
|
||||
json['linked']['outcomes'].size.should == 1
|
||||
json['linked']['courses'].size.should == 1
|
||||
end
|
||||
|
||||
describe "user_ids parameter" do
|
||||
|
@ -372,16 +379,16 @@ describe "Outcome Results API", :type => :integration do
|
|||
user_ids: student_id_str)
|
||||
json = JSON.parse(response.body)
|
||||
json.keys.sort.should == %w(linked rollups)
|
||||
json['linked'].keys.sort.should == %w(courses outcomes)
|
||||
json['rollups'].size.should == 1
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id name scores)
|
||||
rollup['id'].should == @course.id.to_s
|
||||
rollup['name'].should == @course.name
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links']['course'].should == @course.id.to_s
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
score['score'].should == 0.5
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -399,14 +406,13 @@ describe "Outcome Results API", :type => :integration do
|
|||
json.keys.sort.should == %w(linked rollups)
|
||||
json['rollups'].size.should == 1
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id name scores)
|
||||
rollup['id'].should == outcome_course.id.to_s
|
||||
rollup['name'].should == outcome_course.name
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['links']['course'].should == outcome_course.id.to_s
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['scores'].each do |score|
|
||||
score.keys.sort.should == %w(links score)
|
||||
score['score'].should == 1
|
||||
score['links'].keys.should == %w(outcome)
|
||||
score['links'].keys.sort.should == %w(outcome)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -430,13 +436,15 @@ describe "Outcome Results API", :type => :integration do
|
|||
json = JSON.parse(response.body)
|
||||
json.keys.sort.should == %w(linked meta rollups)
|
||||
json['rollups'].size.should == 2
|
||||
json['rollups'].collect{|x| x['id']}.sort.should == [student.id.to_s, student2.id.to_s].sort
|
||||
json['rollups'].collect{|x| x['links']['user']}.sort.should == [student.id.to_s, student2.id.to_s].sort
|
||||
json['rollups'].each do |rollup|
|
||||
rollup.keys.sort.should == %w(id links name scores)
|
||||
rollup.keys.sort.should == %w(links scores)
|
||||
rollup['scores'].size.should == 1
|
||||
rollup['links'].keys.sort.should == %w(section user)
|
||||
end
|
||||
json['linked'].keys.should == %w(outcomes)
|
||||
json['linked'].keys.sort.should == %w(outcomes users)
|
||||
json['linked']['outcomes'].size.should == 1
|
||||
json['linked']['users'].size.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue