refactor: de-dupe factories between courseware and course-home (#400)

This commit is contained in:
Kyle McCormick
2021-03-29 16:05:51 -04:00
committed by GitHub
parent d94c7ad003
commit 4d1ed0f357
19 changed files with 163 additions and 333 deletions

View File

@@ -0,0 +1,59 @@
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
Factory.define('block')
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
.option('host', 'http://localhost:18000')
// Generating block_id that is similar to md5 hash, but still deterministic
.sequence('block_id', id => ('abcd'.repeat(8) + id).slice(-32))
.attrs({
complete: false,
description: null,
due: null,
graded: false,
icon: null,
showLink: true,
type: 'course',
children: [],
})
.attr('display_name', ['display_name', 'block_id'], (displayName, blockId) => {
if (displayName) {
return displayName;
}
return blockId;
})
.attr(
'id',
['id', 'block_id', 'type', 'courseId'],
(id, blockId, type, courseId) => {
if (id) {
return id;
}
const courseInfo = courseId.split(':')[1];
return `block-v1:${courseInfo}+type@${type}+block@${blockId}`;
},
)
.attr(
'student_view_url',
['student_view_url', 'host', 'id'],
(url, host, id) => {
if (url) {
return url;
}
return `${host}/xblock/${id}`;
},
)
.attr(
'lms_web_url',
['lms_web_url', 'host', 'courseId', 'id'],
(url, host, courseId, id) => {
if (url) {
return url;
}
return `${host}/courses/${courseId}/jump_to/${id}`;
},
);

View File

@@ -0,0 +1,142 @@
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
import './block.factory';
// Generates an Array of block IDs, either from a single block or an array of blocks.
const getIds = (attr) => {
const blocks = Array.isArray(attr) ? attr : [attr];
return blocks.map(block => block.id);
};
// Generates an Object in { [block.id]: block } format, either from a single block or an array of blocks.
const getBlocks = (attr) => {
const blocks = Array.isArray(attr) ? attr : [attr];
// eslint-disable-next-line no-return-assign,no-sequences
return blocks.reduce((acc, block) => (acc[block.id] = block, acc), {});
};
Factory.define('courseBlocks')
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
.option('units', ['courseId'], courseId => ([
Factory.build(
'block',
{ type: 'vertical' },
{ courseId },
),
]))
.option('sequence', ['courseId', 'units'], (courseId, child) => Factory.build(
'block',
{ type: 'sequential', children: getIds(child) },
{ courseId },
))
.option('section', ['courseId', 'sequence'], (courseId, child) => Factory.build(
'block',
{ type: 'chapter', children: getIds(child) },
{ courseId },
))
.option('course', ['courseId', 'section'], (courseId, child) => Factory.build(
'block',
{ type: 'course', children: getIds(child) },
{ courseId },
))
.attr(
'blocks',
['course', 'section', 'sequence', 'units'],
(course, section, sequence, units) => ({
[course.id]: course,
...getBlocks(section),
...getBlocks(sequence),
...getBlocks(units),
}),
)
.attr('root', ['course'], course => course.id);
/**
* Builds a course with a single chapter, sequence, and unit.
*/
export function buildSimpleCourseBlocks(courseId, title, options = {}) {
const unitBlocks = options.unitBlocks || [Factory.build(
'block',
{ type: 'vertical' },
{ courseId },
)];
const sequenceBlock = options.sequenceBlock || [Factory.build(
'block',
{ type: 'sequential', children: unitBlocks.map(block => block.id) },
{ courseId },
)];
const sectionBlock = options.sectionBlock || Factory.build(
'block',
{ type: 'chapter', children: sequenceBlock.map(block => block.id) },
{ courseId },
);
const courseBlock = options.courseBlocks || Factory.build(
'block',
{ type: 'course', display_name: title, children: [sectionBlock.id] },
{ courseId },
);
return {
courseBlocks: options.courseBlocks || Factory.build(
'courseBlocks',
{
courseId,
hasScheduledContent: options.hasScheduledContent || false,
title: 'Demo Course',
},
{
units: unitBlocks,
sequence: sequenceBlock,
section: sectionBlock,
course: courseBlock,
},
),
unitBlocks,
sequenceBlock,
sectionBlock,
courseBlock,
};
}
/**
* Builds a course with a single chapter and sequence, but no units.
*/
export function buildMinimalCourseBlocks(courseId, title, options = {}) {
const sequenceBlock = options.sequenceBlock || [Factory.build(
'block',
{ display_name: 'Title of Sequence', type: 'sequential' },
{ courseId },
)];
const sectionBlock = options.sectionBlock || Factory.build(
'block',
{
type: 'chapter',
display_name: 'Title of Section',
complete: options.complete || false,
effort_time: 15,
effort_activities: 2,
resume_block: options.resumeBlock || false,
children: sequenceBlock.map(block => block.id),
},
{ courseId },
);
const courseBlock = options.courseBlock || Factory.build(
'block',
{ type: 'course', display_name: title, children: [sectionBlock.id] },
{ courseId },
);
return {
courseBlocks: options.courseBlocks || Factory.build(
'courseBlocks',
{ courseId },
{
sequence: sequenceBlock,
section: sectionBlock,
course: courseBlock,
units: [],
},
),
unitBlocks: [],
sequenceBlock,
sectionBlock,
courseBlock,
};
}

View File

@@ -0,0 +1,83 @@
/* A basic course metadata factory, to be specialized in courseware and course-home., */
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
import './tab.factory';
export default new Factory()
.sequence('id', (i) => `course-v1:edX+DemoX+Demo_Course_${i}`)
.option('host')
.attrs({
is_staff: false,
original_user_is_staff: false,
number: 'DemoX',
org: 'edX',
})
.attr(
'tabs', ['id', 'host'], (id, host) => {
const tabs = [
Factory.build(
'tab',
{
title: 'Course',
priority: 0,
slug: 'courseware',
type: 'courseware',
},
{ courseId: id, host, path: 'course/' },
),
Factory.build(
'tab',
{
title: 'Discussion',
priority: 1,
slug: 'discussion',
type: 'discussion',
},
{ courseId: id, host, path: 'discussion/forum/' },
),
Factory.build(
'tab',
{
title: 'Wiki',
priority: 2,
slug: 'wiki',
type: 'wiki',
},
{ courseId: id, host, path: 'course_wiki' },
),
Factory.build(
'tab',
{
title: 'Progress',
priority: 3,
slug: 'progress',
type: 'progress',
},
{ courseId: id, host, path: 'progress' },
),
Factory.build(
'tab',
{
title: 'Instructor',
priority: 4,
slug: 'instructor',
type: 'instructor',
},
{ courseId: id, host, path: 'instructor' },
),
Factory.build(
'tab',
{
title: 'Dates',
priority: 5,
slug: 'dates',
type: 'dates',
},
{ courseId: id, host, path: 'dates' },
),
];
return tabs;
},
);

View File

@@ -0,0 +1,4 @@
import './block.factory';
import './courseBlocks.factory';
import './courseMetadataBase.factory';
import './tab.factory';

View File

@@ -0,0 +1,18 @@
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
Factory.define('tab')
.option('courseId', 'course-v1:edX+DemoX+Demo_Course')
.option('path', 'course/')
.option('host', 'http://localhost:18000')
.attrs({
title: 'Course',
priority: 0,
slug: 'courseware',
type: 'courseware',
})
.attr('tab_id', ['slug'], (slug) => slug)
.attr(
'url',
['courseId', 'path', 'host'],
(courseId, path, host) => `${host}/courses/${courseId}/${path}`,
);