diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..cca63b3 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +AZURE_COSMOSDB_DATABASE= +AZURE_COSMOSDB_ENDPOINT= +AZURE_COSMOSDB_KEY= diff --git a/.gitignore b/.gitignore index d545bd7..ba3b7b5 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,12 @@ next-env.d.ts **/public/sw.js **/public/worker-*.js **/public/sw.js.map + +bundles +.env + +# service worker +sw.js +sw.js.map +workbox-*.js +workbox-*.js.map diff --git a/app/api/graphql/route.ts b/app/api/graphql/route.ts index 38bc5b6..411bd78 100644 --- a/app/api/graphql/route.ts +++ b/app/api/graphql/route.ts @@ -1,11 +1,12 @@ -// import { CosmosContainer } from "@azure-fundamentals/src/graphql/cosmos-client"; -// import { QuestionsDataSource, LocalQuestionsDataSource } from "@azure-fundamentals/src/graphql/questionsDataSource"; +import { + CombinedQuestionsDataSource, + RepoQuestionsDataSource, +} from "@azure-fundamentals/lib/graphql/questionsDataSource"; import { ApolloServer, BaseContext } from "@apollo/server"; import { startServerAndCreateNextHandler } from "@as-integrations/next"; import typeDefs from "@azure-fundamentals/lib/graphql/schemas"; import resolvers from "@azure-fundamentals/lib/graphql/resolvers"; -//import { RepoQuestionsDataSource } from "@azure-fundamentals/lib/graphql/questionsDataSource"; -//import { FetchQuestions } from "@azure-fundamentals/lib/graphql/repoQuestions"; +import { fetchQuestions } from "@azure-fundamentals/lib/graphql/repoQuestions"; interface ContextValue { dataSources: { @@ -19,22 +20,57 @@ const server = new ApolloServer({ introspection: process.env.NODE_ENV !== "production", }); -//const questions = await FetchQuestions(); - -const handler = startServerAndCreateNextHandler( - server, - /*{ +const handler = startServerAndCreateNextHandler(server, { context: async () => { - return { - dataSources: { - // questionsDB: process.env.AZURE_COSMOSDB_ENDPOINT - // ? QuestionsDataSource(CosmosContainer()) - // : LocalQuestionsDataSource(questions), - questionsDB: RepoQuestionsDataSource(questions), - }, - }; + if (process.env.AZURE_COSMOSDB_ENDPOINT) { + return { + dataSources: { + questionsDB: CombinedQuestionsDataSource(), + }, + }; + } else { + // Fallback to GitHub-only data source + return { + dataSources: { + questionsDB: { + getQuestion: async (id: string, link: string) => { + const questions = await fetchQuestions(link); + return questions?.find((q: any) => q.id === id); + }, + getQuestions: async (link: string) => { + const questions = await fetchQuestions(link); + return { count: questions?.length || 0 }; + }, + getRandomQuestions: async (range: number, link: string) => { + const questions = await fetchQuestions(link); + const shuffled = questions?.sort(() => 0.5 - Math.random()); + return shuffled?.slice(0, range) || []; + }, + }, + }, + }; + } }, -}*/ -); +}); + +// Wrap the handler to handle errors +const wrappedHandler = async (req: Request) => { + try { + return await handler(req); + } catch (error) { + console.error("GraphQL Error:", error); + return new Response( + JSON.stringify({ + errors: [{ message: "Internal server error" }], + }), + { + status: 500, + headers: { + "Content-Type": "application/json", + }, + }, + ); + } +}; -export { handler as GET, handler as POST }; +export { wrappedHandler as GET, wrappedHandler as POST }; diff --git a/app/layout.tsx b/app/layout.tsx index 236204a..93a119a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,11 +1,17 @@ import { type ReactNode } from "react"; -import { type Metadata } from "next"; +import { type Metadata, type Viewport } from "next"; import TopNav from "@azure-fundamentals/components/TopNav"; import Footer from "@azure-fundamentals/components/Footer"; import ApolloProvider from "@azure-fundamentals/components/ApolloProvider"; import Cookie from "@azure-fundamentals/components/Cookie"; import "styles/globals.css"; +export const viewport: Viewport = { + themeColor: "#3f51b5", + width: "device-width", + initialScale: 1, +}; + export const metadata: Metadata = { appleWebApp: { capable: true, @@ -71,7 +77,6 @@ export const metadata: Metadata = { follow: true, index: true, }, - themeColor: "#3f51b5", title: { default: "🧪 Practice Exams Platform | Ditectrev", template: "🧪 Practice Exams Platform | Ditectrev", @@ -90,10 +95,6 @@ export const metadata: Metadata = { site: "@ditectrev", title: "🧪 Practice Exams Platform | Ditectrev", }, - viewport: { - initialScale: 1, - width: "device-width", - }, }; type RootLayoutProps = { diff --git a/lib/graphql/cosmos-client.tsx b/lib/graphql/cosmos-client.tsx index 555468e..31a7cb8 100644 --- a/lib/graphql/cosmos-client.tsx +++ b/lib/graphql/cosmos-client.tsx @@ -1,14 +1,36 @@ import { CosmosClient } from "@azure/cosmos"; -export const CosmosContainer = () => { +export const getDatabase = () => { const client = new CosmosClient({ endpoint: process.env.AZURE_COSMOSDB_ENDPOINT!, key: process.env.AZURE_COSMOSDB_KEY!, }); - const container = client - .database(process.env.AZURE_COSMOSDB_DATABASE!) - .container(process.env.AZURE_COSMOSDB_CONTAINER!); + return client.database(process.env.AZURE_COSMOSDB_DATABASE!); +}; + +export const getQuestionsContainer = async () => { + const database = getDatabase(); - return container; + // Try to create container if it doesn't exist + try { + const { container } = await database.containers.createIfNotExists({ + id: "questions", + partitionKey: { + paths: ["/examId"], + }, + }); + return container; + } catch (error: any) { + // If container creation fails, try to get the existing container + if (error.code === 409) { + console.log( + `Container questions already exists, using existing container`, + ); + return database.container("questions"); + } else { + console.error("Error creating container:", error); + throw error; + } + } }; diff --git a/lib/graphql/questionsDataSource.tsx b/lib/graphql/questionsDataSource.tsx index 5788d2b..74a2ce6 100644 --- a/lib/graphql/questionsDataSource.tsx +++ b/lib/graphql/questionsDataSource.tsx @@ -1,4 +1,6 @@ -/*import { Container } from "@azure/cosmos"; +import { Container } from "@azure/cosmos"; +import { fetchQuestions } from "./repoQuestions"; +import { getQuestionsContainer } from "./cosmos-client"; export const QuestionsDataSource = (container: Container) => { return { @@ -38,7 +40,7 @@ export const QuestionsDataSource = (container: Container) => { }, }; }; -*/ + export const RepoQuestionsDataSource = (container: any) => { return { async getQuestion(id: string) { @@ -65,3 +67,150 @@ export const RepoQuestionsDataSource = (container: any) => { }, }; }; + +// Helper function to extract exam ID from URL +const extractExamId = (link: string): string => { + const segments = link.split("/"); + return segments[segments.length - 3].replace(/-/g, "_").toLowerCase(); +}; + +export const CombinedQuestionsDataSource = () => { + return { + async getQuestion(id: string, link: string) { + try { + const examId = extractExamId(link); + const questionsContainer = await getQuestionsContainer(); + + // Try Cosmos DB first (most efficient) + const querySpec = { + query: "SELECT * FROM c WHERE c.id = @id AND c.examId = @examId", + parameters: [ + { name: "@id", value: id }, + { name: "@examId", value: examId }, + ], + }; + const { resources: items } = await questionsContainer.items + .query(querySpec) + .fetchAll(); + + if (items.length > 0) { + return items[0]; + } + + // Fallback to GitHub if not found in database + const questions = await fetchQuestions(link); + if (questions) { + const question = questions.find((q: any) => q.id === id); + if (question) { + // Add examId to the question document and upload to database + const questionWithExamId = { + ...question, + examId: examId, + }; + + try { + await questionsContainer.items.upsert(questionWithExamId); + } catch (err) { + console.warn("Failed to upload question to Cosmos DB:", err); + } + return question; + } + } + + return null; + } catch (err) { + throw new Error("Error fetching question: " + err); + } + }, + + async getQuestions(link: string) { + try { + const examId = extractExamId(link); + const questionsContainer = await getQuestionsContainer(); + + // Try Cosmos DB first + const querySpec = { + query: "SELECT VALUE COUNT(c.id) FROM c WHERE c.examId = @examId", + parameters: [{ name: "@examId", value: examId }], + }; + const { resources: items } = await questionsContainer.items + .query(querySpec) + .fetchAll(); + + if (items[0] > 0) { + return { count: items[0] }; + } + + // Fallback to GitHub if no questions found in database + const questions = await fetchQuestions(link); + if (questions) { + // Upload all questions to database (only if they don't exist) + try { + for (const question of questions) { + const questionWithExamId = { + ...question, + examId: examId, + }; + await questionsContainer.items.upsert(questionWithExamId); + } + } catch (err) { + console.warn("Failed to upload questions to Cosmos DB:", err); + } + return { count: questions.length }; + } + + return { count: 0 }; + } catch (err) { + throw new Error("Error fetching questions: " + err); + } + }, + + async getRandomQuestions(range: number, link: string) { + try { + const examId = extractExamId(link); + const questionsContainer = await getQuestionsContainer(); + + // Try Cosmos DB first + const querySpec = { + query: "SELECT * FROM c WHERE c.examId = @examId", + parameters: [{ name: "@examId", value: examId }], + }; + const { resources: items } = await questionsContainer.items + .query(querySpec) + .fetchAll(); + + if (items.length > 0) { + // Questions exist in database, return random selection + const shuffled = [...items].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, range); + } + + // Fallback to GitHub if no questions found in database + const questions = await fetchQuestions(link); + if (questions) { + const shuffled = [...questions].sort(() => 0.5 - Math.random()); + const selected = shuffled.slice(0, range); + + // Upload selected questions to database (only if they don't exist) + try { + for (const question of selected) { + const questionWithExamId = { + ...question, + examId: examId, + }; + await questionsContainer.items.upsert(questionWithExamId); + } + } catch (err) { + console.warn("Failed to upload questions to Cosmos DB:", err); + } + + return selected; + } + + return []; + } catch (err) { + throw new Error("Error fetching random questions: " + err); + } + }, + }; +}; diff --git a/lib/graphql/resolvers.tsx b/lib/graphql/resolvers.tsx index 34b15b2..ac9a6fd 100644 --- a/lib/graphql/resolvers.tsx +++ b/lib/graphql/resolvers.tsx @@ -7,25 +7,21 @@ const resolvers = { { link }: { link: string }, { dataSources }: { dataSources: any }, ) => { - const response = await fetchQuestions(link); - return { count: response?.length }; + return dataSources.questionsDB.getQuestions(link); }, questionById: async ( _: unknown, { id, link }: { id: string; link: string }, { dataSources }: { dataSources: any }, ) => { - const response = await fetchQuestions(link); - return response?.filter((el: any) => el.id === id)[0]; + return dataSources.questionsDB.getQuestion(id, link); }, randomQuestions: async ( _: unknown, { range, link }: { range: number; link: string }, { dataSources }: { dataSources: any }, ) => { - const response = await fetchQuestions(link); - const shuffled = response?.sort(() => 0.5 - Math.random()); - return shuffled?.slice(0, range); + return dataSources.questionsDB.getRandomQuestions(range, link); }, }, }; diff --git a/lib/graphql/schemas.tsx b/lib/graphql/schemas.tsx index 6428fc8..e2828a5 100644 --- a/lib/graphql/schemas.tsx +++ b/lib/graphql/schemas.tsx @@ -14,6 +14,7 @@ const typeDefs = gql` question: String options: [Option] images: [Images] + examId: String } type Questions { count: Int diff --git a/package-lock.json b/package-lock.json index d30589d..0dc5f71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "practice-exams-platform", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "practice-exams-platform", - "version": "1.2.0", + "version": "1.3.0", "dependencies": { "@apollo/client": "^3.7.9", "@apollo/server": "^4.11.0", @@ -494,7 +494,6 @@ "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -821,7 +820,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -831,7 +829,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -862,7 +859,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.0", @@ -876,7 +872,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.0" @@ -2151,7 +2146,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -2191,7 +2185,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", diff --git a/package.json b/package.json index 94c859a..319a9c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "practice-exams-platform", - "version": "1.2.0", + "version": "1.3.0", "private": true, "engines": { "node": "20.x" @@ -60,6 +60,7 @@ "postcss": "^8.4.21", "prettier": "^3.0.3", "tailwindcss": "^3.2.7", - "ts-jest": "^29.1.1" + "ts-jest": "^29.1.1", + "tsx": "^4.7.0" } } diff --git a/public/sw.js.map b/public/sw.js.map index 3cb498b..4064675 100644 --- a/public/sw.js.map +++ b/public/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../../private/var/folders/46/z6lcqr1s05j43ppcygmcd6n00000gn/T/70173c6dd7fe01f4597ff5e792adc7bf/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../private/var/folders/46/z6lcqr1s05j43ppcygmcd6n00000gn/T/d6822973d61f3cff46f33c53d5e6100b/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/danieldanielecki/Downloads/Practice-Exams-Platform/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file