-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from vinayakjaas/video_player
Server side code for video content player and Documentation for XAPI
- Loading branch information
Showing
7 changed files
with
1,787 additions
and
0 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
Pdf_Library/Documentation/docs/tutorial-basics copy/_category_.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"label": "XAPI(Experience API)", | ||
"position": 2, | ||
"link": { | ||
"type": "generated-index", | ||
"description": "Pdf Library Introduction " | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
Pdf_Library/Documentation/docs/tutorial-basics copy/create-a-page.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
# Transferring Data from xAPI to SCORM Cloud | ||
|
||
## Introduction | ||
|
||
This guide provides a step-by-step approach for transferring data from an xAPI-based system to SCORM Cloud using JavaScript and the TinCanJS package. SCORM Cloud is a cloud-based service that supports SCORM and xAPI (Tin Can API) content. TinCanJS is a JavaScript library that facilitates communication with xAPI endpoints. | ||
|
||
## Prerequisites | ||
|
||
- **Node.js**: Ensure you have Node.js installed on your system. | ||
- **NPM/Yarn**: Node package manager to install dependencies. | ||
- **SCORM Cloud Account**: Access to SCORM Cloud credentials (endpoint, key, and secret). | ||
- **TinCanJS Library**: JavaScript library for xAPI interactions. | ||
|
||
## Setup | ||
|
||
### 1. Install Dependencies | ||
|
||
Start by setting up a new Node.js project and installing the required packages: | ||
|
||
```bash | ||
mkdir xapi-to-scorm | ||
cd xapi-to-scorm | ||
npm init -y | ||
npm install tincanjs axios | ||
``` | ||
|
||
### 2. Configure SCORM Cloud Credentials | ||
Create a .env file in the root directory of your project to store SCORM Cloud credentials securely: | ||
```bash | ||
SCORM_CLOUD_ENDPOINT=https://cloud.scorm.com/lrs/VRIH0Z14DH/ | ||
SCORM_CLOUD_KEY=4gPlyMtlpy18FccetKM | ||
SCORM_CLOUD_SECRET=vV4rzTZ8Q-yjnpakVIY | ||
``` | ||
### 3. Create a JavaScript File for Data Transfer | ||
Create a file transferData.js in the root directory of your project: | ||
```bash | ||
// Define the xAPI statements to be transferred | ||
const statements = [ | ||
// Example xAPI statement | ||
{ | ||
actor: { | ||
mbox: "mailto:[email protected]", | ||
name: "Example Learner" | ||
}, | ||
verb: { | ||
id: "http://adlnet.gov/expapi/verbs/completed", | ||
display: { "en-US": "completed" } | ||
}, | ||
object: { | ||
id: "http://example.com/activities/example-activity", | ||
objectType: "Activity", | ||
name: { "en-US": "Example Activity" } | ||
}, | ||
result: { | ||
score: { | ||
scaled: 0.9 | ||
} | ||
}, | ||
timestamp: new Date().toISOString() | ||
} | ||
]; | ||
``` | ||
## Explanation | ||
TinCanJS Configuration: Configures the library with SCORM Cloud credentials. | ||
Statements Definition: Defines the xAPI statements that you wish to transfer. | ||
Data Transfer Function: Sends the xAPI statements to the SCORM Cloud endpoint using Axios for HTTP requests. | ||
Execution: Runs the data transfer script. | ||
## Error Handling | ||
Ensure valid SCORM Cloud credentials are provided in the .env file. | ||
Check network connectivity and SCORM Cloud endpoint status. | ||
Monitor the console output for successful or failed transfer messages. | ||
## Conclusion | ||
This documentation outlines the process of transferring data from an xAPI system to SCORM Cloud using JavaScript and the TinCanJS library. Adjust the xAPI statements as needed for your specific use case. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
env | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
!.vscode/extensions.json | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
require('dotenv').config(); | ||
const express = require('express'); | ||
const bodyParser = require('body-parser'); | ||
const TinCan = require('tincanjs'); | ||
const jwt = require('jsonwebtoken'); | ||
const morgan = require('morgan'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const app = express(); | ||
const port = process.env.PORT || 5000; | ||
|
||
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' }); | ||
app.use(morgan('combined', { stream: accessLogStream })); | ||
|
||
app.use(bodyParser.json()); | ||
|
||
app.use((req, res, next) => { | ||
res.header("Access-Control-Allow-Origin", "*"); | ||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization"); | ||
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); | ||
next(); | ||
}); | ||
|
||
|
||
const authenticateJWT = (req, res, next) => { | ||
const token = req.header('Authorization')?.split(' ')[1]; | ||
|
||
if (token) { | ||
jwt.verify(token, process.env.JWT_SECRET, (err, user) => { | ||
if (err) { | ||
console.error('JWT verification failed:', err); | ||
return res.status(403).send('Forbidden'); | ||
} | ||
req.user = user; | ||
next(); | ||
}); | ||
} else { | ||
res.status(401).send('Unauthorized'); | ||
} | ||
}; | ||
|
||
// // Route to Generate JWT Token (For Testing Purposes) | ||
// app.post('/api/login', (req, res) => { | ||
// const { username, email } = req.body; | ||
|
||
// // Generate a JWT token | ||
// const token = jwt.sign( | ||
// { name: username, email: email }, | ||
// process.env.JWT_SECRET, | ||
// { expiresIn: '1h' } | ||
// ); | ||
|
||
// res.json({ token }); | ||
// }); | ||
app.post('/api/login', (req, res) => { | ||
const { username, email } = req.body; | ||
const token = jwt.sign( | ||
{ name: username, email: email }, | ||
process.env.JWT_SECRET, | ||
{ expiresIn: '1h' } | ||
); | ||
|
||
res.json({ token }); | ||
}); | ||
|
||
let lrs; | ||
try { | ||
lrs = new TinCan.LRS({ | ||
endpoint: process.env.LRS_ENDPOINT, | ||
username: process.env.LRS_KEY, | ||
password: process.env.LRS_SECRET, | ||
allowFail: false | ||
}); | ||
console.log("LRS object setup successfully."); | ||
} catch (ex) { | ||
console.error("Failed to setup LRS object: ", ex); | ||
process.exit(1); | ||
} | ||
|
||
|
||
app.post('/api/video-metadata', authenticateJWT, (req, res) => { | ||
const { videoId, title, description, duration, format } = req.body; | ||
|
||
if (!videoId || !title || !duration || !format) { | ||
console.error("Missing video metadata in request body"); | ||
return res.status(400).send("Missing video metadata in request body"); | ||
} | ||
|
||
|
||
console.log("Received video metadata:", { videoId, title, description, duration, format }); | ||
|
||
const supportedFormats = ['mp4', 'avi', 'mov']; | ||
if (!supportedFormats.includes(format)) { | ||
console.error(`Unsupported video format: ${format}`); | ||
return res.status(400).send(`Unsupported video format: ${format}`); | ||
} | ||
|
||
const statement = new TinCan.Statement({ | ||
actor: { | ||
mbox: `mailto:${req.user.email}`, | ||
name: req.user.name, | ||
}, | ||
verb: { | ||
id: "http://adlnet.gov/expapi/verbs/experienced", | ||
display: { "en-US": "experienced" } | ||
}, | ||
object: { | ||
id: `http://example.com/videos/${videoId}`, | ||
definition: { | ||
name: { "en-US": title }, | ||
description: { "en-US": description } | ||
} | ||
}, | ||
result: { | ||
duration: `PT${Math.floor(duration / 60)}M${duration % 60}S` | ||
}, | ||
context: { | ||
extensions: { | ||
"http://example.com/metadata/format": format | ||
} | ||
} | ||
}); | ||
|
||
console.log("Attempting to save video metadata statement:", statement); | ||
|
||
|
||
lrs.saveStatement(statement, { | ||
callback: function (err, xhr) { | ||
if (err !== null) { | ||
console.error("Failed to save statement:", err); | ||
console.error("Error details:", xhr ? xhr.responseText : "No response text"); | ||
res.status(500).send("Failed to save video metadata"); | ||
} else { | ||
console.log("Video metadata saved successfully to SCORM Cloud"); | ||
res.status(200).send("Video metadata saved successfully"); | ||
} | ||
} | ||
}); | ||
}); | ||
|
||
app.use((err, req, res, next) => { | ||
console.error("An error occurred:", err.message); | ||
res.status(500).send("Internal Server Error"); | ||
}); | ||
|
||
app.listen(port, () => { | ||
console.log(`Server is running on http://localhost:${port}`); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const mongoose = require('mongoose'); | ||
|
||
const QuizSchema = new mongoose.Schema({ | ||
question: String, | ||
type: { type: String, enum: ['multiple-choice', 'fill-in-the-blank'], required: true }, | ||
options: [String], // Only for multiple-choice questions | ||
correctAnswer: String, // Correct option or answer | ||
points: { type: Number, default: 4 } | ||
}); | ||
|
||
const Quiz = mongoose.model('Quiz', QuizSchema); |
Oops, something went wrong.