Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions lib/CourseThemeModule.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import _ from 'lodash'
import AbstractApiModule from 'adapt-authoring-api'
import fs from 'fs/promises'
import semver from 'semver'
import { getVariablesString, processCustomStyling } from './utils.js'

const CONFIG_THEME_VARS_MIN_VERSION = '6.61.0' // adjust to actual release version

/**
* Module which handles course theming
* @memberof coursetheme
Expand All @@ -26,20 +30,43 @@ class CourseThemeModule extends AbstractApiModule {
* @type {ContentModule}
*/
this.content = content
/**
* Cached module instance for easy access
* @type {AdaptFrameworkModule}
*/
this.framework = framework
framework.preBuildHook.tap(this.writeCustomLess.bind(this))
framework.registerImportContentMigration(async (data, importer) => {
if (data._type === 'course' && data.themeVariables) {
importer._themeVariablesMigration = data.themeVariables
delete data.themeVariables
}
if (data._type === 'config' && importer._themeVariablesMigration) {
data.themeVariables = importer._themeVariablesMigration
delete importer._themeVariablesMigration
}
})
}

/**
* Writes the customStyle and themeVariables attributes to LESS files. themeVariables are reduced into a string of variables, in the format `@key: value;`
* @param {AdaptFrameworkBuild} fwBuild Reference to the current build
*/
async writeCustomLess (fwBuild) {
const fontImportString = await this.processFileVariables(fwBuild)
processCustomStyling(fwBuild.courseData)
const configData = fwBuild.courseData.config.data
const courseData = fwBuild.courseData.course.data
// prefer config, fall back to course for unmigrated data
const variables = configData[this.attributeKey] || courseData[this.attributeKey] || {}

const fontImportString = await this.processFileVariables(fwBuild, variables)
processCustomStyling(fwBuild.courseData, variables)

const { customStyle, themeCustomStyle } = courseData
const frameworkHandlesVars = semver.gte(this.framework.version, CONFIG_THEME_VARS_MIN_VERSION)

const { customStyle, [this.attributeKey]: variables, themeCustomStyle } = fwBuild.courseData.course.data
return Promise.all([
this.writeFile(fwBuild, '1-variables.less', fontImportString + getVariablesString(variables)),
this.writeFile(fwBuild, '1-variables.less',
frameworkHandlesVars ? fontImportString : fontImportString + getVariablesString(variables)),
this.writeFile(fwBuild, '2-customStyles.less', customStyle),
this.writeFile(fwBuild, '3-themeCustomStyles.less', themeCustomStyle)
])
Expand Down Expand Up @@ -74,8 +101,9 @@ class CourseThemeModule extends AbstractApiModule {
async applyHandler (req, res, next) {
try {
const { _id, courseId } = req.apiData.query
const [{ properties: presetProps }] = await this.find({ _id })
await this.content.update({ _id: courseId }, { [this.attributeKey]: presetProps })
const { properties: presetProps } = await this.findOne({ _id })
const config = await this.content.findOne({ _courseId: courseId, _type: 'config' })
await this.content.update({ _id: config._id }, { [this.attributeKey]: presetProps })
res.sendStatus(204)
} catch (e) {
return next(e)
Expand All @@ -91,9 +119,10 @@ class CourseThemeModule extends AbstractApiModule {
async removeHandler (req, res, next) {
try {
const { _id, courseId } = req.apiData.query
const [{ properties: presetProps }] = await this.find({ _id })
const [{ themeVariables: existingProps }] = await this.content.find({ _id: courseId })
await this.content.update({ _id: courseId }, { [this.attributeKey]: _.pickBy(existingProps, (v, k) => v !== presetProps[k]) })
const { properties: presetProps } = await this.findOne({ _id })
const config = await this.content.findOne({ _courseId: courseId, _type: 'config' })
const existingProps = config[this.attributeKey] || {}
await this.content.update({ _id: config._id }, { [this.attributeKey]: _.pickBy(existingProps, (v, k) => v !== presetProps[k]) })
res.sendStatus(204)
} catch (e) {
return next(e)
Expand All @@ -102,11 +131,12 @@ class CourseThemeModule extends AbstractApiModule {

/**
* Copies uploaded font files into the build
* @param {object} data The data to process
* @param {AdaptFrameworkBuild} fwBuild Reference to the current build
* @param {Object} variables The theme variables object
*/
async processFileVariables (fwBuild) {
async processFileVariables (fwBuild, variables) {
const assets = await this.app.waitForModule('assets')
const fontData = fwBuild.courseData.course.data.themeVariables._font
const fontData = variables?._font

if (!fontData) {
return ''
Expand All @@ -118,7 +148,7 @@ class CourseThemeModule extends AbstractApiModule {
if (!f['font-family']) return
// copy each uploaded font file
for (const font in f._files) {
const [data] = await assets.find({ _id: f._files[font] })
const data = await assets.findOne({ _id: f._files[font] })
const asset = assets.createFsWrapper(data)
try {
const relativeFontPath = `fonts/${f._files[font]}.${asset.data.subtype}`
Expand Down
7 changes: 4 additions & 3 deletions lib/utils/processCustomStyling.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
* Processes custom styling by moving the themeCustomStyle attribute from
* themeVariables to the top-level course data
* @param {Object} courseData The course data object (fwBuild.courseData)
* @param {Object} variables The theme variables object
* @memberof coursetheme
*/
export function processCustomStyling (courseData) {
const customStyling = courseData.course.data.themeVariables.themeCustomStyle
export function processCustomStyling (courseData, variables) {
const customStyling = variables?.themeCustomStyle

if (!customStyling) return

courseData.course.data.themeCustomStyle = customStyling

delete courseData.course.data.themeVariables.themeCustomStyle
delete variables.themeCustomStyle
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"repository": "github:adapt-security/adapt-authoring-coursetheme",
"dependencies": {
"adapt-authoring-api": "^3.0.0",
"lodash": "^4.17.21"
"lodash": "^4.17.21",
"semver": "^7.6.0"
},
"peerDependencies": {
"adapt-authoring-adaptframework": "^2.0.0",
Expand Down
Loading