Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Commit

Permalink
Finished implementing the last route, /sarvuxgru
Browse files Browse the repository at this point in the history
  • Loading branch information
themaxsandelin committed Nov 9, 2018
1 parent 09e53fd commit cc58227
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 6 deletions.
8 changes: 3 additions & 5 deletions src/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,12 @@ router.get('/', (req, res) => {
'Kommunal vuxenutbildning grundläggande<br>' +
'<a href="/vuxgru">/vuxgru</a><br><br>' +

'Särvux grundläggande<br>' +
'<a href="/sarvuxgru">/sarvuxgru</a><br><br>' +

'Komvux sfi<br>' +
'<a href="/sfi">/sfi</a><br><br><br>' +

'<b>Work-in-progress routes:</b><br><br>' +

'Särvux grundläggande (WIP)<br>' +
'<a href="/sarvuxgru">/sarvuxgru</a><br><br>' +

'<b>Built and facilitated by <a href="https://github.com/themaxsandelin" target="_blank">Max Sandelin</a></b><br><br>' +
'This API is completely open source, and you can find the <a href="https://github.com/themaxsandelin/skolverket-api" target="_blank">repository here.</a>' +
'</p>'
Expand Down
6 changes: 5 additions & 1 deletion src/controllers/sarvuxgru/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Route manager for /sarvuxgru.
const router = require('express').Router()

// Sub routes
router.use('/subjects', require('./subjects'))
router.use('/subject-areas', require('./subjectAreas'))

router.get('/', (req, res) => {
res.json({
level: 'Särvux grundläggande',
routes: [ ]
routes: [ '/subjects', '/subjects/[code]', '/subject-areas', '/subject-areas/[code]' ]
})
})

Expand Down
60 changes: 60 additions & 0 deletions src/controllers/sarvuxgru/subjectAreas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Route manager for: /sarvuxgru/subject-areas
// Data folder: sarvuxgr

// Dependencies
const router = require('express').Router()
const path = require('path')
const fs = require('fs')
const { parseString } = require('xml2js')
const async = require('async')

// Helpers
const formatter = require('../../helpers/sarvuxgru/formatter')
const latinize = require('../../helpers/latinize')

const rootPath = path.resolve(__dirname + '/../../../files/sarvuxgr')

router.get('/', (req, res) => {
const folder = rootPath + '/subjectArea'
const files = fs.readdirSync(folder)

let areas = []
async.each(files, (file, callback) => {
parseString(fs.readFileSync(folder + '/' + file), (err, result) => {
areas.push({
name: result.subject.name[0],
code: result.subject.code[0]
})

callback()
})
}, (error) => {
res.json(areas)
})
})

router.get('/:code', (req, res) => {
const code = req.params.code.toLowerCase()
const folder = rootPath + '/subjectArea'
const files = fs.readdirSync(folder)

let area
async.each(files, (file, callback) => {
parseString(fs.readFileSync(folder + '/' + file), (err, result) => {
if (result.subject.code[0].toLowerCase() === code) {
const data = result.subject
area = formatter.formatSubjectData(result.subject)
}

callback()
})
}, (error) => {
if (area) {
res.json(area)
} else {
res.status(404).send('Not found')
}
})
})

module.exports = router
50 changes: 50 additions & 0 deletions src/controllers/sarvuxgru/subjects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Route manager for /sarvuxgru/subjects
// Data folder: sarvuxgr

// Dependencies
const router = require('express').Router()
const path = require('path')
const fs = require('fs')
const { parseString } = require('xml2js')

// Helpers
const formatter = require('../../helpers/sarvuxgru/formatter')
const latinize = require('../../helpers/latinize')

const rootPath = path.resolve(__dirname + '/../../../files/sarvuxgr')

router.get('/', (req, res) => {
const file = rootPath + '/subjectsAndCourses/amnen_och_kurser.xml'

parseString(fs.readFileSync(file).toString(), (err, result) => {
res.json(formatter.formatSubjects(result.SubjectsAndCourses.subject))
})
})

router.get('/:code', (req, res) => {
const code = req.params.code.toLowerCase()
const file = rootPath + '/subjectsAndCourses/amnen_och_kurser.xml'

parseString(fs.readFileSync(file).toString(), (err, result) => {
let validCode = false

result.SubjectsAndCourses.subject.forEach(subject => {
if (subject.code[0].toLowerCase() === code) {
validCode = true

let file = rootPath + '/subject/' + latinize(subject.name[0]) + '.xml'
while (file.indexOf('–') > -1) {
file = file.replace('–', '-')
}

parseString(fs.readFileSync(file), (err, result) => {
res.json(formatter.formatSubjectData(result.subject))
})
}
})

if (!validCode) res.status(404).send('Not found.')
})
})

module.exports = router
248 changes: 248 additions & 0 deletions src/helpers/sarvuxgru/formatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// Dependencies
const Turndown = require('turndown')

function Formatter() {
const turndownService = new Turndown()

function formatProgramme(data) {
const programme = {
name: data.name[0],
code: data.code[0],
skolfs: data.skolfsId[0],
applianceDate: data.applianceDate[0],
typeOfSchooling: data.typeOfSchooling[0],
typeOfProgram: data.typeOfProgram[0],
purpose: {},
generalSubjects: [],
programmeSubjects: [],
specializationSubjects: [],
orientations: [],
profiles: [],
individualChoice: [],
projectAssignments: [],
professionalDegrees: []
}

if (data.purpose[0].degreeObjective && data.purpose[0].degreeObjective[0] !== '') {
programme.purpose.degreeObjective = {
title: (typeof data.purpose[0].degreeObjective[0].title[0] === 'string') ? data.purpose[0].degreeObjective[0].title[0] : '',
content: turndownService.turndown(data.purpose[0].degreeObjective[0].content[0])
}
}

if (data.purpose[0].orientation && data.purpose[0].orientation[0] !== '') {
programme.purpose.orientation = {
title: (typeof data.purpose[0].orientation[0].title[0] === 'string') ? data.purpose[0].orientation[0].title[0] : '',
content: turndownService.turndown(data.purpose[0].orientation[0].content[0])
}
}

if (data.purpose[0].educationObjective && data.purpose[0].educationObjective[0] !== '') {
programme.purpose.educationObjective = {
title: (typeof data.purpose[0].educationObjective[0].title[0] === 'string') ? data.purpose[0].educationObjective[0].title[0] : '',
content: turndownService.turndown(data.purpose[0].educationObjective[0].content[0])
}
}

// Go through "commonMandatory" to get all general subjects.
if (data.commonMandatory && data.commonMandatory[0] !== '') {
programme.generalSubjects = formatSubjects(data.commonMandatory[0].subject)
}

// Go through "commonProgram" to get all programme specific subjects.
if (data.commonProgram && data.commonProgram[0] !== '') {
programme.programmeSubjects = formatSubjects(data.commonProgram[0].subject)
}

// Go through all "programOrientations" to get programme orientations.
if (data.programOrientations && data.programOrientations[0] !== '') {
data.programOrientations[0].programOrientation.forEach(orientationData => {
const orientation = {
name: orientationData.name[0],
code: orientationData.code[0],
points: parseInt(orientationData.point[0]),
subjects: (orientationData.subject[0] !== '') ? formatSubjects(orientationData.subject) : []
}
programme.orientations.push(orientation)
})
}

if (data.specialization && data.specialization[0] !== '') {
programme.specializationSubjects = formatSubjects(data.specialization[0].subject)
}

// Go through "professionalDegrees"
if (data.professionalDegrees && data.professionalDegrees[0] !== '') {
data.professionalDegrees[0].professionalDegree.forEach(degreeData => {
const degree = {
name: degreeData.name[0],
code: degreeData.programOrientationCode[0],
subjects: (degreeData.subject && degreeData.subject[0] !== '') ? formatSubjects(degreeData.subject) : []
}

programme.professionalDegrees.push(degree)
})
}

// Go through "projectAssignments"
if (data.projectAssignment && data.projectAssignment[0] !== '') {
data.projectAssignment[0].subject.forEach(subjectData => {
programme.projectAssignments.push({
name: subjectData.name[0],
code: subjectData.code[0],
optional: subjectData.optional[0] === 'true' ? true : false,
alias: subjectData.alias[0] === 'true' ? true : false
})
})
}

// Go through "profiles"
if (data.profiles && data.profiles[0] !== '') {
programme.profiles = formatProfiles(data.profiles[0].profile)
}

return programme
}

function formatProfiles(profileList) {
const profiles = []
profileList.forEach(profileData => {
const profile = {
name: profileData.name[0],
code: profileData.code[0],
points: parseInt(profileData.points[0])
}
if (profileData.subject) {
profile.subjects = formatSubjects(profileData.subject)
}
if (profileData.profileExits) {
profile.exits = formatProfileExits(profileData.profileExits[0].profileExit)
}

profiles.push(profile)
})

return profiles
}

function formatProfileExits(exitList) {
const exits = []

exitList.forEach(exitData => {
const exit = {
name: exitData.name[0],
points: parseInt(exitData.points[0])
}
if (exitData.subject) {
exit.subjects = formatSubjects(exitData.subject)
}
if (exitData.optionalCourses) {
exit.optionalCourses = formatSubjects(exitData.optionalCourses[0].subject)
}

exits.push(exit)
})

return exits
}

function formatSubjects(subjectList) {
const subjects = []

subjectList.forEach(subjectData => {
const subject = {
name: subjectData.name[0],
code: subjectData.code[0]
}
if (subjectData.point) {
subject.points = parseInt(subjectData.point[0])
}
if (subjectData.optional) {
subject.optional = (subjectData.optional[0] === 'true')
}
if (subjectData.courses || subjectData.course) {
subject.courses = formatCourses(subjectData.courses ? subjectData.courses : subjectData.course)
}

subjects.push(subject)
})

return subjects
}

function formatSubjectData(data) {
const subject = {
name: data.name[0],
code: data.code[0],
skolfs: data.skolfsId[0],
applianceDate: data.applianceDate[0],
typeOfSchooling: data.typeOfSchooling[0],
description: turndownService.turndown(data.description[0]),
purpose: turndownService.turndown(data.purpose[0])
}
if (data.category) subject.category = data.category[0]
if (data.courses) subject.courses = formatCourses(data.courses)
if (data.centralContents) subject.centralContent = formatCentralContent(data.centralContents)
if (data.knowledgeRequirements) subject.knowledgeRequirements = formatKnowledgeRequirements(data.knowledgeRequirements)

return subject
}

function formatCourses(courseList) {
const courses = []
courseList.forEach(courseData => {
courses.push(formatCourseData(courseData))
})
return courses
}

function formatCourseData(courseData) {
const course = {
name: courseData.name[0],
code: courseData.code[0]
}
if (courseData.point) course.points = parseInt(courseData.point[0])
if (courseData.description) course.description = turndownService.turndown(courseData.description[0])
if (courseData.centralContent) course.centralContent = turndownService.turndown(courseData.centralContent[0])
if (courseData.knowledgeRequirements) course.knowledgeRequirements = formatKnowledgeRequirements(courseData.knowledgeRequirements)

return course
}

function formatCentralContent(blocks) {
const content = []
blocks.forEach(block => {
const row = {
text: turndownService.turndown(block.text[0])
}
if (block.year && typeof block.year[0] === 'string') row.year = block.year[0]

content.push(row)
})

return content.length > 1 ? content : content[0]
}

function formatKnowledgeRequirements(requirementsList) {
const requirements = []
requirementsList.forEach(reqData => {
const req = { description: turndownService.turndown(reqData.text[0]) }

if (reqData.gradeStep) req.grade = reqData.gradeStep[0]
if (reqData.year && typeof reqData.year[0] === 'string') req.year = reqData.year[0]

requirements.push(req)
})

return requirements
}

return {
formatProgramme,
formatSubjects,
formatSubjectData,
formatCourseData
}
}

module.exports = Formatter()

0 comments on commit cc58227

Please sign in to comment.