Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCORE Environment - Beta Authoring and Roomcasting #660

Merged
merged 32 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d727471
Created new isScoreRun property for CK projects; Added menu item and …
JoelWiebe Jan 9, 2025
3cdf0bd
Separate SCORE Runs and CK Projects in projects dashboard
JoelWiebe Jan 9, 2025
2bb09b6
Rename Boards to Activity Spaces on project dashboard; Add Script SCO…
JoelWiebe Jan 9, 2025
e6d721f
Added SCORE Authoring page and routing; Added add activity modal with…
JoelWiebe Jan 10, 2025
896c2ff
Fixed adding and fetching activities from DB
JoelWiebe Jan 11, 2025
5dd1b94
Add resources as the means of assigning views (e.g., canvas, workspac…
JoelWiebe Jan 11, 2025
1062c6a
Added reordering of activities to frontend, backend, and styling
JoelWiebe Jan 11, 2025
4a8b5eb
Created a Resources model, api routing, and database calls; Added res…
JoelWiebe Jan 14, 2025
020b14d
Add edit activity component; Add deleting and updating activities; Ad…
JoelWiebe Jan 15, 2025
f8ebe1d
Added group to resource assignment logic and UI
JoelWiebe Jan 15, 2025
6181505
Added a classroom canvas for SCORE authoring; Added a classroom objec…
JoelWiebe Jan 16, 2025
e425c6c
Added and styled teacher activity list for SCORE authoring; Minor sty…
JoelWiebe Jan 20, 2025
a7fc0a7
Added View Canvas as an additional teacher task and created SCORE vie…
JoelWiebe Jan 21, 2025
e1603c2
Added bucket and workflow editing to SCORE authoring
JoelWiebe Jan 22, 2025
57fa8ad
Renamed Activities to Activity Phases in activity pane
JoelWiebe Jan 22, 2025
cf02826
Fixed resizing of canvas in SCORE view modal; Removed heading from bu…
JoelWiebe Feb 2, 2025
3b829e8
Added display of CK Monitor and CK workspace within the SCORE authori…
JoelWiebe Feb 4, 2025
6993be0
Added implementation of activate workflow and custom prompt teacher t…
JoelWiebe Feb 5, 2025
9e75808
Added show join code teacher task; Set all teacher tasks as clickable
JoelWiebe Feb 5, 2025
242b676
Set Teacher Tasks as an expandable module in SCORE authoring
JoelWiebe Feb 5, 2025
cbbaea3
Created AI Agent model, AI Agent class, sub-class agents, ai-agent co…
JoelWiebe Feb 10, 2025
77d121b
Added roomcasting component, logic, and socket connections; modified …
JoelWiebe Feb 11, 2025
8ba7409
Included backend files in commit
JoelWiebe Feb 11, 2025
564e848
Included additional missing files
JoelWiebe Feb 11, 2025
5f4fdcd
Resolved conflicts with develop
JoelWiebe Feb 12, 2025
06d4fc8
Hide SCORE authoring from students and fixed CK Bucket, Workspace, an…
JoelWiebe Feb 13, 2025
a44b322
Fixed unnecessary try/catch
JoelWiebe Feb 13, 2025
6901fd7
Fixed unnecessary escape characters in string
JoelWiebe Feb 13, 2025
dd01485
Added Teacher Agent button
JoelWiebe Feb 13, 2025
6e05c64
Added server URL to join code pop-up
JoelWiebe Feb 13, 2025
c03b485
Merge branch 'develop' into 593-feature-create-score-runs
JoelWiebe Feb 13, 2025
13f0fb6
Merged with develop
JoelWiebe Feb 13, 2025
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
92 changes: 92 additions & 0 deletions backend/src/api/activities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

import express from 'express';
import dalActivity from '../repository/dalActivity';
import dalResource from '../repository/dalResource';
import { ActivityModel } from '../models/Activity';

const router = express.Router();

// Create a new activity
router.post('/', async (req, res) => {
try {
const activityData: ActivityModel = req.body;
const newActivity = await dalActivity.create(activityData);
res.status(201).json(newActivity); // 201 Created status
} catch (error) {
console.error("Error creating activity:", error);
res.status(500).json({ error: 'Failed to create activity.' });
}
});

// Get all activities for a project
router.get('/project/:projectID', async (req, res) => {
try {
const projectID = req.params.projectID;
const activities = await dalActivity.getByProject(projectID);
res.status(200).json(activities);
} catch (error) {
console.error("Error fetching activities:", error);
res.status(500).json({ error: 'Failed to fetch activities.' });
}
});

// Update an activity
router.put('/:activityID', async (req, res) => {
try {
const activityID = req.params.activityID;
const updatedData: Partial<ActivityModel> = req.body;

// If groupIDs are modified, update the resources
if (updatedData.groupIDs) {
const originalGroupIDs = (await dalActivity.getById(activityID))?.groupIDs;
const removedGroupIDs = originalGroupIDs?.filter(id => !updatedData.groupIDs?.includes(id)) || [];
const removePromises = removedGroupIDs.map(groupID =>
dalResource.removeGroupFromActivityResources(activityID, groupID)
);
await Promise.all(removePromises);
}

const updatedActivity = await dalActivity.update(activityID, updatedData);

if (updatedActivity) {
res.status(200).json(updatedActivity);
} else {
res.status(404).json({ error: 'Activity not found.' });
}
} catch (error) {
console.error("Error updating activity:", error);
res.status(500).json({ error: 'Failed to update activity.' });
}
});

// Delete an activity
router.delete('/:activityID', async (req, res) => {
try {
const activityID = req.params.activityID;
const deletedActivity = await dalActivity.remove(activityID);
if (deletedActivity) {
res.status(200).json(deletedActivity);
} else {
res.status(404).json({ error: 'Activity not found.' });
}
} catch (error) {
console.error("Error deleting activity:", error);
res.status(500).json({ error: 'Failed to delete activity.' });
}
});

router.post('/order', async (req, res) => {
try {
const activities: { activityID: string; order: number }[] = req.body.activities;
const updatePromises = activities.map(activity =>
dalActivity.update(activity.activityID, { order: activity.order })
);
await Promise.all(updatePromises);
res.status(200).json({ message: 'Activity order updated successfully.' });
} catch (error) {
console.error("Error updating activity order:", error);
res.status(500).json({ error: 'Failed to update activity order.' });
}
});

export default router;
97 changes: 97 additions & 0 deletions backend/src/api/aiAgents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// src/api/aiAgents.ts
import express from 'express';
import dalAiAgent from '../repository/dalAiAgent';
import AiAgent, { AiAgentModel } from '../models/AiAgent';

Check warning on line 4 in backend/src/api/aiAgents.ts

View workflow job for this annotation

GitHub Actions / Linting and Code Formating Check CI (backend)

'AiAgent' is defined but never used

const router = express.Router();

// Create a new AI agent
router.post('/', async (req, res) => {
try {
const agentData: AiAgentModel = req.body;
const newAgent = await dalAiAgent.create(agentData);
res.status(201).json(newAgent);
} catch (error) {
console.error("Error creating AI agent:", error);
res.status(500).json({ error: 'Failed to create AI agent.' });
}
});

// Get all AI agents for an activity
router.get('/activity/:activityID', async (req, res) => {
try {
const activityID = req.params.activityID;
const agents = await dalAiAgent.getByActivity(activityID);
res.status(200).json(agents);
} catch (error) {
console.error("Error fetching AI agents:", error);
res.status(500).json({ error: 'Failed to fetch AI agents.' });
}
});

// Update an AI agent
router.put('/:aiAgentID', async (req, res) => {
try {
const aiAgentID = req.params.aiAgentID;
const updatedData: Partial<AiAgentModel> = req.body;
const updatedAgent = await dalAiAgent.update(aiAgentID, updatedData);
if (updatedAgent) {
res.status(200).json(updatedAgent);
} else {
res.status(404).json({ error: 'AI Agent not found.' });
}
} catch (error) {
console.error("Error updating AI agent:", error);
res.status(500).json({ error: 'Failed to update AI agent.' });
}
});

// Delete an AI agent
router.delete('/:aiAgentID', async (req, res) => {
try {
const aiAgentID = req.params.aiAgentID;
const deletedAgent = await dalAiAgent.remove(aiAgentID);
if (deletedAgent) {
res.status(200).json(deletedAgent);
} else {
res.status(404).json({ error: 'AI Agent not found.' });
}
} catch (error) {
console.error("Error deleting AI agent:", error);
res.status(500).json({ error: 'Failed to delete AI agent.' });
}
});

// Get a single AI Agent by ID. Good for editing.
router.get('/:aiAgentID', async (req, res) => {
try {
const aiAgentID = req.params.aiAgentID;
const agent = await dalAiAgent.getById(aiAgentID);
if (agent) {
res.status(200).json(agent);
} else {
res.status(404).json({ error: 'AI Agent not found.' });
}
} catch (error) {
console.error("Error getting AI agent:", error);
res.status(500).json({ error: "Failed to get AI Agent."})
}
});

//Update order
router.post('/order', async (req, res) => {
try {
const activityID = req.body.activityID; //used for scoping

Check warning on line 84 in backend/src/api/aiAgents.ts

View workflow job for this annotation

GitHub Actions / Linting and Code Formating Check CI (backend)

'activityID' is assigned a value but never used
const agents: { aiAgentID: string; order: number }[] = req.body.agents;
const updatePromises = agents.map(agent =>
dalAiAgent.update(agent.aiAgentID, { order: agent.order })
);
await Promise.all(updatePromises);
res.status(200).json({ message: 'AI Agent order updated successfully.' });
} catch (error) {
console.error("Error updating AI Agent order:", error);
res.status(500).json({ error: 'Failed to update AI Agent order.' });
}
});

export default router;
12 changes: 12 additions & 0 deletions backend/src/api/groups.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router } from 'express';
import { GroupModel } from '../models/Group';
import dalGroup from '../repository/dalGroup';
import Group from '../models/Group';

const router = Router();

Expand All @@ -22,6 +23,17 @@ router.get('/user/:id', async (req, res) => {
res.status(200).json(groups);
});

router.post('/multiple', async (req, res) => {
try {
const groupIDs: string[] = req.body.groupIDs;
const groups = await Group.find({ groupID: { $in: groupIDs } }); // Fetch groups from the database
res.status(200).json(groups);
} catch (error) {
console.error("Error fetching multiple groups:", error);
res.status(500).json({ error: 'Failed to fetch groups.' });
}
});

router.get('/user/:userID/project/:projectID', async (req, res) => {
const { userID, projectID } = req.params;

Expand Down
35 changes: 30 additions & 5 deletions backend/src/api/projects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router } from 'express';
import { mongo } from 'mongoose';
import { BoardScope, ViewSettings, ViewType } from '../models/Board';

Check warning on line 3 in backend/src/api/projects.ts

View workflow job for this annotation

GitHub Actions / Linting and Code Formating Check CI (backend)

'ViewSettings' is defined but never used
import { ProjectModel } from '../models/Project';
import { UserModel } from '../models/User';
import dalBoard from '../repository/dalBoard';
Expand All @@ -24,28 +24,53 @@
return res.status(403).end('Unauthorized to create project.');
}

// Set isScoreRun to false if not provided
project.isScoreRun = project.isScoreRun || false;

let savedProject = await dalProject.create(project);
if (project.personalBoardSetting.enabled) {
const image = project.personalBoardSetting.bgImage;
const boardID = new mongo.ObjectId().toString();
const board = await dalBoard.create({
const personalBoardID = new mongo.ObjectId().toString();
const personalBoard = await dalBoard.create({
projectID: project.projectID,
boardID: boardID,
boardID: personalBoardID,
ownerID: user.userID,
name: `${user.username}'s Personal Board`,
scope: BoardScope.PROJECT_PERSONAL,
task: undefined,
permissions: getDefaultBoardPermissions(),
bgImage: image,
type: BoardType.BRAINSTORMING,
tags: getDefaultBoardTags(boardID),
tags: getDefaultBoardTags(personalBoardID),
initialZoom: 100,
upvoteLimit: 5,
visible: true,
defaultView: ViewType.CANVAS,
viewSettings: getAllViewsAllowed(),
});
savedProject = await savedProject.updateOne({ boards: [personalBoard.boardID] });

// --- Create default shared board ---
const communityBoardID = new mongo.ObjectId().toString();
const communityBoard = await dalBoard.create({
projectID: savedProject.projectID, // Use the saved project's ID
boardID: communityBoardID,
ownerID: user.userID,
name: 'Demo Community Board', // Or any default name you prefer
scope: BoardScope.PROJECT_SHARED,
task: undefined,
permissions: getDefaultBoardPermissions(),
bgImage: undefined,
type: BoardType.BRAINSTORMING, // Or another default type
tags: getDefaultBoardTags(communityBoardID),
initialZoom: 100,
upvoteLimit: 5,
visible: true,
defaultView: ViewType.CANVAS,
viewSettings: getAllViewsAllowed(),
});
savedProject = await savedProject.updateOne({ boards: [board.boardID] });
// Add the board to the project's boards array
savedProject = await savedProject.updateOne({ $push: { boards: communityBoard.boardID } });
}

res.status(200).json(savedProject);
Expand Down
101 changes: 101 additions & 0 deletions backend/src/api/resources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// backend/src/api/resources.ts

import express from 'express';
import dalResource from '../repository/dalResource';
import { ResourceModel } from '../models/Resource';

const router = express.Router();

router.post('/create', async (req, res) => { // Define the POST route
try {
const resourceData: ResourceModel = req.body;
const newResource = await dalResource.create(resourceData);
res.status(201).json(newResource); // 201 Created status
} catch (error) {
console.error("Error creating resource:", error);
res.status(500).json({ error: 'Failed to create resource.' });
}
});

router.delete('/delete/:resourceID', async (req, res) => { // Add the /delete segment to the path
try {
const resourceID = req.params.resourceID;
const deletedResource = await dalResource.remove(resourceID); // Assuming you have a remove() method in dalResource

if (deletedResource) {
res.status(200).json(deletedResource);
} else {
res.status(404).json({ error: 'Resource not found.' });
}
} catch (error) {
console.error("Error deleting resource:", error);
res.status(500).json({ error: 'Failed to delete resource.' });
}
});

router.get('/activity/:activityID', async (req, res) => {
try {
const activityID = req.params.activityID;
const resources = await dalResource.getByActivity(activityID);
res.status(200).json(resources);
} catch (error) {
console.error("Error fetching resources:", error);
res.status(500).json({ error: 'Failed to fetch resources.' });
}
});

router.post('/order', async (req, res) => {
try {
const activityID = req.body.activityID;

Check warning on line 49 in backend/src/api/resources.ts

View workflow job for this annotation

GitHub Actions / Linting and Code Formating Check CI (backend)

'activityID' is assigned a value but never used
const resources = req.body.resources;
const updatePromises = resources.map((resource: any) =>
dalResource.update(resource.resourceID, { order: resource.order })
);
await Promise.all(updatePromises);
res.status(200).json({ message: 'Resource order updated successfully.' });
} catch (error) {
console.error("Error updating resource order:", error);
res.status(500).json({ error: 'Failed to update resource order.' });
}
});

// Add a group to a resource
router.post('/:resourceID/groups/:groupID', async (req, res) => {
try {
const resourceID = req.params.resourceID;
const groupID = req.params.groupID;
const updatedResource = await dalResource.addGroupToResource(resourceID, groupID);

if (updatedResource) {
res.status(200).json(updatedResource);
} else {
res.status(404).json({ error: 'Resource not found.' });
}
} catch (error) {
console.error("Error adding group to resource:", error);
res.status(500).json({ error: 'Failed to add group to resource.' });
}
});

// Remove a group from a resource
router.delete('/:resourceID/groups/:groupID', async (req, res) => {
try {
const resourceID = req.params.resourceID;
const groupID = req.params.groupID;
const updatedResource = await dalResource.removeGroupFromResource(resourceID, groupID);

if (updatedResource) {
res.status(200).json(updatedResource);
} else {
res.status(404).json({ error: 'Resource not found.' });
}
} catch (error) {
console.error("Error removing group from resource:", error);
res.status(500).json({ error: 'Failed to remove group from resource.' });
}
});


// ... add other routes for creating, updating, deleting, reordering resources ...

export default router;
Loading
Loading