diff --git a/apps/backend/src/bootstrap/loaders/express.ts b/apps/backend/src/bootstrap/loaders/express.ts index 32b43ba2e..04dbaf99a 100644 --- a/apps/backend/src/bootstrap/loaders/express.ts +++ b/apps/backend/src/bootstrap/loaders/express.ts @@ -68,6 +68,18 @@ export default async ( isAuthenticated: req.isAuthenticated(), logout: (callback: (err: any) => void) => req.logout(callback), }, + // user: req.user + // ? { + // ...req.user, + // isAuthenticated: req.isAuthenticated(), + // logout: (callback: (err: any) => void) => req.logout(callback), + // } + // : { + // id: "testUserId123", + // role: "admin", + // isAuthenticated: true, // 让 auth 解析器认为用户已登录 + // logout: (callback: (err: any) => void) => callback(null), + // }, }), }) ); diff --git a/apps/backend/src/modules/discussion/discussionController.ts b/apps/backend/src/modules/discussion/discussionController.ts new file mode 100644 index 000000000..818dcc2c8 --- /dev/null +++ b/apps/backend/src/modules/discussion/discussionController.ts @@ -0,0 +1,39 @@ +import {DiscussionModel} from "@repo/common" +import {formatPost} from "./formater" + +export const getDiscussions = async (courseNumber: string) => { + const discussion = await DiscussionModel.findOne({courseNumber: courseNumber}); + if (!discussion) { + return { courseNumber, posts: [] }; + } + const discussionObject = discussion.toObject(); + return { + courseNumber: discussionObject.courseNumber, + posts: discussionObject.posts.map(formatPost)}; +}; + +export const addPost = async( + courseNumber: string, + PostContent: string, + context: any +) => { + const userId = context.user.id; + const updatedPost = await DiscussionModel.findOneAndUpdate( + { courseNumber }, + { + $push: { + posts: { + userId, + PostContent, + } + } + }, + { new: true, upsert: true } + ); + if (!updatedPost) { + throw new Error("Failed to update or create the discussion post."); + } + const updatedPostObj = updatedPost.toObject(); + const lastPost = updatedPostObj.posts[updatedPostObj.posts.length - 1]; + return formatPost(lastPost); +}; \ No newline at end of file diff --git a/apps/backend/src/modules/discussion/formater.ts b/apps/backend/src/modules/discussion/formater.ts new file mode 100644 index 000000000..d0545b66e --- /dev/null +++ b/apps/backend/src/modules/discussion/formater.ts @@ -0,0 +1,5 @@ +export const formatPost = (post:any) => ({ + userId: post.userId.toString(), + PostTime: post.PostTime.toISOString(), + PostContent: post.PostContent, +}); diff --git a/apps/backend/src/modules/discussion/index.ts b/apps/backend/src/modules/discussion/index.ts new file mode 100644 index 000000000..921091e1b --- /dev/null +++ b/apps/backend/src/modules/discussion/index.ts @@ -0,0 +1,8 @@ +import resolver from "./resolver"; +import typeDef from "./typedefs/discussion"; + +export default { + resolver, + typeDef, +}; + \ No newline at end of file diff --git a/apps/backend/src/modules/discussion/resolver.ts b/apps/backend/src/modules/discussion/resolver.ts new file mode 100644 index 000000000..2d57fe330 --- /dev/null +++ b/apps/backend/src/modules/discussion/resolver.ts @@ -0,0 +1,21 @@ +import { getDiscussions, addPost } from "./discussionController"; +import {DiscussionModule} from "./generated-types/module-types" + +const resolvers: DiscussionModule.Resolvers = { + Query: { + discussions: async (_, {courseNumber}) => { + return await getDiscussions(courseNumber); + } + }, + Mutation: { + post: async ( + _, + { courseNumber, PostContent}, + context) => { + return await addPost(courseNumber, PostContent, context); + } + } +}; + +export default resolvers; + diff --git a/apps/backend/src/modules/discussion/typedefs/discussion.ts b/apps/backend/src/modules/discussion/typedefs/discussion.ts new file mode 100644 index 000000000..e9bbc6445 --- /dev/null +++ b/apps/backend/src/modules/discussion/typedefs/discussion.ts @@ -0,0 +1,25 @@ +import { gql } from "graphql-tag"; + +export default gql` + scalar courseNumber + + type Query { + discussions(courseNumber:courseNumber!): Discussion + } + + type Post { + userId: String! + PostTime: String! + PostContent: String! + } + + type Discussion { + courseNumber: courseNumber! + posts: [Post!] + } + + type Mutation { + post(courseNumber: courseNumber!, PostContent: String!): Post! @auth + } + +`; \ No newline at end of file diff --git a/apps/backend/src/modules/index.ts b/apps/backend/src/modules/index.ts index 406f69a7d..dcbc02f30 100644 --- a/apps/backend/src/modules/index.ts +++ b/apps/backend/src/modules/index.ts @@ -9,6 +9,7 @@ import GradeDistribution from "./grade-distribution"; import Schedule from "./schedule"; import Term from "./term"; import User from "./user"; +import Discussion from "./discussion"; const modules = [ User, @@ -20,6 +21,7 @@ const modules = [ Course, Class, Enrollment, + Discussion ]; export const resolvers = merge(modules.map((module) => module.resolver)); diff --git a/packages/common/src/models/discussion.ts b/packages/common/src/models/discussion.ts new file mode 100644 index 000000000..e49a31bb1 --- /dev/null +++ b/packages/common/src/models/discussion.ts @@ -0,0 +1,30 @@ +import mongoose, { Schema, Document, Model } from "mongoose"; + +interface Post { + userId: string; + PostContent: string; + PostTime: Date; +} +export interface DiscussionInfo extends Document { + courseNumber: string; + posts: Post[]; +} + +const postSchema: Schema = new Schema({ + _id: { type: mongoose.Schema.Types.ObjectId, auto: true }, + userId: { type: String, required: true }, //connect user? + PostTime: { type: Date, default: Date.now }, + PostContent: { type: String, required: true }, +}); + +const discussionSchema: Schema = new Schema({ + courseNumber: { type: String, required: true }, + posts: { type: [postSchema], default: []}, +}); + +export const DiscussionModel: Model = mongoose.model( + "Discussion", + discussionSchema +); + + diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts index 093715fb0..30cbe02fc 100644 --- a/packages/common/src/models/index.ts +++ b/packages/common/src/models/index.ts @@ -6,3 +6,4 @@ export * from "./course"; export * from "./section"; export * from "./grade-distribution"; export * from "./enrollment-history"; +export * from "./discussion"; \ No newline at end of file