Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9bffc39
Add currentView field to tracing
markiianbabiak Jan 5, 2025
2c7492e
Add tracing of post creation in a workflow
markiianbabiak Jan 5, 2025
9d23c38
Tracing Bug Fix
markiianbabiak Jan 5, 2025
7e24beb
Tracing Bug Fix
markiianbabiak Jan 5, 2025
da08ee2
Tracing Bug Fix
markiianbabiak Jan 5, 2025
7a37240
CK Workspace - Socket Events
markiianbabiak Feb 5, 2025
8e777d2
Board Permission Updates
markiianbabiak Feb 5, 2025
b1e97dd
Anonymization fix
markiianbabiak Feb 7, 2025
79c50b3
Further Anonymization and Socket Events Fixes
markiianbabiak Feb 8, 2025
46ede0e
Added group events
markiianbabiak Feb 9, 2025
c50b36c
Task Completion Event added
markiianbabiak Feb 9, 2025
abdf5e6
Group Task Complete Fix
markiianbabiak Feb 9, 2025
297f8b0
Tag addition bug fix
markiianbabiak Feb 9, 2025
90d75ae
Bug fix - peer review
markiianbabiak Feb 9, 2025
0eb7b58
Various bug fixes
markiianbabiak Feb 9, 2025
81e2a2e
Redis compatibility fix
markiianbabiak Mar 10, 2025
30782e7
Merged with develop
JoelWiebe Mar 10, 2025
eba691a
Resolved additional remote conflict
JoelWiebe Mar 10, 2025
1c9540c
Fixed post duplication and task duplication in workspace from merge r…
JoelWiebe Mar 10, 2025
b1b0e11
Added assignment type, prompt, and groups info to Manage Workflows
JoelWiebe Mar 10, 2025
c750036
Fixed scss encapsulation issue where ck-monitor was affecting ck-work…
JoelWiebe Mar 10, 2025
e29c445
Hide group names in workspace for individually assigned tasks
JoelWiebe Mar 10, 2025
bd199aa
Fixed bug where current individual members were not used for individu…
JoelWiebe Mar 10, 2025
f33ad86
Double post creation fix
markiianbabiak Mar 11, 2025
7c26bb4
Resolved merge conflicts
JoelWiebe Mar 11, 2025
2fcf12d
Merge pull request #681 from encorelab/577-bug-trace-logs-only-works-…
JoelWiebe Mar 11, 2025
74ca028
Canvas not working fix
markiianbabiak Mar 11, 2025
b370e48
ViewType value fixed for tracing
markiianbabiak Mar 12, 2025
12538de
Eliminating double socket connection
markiianbabiak Mar 12, 2025
60ed62b
Removing the rest of currentView board implementation
markiianbabiak Mar 12, 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
19 changes: 15 additions & 4 deletions backend/src/agents/workflow.agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
import dalBucket from '../repository/dalBucket';
import dalPost from '../repository/dalPost';
import dalWorkflow from '../repository/dalWorkflow';
import dalGroupTask, { GroupTaskExpanded } from '../repository/dalGroupTask';

Check warning on line 22 in backend/src/agents/workflow.agent.ts

View workflow job for this annotation

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

'GroupTaskExpanded' is defined but never used
import dalVote from '../repository/dalVote';
import dalGroup from '../repository/dalGroup';
import { convertPostsFromID } from '../utils/converter';
import {
isDistribution,
Expand All @@ -31,8 +32,8 @@
removePostFromSource,
} from '../utils/workflow.helpers';
import { mongo } from 'mongoose';
import Socket from '../socket/socket';

Check warning on line 35 in backend/src/agents/workflow.agent.ts

View workflow job for this annotation

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

'Socket' is defined but never used
import { SocketEvent } from '../constants';

Check warning on line 36 in backend/src/agents/workflow.agent.ts

View workflow job for this annotation

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

'SocketEvent' is defined but never used

class WorkflowManager {
private static _instance: WorkflowManager;
Expand Down Expand Up @@ -114,7 +115,7 @@
const tagAction = taskWorkflow.requiredActions.find(
(a) => a.type == TaskActionType.TAG
);
const createPostAction = taskWorkflow.requiredActions.find(

Check warning on line 118 in backend/src/agents/workflow.agent.ts

View workflow job for this annotation

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

'createPostAction' is assigned a value but never used
(a) => a.type == TaskActionType.CREATE_POST
);

Expand Down Expand Up @@ -167,12 +168,22 @@
} else if (assignmentType === AssignmentType.INDIVIDUAL) {
const assignedIndividual = taskWorkflow.assignedIndividual;
if (!assignedIndividual) return;

// Fetch the group to get current members
const group = await dalGroup.getById(assignedIndividual.groupID);
if (!group) {
console.error(`Group not found for ID: ${assignedIndividual.groupID}`);
return; // Or throw an error, depending on your error handling
}
const members = group.members; // Use the *current* members from the group

const split: string[][] = await distribute(
shuffle(sourcePosts),
sourcePosts.length / assignedIndividual.members.length
sourcePosts.length / members.length
);
for (let i = 0; i < assignedIndividual?.members.length; i++) {
const assignedMember = assignedIndividual.members[i];

for (let i = 0; i < members.length; i++) {
const assignedMember = members[i];
const posts =
taskWorkflow?.type === TaskWorkflowType.GENERATION
? []
Expand Down Expand Up @@ -323,4 +334,4 @@
}
}

export default WorkflowManager;
export default WorkflowManager;
53 changes: 36 additions & 17 deletions backend/src/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

const exists = await dalUser.findByEmail(body.email);
if (exists) {
return res.status(400).send({message: 'Email already in use.'});
return res.status(400).send({ message: 'Email already in use.' });
}

const savedUser = await dalUser.create(body);
Expand Down Expand Up @@ -107,27 +107,21 @@

// 5. Send an email to the user with a link containing the token
const resetLink = `${
process.env.CKBOARD_SERVER_ADDRESS!.startsWith('http')
? ''
: 'https://'
process.env.CKBOARD_SERVER_ADDRESS!.startsWith('http') ? '' : 'https://'

Check warning on line 110 in backend/src/api/auth.ts

View workflow job for this annotation

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

Forbidden non-null assertion
}${process.env.CKBOARD_SERVER_ADDRESS!}/reset-password?token=${resetToken}`;

Check warning on line 111 in backend/src/api/auth.ts

View workflow job for this annotation

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

Forbidden non-null assertion

try {
await generateEmail(email, 'Password Reset Request', resetLink);
return res
.status(200)
.send({
success: true,
message:
'If an account with that email exists, a password reset link has been sent.',
});
return res.status(200).send({
success: true,
message:
'If an account with that email exists, a password reset link has been sent.',
});
} catch (err) {
return res
.status(500)
.send({
success: false,
message: 'There was an error sending the password reset email.',
});
return res.status(500).send({
success: false,
message: 'There was an error sending the password reset email.',
});
}
} catch (error) {
console.error('Error in /forgot-password route:', error);
Expand Down Expand Up @@ -247,4 +241,29 @@
res.status(200).json(users);
});

router.patch('/:boardID/currentView', async (req, res) => {
const { boardID } = req.params;
const { viewType } = req.body; // Expect viewType in the request body

if (!viewType) {
return res.status(400).json({ error: 'viewType is required' });
}

try {
// Update the board with the new currentView
const updatedBoard = await dalUser.update(boardID, {
currentView: viewType,
});

if (!updatedBoard) {
return res.status(404).json({ error: 'Board not found' });
}

res.status(200).json(updatedBoard);
} catch (error) {
console.error('Error updating currentView:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

export default router;
33 changes: 25 additions & 8 deletions backend/src/api/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ router.get('/task/boards/:id', async (req, res) => {
router.delete('/task/:id', async (req, res) => {
const id = req.params.id;

await dalWorkflow.remove(WorkflowType.TASK, id);
const deletedWorkflow = await dalWorkflow.remove(WorkflowType.TASK, id);

res.status(200).end();
res.status(200).json(deletedWorkflow);
});

router.get('/task/group/:id', async (req, res) => {
Expand Down Expand Up @@ -375,23 +375,40 @@ router.post('/task/groupTask/:groupTaskID/submit', async (req, res) => {
// if post from bucket => delete from bucket
if (workflow.source.type === ContainerType.WORKFLOW) {
if (destination.type === ContainerType.BOARD) {
await dalPost.update(post, { type: PostType.BOARD });
const updatedPost = await dalPost.update(post, {
type: PostType.BOARD,
});
Socket.Instance.emit(
SocketEvent.POST_CREATE,
updatedPost,
workflow.boardID
);
} else {
await dalPost.update(post, { type: PostType.BUCKET });
Socket.Instance.emit(
SocketEvent.WORKFLOW_POST_SUBMIT,
post,
workflow.boardID
);
}
} else {
if (workflow.source.type === ContainerType.BOARD) {
await dalPost.update(post, { type: PostType.LIST });
Socket.Instance.emit(
SocketEvent.WORKFLOW_POST_SUBMIT,
post,
workflow.boardID
);
} else if (workflow.source.type === ContainerType.BUCKET) {
await dalBucket.removePost(workflow.source.id, [post]);
Socket.Instance.emit(
SocketEvent.WORKFLOW_POST_SUBMIT,
post,
workflow.boardID
);
}
}

Socket.Instance.emit(
SocketEvent.WORKFLOW_POST_SUBMIT,
post,
workflow.boardID
);
return res.status(200).json(updatedGroupTask);
} catch (e) {
return res.status(500).end('Unable to submit post!');
Expand Down
6 changes: 6 additions & 0 deletions backend/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export enum SocketEvent {
WORKFLOW_RUN_TASK = 'WORKFLOW_RUN_TASK',
WORKFLOW_PROGRESS_UPDATE = 'WORKFLOW_PROGRESS_UPDATE',
WORKFLOW_POST_SUBMIT = 'WORKFLOW_POST_SUBMIT',
WORKFLOW_DELETE_TASK = 'WORKFLOW_DELETE_TASK',
WORKFLOW_POST_ADD = 'WORKFLOW_POST_ADD',
WORKFLOW_TASK_COMPLETE = 'WORKFLOW_TASK_COMPLETE',

GROUP_CHANGE = 'GROUP_CHANGE',
GROUP_DELETE = 'GROUP_DELETE',

NOTIFICATION_CREATE = 'NOTIFICATION_CREATE',
BOARD_NOTIFICATION_CREATE = 'BOARD_NOTIFICATION_CREATE',
Expand Down
5 changes: 4 additions & 1 deletion backend/src/models/Trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Severity,
} from '@typegoose/typegoose';

import { BoardType } from './Board';
import { BoardType, ViewType } from './Board';

@modelOptions({
schemaOptions: { collection: 'trace', timestamps: true },
Expand All @@ -30,6 +30,9 @@ export class TraceModel {
@prop({ required: true })
boardContext!: string;

@prop({ required: false })
viewType?: ViewType | undefined;

@prop({ required: true })
agentUserID!: string;

Expand Down
4 changes: 4 additions & 0 deletions backend/src/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { prop, getModelForClass, modelOptions } from '@typegoose/typegoose';
import { ViewType } from './Board';

export enum Role {
TEACHER = 'TEACHER',
Expand Down Expand Up @@ -27,6 +28,9 @@ export class UserModel {

@prop()
public resetPasswordExpires?: Date;

@prop({ required: false })
public currentView?: ViewType;
}

export default getModelForClass(UserModel);
1 change: 1 addition & 0 deletions backend/src/models/Workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum WorkflowType {
export enum TaskWorkflowType {
PEER_REVIEW = 'PEER_REVIEW',
GENERATION = 'GENERATION',
DISTRIBUTION = 'DISTRIBUTION'
}

export enum DistributionWorkflowType {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/socket/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import postEvents from './events/post.events';
import workflowEvents from './events/workflow.events';
import notificationEvents from './events/notification.events';
import bucketEvents from './events/bucket.events';
import groupEvents from './events/group.events';
import aiEvents from './events/ai.events';
import roomcastEvents from './events/roomcast.events';

Expand All @@ -13,6 +14,7 @@ const events = [
...notificationEvents,
...bucketEvents,
...aiEvents,
...groupEvents,
...roomcastEvents,
];

Expand Down
44 changes: 44 additions & 0 deletions backend/src/socket/events/group.events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { SocketEvent } from '../../constants';
import { GroupModel } from '../../models/Group';
import { SocketPayload } from '../types/event.types';
import { Server, Socket } from 'socket.io';

class GroupChange {
static type: SocketEvent = SocketEvent.GROUP_CHANGE;

static async handleEvent(
input: SocketPayload<GroupModel>
): Promise<GroupModel | null> {
return input.eventData;
}

static async handleResult(
io: Server,
socket: Socket,
result: GroupModel | null
) {
socket.to(socket.data.room).emit(this.type, result);
}
}

class GroupDelete {
static type: SocketEvent = SocketEvent.GROUP_DELETE;

static async handleEvent(
input: SocketPayload<GroupModel>
): Promise<GroupModel | null> {
return input.eventData;
}

static async handleResult(
io: Server,
socket: Socket,
result: GroupModel | null
) {
socket.to(socket.data.room).emit(this.type, result);
}
}

const groupEvents = [GroupChange, GroupDelete];

export default groupEvents;
74 changes: 74 additions & 0 deletions backend/src/socket/events/workflow.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
import { SocketPayload } from '../types/event.types';
import { GroupTaskModel } from '../../models/GroupTask';
import { GroupModel } from '../../models/Group';
import { PostModel } from '../../models/Post';
import workflowTrace from '../trace/workflow.trace';

class WorkflowRunDistribution {
static type: SocketEvent = SocketEvent.WORKFLOW_RUN_DISTRIBUTION;
Expand Down Expand Up @@ -62,10 +64,82 @@ class WorkflowUpdate {
}
}

class WorkflowPostSubmit {
static type: SocketEvent = SocketEvent.WORKFLOW_POST_SUBMIT;

static async handleEvent(
input: SocketPayload<PostModel>
): Promise<PostModel> {
if (input.trace.allowTracing) await workflowTrace.addPost(input, this.type);
return input.eventData;
}

static async handleResult(io: Server, socket: Socket, result: PostModel) {
socket.to(socket.data.room).emit(this.type, result);
}
}
class WorkflowDeleteTask {
static type: SocketEvent = SocketEvent.WORKFLOW_DELETE_TASK;

static async handleEvent(
input: SocketPayload<GroupTaskModel>
): Promise<GroupTaskModel | null> {
return input.eventData;
}

static async handleResult(
io: Server,
socket: Socket,
result: GroupTaskModel | null
) {
socket.to(socket.data.room).emit(this.type, result);
}
}

class WorkflowPostAdd {
static type: SocketEvent = SocketEvent.WORKFLOW_POST_ADD;

static async handleEvent(
input: SocketPayload<GroupModel>
): Promise<GroupModel | null> {
return input.eventData;
}

static async handleResult(
io: Server,
socket: Socket,
result: GroupModel | null
) {
socket.to(socket.data.room).emit(this.type, result);
}
}

class WorkflowTaskComplete {
static type: SocketEvent = SocketEvent.WORKFLOW_TASK_COMPLETE;

static async handleEvent(
input: SocketPayload<GroupTaskModel>
): Promise<GroupTaskModel | null> {
return input.eventData;
}

static async handleResult(
io: Server,
socket: Socket,
result: GroupTaskModel | null
) {
socket.to(socket.data.room).emit(this.type, result);
}
}

const workflowEvents = [
WorkflowRunDistribution,
WorkflowRunTask,
WorkflowUpdate,
WorkflowPostSubmit,
WorkflowDeleteTask,
WorkflowPostAdd,
WorkflowTaskComplete,
];

export default workflowEvents;
1 change: 1 addition & 0 deletions backend/src/socket/trace/base.trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const createTrace = async (
boardName: board.name,
boardType: board.type,
boardContext: boardScopeAsString(board.scope),
viewType: user.currentView,
agentUserID: user.userID,
agentUserName: user.username,
clientTimestamp: new Date(traceContext.clientTimestamp),
Expand Down
Loading
Loading