From 85f8231102a742045bbd2345d759d7037195d130 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Fri, 22 Sep 2023 01:57:35 -0400 Subject: [PATCH 01/12] updated error import --- apps/web/src/components/dashboard/error.tsx | 2 +- apps/web/src/layout/Layout.D_Calendar.tsx | 1 + apps/web/src/layout/Layout.D_Code.tsx | 2 +- apps/web/src/layout/Layout.D_Docs.tsx | 1 + apps/web/src/layout/Layout.D_Home.tsx | 1 + apps/web/src/layout/Layout.D_Notes.tsx | 1 + apps/web/src/layout/Layout.D_Plans.tsx | 1 + apps/web/src/layout/Layout.D_Search.tsx | 1 + apps/web/src/layout/Layout.D_Settings.tsx | 1 + apps/web/src/layout/Layout.D_Settings_User.tsx | 1 + 10 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/dashboard/error.tsx b/apps/web/src/components/dashboard/error.tsx index fd490b9..69e7bcf 100644 --- a/apps/web/src/components/dashboard/error.tsx +++ b/apps/web/src/components/dashboard/error.tsx @@ -7,7 +7,7 @@ const DashboardError = (error) => { const darkMode = state.darkMode; return ( -
{error}
+
{error}
) } diff --git a/apps/web/src/layout/Layout.D_Calendar.tsx b/apps/web/src/layout/Layout.D_Calendar.tsx index 7f709de..e0b45b0 100644 --- a/apps/web/src/layout/Layout.D_Calendar.tsx +++ b/apps/web/src/layout/Layout.D_Calendar.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Code.tsx b/apps/web/src/layout/Layout.D_Code.tsx index 595cdbf..a7a0f75 100644 --- a/apps/web/src/layout/Layout.D_Code.tsx +++ b/apps/web/src/layout/Layout.D_Code.tsx @@ -16,7 +16,7 @@ import { menuQuestion } from '../redux/slices/dashboardSlice.ts'; import { useQuery } from "@tanstack/react-query"; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; -//import ErrorDashboard from '../components/dashboard/error'; +import ErrorDashboard from '../components/dashboard/error'; /** API url | Custom env mandatory to begin with VITE * https://vitejs.dev/guide/env-and-mode.html#env-files */ diff --git a/apps/web/src/layout/Layout.D_Docs.tsx b/apps/web/src/layout/Layout.D_Docs.tsx index efd3bbd..4732094 100644 --- a/apps/web/src/layout/Layout.D_Docs.tsx +++ b/apps/web/src/layout/Layout.D_Docs.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Home.tsx b/apps/web/src/layout/Layout.D_Home.tsx index 2db9558..c30ad0b 100644 --- a/apps/web/src/layout/Layout.D_Home.tsx +++ b/apps/web/src/layout/Layout.D_Home.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Notes.tsx b/apps/web/src/layout/Layout.D_Notes.tsx index 78774d0..034482d 100644 --- a/apps/web/src/layout/Layout.D_Notes.tsx +++ b/apps/web/src/layout/Layout.D_Notes.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Plans.tsx b/apps/web/src/layout/Layout.D_Plans.tsx index 95f4c5f..038de79 100644 --- a/apps/web/src/layout/Layout.D_Plans.tsx +++ b/apps/web/src/layout/Layout.D_Plans.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Search.tsx b/apps/web/src/layout/Layout.D_Search.tsx index 8ffa06c..302f806 100644 --- a/apps/web/src/layout/Layout.D_Search.tsx +++ b/apps/web/src/layout/Layout.D_Search.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Settings.tsx b/apps/web/src/layout/Layout.D_Settings.tsx index 03adf5d..6d06c55 100644 --- a/apps/web/src/layout/Layout.D_Settings.tsx +++ b/apps/web/src/layout/Layout.D_Settings.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; diff --git a/apps/web/src/layout/Layout.D_Settings_User.tsx b/apps/web/src/layout/Layout.D_Settings_User.tsx index 1a6acac..40fe1f2 100644 --- a/apps/web/src/layout/Layout.D_Settings_User.tsx +++ b/apps/web/src/layout/Layout.D_Settings_User.tsx @@ -2,6 +2,7 @@ import { useContext, useState } from 'react'; /** Custom State Components*/ import {LoadingDashboardXL} from '../components/dashboard/loading'; +//import ErrorDashboard from '../components/dashboard/error'; /**Custom Hooks */ import { ThemeContext } from '../context/ThemeContext'; import useWindowSize from '../hooks/useWindowSize'; From 311ba3eb948e2057af0d575d5caa87301d2e3bb4 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Fri, 22 Sep 2023 16:11:35 -0400 Subject: [PATCH 02/12] created delete api endpoint --- .../src/controllers/guest/guest.controller.ts | 170 +++++++++++------- 1 file changed, 102 insertions(+), 68 deletions(-) diff --git a/apps/api/src/controllers/guest/guest.controller.ts b/apps/api/src/controllers/guest/guest.controller.ts index b10a13b..184e68e 100644 --- a/apps/api/src/controllers/guest/guest.controller.ts +++ b/apps/api/src/controllers/guest/guest.controller.ts @@ -51,70 +51,7 @@ class Guest_Routes { this.router.post(this.pathGuestAuth, this.guestAuth); } - /**Public: Get Guest by ID*/ - public guestId = async (req: Request, res: Response) => { - switch(req.method) { - case('GET'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Public: Update Guest by ID*/ - public guestUpdate = async (req: Request, res: Response) => { - switch(req.method) { - case('PUT'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Public: Guest Registers Passcode*/ - public guestRegister = async (req: Request, res: Response) => { - switch(req.method) { - case('POST'): - try { - const { email, passcode } = req.body; - const data = await sql`SELECT * FROM _GUEST WHERE _PASSCODE = ${passcode} AND _EMAIL = ${email}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Private: Admin Gets All Guests*/ - public guestAll = async (req: Request, res: Response) => { - switch(req.method) { - case('GET'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; + /**Public: Create Guest*/ public guestNew = async (req: Request, res: Response) => { //console.log("route: api/guest/new") @@ -297,13 +234,46 @@ class Guest_Routes { public guestDelete = async (req: Request, res: Response) => { switch(req.method) { case('DELETE'): - try { - const id = req.params.id; - const results = await sql`DELETE * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200); + try { + /** <-- Validate User Info --> */ + const data = req.body; + /**Retrieve Guest */ + // Check Email in database + const getGuest = await sql`SELECT * FROM _GUEST WHERE _EMAIL = ${data._EMAIL}`; + const guestResult = getGuest[0]; + //console.log("guestResult:", guestResult) + + /**Validate Guest Data */ + // Check Guest IP Address + const guestIP = req.socket.remoteAddress; + const validIP = z.string().ip(guestIP); + // Check Email & Password + //const validEmail = data._EMAIL === guestResult._email; + //console.log("validEmail", validEmail); + // Compare Encrypted Password + const validPasswordCompare = bcrypt.compareSync( + data._PASSWORD, + guestResult._password + ); + //console.log("validPasswordCompare:", validPasswordCompare); + + if(!validIP) { + return res.status(400).send({ error: "Invalid IP Address" }) + } + if(!validPasswordCompare) { + return res.status(400).send({ error: "Invalid Password" }) + } + try { + const id = req.params.id; + const results = await sql`DELETE * FROM _GUEST WHERE _ID = ${id}`; + return res.status(200); + } catch { + return res.status(500).send({ error: "Guest Not Found" }) + } } catch { return res.status(500).send({ error: "Something went wrong"}); } + break default: return res.status(400).send({ error: `${req.method} Method Not Allowed` }); @@ -346,6 +316,70 @@ class Guest_Routes { res.status(400).json(defaultReturnObject); } } + /**Public: Get Guest by ID*/ + public guestId = async (req: Request, res: Response) => { + switch(req.method) { + case('GET'): + try { + const id = req.params.id; + const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; + return res.status(200).send(data); + } catch { + return res.status(500).send({ error: "Something went wrong"}); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; + /**Public: Update Guest by ID*/ + public guestUpdate = async (req: Request, res: Response) => { + switch(req.method) { + case('PUT'): + try { + const id = req.params.id; + const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; + return res.status(200).send(data); + } catch { + return res.status(500).send({ error: "Something went wrong"}); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; + /**Public: Guest Registers Passcode*/ + public guestRegister = async (req: Request, res: Response) => { + switch(req.method) { + case('POST'): + try { + const { email, passcode } = req.body; + const data = await sql`SELECT * FROM _GUEST WHERE _PASSCODE = ${passcode} AND _EMAIL = ${email}`; + return res.status(200).send(data); + } catch { + return res.status(500).send({ error: "Something went wrong"}); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; + /**Private: Admin Gets All Guests*/ + public guestAll = async (req: Request, res: Response) => { + switch(req.method) { + case('GET'): + try { + const id = req.params.id; + const data = await sql`SELECT * FROM _GUEST`; + return res.status(200).send(data); + } catch { + return res.status(500).send({ error: "Something went wrong"}); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; } export default Guest_Routes; From 6439f10d4c744e82c4f2fd0fd13a15d496526ef3 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 18:26:36 -0400 Subject: [PATCH 03/12] update api --- apps/api/src/classes/guest.ts | 4 +- apps/api/src/classes/user.ts | 394 +++++++++------- apps/api/src/config/other.sql | 41 ++ apps/api/src/config/{seed.sql => user.sql} | 107 ++--- .../src/controllers/guest/guest.controller.ts | 115 ++--- .../guest/guest.passcodes.controller.ts | 51 +++ .../src/controllers/user/user.controller.ts | 430 +++++++++++++----- apps/api/src/index.ts | 21 +- apps/api/src/middleware/transform.ts | 0 apps/api/src/server.ts | 9 +- apps/api/src/types/types.user.ts | 52 ++- 11 files changed, 753 insertions(+), 471 deletions(-) create mode 100644 apps/api/src/config/other.sql rename apps/api/src/config/{seed.sql => user.sql} (64%) create mode 100644 apps/api/src/controllers/guest/guest.passcodes.controller.ts create mode 100644 apps/api/src/middleware/transform.ts diff --git a/apps/api/src/classes/guest.ts b/apps/api/src/classes/guest.ts index 117ff71..f36ef7a 100644 --- a/apps/api/src/classes/guest.ts +++ b/apps/api/src/classes/guest.ts @@ -44,10 +44,10 @@ export class Guest implements _Guest { _IP_ADDRESS: 'Empty', _PASSCODE: uuidv4(), _PASSCODE_CONFIRMED: false, - _EMAIL: data._EMAIL.toLowerCase().trim(), + _EMAIL: 'john@doe.com', _EMAIL_CONFIRMED: false, _EMAIL_PASSCODE: uuidv4(), - _PASSWORD: data._PASSWORD, + _PASSWORD: '', _DEFAULT_LANGUAGE: 'javascript', _DEFAULT_ROUTE: 'var/declare/var', _POINTS_TOTAL: 0, diff --git a/apps/api/src/classes/user.ts b/apps/api/src/classes/user.ts index 6fb9082..dc2d6e3 100644 --- a/apps/api/src/classes/user.ts +++ b/apps/api/src/classes/user.ts @@ -4,278 +4,332 @@ import { v4 as uuidv4 } from 'uuid'; import { nanoid } from 'nanoid'; export class User implements User { - _USER_ID!: string; - _USER_CREATED_AT!: Date; - _USER_UPDATED_AT!: Date; - _USER_GUEST!: boolean; - _USER_ADMIN!: boolean; - _USER_SUBSCRIPTION!: number; - _USER_IP_ADDRESS!: string; - _USER_PASSCODE!: string; - _USER_PASSCODE_CONFIRMED!: boolean - _USER_EMAIL!: string; - _USER_EMAIL_CONFIRMED!: boolean; - _USER_PASSWORD!: string; - _USER_USERNAME!: string; - _USER_FIRST_NAME!: string; - _USER_LAST_NAME!: string; - _USER_SOCIAL_HANDLE_GITHUB!: string; - _USER_SOCIAL_HANDLE_GOOGLE!: string; - _USER_SOCIAL_HANDLE_APPLE!: string; - _USER_SOCIAL_HANDLE_FACEBOOK!: string; - _USER_SOCIAL_HANDLE_TWITTER!: string; - _USER_SOCIAL_HANDLE_LINKEDIN!: string; - _USER_DEFAULT_LANGUAGE!: string; - _USER_DEFAULT_ROUTE!: string; - _USER_POINTS_TOTAL!: number; - _USER_COURSES!: Course[] | string[]; + _ID!: string; + _CREATED_AT!: Date; + _UPDATED_AT!: Date; + _GUEST!: boolean; + _ADMIN!: boolean; + _ACCESS_TOKEN!: string; + _FIRST_LOGIN!: boolean; + _ADMIN!: boolean; + _SUBSCRIPTION!: Array | string; + _IP_ADDRESS!: string; + _PASSCODE!: string; + _PASSCODE_CONFIRMED!: boolean; + _EMAIL!: string; + _EMAIL_CONFIRMED!: boolean; + _EMAIL_PASSCODE!: string; + _PASSWORD!: string; + _USERNAME!: string; + _FIRST_NAME!: string; + _LAST_NAME!: string; + _SOCIAL_HANDLE_GITHUB!: string; + _SOCIAL_HANDLE_GOOGLE!: string; + _SOCIAL_HANDLE_APPLE!: string; + _SOCIAL_HANDLE_FACEBOOK!: string; + _SOCIAL_HANDLE_TWITTER!: string; + _SOCIAL_HANDLE_LINKEDIN!: string; + _DEFAULT_LANGUAGE!: string; + _DEFAULT_ROUTE!: string; + _POINTS_TOTAL!: number; + _COURSES!: Course[] | string[] | string; + + constructor(opts) { + const default { + _ID: uuidv4(), + _CREATED_AT: new Date(), + _UPDATED_AT: new Date(), + _GUEST = false, + _ADMIN = false, + _FIRST_LOGIN = false, + _ACCESS_TOKEN = '', + /** 1000 === Subscription(Basic Account)*/ + _SUBSCRIPTION = [1000, user], + _IP_ADDRESS = '', + _PASSCODE = uuidv4(), + _PASSCODE_CONFIRMED = false, + _EMAIL = "", + _EMAIL_PASSCODE = "", + _EMAIL_CONFIRMED = false, + _USERNAME = "", + _PASSWORD = nanoid(10), + _FIRST_NAME = '', + _LAST_NAME = '', + _SOCIAL_HANDLE_GITHUB = '', + _SOCIAL_HANDLE_GOOGLE = '', + _SOCIAL_HANDLE_APPLE = '', + _SOCIAL_HANDLE_FACEBOOK = '', + _SOCIAL_HANDLE_TWITTER = '', + _SOCIAL_HANDLE_LINKEDIN = '', + _DEFAULT_LANGUAGE = 'Javascript', + _DEFAULT_ROUTE = '', + _POINTS_TOTAL = 0, + _COURSES = [], + } + let opts = Object.assign({}, defaults, opts); + // assign options to instance opts (using only property names contained + // in defaults object to avoid copying properties we don't want) + // Object.keys(defaults).forEach(prop => { + // this[prop] = opts[prop]; + // }); + this._ID = opts._ID; + this._CREATED_AT = opts._CREATED_AT; + this._UPDATED_AT = opts._UPDATED_AT; + this._GUEST = opts._USER_GUEST; + this._ADMIN = opts._USER_ADMIN; + this._ACCESS_TOKEN = opts._ACCESS_TOKEN; + /** 1000 === Subscription(Basic Account)*/ + this._SUBSCRIPTION = opts._SUBSCRIPTION, + this._IP_ADDRESS = opts._IP_ADDRESS, + this._PASSCODE = opts.PASSCODE; + this._PASSCODE_CONFIRMED = opts._PASSCODE_CONFIRMED; + this._EMAIL = opts._EMAIL.toLowerCase().trim(); + this._EMAIL_PASSCODE = opts._EMAIL_PASSCODE, + this._EMAIL_CONFIRMED = opts._EMAIL_CONFIRMED; + this._PASSWORD = opts._PASSWORD; + this._USERNAME = opts._USERNAME; + this._FIRST_NAME = opts._FIRST_NAME.toLowerCase(); + this._LAST_NAME = opts._LAST_NAME.toLowerCase(); + this._SOCIAL_HANDLE_GITHUB = opts._SOCIAL_HANDLE_GITHUB; + this._SOCIAL_HANDLE_GOOGLE = opts._SOCIAL_HANDLE_GOOGLE; + this._SOCIAL_HANDLE_APPLE = opts._SOCIAL_HANDLE_APPLE; + this._SOCIAL_HANDLE_FACEBOOK = opts._SOCIAL_HANDLE_FACEBOOK; + this._SOCIAL_HANDLE_TWITTER = opts._SOCIAL_HANDLE_TWITTER; + this._SOCIAL_HANDLE_LINKEDIN = opts._SOCIAL_HANDLE_LINKEDIN; + this._DEFAULT_LANGUAGE = opts._DEFAULT_LANGUAGE; + this._DEFAULT_ROUTE = opts._DEFAULT_ROUTE; + this._POINTS_TOTAL = opts._POINTS_TOTAL; + this._COURSES = opts._COURSES; + }; + + /** _ID */ + public get get_ID(): string { + return this._ID + }; - constructor(data) { - this._USER_ID = uuidv4(); - this._USER_CREATED_AT = new Date(); - this._USER_UPDATED_AT = new Date(); - this._USER_GUEST = data._USER_GUEST || false - this._USER_ADMIN = data._USER_ADMIN || false; - /** 001001002 === Subscription(Basic Account)*/ - this._USER_SUBSCRIPTION = data._USER_SUBSCRIPTION || 001001002, - this._USER_IP_ADDRESS = data._USER_IP_ADDRESS || '', - this._USER_PASSCODE = uuidv4(); - this._USER_PASSCODE_CONFIRMED = false; - this._USER_EMAIL = data._USER_EMAIL.toLowerCase(); - this._USER_EMAIL_CONFIRMED = false; - this._USER_PASSWORD = nanoid(10); - this._USER_FIRST_NAME = data._USER_FIRST_NAME.toLowerCase() || ''; - this._USER_LAST_NAME = data._USER_LAST_NAME.toLowerCase() || ''; - this._USER_SOCIAL_HANDLE_GITHUB = data._USER_SOCIAL_HANDLE_GITHUB || ''; - this._USER_SOCIAL_HANDLE_GOOGLE = data._USER_SOCIAL_HANDLE_GOOGLE || ''; - this._USER_SOCIAL_HANDLE_APPLE = data._USER_SOCIAL_HANDLE_APPLE || ''; - this._USER_SOCIAL_HANDLE_FACEBOOK = data._USER_SOCIAL_HANDLE_FACEBOOK || ''; - this._USER_SOCIAL_HANDLE_TWITTER = data._USER_SOCIAL_HANDLE_TWITTER || ''; - this._USER_SOCIAL_HANDLE_LINKEDIN = data._USER_SOCIAL_HANDLE_LINKEDIN || ''; - this._USER_DEFAULT_LANGUAGE = data._USER_DEFAULT_LANGUAGE || 'Javascript'; - this._USER_DEFAULT_ROUTE = data._USER_DEFAULT_ROUTE || ''; - this._USER_POINTS_TOTAL = data._USER_POINTS_TOTAL || 0; - this._USER_COURSES = data._USER_COURSES || []; + public set set_ID(_ID: string) { + this._ID = _ID }; - /** _USER_ID */ - public get get_USER_ID(): string { - return this._USER_ID + /** _CREATED_AT */ + public get get_CREATED_AT(): Date { + return this._CREATED_AT }; - public set set_USER_ID(_USER_ID: string) { - this._USER_ID = _USER_ID + /** _UPDATED_AT */ + public get get_UPDATED_AT(): Date { + return this._UPDATED_AT }; - /** _USER_CREATED_AT */ - public get get_USER_CREATED_AT(): Date { - return this._USER_CREATED_AT + public set set_UPDATED_AT(_UPDATED_AT: string) { + this._UPDATED_AT = _UPDATED_AT }; - /** _USER_UPDATED_AT */ - public get get_USER_UPDATED_AT(): Date { - return this._USER_UPDATED_AT + /** _GUEST */ + public get get_GUEST(): boolean { + return this._GUEST }; - public set set_USER_UPDATED_AT(_USER_UPDATED_AT: string) { - this._USER_UPDATED_AT = _USER_UPDATED_AT + private set set_GUEST(_GUEST: boolean) { + this._GUEST = _GUEST }; - /** _USER_GUEST */ - public get get_USER_GUEST(): boolean { - return this._USER_GUEST + /** _ADMIN */ + public get get_ADMIN(): boolean { + return this._ADMIN }; - private set set_USER_GUEST(_USER_GUEST: boolean) { - this._USER_GUEST = _USER_GUEST + private set set_ADMIN(_ADMIN: boolean) { + this._ADMIN = _ADMIN }; - /** _USER_ADMIN */ - public get get_USER_ADMIN(): boolean { - return this._USER_ADMIN + /** _SUBSCRIPTION */ + public get get_SUBSCRIPTION(): number { + return this._SUBSCRIPTION }; - private set set_USER_ADMIN(_USER_ADMIN: boolean) { - this._USER_ADMIN = _USER_ADMIN + public set set_SUBSCRIPTION(_SUBSCRIPTION: number) { + this._SUBSCRIPTION = _SUBSCRIPTION }; - /** _USER_SUBSCRIPTION */ - public get get_USER_SUBSCRIPTION(): number { - return this._USER_SUBSCRIPTION + /** _IP_ADDRESS */ + public get get_IP_ADDRESS(): string { + return this._IP_ADDRESS }; - public set set_USER_SUBSCRIPTION(_USER_SUBSCRIPTION: number) { - this._USER_SUBSCRIPTION = _USER_SUBSCRIPTION + public set set_IP_ADDRESS(_IP_ADDRESS: string) { + this._IP_ADDRESS = _IP_ADDRESS }; - /** _USER_IP_ADDRESS */ - public get get_USER_IP_ADDRESS(): string { - return this._USER_IP_ADDRESS + + /** _PASSCODE */ + public get get_PASSCODE(): string { + return this._PASSCODE }; - public set set_USER_IP_ADDRESS(_USER_IP_ADDRESS: string) { - this._USER_IP_ADDRESS = _USER_IP_ADDRESS + public set set_PASSCODE(_PASSCODE: string) { + this._PASSCODE = _PASSCODE }; - /** _USER_PASSCODE */ - public get get_USER_PASSCODE(): string { - return this._USER_PASSCODE + /** _PASSCODE_CONFIRMED */ + public get get_PASSCODE_CONFIRMED(): boolean { + return this._PASSCODE_CONFIRMED }; - public set set_USER_PASSCODE(_USER_PASSCODE: string) { - this._USER_PASSCODE = _USER_PASSCODE + public set set_PASSCODE_CONFIRMED(_PASSCODE_CONFIRMED: boolean) { + this._PASSCODE_CONFIRMED = _PASSCODE_CONFIRMED }; - /** _USER_PASSCODE_CONFIRMED */ - public get get_USER_PASSCODE_CONFIRMED(): boolean { - return this._USER_PASSCODE_CONFIRMED + /** _EMAIL */ + public get get_EMAIL(): string { + return this._EMAIL }; - public set set_USER_PASSCODE_CONFIRMED(_USER_PASSCODE_CONFIRMED: boolean) { - this._USER_PASSCODE_CONFIRMED = _USER_PASSCODE_CONFIRMED + public set set_EMAIL(_EMAIL: string) { + this._EMAIL = _EMAIL }; - /** _USER_EMAIL */ - public get get_USER_EMAIL(): string { - return this._USER_EMAIL + /** _EMAIL_PASSCODE */ + public get get_EMAIL_PASSCODE(): string { + return this._EMAIL_PASSCODE }; - public set set_USER_EMAIL(_USER_EMAIL: string) { - this._USER_EMAIL = _USER_EMAIL + public set set_EMAIL(_EMAIL_PASSCODE: string) { + this._EMAIL_PASSCODE = _EMAIL_PASSCODE }; - /** _USER_EMAIL_CONFIRMED */ - public get get_USER_EMAIL_CONFIRMED(): boolean { - return this._USER_EMAIL_CONFIRMED + /** _EMAIL_CONFIRMED */ + public get get_EMAIL_CONFIRMED(): boolean { + return this._EMAIL_CONFIRMED }; - public set set_USER_EMAIL_CONFIRMED(_USER_EMAIL_CONFIRMED: boolean) { - this._USER_EMAIL_CONFIRMED = _USER_EMAIL_CONFIRMED + public set set_EMAIL_CONFIRMED(_EMAIL_CONFIRMED: boolean) { + this._EMAIL_CONFIRMED = _EMAIL_CONFIRMED }; - /** _USER_PASSWORD */ - public get get_USER_PASSWORD(): string { - return this._USER_PASSWORD + /** _PASSWORD */ + public get get_PASSWORD(): string { + return this._PASSWORD }; - public set set_USER_PASSCODE(_USER_PASSWORD: string) { - this._USER_PASSWORD = _USER_PASSWORD + public set set_PASSCODE(_PASSWORD: string) { + this._PASSWORD = _PASSWORD }; - /** _USER_USERNAME */ - public get get_USER_USERNAME(): string { - return this._USER_USERNAME + /** _USERNAME */ + public get get_USERNAME(): string { + return this._USERNAME }; - public set set_USER_USERNAME(_USER_USERNAME: string) { - this._USER_USERNAME = _USER_USERNAME + public set set_USERNAME(_USERNAME: string) { + this._USERNAME = _USERNAME }; - /** _USER_FIRST_NAME */ - public get get_USER_FIRST_NAME(): string { - return this._USER_FIRST_NAME + /** _FIRST_NAME */ + public get get_FIRST_NAME(): string { + return this._FIRST_NAME }; - public set set_USER_FIRST_NAME(_USER_FIRST_NAME: string) { - this._USER_FIRST_NAME = _USER_FIRST_NAME + public set set_FIRST_NAME(_FIRST_NAME: string) { + this._FIRST_NAME = _FIRST_NAME }; - /** _USER_LAST_NAME */ - public get get_USER_LAST_NAME(): string { - return this._USER_LAST_NAME + /** _LAST_NAME */ + public get get_LAST_NAME(): string { + return this._LAST_NAME }; - public set set_USER_LAST_NAME(_USER_LAST_NAME: string) { - this._USER_LAST_NAME = _USER_LAST_NAME + public set set_LAST_NAME(_LAST_NAME: string) { + this._USER_LAST_NAME = _LAST_NAME }; - /** _USER_SOCIAL_HANDLE_GITHUB */ - public get get_USER_SOCIAL_HANDLE_GITHUB(): string { - return this._USER_SOCIAL_HANDLE_GITHUB + /** _SOCIAL_HANDLE_GITHUB */ + public get get_SOCIAL_HANDLE_GITHUB(): string { + return this._SOCIAL_HANDLE_GITHUB }; - public set set_USER_SOCIAL_HANDLE_GITHUB(_USER_SOCIAL_HANDLE_GITHUB: string) { - this._USER_SOCIAL_HANDLE_GITHUB = _USER_SOCIAL_HANDLE_GITHUB + public set set_SOCIAL_HANDLE_GITHUB(_SOCIAL_HANDLE_GITHUB: string) { + this._SOCIAL_HANDLE_GITHUB = _SOCIAL_HANDLE_GITHUB }; /** _USER_SOCIAL_HANDLE_GOOGLE */ - public get get_USER_SOCIAL_HANDLE_GOOGLE(): string { + public get get_SOCIAL_HANDLE_GOOGLE(): string { return this._USER_SOCIAL_HANDLE_GOOGLE }; - public set set_USER_SOCIAL_HANDLE_GITHUB(_USER_SOCIAL_HANDLE_GITHUB: string) { - this._USER_SOCIAL_HANDLE_GOOGLE = _USER_SOCIAL_HANDLE_GOOGLE + public set set_SOCIAL_HANDLE_GITHUB(_SOCIAL_HANDLE_GITHUB: string) { + this._SOCIAL_HANDLE_GOOGLE = _SOCIAL_HANDLE_GOOGLE }; /** _USER_SOCIAL_HANDLE_APPLE */ - public get get_USER_SOCIAL_HANDLE_APPLE(): string { - return this._USER_SOCIAL_HANDLE_APPLE + public get get_SOCIAL_HANDLE_APPLE(): string { + return this._SOCIAL_HANDLE_APPLE }; - public set set_USER_SOCIAL_HANDLE_APPLE(_USER_SOCIAL_HANDLE_APPLE: string) { + public set set_SOCIAL_HANDLE_APPLE(_SOCIAL_HANDLE_APPLE: string) { this._USER_SOCIAL_HANDLE_APPLE = _USER_SOCIAL_HANDLE_APPLE }; - /** _USER_SOCIAL_HANDLE_FACEBOOK */ - public get get_USER_SOCIAL_HANDLE_FACEBOOK(): string { - return this._USER_SOCIAL_HANDLE_FACEBOOK + /** _SOCIAL_HANDLE_FACEBOOK */ + public get get_SOCIAL_HANDLE_FACEBOOK(): string { + return this._SOCIAL_HANDLE_FACEBOOK }; - public set set_USER_SOCIAL_HANDLE_FACEBOOK(_USER_SOCIAL_HANDLE_FACEBOOK: string) { - this._USER_SOCIAL_HANDLE_FACEBOOK = _USER_SOCIAL_HANDLE_FACEBOOK + public set set_SOCIAL_HANDLE_FACEBOOK(_SOCIAL_HANDLE_FACEBOOK: string) { + this._SOCIAL_HANDLE_FACEBOOK = _SOCIAL_HANDLE_FACEBOOK }; - /** _USER_SOCIAL_HANDLE_TWITTER */ - public get get_USER_SOCIAL_HANDLE_TWITTER(): string { - return this._USER_SOCIAL_HANDLE_TWITTER + /** _SOCIAL_HANDLE_TWITTER */ + public get get_SOCIAL_HANDLE_TWITTER(): string { + return this._SOCIAL_HANDLE_TWITTER }; - public set set_USER_SOCIAL_HANDLE_TWITTER(_USER_SOCIAL_HANDLE_TWITTER: string) { - this._USER_SOCIAL_HANDLE_TWITTER = _USER_SOCIAL_HANDLE_TWITTER + public set set_SOCIAL_HANDLE_TWITTER(_SOCIAL_HANDLE_TWITTER: string) { + this._SOCIAL_HANDLE_TWITTER = _SOCIAL_HANDLE_TWITTER }; - /** _USER_SOCIAL_HANDLE_LINKEDIN */ - public get get_USER_SOCIAL_HANDLE_LINKEDIN(): string { - return this._USER_SOCIAL_HANDLE_LINKEDIN + /** _SOCIAL_HANDLE_LINKEDIN */ + public get get_SOCIAL_HANDLE_LINKEDIN(): string { + return this._SOCIAL_HANDLE_LINKEDIN }; - public set set_USER_SOCIAL_HANDLE_LINKEDIN(_USER_SOCIAL_HANDLE_LINKEDIN: string) { - this._USER_SOCIAL_HANDLE_LINKEDIN = _USER_SOCIAL_HANDLE_LINKEDIN + public set set_SOCIAL_HANDLE_LINKEDIN(_SOCIAL_HANDLE_LINKEDIN: string) { + this._SOCIAL_HANDLE_LINKEDIN = _SOCIAL_HANDLE_LINKEDIN }; - /** _USER_DEFAULT_LANGUAGE */ - public get get_USER_DEFAULT_LANGUAGE(): string { - return this._USER_DEFAULT_LANGUAGE + /** _DEFAULT_LANGUAGE */ + public get get_DEFAULT_LANGUAGE(): string { + return this._DEFAULT_LANGUAGE }; - public set set_USER_DEFAULT_LANGUAGE(_USER_DEFAULT_LANGUAGE: string) { - this._USER_DEFAULT_LANGUAGE = _USER_DEFAULT_LANGUAGE + public set set_DEFAULT_LANGUAGE(_DEFAULT_LANGUAGE: string) { + this._DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE }; - /** _USER_DEFAULT_ROUTE */ - public get get_USER_DEFAULT_ROUTE(): string { - return this._USER_DEFAULT_ROUTE + /** _DEFAULT_ROUTE */ + public get get_DEFAULT_ROUTE(): string { + return this._DEFAULT_ROUTE }; - public set set_USER_DEFAULT_LANGUAGE(_USER_DEFAULT_ROUTE: string) { - this._USER_DEFAULT_ROUTE = _USER_DEFAULT_ROUTE + public set set_DEFAULT_LANGUAGE(_DEFAULT_ROUTE: string) { + this._DEFAULT_ROUTE = _DEFAULT_ROUTE }; - /** _USER_POINTS_POINTS */ - public get _USER_POINTS_POINTS(): number { - return this._USER_POINTS_POINTS + /** _POINTS_POINTS */ + public get _POINTS_POINTS(): number { + return this._POINTS_POINTS }; - public set set_USER_POINTS_POINTS (_USER_POINTS_POINTS : number) { - this._USER_POINTS_POINTS = _USER_POINTS_POINTS + public set set_POINTS_POINTS (_POINTS_POINTS : number) { + this._POINTS_POINTS = _POINTS_POINTS }; - /** _USER_COURSES */ - public get _USER_COURSES(): Course[] || string[] { - return this._USER_COURSES + /** _COURSES */ + public get _COURSES(): Course[] || string[] { + return this._COURSES }; - public set set_USER_COURSES(_USER_COURSES): Course[] || string[] { - this._USER_COURSES = _USER_COURSES + public set set_COURSES(_COURSES): Course[] || string[] { + this._COURSES = _COURSES }; } diff --git a/apps/api/src/config/other.sql b/apps/api/src/config/other.sql new file mode 100644 index 0000000..6829ec0 --- /dev/null +++ b/apps/api/src/config/other.sql @@ -0,0 +1,41 @@ + +--- --- --- + +DROP TABLE IF EXISTS _COURSE; + +CREATE TABLE IF NOT EXISTS _COURSE( + _COURSE_ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), + _COURSE_CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _COURSE_UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _COURSE_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), + _COURSE_ADMIN_STATUS VARCHAR(255) NOT NULL, + _COURSE_LANGUAGES VARCHAR(100) NOT NULL, + _COURSE_SUBJECT VARCHAR(30) NOT NULL, + _COURSE_QUESTION_IDS VARCHAR(255) NOT NULL, + _COURSE_COMPLETE BOOLEAN NOT NULL, + _COURSE_POINTS INT NOT NULL +); + +--- --- --- + +DROP TABLE IF EXISTS _QUESTIONS; + +CREATE TABLE IF NOT EXISTS _QUESTIONS( + _QUESTION_CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _QUESTION_UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _QUESTION_ID VARCHAR(30) PRIMARY KEY, + _QUESTION_LANGUAGE VARCHAR(30) NOT NULL, + _QUESTION_LEVEL INT NOT NULL, + _QUESTION_POINTS INT NOT NULL, + _QUESTION_TASK VARCHAR(255) NOT NULL, + _QUESTION_DATA VARCHAR(255) NOT NULL, + _QUESTION_RESULT VARCHAR(255) NOT NULL, + _QUESTION_HINTS VARCHAR(255) NOT NULL, + _QUESTION_BOILERPLATE VARCHAR(255) NOT NULL, + _QUESTION_CONDITIONS VARCHAR(255) NOT NULL, + _QUESTION_CONSTRAINTS VARCHAR(255) NOT NULL, + _QUESTION_CATEGORY VARCHAR(155) NOT NULL, + _QUESTION_CATEGORY_SUB VARCHAR(155) NOT NULL, + _QUESTION_TAGS VARCHAR(255) NOT NULL, + _QUESTION_REFS VARCHAR(255) NOT NULL +); diff --git a/apps/api/src/config/seed.sql b/apps/api/src/config/user.sql similarity index 64% rename from apps/api/src/config/seed.sql rename to apps/api/src/config/user.sql index 9b42091..7b8c050 100644 --- a/apps/api/src/config/seed.sql +++ b/apps/api/src/config/user.sql @@ -2,38 +2,37 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; --- --- --- -/** -CREATE TABLE IF NOT EXISTS _USER( _USER_ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), _USER_UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, _USER_GUEST BOOLEAN NOT NULL DEFAULT false, _USER_ADMIN BOOLEAN NOT NULL DEFAULT false, _USER_SUBSCRIPTION Int NOT NULL DEFAULT 001001002, _USER_IP_ADDRESS VARCHAR(50) NOT NULL, _USER_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), _USER_PASSCODE_CONFIRMED BOOLEAN NOT NULL DEFAULT false, _USER_EMAIL VARCHAR(50) UNIQUE NOT NULL, _USER_EMAIL_CONFIRMED BOOLEAN NOT NULL DEFAULT false, _USER_PASSWORD VARCHAR(30) NOT NULL, _USER_USERNAME VARCHAR(30) NOT NULL, _USER_FIRST_NAME VARCHAR(30) NOT NULL, _USER_LAST_NAME VARCHAR(30) NOT NULL, _USER_SOCIAL_HANDLE_GITHUB VARCHAR(30) NOT NULL, _USER_SOCIAL_HANDLE_GOOGLE VARCHAR(30) NOT NULL, _USER_SOCIAL_HANDLE_APPLE VARCHAR(30) NOT NULL, _USER_SOCIAL_HANDLE_FACEBOOK VARCHAR(30) NOT NULL, _USER_SOCIAL_HANDLE_TWITTER VARCHAR(30) NOT NULL, _USER_DEFAULT_LANGUAGE VARCHAR(30) NOT NULL, _USER_DEFAULT_ROUTE VARCHAR(50) NOT NULL, _USER_POINTS INT NOT NULL, _USER_COURSES VARCHAR(255) NOT NULL); -*/ DROP TABLE IF EXISTS _USER; CREATE TABLE IF NOT EXISTS _USER( - _USER_ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), - _USER_CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _USER_UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _USER_GUEST BOOLEAN NOT NULL DEFAULT false, - _USER_ADMIN BOOLEAN NOT NULL DEFAULT false, - _USER_SUBSCRIPTION Int NOT NULL DEFAULT 001001002, - _USER_IP_ADDRESS VARCHAR(50) NOT NULL, - _USER_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), - _USER_PASSCODE_CONFIRMED BOOLEAN NOT NULL DEFAULT false, - _USER_EMAIL VARCHAR(50) UNIQUE NOT NULL, - _USER_EMAIL_CONFIRMED BOOLEAN NOT NULL DEFAULT false, - _USER_EMAIL_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), - _USER_PASSWORD VARCHAR(30) NOT NULL, - _USER_USERNAME VARCHAR(30) NOT NULL, - _USER_FIRST_NAME VARCHAR(30) NOT NULL, - _USER_LAST_NAME VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_GITHUB VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_GOOGLE VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_APPLE VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_FACEBOOK VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_TWITTER VARCHAR(30) NOT NULL, - _USER_SOCIAL_HANDLE_LINKEDIN VARCHAR(30) NOT NULL, - _USER_DEFAULT_LANGUAGE VARCHAR(30) NOT NULL, - _USER_DEFAULT_ROUTE VARCHAR(50) NOT NULL, - _USER_POINTS_TOTAL INT NOT NULL, - _USER_COURSES VARCHAR(255) NOT NULL + _ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), + _CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + _GUEST BOOLEAN NOT NULL DEFAULT false, + _ADMIN BOOLEAN NOT NULL DEFAULT false, + _ACCESS_TOKEN VARCHAR(255) NOT NULL, + _FIRST_LOGIN BOOLEAN NOT NULL DEFAULT false, + _SUBSCRIPTION VARCHAR(255) NOT NULL, + _IP_ADDRESS VARCHAR(255) NOT NULL, + _PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), + _PASSCODE_CONFIRMED BOOLEAN NOT NULL DEFAULT false, + _EMAIL VARCHAR(50) UNIQUE NOT NULL, + _EMAIL_CONFIRMED BOOLEAN NOT NULL DEFAULT false, + _EMAIL_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), + _PASSWORD VARCHAR(30) NOT NULL, + _USERNAME VARCHAR(30) NOT NULL, + _FIRST_NAME VARCHAR(30) NOT NULL, + _LAST_NAME VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_GITHUB VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_GOOGLE VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_APPLE VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_FACEBOOK VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_TWITTER VARCHAR(30) NOT NULL, + _SOCIAL_HANDLE_LINKEDIN VARCHAR(30) NOT NULL, + _DEFAULT_LANGUAGE VARCHAR(30) NOT NULL, + _DEFAULT_ROUTE VARCHAR(50) NOT NULL, + _POINTS_TOTAL INT NOT NULL, + _COURSES VARCHAR(255) NOT NULL ); --- --- --- @@ -116,31 +115,6 @@ CREATE TABLE IF NOT EXISTS _USER_POINTS_PYTHON( --- --- --- -/** -CREATE TABLE IF NOT EXISTS _GUEST( - _ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), - _CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _ACCESS_TOKEN VARCHAR(255) NOT NULL, - _FIRST_LOGIN BOOLEAN NOT NULL DEFAULT false, - _ADMIN BOOLEAN NOT NULL DEFAULT false, - _SUBSCRIPTION VARCHAR(50) NOT NULL, - _IP_ADDRESS VARCHAR(50) NOT NULL, - _PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), - _PASSCODE_CONFIRMED BOOLEAN NOT NULL DEFAULT false, - _EMAIL VARCHAR(50) UNIQUE NOT NULL, - _EMAIL_CONFIRMED BOOLEAN NOT NULL DEFAULT false, - _EMAIL_PASSCODE UUID NOT NULL DEFAULT gen_random_uuid(), - _PASSWORD VARCHAR(100) NOT NULL, - _DEFAULT_LANGUAGE VARCHAR(30) NOT NULL, - _DEFAULT_ROUTE VARCHAR(50) NOT NULL, - _POINTS_TOTAL INT NOT NULL, - _POINTS_JAVASCRIPT INT NOT NULL, - _POINTS_JAVA INT NOT NULL, - _POINTS_PYTHON INT NOT NULL, - _COURSES VARCHAR(255) NOT NULL); -*/ - DROP TABLE IF EXISTS _GUEST; CREATE TABLE IF NOT EXISTS _GUEST( @@ -223,7 +197,7 @@ CREATE TABLE IF NOT EXISTS _ADMIN( --- --- --- -DROP TABLE IF EXISTS _COURSE; +DROP TABLE IF EXISTS _SUBSCRIPTION; CREATE TABLE IF NOT EXISTS _COURSE( _COURSE_ID UUID PRIMARY KEY DEFAULT gen_random_uuid(), @@ -238,26 +212,3 @@ CREATE TABLE IF NOT EXISTS _COURSE( _COURSE_POINTS INT NOT NULL ); ---- --- --- - -DROP TABLE IF EXISTS _QUESTIONS; - -CREATE TABLE IF NOT EXISTS _QUESTIONS( - _QUESTION_CREATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _QUESTION_UPDATED_AT DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, - _QUESTION_ID VARCHAR(30) PRIMARY KEY, - _QUESTION_LANGUAGE VARCHAR(30) NOT NULL, - _QUESTION_LEVEL INT NOT NULL, - _QUESTION_POINTS INT NOT NULL, - _QUESTION_TASK VARCHAR(255) NOT NULL, - _QUESTION_DATA VARCHAR(255) NOT NULL, - _QUESTION_RESULT VARCHAR(255) NOT NULL, - _QUESTION_HINTS VARCHAR(255) NOT NULL, - _QUESTION_BOILERPLATE VARCHAR(255) NOT NULL, - _QUESTION_CONDITIONS VARCHAR(255) NOT NULL, - _QUESTION_CONSTRAINTS VARCHAR(255) NOT NULL, - _QUESTION_CATEGORY VARCHAR(155) NOT NULL, - _QUESTION_CATEGORY_SUB VARCHAR(155) NOT NULL, - _QUESTION_TAGS VARCHAR(255) NOT NULL, - _QUESTION_REFS VARCHAR(255) NOT NULL -); diff --git a/apps/api/src/controllers/guest/guest.controller.ts b/apps/api/src/controllers/guest/guest.controller.ts index 184e68e..3dbb09b 100644 --- a/apps/api/src/controllers/guest/guest.controller.ts +++ b/apps/api/src/controllers/guest/guest.controller.ts @@ -12,21 +12,13 @@ import * as dotenv from 'dotenv'; dotenv.config(); class Guest_Routes { - /**Public: Get Guest by ID*/ - public pathGuest = '/guest/:id'; - /**Public: Validate Guest*/ - public pathGuestLogin = '/guest/login'; - /**Public: Guest Registers Passcode*/ - public pathGuestRegister = '/guest/register'; - /**Public: Update Guest*/ - public pathGuestUpdate = '/guest/update/:id'; - /**Private: Admin Deletes Guest*/ + /**Public: Guest Delete Routes*/ public pathGuestDelete = '/guest/delete/:id'; - /**Private: Admin Gets All Guests*/ - public pathGuestAll = '/guest/all'; /**Public: Create Guest*/ public pathGuestNew = '/guest/new'; - /**Public: Auth guest*/ + /**Public: Validate Guest*/ + public pathGuestLogin = '/guest/login'; + /**Public: Auth guest*/ public pathGuestAuth = '/guest/verify'; /**Express Router*/ public router = Router(); @@ -41,12 +33,8 @@ class Guest_Routes { } public initializeRoutes() { - this.router.get(this.pathGuest, this.guestId); - this.router.post(this.pathGuestLogin, this.guestLogin); - this.router.get(this.pathGuestRegister, this.guestRegister); - this.router.get(this.pathGuestAll, this.corsOptions, this.guestAll); this.router.post(this.pathGuestNew, this.guestNew); - this.router.put(this.pathGuestUpdate, this.guestUpdate); + this.router.post(this.pathGuestLogin, this.guestLogin); this.router.delete(this.pathGuestDelete, this.corsOptions, this.guestDelete); this.router.post(this.pathGuestAuth, this.guestAuth); } @@ -218,7 +206,10 @@ class Guest_Routes { } else if(!validEmail || !validPasswordCompare) { return res.status(400).send({ error: "Invalid Guest Information" }); } else if(validIP && validEmail && validPasswordCompare) { - return res.status(200).send({data: guestObj}); + return res.cookie("access_token", getToken, { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + }).status(200).send({data: guestObj}); } else { return res.status(400).send({ error: "Invalid Data" }); } @@ -230,6 +221,7 @@ class Guest_Routes { return res.status(400).send({ error: `${req.method} Method Not Allowed` }); } }; + /**Private: Admin Deletes Guest*/ public guestDelete = async (req: Request, res: Response) => { switch(req.method) { @@ -263,6 +255,8 @@ class Guest_Routes { if(!validPasswordCompare) { return res.status(400).send({ error: "Invalid Password" }) } + + /**Delete Guest */ try { const id = req.params.id; const results = await sql`DELETE * FROM _GUEST WHERE _ID = ${id}`; @@ -316,61 +310,40 @@ class Guest_Routes { res.status(400).json(defaultReturnObject); } } - /**Public: Get Guest by ID*/ - public guestId = async (req: Request, res: Response) => { - switch(req.method) { - case('GET'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Public: Update Guest by ID*/ - public guestUpdate = async (req: Request, res: Response) => { - switch(req.method) { - case('PUT'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Public: Guest Registers Passcode*/ - public guestRegister = async (req: Request, res: Response) => { - switch(req.method) { - case('POST'): - try { - const { email, passcode } = req.body; - const data = await sql`SELECT * FROM _GUEST WHERE _PASSCODE = ${passcode} AND _EMAIL = ${email}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Private: Admin Gets All Guests*/ - public guestAll = async (req: Request, res: Response) => { + + /**Public: Delete Guest*/ + public guestRemove = async (req: Request, res: Response) => { switch(req.method) { - case('GET'): + case('DELETE'): try { - const id = req.params.id; - const data = await sql`SELECT * FROM _GUEST`; + const data = req.body; + const guestResult = await sql`SELECT * FROM _GUEST WHERE _EMAIL = ${data._EMAIL}`; + /**Validate Guest Data */ + // Check Guest IP Address + const guestIP = req.socket.remoteAddress; + const validIP = z.string().ip(guestIP); + // Check Email & Password + //const validEmail = data._EMAIL === guestResult._email; + //console.log("validEmail", validEmail); + // Compare Encrypted Password + const validPasswordCompare = bcrypt.compareSync( + data._PASSWORD, + guestResult._password + ); + //console.log("validPasswordCompare:", validPasswordCompare); + if(!validIP) { + return res.status(400).send({ error: "Invalid IP Address" }) + } + if(!validPasswordCompare) { + return res.status(400).send({ error: "Invalid Password" }) + } + try { + const id = req.params.id; + const results = await sql`DELETE * FROM _GUEST WHERE _ID = ${id}`; + return res.status(200); + } catch { + return res.status(500).send({ error: "Guest Not Found" }) + } return res.status(200).send(data); } catch { return res.status(500).send({ error: "Something went wrong"}); diff --git a/apps/api/src/controllers/guest/guest.passcodes.controller.ts b/apps/api/src/controllers/guest/guest.passcodes.controller.ts new file mode 100644 index 0000000..77780d9 --- /dev/null +++ b/apps/api/src/controllers/guest/guest.passcodes.controller.ts @@ -0,0 +1,51 @@ +import { Request, Response } from 'express'; +import Router from 'express-promise-router'; +import { Guest } from '../../classes/guest'; +import { _Guest } from '../../types/types.guest'; +import sql from '../../config/db'; +import cors from 'cors'; +import { z } from "zod"; +import jwt from "jsonwebtoken"; +import bcrypt from "bcryptjs"; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +class Guest_Routes { + /**Public: Guest Registers Passcode*/ + public pathGuestRegister = '/guest/register'; + /**Express Router*/ + public router = Router(); + /**Cors Options*/ + private corsOptions = cors({ + origin: process.env.WEBURL, + optionsSuccessStatus: 200 + }); + + constructor() { + this.initializeRoutes(); + } + + public initializeRoutes() { + this.router.get(this.pathGuestRegister, this.guestRegister); + } + + /**Public: Guest Registers Passcode*/ + public guestRegister = async (req: Request, res: Response) => { + switch(req.method) { + case('POST'): + try { + const { email, passcode } = req.body; + const data = await sql`SELECT * FROM _GUEST WHERE _PASSCODE = ${passcode} AND _EMAIL = ${email}`; + return res.status(200).send(data); + } catch { + return res.status(500).send({ error: "Something went wrong"}); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; +} + +export default Guest_Routes; diff --git a/apps/api/src/controllers/user/user.controller.ts b/apps/api/src/controllers/user/user.controller.ts index c9993ec..ec8e947 100644 --- a/apps/api/src/controllers/user/user.controller.ts +++ b/apps/api/src/controllers/user/user.controller.ts @@ -1,25 +1,27 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { User } from '../../classes/user'; -import { User } from '../../types/types.user'; +import { user } from '../../classes/user'; +import { _user } from '../../types/types.user'; import sql from '../../config/db'; import cors from 'cors'; +import { z } from "zod"; +import jwt from "jsonwebtoken"; +import bcrypt from "bcryptjs"; +import * as dotenv from 'dotenv'; -class User { - /**Public: Get User by ID*/ - public pathUser = '/user/:id'; - /**Public: User Registers Passcode*/ - public pathUserRegister = '/user/register'; - /**Public: Update User*/ - public pathUserUpdate = '/user/update/:id'; - /**Private: Admin Deletes User*/ - public pathUserDelete = '/user/delete/:id'; - /**Private: Admin Gets All Users*/ - public pathUserAll = '/user/all'; - /**Private: Admin Creates User*/ - public pathUserNew = '/user/new'; +dotenv.config(); + +class user_Routes { + /**Public: user Delete Routes*/ + public pathUserDelete = '/delete/:id'; + /**Public: Create user*/ + public pathUserNew = '/new'; + /**Public: Validate user*/ + public pathUserLogin = '/login'; + /**Public: Auth user*/ + public pathUserAuth = '/verify'; /**Express Router*/ - public router = Router(); + public router = Router({ mergeParams: true }); /**Cors Options*/ private corsOptions = cors({ origin: process.env.WEBURL, @@ -31,135 +33,333 @@ class User { } public initializeRoutes() { - this.router.get(this.pathUser, this.userId); - this.router.get(this.pathUserRegister, this.userRegister); - this.router.get(this.pathUserAll, this.corsOptions, this.userAll); - this.router.post(this.pathUserNew, this.corsOptions, this.userNew); - this.router.put(this.pathUserUpdate, this.userUpdate); - this.router.delete(this.pathUserDelete, this.corsOptions, this.userDelete); + this.router.post(this.pathuserNew, this.userNew); + this.router.post(this.pathuserLogin, this.userLogin); + this.router.delete(this.pathuserDelete, this.corsOptions, this.userDelete); + this.router.post(this.pathuserAuth, this.userAuth); } - /**Public: Get User by ID*/ - public userId = async (req: Request, res: Response) => { + + /**Public: Create user*/ + public userNew = async (req: Request, res: Response) => { + //console.log("route: api/user/new") switch(req.method) { - case('GET'): + case('POST'): try { - const id = req.params.id; - const data = await sql`SELECT * FROM _User WHERE _USER_ID = ${id}`; - return res.status(200).send(data); - } catch { - return res.status(500).send({ error: "Something went wrong"}); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; - }; - /**Public: Update User by ID*/ - public userUpdate = async (req: Request, res: Response) => { - switch(req.method) { - case('PUT'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _User WHERE _USER_ID = ${id}`; - return res.status(200).send(data); + const data = req.body; + //console.log("data:", data); + const userIP = req.socket.remoteAddress; + const validIP = z.string().ip(userIP); + const validEmail = z.string().email(data._EMAIL); + const validPasswordMin = z.string().min(8,data._PASSWORD); + const validPasswordMax = z.string().max(16,data._PASSWORD); + const validPasswordRegex = z.string().regex(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$,;%^*-]).{8,16}$/,data._PASSWORD); + //console.log('validIP', validIP); + //console.log('validEmail', validEmail); + if(!validIP) { + return res.status(400).send({ error: "user Network Error" }); + } else if(!validEmail) { + return res.status(400).send({ error: "Invalid Email" }); + } else if(!validPasswordMin) { + return res.status(400).send({ error: "Password Not Minimum Length" }); + } else if(!validPasswordMax) { + return res.status(400).send({ error: "Password Bigger than Max Length" }); + } else if(!validPasswordRegex) { + return res.status(400).send({ error: "Password Requires At Least One Special Character" }); + } else if(validIP && validEmail && validPasswordMin && validPasswordMax && validPasswordRegex) { + const user = new user(data); + // set user ip address + user._IP_ADDRESS = userIP as string; + // Encrypt user password + const encryptedPassword = await bcrypt.hash(data._PASSWORD, 10); + // set encrypted password + user._PASSWORD = encryptedPassword; + // convert subscription to string value + user._SUBSCRIPTION = user._SUBSCRIPTION.toString().trim(); + // convert courses to string value + user._COURSES = user._COURSES.toString().trim(); + // user after updates + //console.log("user", user); + const createUser = await sql`INSERT INTO _USER( + _ID, + _CREATED_AT, + _UPDATED_AT, + _GUEST, + _ADMIN, + _FIRST_LOGIN, + _ACCESS_TOKEN, + _SUBSCRIPTION, + _IP_ADDRESS, + _PASSCODE, + _PASSCODE_CONFIRMED, + _EMAIL, + _EMAIL_CONFIRMED, + _EMAIL_PASSCODE, + _USERNAME, + _PASSWORD, + _FIRST_NAME, + _LAST_NAME, + _SOCIAL_HANDLE_GITHUB, + _SOCIAL_HANDLE_GOOGLE, + _SOCIAL_HANDLE_APPLE, + _SOCIAL_HANDLE_FACEBOOK, + _SOCIAL_HANDLE_TWITTER, + _SOCIAL_HANDLE_LINKEDIN, + _DEFAULT_LANGUAGE, + _DEFAULT_ROUTE, + _POINTS_TOTAL, + _COURSES, + ) VALUES ( + ${user._ID}, + ${user._CREATED_AT}, + ${user._UPDATED_AT}, + ${user._GUEST}, + ${user._ADMIN}, + ${user._FIRST_LOGIN}, + ${user._ACCESS_TOKEN}, + ${user._SUBSCRIPTION}, + ${user._IP_ADDRESS}, + ${user._PASSCODE}, + ${user._PASSCODE_CONFIRMED}, + ${user._EMAIL}, + ${user._EMAIL_CONFIRMED}, + ${user._EMAIL_PASSCODE}, + ${user._USERNAME}, + ${user._PASSWORD}, + ${user._FIRST_NAME}, + ${user._LAST_NAME}, + ${user._SOCIAL_HANDLE_GITHUB}, + ${user._SOCIAL_HANDLE_GOOGLE}, + ${user._SOCIAL_HANDLE_APPLE}, + ${user._SOCIAL_HANDLE_FACEBOOK}, + ${user._SOCIAL_HANDLE_TWITTER}, + ${user._SOCIAL_HANDLE_LINKEDIN}, + ${user._DEFAULT_LANGUAGE}, + ${user._DEFAULT_ROUTE}, + ${user._POINTS_TOTAL}, + ${user._COURSES}, + )`; + const getuser = await sql`SELECT * FROM _user WHERE _ID = ${user._ID}`; + //console.log("user info:", getuser); + if(getUser !== undefined) { + return res.sendStatus(200); + } else { + return res.status(500).send({ error: "user Creation Error" }); + } + } else { + return res.status(400).send({ error: "Invalid Data" }); + } } catch { - return res.status(500).send({ error: "Something went wrong"}); + return res.status(500).send({ error: "Database Connection Error" }); } break default: return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; + } }; - /**Public: User Registers Passcode*/ - public userRegister = async (req: Request, res: Response) => { + /**Public: Login user*/ + public userLogin = async (req: Request, res: Response) => { switch(req.method) { case('POST'): - try { - const { email, passcode } = req.body; - const data = await sql`SELECT * FROM _User WHERE _USER_PASSCODE = ${passcode} AND _USER_EMAIL = ${email}`; - return res.status(200).send(data); + try { + const data = req.body; + //console.log(data); + + /**Retrieve user */ + // Check Email in database + const getUser = await sql`SELECT * FROM _user WHERE _EMAIL = ${data._EMAIL}`; + const userResult = getuser[0]; + //console.log("userResult:", userResult) + + /**Validate user Data */ + // Check user IP Address + const userIP = req.socket.remoteAddress; + const validIP = z.string().ip(userIP); + // Check Email & Password + const validEmail = data._EMAIL === userResult._email; + //console.log("validEmail", validEmail); + // Compare Encrypted Password + const validPasswordCompare = bcrypt.compareSync( + data._PASSWORD, + userResult._password + ); + //console.log("validPasswordCompare:", validPasswordCompare); + + /**Transform Data */ + // uppercase userResult keys + Object.entries(userResult).forEach(([key, value]) => { + userResult[key.toUpperCase()] = userResult[key]; + //console.log(`${key}: ${value}`); + }); + // Create user Object + const userObj = new user(userResult); + //console.log("user:", userObj); + + /**Update Data */ + // Set user IP Address + userObj._IP_ADDRESS = userIP as string; + // Update user Login Time + userObj._UPDATED_AT = new Date(); + // Save Updated Time to DB + + await sql` UPDATE _user SET _UPDATED_AT = ${userObj._UPDATED_AT} WHERE _ID = ${userObj._ID}`; + + /**Create JWT Token */ + // Create Token + const getToken = jwt.sign({ _ID: userObj._ID, _EMAIL: userObj._EMAIL }, process.env.SECRET_TOKEN, { + algorithm: 'HS256', + allowInsecureKeySizes: true, + expiresIn: 86400, // 24 hours + }); + // Save user Token + userObj._ACCESS_TOKEN = getToken; + + //console.log("userObj:", userObj) + + if(!validIP) { + return res.status(400).send({ error: "User Network Error" }); + } else if(!validEmail || !validPasswordCompare) { + return res.status(400).send({ error: "Invalid user Information" }); + } else if(validIP && validEmail && validPasswordCompare) { + return res.cookie("access_token", getToken, { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + }).status(200).send({data: userObj}); + } else { + return res.status(400).send({ error: "Invalid Data" }); + } } catch { - return res.status(500).send({ error: "Something went wrong"}); + return res.status(500).send({ error: "Database Connection Error" }); } break default: return res.status(400).send({ error: `${req.method} Method Not Allowed` }); - }; + } }; - /**Private: Admin Gets All Users*/ - public userAll = async (req: Request, res: Response) => { + + /**Private: Admin Deletes user*/ + public userDelete = async (req: Request, res: Response) => { switch(req.method) { - case('GET'): - try { - const id = req.params.id; - const data = await sql`SELECT * FROM _User`; - return res.status(200).send(data); + case('DELETE'): + try { + /** <-- Validate User Info --> */ + const data = req.body; + /**Retrieve user */ + // Check Email in database + const getuser = await sql`SELECT * FROM _user WHERE _EMAIL = ${data._EMAIL}`; + const userResult = getuser[0]; + //console.log("userResult:", userResult) + + /**Validate user Data */ + // Check user IP Address + const userIP = req.socket.remoteAddress; + const validIP = z.string().ip(userIP); + // Check Email & Password + //const validEmail = data._EMAIL === userResult._email; + //console.log("validEmail", validEmail); + // Compare Encrypted Password + const validPasswordCompare = bcrypt.compareSync( + data._PASSWORD, + userResult._password + ); + //console.log("validPasswordCompare:", validPasswordCompare); + + if(!validIP) { + return res.status(400).send({ error: "Invalid IP Address" }) + } + if(!validPasswordCompare) { + return res.status(400).send({ error: "Invalid Password" }) + } + + /**Delete user */ + try { + const id = req.params.id; + const results = await sql`DELETE * FROM _user WHERE _ID = ${id}`; + return res.status(200); + } catch { + return res.status(500).send({ error: "user Not Found" }) + } } catch { return res.status(500).send({ error: "Something went wrong"}); } + break default: return res.status(400).send({ error: `${req.method} Method Not Allowed` }); }; }; - /**Private: Admin Creates User*/ - public userNew = async (req: Request, res: Response) => { - switch(req.method) { - case('POST'): - try { - const data: JS_Type = req.body; - const user = new User(data); - const encryptedUserPassword = await bcrypt.hash(user._USER_PASSWORD, 10); - const results = await sql`INSERT INTO _USER ( - _USER_CREATED_AT, - _USER_UPDATED_AT, - _USER_ID, - _USER_PASSCODE, - _USER_PASSCODE_CONFIRMED, - _USER_EMAIL, - _USER_EMAIL_CONFIRMED, - _USER_PASSWORD, - _USER_FIRSTNAME, - _USER_LASTNAME, - _USER_DEFAULT_LANGUAGE, - _USER_DEFAULT_ROUTE, - _USER_POINTS, - _USER_COURSES, - ) VALUES ( - ${user._USER_CREATED_AT}, - ${user._USER_UPDATED_AT}, - ${user._USER_ID}, - ${user._USER_PASSCODE}, - ${user._USER_PASSCODE_CONFIRMED}, - ${user._USER_EMAIL}, - ${user._USER_EMAIL_CONFIRMED}, - ${encryptedUserPassword}, - ${user._USER_FIRSTNAME}, - ${user._USER_LASTNAME}, - ${user._USER_DEFAULT_LANGUAGE}, - ${user._USER_DEFAULT_ROUTE}, - ${user._USER_POINTS}, - ${user._USER_COURSES}, - )`; - const getUser = await sql`SELECT * FROM _User WHERE _USER_ID = ${user.id}`; - return res.status(200).send(getUser); - } catch { - return res.status(500).send({ error: "Something went wrong" }); - } - break - default: - return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + /**Public: Auth user*/ + public userAuth = async (req: Request, res: Response) => { + const defaultReturnObject = { authenticated: false, user: null }; + + try { + const { token } = req.body + // const token = String(req?.headers?.authorization?.replace('Bearer ', '')); + // console.log("token", token) + //console.log("data", token); + const decoded = jwt.verify(token, process.env.SECRET_TOKEN); + //console.log("decoded", decoded) + // /**Retrieve user */ + // Check Email in database + const getuser = await sql`SELECT * FROM _user WHERE _ID = ${decoded._ID}`; + const userResult = getuser[0]; + //console.log("user:", userResult); + if (!userResult) { + res.status(400).json(defaultReturnObject); + return; + } + /**Transform Data */ + // uppercase userResult keys + Object.entries(userResult).forEach(([key, value]) => { + userResult[key.toUpperCase()] = userResult[key]; + //console.log(`${key}: ${value}`); + }); + // Create user Object + const userObj = new user(userResult); + //console.log("user:", userObj); + const result = { authenticated: true, user: userObj } + res.status(200).json(result); } - }; - /**Private: Admin Deletes User*/ - public userDelete = async (req: Request, res: Response) => { + catch (err) { + console.log('POST auth/me, Something Went Wrong', err); + res.status(400).json(defaultReturnObject); + } + } + + /**Public: Delete user*/ + public userRemove = async (req: Request, res: Response) => { switch(req.method) { case('DELETE'): try { - const id = req.params.id; - const results = await sql`DELETE * FROM _USER WHERE _USER_ID = ${id}`; - return res.status(200); + const data = req.body; + const userResult = await sql`SELECT * FROM _user WHERE _EMAIL = ${data._EMAIL}`; + /**Validate user Data */ + // Check user IP Address + const userIP = req.socket.remoteAddress; + const validIP = z.string().ip(userIP); + // Check Email & Password + //const validEmail = data._EMAIL === userResult._email; + //console.log("validEmail", validEmail); + // Compare Encrypted Password + const validPasswordCompare = bcrypt.compareSync( + data._PASSWORD, + userResult._password + ); + //console.log("validPasswordCompare:", validPasswordCompare); + if(!validIP) { + return res.status(400).send({ error: "Invalid IP Address" }) + } + if(!validPasswordCompare) { + return res.status(400).send({ error: "Invalid Password" }) + } + try { + const id = req.params.id; + const results = await sql`DELETE * FROM _user WHERE _ID = ${id}`; + return res.status(200); + } catch { + return res.status(500).send({ error: "user Not Found" }) + } + return res.status(200).send(data); } catch { return res.status(500).send({ error: "Something went wrong"}); } @@ -170,4 +370,4 @@ class User { }; } -export default User; +export default user_Routes; diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 7190111..4bb7da9 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -9,15 +9,18 @@ import VarDeclare from './controllers/variables/var.declare.controller'; import VarScope from './controllers/variables/var.scope.controller'; import VarScopeReassign from './controllers/variables/var.scope.reassign.controller'; -const app = new App([ - new Index(), - new Guest_Routes(), - new Comments(), - new VarGeneral(), - new VarDeclare(), - new VarScope(), - new VarScopeReassign() -]); +const app = new App( + [], + [ + new Index(), + new Guest_Routes(), + new Comments(), + new VarGeneral(), + new VarDeclare(), + new VarScope(), + new VarScopeReassign() + ] +); app.listen(); diff --git a/apps/api/src/middleware/transform.ts b/apps/api/src/middleware/transform.ts new file mode 100644 index 0000000..e69de29 diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index 64b9d99..d3120e0 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -12,10 +12,11 @@ class App { public port: number; private corsOptions; - constructor(controllers) { + constructor(authControllers, controllers) { this.app = express(); this.port = parseInt(process.env.PORT as string) || 8000; this.initMiddlewares(); + this.initAuthControllers(authControllers); this.initControllers(controllers); this.corsOptions = process.env.CORS_URLS; } @@ -35,6 +36,12 @@ class App { // })); } + private initAuthControllers(controllers) { + controllers.forEach((controller) => { + this.app.use('/auth', controller.router); + }); + } + private initControllers(controllers) { controllers.forEach((controller) => { this.app.use('/', controller.router); diff --git a/apps/api/src/types/types.user.ts b/apps/api/src/types/types.user.ts index 34193f2..68ef20d 100644 --- a/apps/api/src/types/types.user.ts +++ b/apps/api/src/types/types.user.ts @@ -23,31 +23,33 @@ export interface Admin extends User { } export interface User { - _USER_ID: string; - _USER_CREATED_AT: Date; - _USER_UPDATED_AT: Date; - _USER_GUEST: boolean; - _USER_ADMIN: boolean; - _USER_SUBSCRIPTION: number; - _USER_IP_ADDRESS: string; - _USER_PASSCODE: string; - _USER_PASSCODE_CONFIRMED: boolean - _USER_EMAIL: string; - _USER_EMAIL_CONFIRMED: boolean; - _USER_PASSWORD: string; - _USER_USERNAME: string; - _USER_FIRST_NAME: string | null; - _USER_LAST_NAME: string | null; - _USER_SOCIAL_HANDLE_GITHUB: string | null; - _USER_SOCIAL_HANDLE_GOOGLE: string | null; - _USER_SOCIAL_HANDLE_APPLE: string | null; - _USER_SOCIAL_HANDLE_FACEBOOK: string | null; - _USER_SOCIAL_HANDLE_TWITTER: string | null; - _USER_SOCIAL_HANDLE_LINKEDIN: string | null; - _USER_DEFAULT_LANGUAGE: string | null; - _USER_DEFAULT_ROUTE: string | null; - _USER_POINTS_TOTAL: number | null; - _USER_COURSES: Course[] | null; + _ID: string; + _CREATED_AT: Date; + _UPDATED_AT: Date; + _GUEST: boolean; + _ADMIN: boolean; + _ACCESS_TOKEN: boolean; + _SUBSCRIPTION: number; + _IP_ADDRESS: string; + _PASSCODE: string; + _PASSCODE_CONFIRMED: boolean + _EMAIL: string; + _EMAIL_PASSCODE: string; + _EMAIL_CONFIRMED: boolean; + _PASSWORD: string; + _USERNAME: string; + _FIRST_NAME: string; + _LAST_NAME: string; + _SOCIAL_HANDLE_GITHUB: string; + _SOCIAL_HANDLE_GOOGLE: string; + _SOCIAL_HANDLE_APPLE: string; + _SOCIAL_HANDLE_FACEBOOK: string; + _SOCIAL_HANDLE_TWITTER: string; + _SOCIAL_HANDLE_LINKEDIN: string; + _DEFAULT_LANGUAGE: string; + _DEFAULT_ROUTE: string; + _POINTS_TOTAL: number; + _COURSES: Course[] | string[] | string; } From 5884762e81071ac8454b111712115dbfafd4efbe Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:36:04 -0400 Subject: [PATCH 04/12] enabled user to delete account --- .../src/controllers/guest/guest.controller.ts | 17 +- apps/web/package.json | 1 + .../dashboard-settings/D_Settings_User.tsx | 156 ++++++++++++++++-- yarn.lock | 11 ++ 4 files changed, 158 insertions(+), 27 deletions(-) diff --git a/apps/api/src/controllers/guest/guest.controller.ts b/apps/api/src/controllers/guest/guest.controller.ts index 3dbb09b..8b585f5 100644 --- a/apps/api/src/controllers/guest/guest.controller.ts +++ b/apps/api/src/controllers/guest/guest.controller.ts @@ -35,7 +35,7 @@ class Guest_Routes { public initializeRoutes() { this.router.post(this.pathGuestNew, this.guestNew); this.router.post(this.pathGuestLogin, this.guestLogin); - this.router.delete(this.pathGuestDelete, this.corsOptions, this.guestDelete); + this.router.delete(this.pathGuestDelete, this.guestDelete); this.router.post(this.pathGuestAuth, this.guestAuth); } @@ -249,6 +249,7 @@ class Guest_Routes { ); //console.log("validPasswordCompare:", validPasswordCompare); + /**Return Error if Invalid Return 400*/ if(!validIP) { return res.status(400).send({ error: "Invalid IP Address" }) } @@ -257,15 +258,13 @@ class Guest_Routes { } /**Delete Guest */ - try { - const id = req.params.id; - const results = await sql`DELETE * FROM _GUEST WHERE _ID = ${id}`; - return res.status(200); - } catch { - return res.status(500).send({ error: "Guest Not Found" }) - } + const id = req.params.id; + //console.log(id) + const result = await sql`DELETE FROM _GUEST WHERE _id = ${id}`; + //console.log(result); + return res.sendStatus(200); } catch { - return res.status(500).send({ error: "Something went wrong"}); + return res.status(500).send({ error: "Guest Not Found"}); } break diff --git a/apps/web/package.json b/apps/web/package.json index 2160284..16b0f4e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -84,6 +84,7 @@ "nanoid": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-emojis": "^1.0.6", "react-hook-form": "^7.45.1", "react-redux": "^8.1.1", "react-router-dom": "^6.14.1", diff --git a/apps/web/src/components/dashboard/dashboard-settings/D_Settings_User.tsx b/apps/web/src/components/dashboard/dashboard-settings/D_Settings_User.tsx index 3e26c10..8ae6ea8 100644 --- a/apps/web/src/components/dashboard/dashboard-settings/D_Settings_User.tsx +++ b/apps/web/src/components/dashboard/dashboard-settings/D_Settings_User.tsx @@ -1,24 +1,39 @@ // Page: Dashboard Settings (User) /**React */ -// import { useContext, useState, useMemo, useRef } from 'react'; -import { useContext, useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; +import { useContext, useEffect, useState, useCallback } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { useForm } from 'react-hook-form'; /**Custom Hooks */ import { ThemeContext } from '../../../context/ThemeContext'; import useWindowSize from '../../../hooks/useWindowSize'; import Transition from '../../../hooks/useTransition'; -/**Redux */ -import { useAppSelector } from '../../../redux/reduxHooks.ts'; -import type { RootState } from '../../../redux/store.ts'; //import bcrypt from 'bcryptjs'; /**User Avatars */ // import { createAvatar } from '@dicebear/core'; // import { pixelArt } from '@dicebear/collection'; -/**Custom Helpers */ -import { detectTokenFromLocalStorage } from '../../../utils/common'; +/** Notifications */ +import { notifications } from '@mantine/notifications'; +//import { IconX, IconCheck } from '@tabler/icons-react'; +import Emoji from 'react-emojis'; /**Modal */ import { useDisclosure } from '@mantine/hooks'; -import { Modal} from '@mantine/core'; +import { Modal, TextInput } from '@mantine/core'; +/**Redux */ +import { useAppSelector, useAppDispatch } from '../../../redux/reduxHooks.ts'; +import type { RootState } from '../../../redux/store.ts'; +import { + menuUser, +} from '../../../redux/slices/dashboardSlice.ts'; +import { DEFAULT_USER } from '../../../utils/constants'; +/**Custom Helpers */ +import { + detectTokenFromLocalStorage, + removeTokenFromLocalStorage +} from '../../../utils/common'; + +interface FormInputs { + multipleErrorInput: string +} const D_Settings_User = () => { /**Detect Auth */ @@ -27,8 +42,14 @@ const D_Settings_User = () => { const { isMobile, isMobileMD } = useWindowSize(); const { state } = useContext(ThemeContext); const darkMode = state.darkMode; + + /**Browser Navigation */ + const navigate = useNavigate(); + + /** Redux | Dispatch Instance */ + const dispatch = useAppDispatch(); - /** User from redux store */ + /** Redux | User from redux store */ const getUser = useAppSelector((state:RootState) => state?.dashboard?.user); //console.log("getUser:", getUser); @@ -52,6 +73,7 @@ const D_Settings_User = () => { setUserId(userIdHide); } }; + /**User Dates */ const userCreatedDate = new Date(getUser._CREATED_AT).toDateString(); const userUpdatedDate = new Date(getUser._UPDATED_AT).toDateString(); @@ -76,16 +98,114 @@ const D_Settings_User = () => { // }).toDataUriSync(); // }, []); + /**Delete Modal Input */ + const { + register, + handleSubmit, + } = useForm({ + criteriaMode: "all", + }) + + /**Request Guest Login Info */ + const onSubmit = handleSubmit( async (data) => { + guestLogin(data); + }); + + /** Guest Login */ + const guestLogin = useCallback( async(data) => { + try { + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/guest/delete/${getUser._ID}`; + } else { + url = `/api/guest/delete/${getUser._ID}`; + } + await fetch(url, { + method: 'DELETE', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }).then(function(response) { + //console.log(response) + if(response.ok) { + removeTokenFromLocalStorage(); + console.log("😿 Guest | Deleted Account"); + // Success Notification + notifications.show({ + id: 'success', + withCloseButton: true, + autoClose: 4000, + title: "Successful Account Deletion", + message: 'Sad to see you go', + color: 'teal', + icon: , + className: 'my-notification-class', + style: { backgroundColor: 'white' }, + sx: { backgroundColor: 'teal' }, + loading: false, + }); + return + } else { + console.log("🚫 Guest | Delete Account Failed") + // Failure Notification + notifications.show({ + id: 'failure', + withCloseButton: true, + autoClose: 2000, + title: "Failed Account Deletion", + message: 'Please try again', + color: 'red', + icon: , + className: 'my-notification-class', + style: { backgroundColor: 'white' }, + sx: { backgroundColor: 'red' }, + loading: false, + }); + } + }).then(function() { + dispatch(menuUser(DEFAULT_USER)); + setTimeout(() => { + console.log("⏳ Delay | Redirect in 1 second."); + navigate("/"); + }, "1000"); + }); + } catch(error) { + console.log("🚫 Guest | Delete Failed") + console.log(error); + } + },[dispatch, getUser._ID, navigate]); + return (
ul]:tw-text-campfire-blue [&_main>h4]:tw-text-campfire-neutral-300' : '[&_main]:tw-text-campfire-neutral-700 [&_main>h4]:tw-text-campfire-neutral-600'} tw-w-full tw-h-full tw-p-2`}> - - {/**#TODO Ask user to confirm delete account. - * If no, close modal. - * If yes send api request to delete account - * If account confirmed as deleted. redirect to homepage. - * */} - {/* Modal content */} + +
+
+ + + + +
@@ -171,7 +291,7 @@ const D_Settings_User = () => { : "hover:tw-bg-campfire-neutral-400/50 hover:tw-text-campfire-neutral-100"} tw-w-full tw-border tw-border-red-400 tw-font-space_mono tw-text-lg tw-text-red-400`}> Account Deletion -

🚨!!!Warning!!! This Action Is Permanent🚨

+

🚨!!!Warning!!!🚨 This Action Is Permanent

diff --git a/yarn.lock b/yarn.lock index 36b0471..919b723 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14790,6 +14790,16 @@ __metadata: languageName: node linkType: hard +"react-emojis@npm:^1.0.6": + version: 1.0.6 + resolution: "react-emojis@npm:1.0.6" + peerDependencies: + react: ^16.8.6 + react-dom: ^16.8.6 + checksum: 9c6a21b7a963ef43735e649db547a843ab757e1a7e3ac322da93a4e7c54fdc6651692ad81ae4c2968eb604c06e7bcf75cf4b0d326643140ec64ed40b50e98531 + languageName: node + linkType: hard + "react-hook-form@npm:^7.45.1": version: 7.45.1 resolution: "react-hook-form@npm:7.45.1" @@ -17854,6 +17864,7 @@ __metadata: prop-types: ^15.8.1 react: ^18.2.0 react-dom: ^18.2.0 + react-emojis: ^1.0.6 react-hook-form: ^7.45.1 react-redux: ^8.1.1 react-router-dom: ^6.14.1 From 3b4c4a24135990e4ec01cb5dbc250fb7fad6cd58 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:43:17 -0400 Subject: [PATCH 05/12] serialized date --- apps/web/src/redux/slices/dashboardSlice.ts | 4 ++-- apps/web/src/utils/constants.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/redux/slices/dashboardSlice.ts b/apps/web/src/redux/slices/dashboardSlice.ts index c01c48d..93065d0 100644 --- a/apps/web/src/redux/slices/dashboardSlice.ts +++ b/apps/web/src/redux/slices/dashboardSlice.ts @@ -29,8 +29,8 @@ const initialState: DashboardState = { consoleMessage: '', user: { _ID: '123-456-789', - _CREATED_AT: new Date, - _UPDATED_AT: new Date, + _CREATED_AT: new Date().toISOString(), + _UPDATED_AT: new Date().toISOString(), _ACCESS_TOKEN: '', _FIRST_LOGIN: false, _ADMIN: false, diff --git a/apps/web/src/utils/constants.ts b/apps/web/src/utils/constants.ts index cde242c..05038d7 100644 --- a/apps/web/src/utils/constants.ts +++ b/apps/web/src/utils/constants.ts @@ -1,7 +1,7 @@ export const DEFAULT_USER = { _ID: '', - _CREATED_AT: new Date, - _UPDATED_AT: new Date, + _CREATED_AT: new Date().toISOString(), + _UPDATED_AT: new Date().toISOString(), _ACCESS_TOKEN: '', _FIRST_LOGIN: false, _ADMIN: false, From 8d5651f5599a363f6937e7b33e269e3df55b9ea6 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:49:16 -0400 Subject: [PATCH 06/12] adjust cookies --- apps/api/src/controllers/guest/guest.controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/api/src/controllers/guest/guest.controller.ts b/apps/api/src/controllers/guest/guest.controller.ts index 8b585f5..f221240 100644 --- a/apps/api/src/controllers/guest/guest.controller.ts +++ b/apps/api/src/controllers/guest/guest.controller.ts @@ -208,7 +208,8 @@ class Guest_Routes { } else if(validIP && validEmail && validPasswordCompare) { return res.cookie("access_token", getToken, { httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: true, + sameSite: 'strict', }).status(200).send({data: guestObj}); } else { return res.status(400).send({ error: "Invalid Data" }); From b610fbe1565949329e6a4bb5a8d656e7872d5530 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:57:29 -0400 Subject: [PATCH 07/12] adjusted mobile home page layout --- apps/web/src/layout/Layout.D_Home.tsx | 8 ++++---- apps/web/tailwind.campfire.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/src/layout/Layout.D_Home.tsx b/apps/web/src/layout/Layout.D_Home.tsx index c30ad0b..1ff4383 100644 --- a/apps/web/src/layout/Layout.D_Home.tsx +++ b/apps/web/src/layout/Layout.D_Home.tsx @@ -53,13 +53,13 @@ const Layout_D_Home = () => {
*]:tw-backdrop-brightness-25 ' : '[&>*]:tw-backdrop-brightness-85'} tw-bg-transparent tw-pb-1 tw-w-full tw-h-full tw-grow [&>*]:tw-backdrop-blur-sm tw-grid tw-grid-rows-layout-dashboard-home-mobile tw-grid-cols-layout-dashboard-home-mobile tw-gap-1 [&>*]:tw-rounded tw-border tw-border-transparent`}> -
- -
+ +
+
-
+
diff --git a/apps/web/tailwind.campfire.js b/apps/web/tailwind.campfire.js index a71922c..1dc79f9 100644 --- a/apps/web/tailwind.campfire.js +++ b/apps/web/tailwind.campfire.js @@ -141,7 +141,7 @@ export default { 'dashboard-no-language-extended': 'minmax(28em, auto)', 'dashboard-no-language-mobile': '3em, 28em, auto, auto, auto', 'layout-dashboard-home': '3.5em, auto', - 'layout-dashboard-home-mobile': '3em, auto', + 'layout-dashboard-home-mobile': '3.5em, auto, minmax(20em, auto)', 'layout-dashboard-code': '3.2em, 25em, minmax(15.8em, auto)', 'layout-dashboard-code-mobile': '3em, minmax(20em, auto), minmax(22em, auto), minmax(10em, auto)', 'layout-dashboard-code-editor': '28.2em, minmax(15.8em, auto)', From d3947c211819111dec51935a565a2276442c4b12 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:26:45 -0400 Subject: [PATCH 08/12] updated folder structure --- .../{ => auth}/guest/guest.controller.ts | 6 +- .../guest/guest.passcodes.controller.ts | 6 +- .../{ => auth}/user/user.controller.ts | 6 +- .../comments/comments.controller.ts | 10 +-- .../questions/questions.controller.ts | 8 +-- .../{ => data}/variables/var.controller.ts | 14 ++-- .../variables/var.declare.controller.ts | 10 +-- .../variables/var.scope.controller.ts | 10 +-- .../var.scope.reassign.controller.ts | 10 +-- apps/api/src/data/{ => java}/comments.data.ts | 4 +- apps/api/src/data/js/comments.data.ts | 69 +++++++++++++++++++ .../api/src/data/{ => js}/var.declare.data.ts | 4 +- apps/api/src/data/{ => js}/var.scope.data.ts | 2 +- .../data/{ => js}/var.scope.reassign.data.ts | 2 +- apps/api/src/data/py/comments.data.ts | 69 +++++++++++++++++++ apps/api/src/index.ts | 12 ++-- 16 files changed, 190 insertions(+), 52 deletions(-) rename apps/api/src/controllers/{ => auth}/guest/guest.controller.ts (99%) rename apps/api/src/controllers/{ => auth}/guest/guest.passcodes.controller.ts (91%) rename apps/api/src/controllers/{ => auth}/user/user.controller.ts (99%) rename apps/api/src/controllers/{ => data}/comments/comments.controller.ts (90%) rename apps/api/src/controllers/{ => data}/questions/questions.controller.ts (96%) rename apps/api/src/controllers/{ => data}/variables/var.controller.ts (94%) rename apps/api/src/controllers/{ => data}/variables/var.declare.controller.ts (92%) rename apps/api/src/controllers/{ => data}/variables/var.scope.controller.ts (93%) rename apps/api/src/controllers/{ => data}/variables/var.scope.reassign.controller.ts (77%) rename apps/api/src/data/{ => java}/comments.data.ts (96%) create mode 100644 apps/api/src/data/js/comments.data.ts rename apps/api/src/data/{ => js}/var.declare.data.ts (97%) rename apps/api/src/data/{ => js}/var.scope.data.ts (98%) rename apps/api/src/data/{ => js}/var.scope.reassign.data.ts (96%) create mode 100644 apps/api/src/data/py/comments.data.ts diff --git a/apps/api/src/controllers/guest/guest.controller.ts b/apps/api/src/controllers/auth/guest/guest.controller.ts similarity index 99% rename from apps/api/src/controllers/guest/guest.controller.ts rename to apps/api/src/controllers/auth/guest/guest.controller.ts index f221240..015426f 100644 --- a/apps/api/src/controllers/guest/guest.controller.ts +++ b/apps/api/src/controllers/auth/guest/guest.controller.ts @@ -1,8 +1,8 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { Guest } from '../../classes/guest'; -import { _Guest } from '../../types/types.guest'; -import sql from '../../config/db'; +import { Guest } from '../../../classes/guest'; +import { _Guest } from '../../../types/types.guest'; +import sql from '../../../config/db'; import cors from 'cors'; import { z } from "zod"; import jwt from "jsonwebtoken"; diff --git a/apps/api/src/controllers/guest/guest.passcodes.controller.ts b/apps/api/src/controllers/auth/guest/guest.passcodes.controller.ts similarity index 91% rename from apps/api/src/controllers/guest/guest.passcodes.controller.ts rename to apps/api/src/controllers/auth/guest/guest.passcodes.controller.ts index 77780d9..0a3b672 100644 --- a/apps/api/src/controllers/guest/guest.passcodes.controller.ts +++ b/apps/api/src/controllers/auth/guest/guest.passcodes.controller.ts @@ -1,8 +1,8 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { Guest } from '../../classes/guest'; -import { _Guest } from '../../types/types.guest'; -import sql from '../../config/db'; +import { Guest } from '../../../classes/guest'; +import { _Guest } from '../../../types/types.guest'; +import sql from '../../../config/db'; import cors from 'cors'; import { z } from "zod"; import jwt from "jsonwebtoken"; diff --git a/apps/api/src/controllers/user/user.controller.ts b/apps/api/src/controllers/auth/user/user.controller.ts similarity index 99% rename from apps/api/src/controllers/user/user.controller.ts rename to apps/api/src/controllers/auth/user/user.controller.ts index ec8e947..85810bd 100644 --- a/apps/api/src/controllers/user/user.controller.ts +++ b/apps/api/src/controllers/auth/user/user.controller.ts @@ -1,8 +1,8 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { user } from '../../classes/user'; -import { _user } from '../../types/types.user'; -import sql from '../../config/db'; +import { user } from '../../../classes/user'; +import { _user } from '../../../types/types.user'; +import sql from '../../../config/db'; import cors from 'cors'; import { z } from "zod"; import jwt from "jsonwebtoken"; diff --git a/apps/api/src/controllers/comments/comments.controller.ts b/apps/api/src/controllers/data/comments/comments.controller.ts similarity index 90% rename from apps/api/src/controllers/comments/comments.controller.ts rename to apps/api/src/controllers/data/comments/comments.controller.ts index 68eedcc..b020524 100644 --- a/apps/api/src/controllers/comments/comments.controller.ts +++ b/apps/api/src/controllers/data/comments/comments.controller.ts @@ -1,11 +1,11 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../config/db'; -import { Question } from '../../classes/question'; -import { Q_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; -import { objSingle, objMulti } from '../../data/comments.data'; +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objSingle, objMulti } from '../../../data/js/comments.data'; export default class VarDeclare { public pathCommentsRandom = '/comments/all'; diff --git a/apps/api/src/controllers/questions/questions.controller.ts b/apps/api/src/controllers/data/questions/questions.controller.ts similarity index 96% rename from apps/api/src/controllers/questions/questions.controller.ts rename to apps/api/src/controllers/data/questions/questions.controller.ts index f8e3af4..df448a5 100644 --- a/apps/api/src/controllers/questions/questions.controller.ts +++ b/apps/api/src/controllers/data/questions/questions.controller.ts @@ -1,11 +1,11 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import sql from '../../config/db'; +import sql from '../../../config/db'; import { faker } from '@faker-js/faker'; -import { JS_Question } from '../../classes/javascript.question'; -import { JS_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; +import { JS_Question } from '../../../classes/javascript.question'; +import { JS_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; import cors from 'cors'; export default class Questions { diff --git a/apps/api/src/controllers/variables/var.controller.ts b/apps/api/src/controllers/data/variables/var.controller.ts similarity index 94% rename from apps/api/src/controllers/variables/var.controller.ts rename to apps/api/src/controllers/data/variables/var.controller.ts index 7f487cf..d0bd0ec 100644 --- a/apps/api/src/controllers/variables/var.controller.ts +++ b/apps/api/src/controllers/data/variables/var.controller.ts @@ -1,14 +1,14 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import sql from '../../config/db'; +import sql from '../../../config/db'; import { faker } from '@faker-js/faker'; -import { Question } from '../../classes/question'; -import { Q_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; -import { objRandom as objDeclare } from '../../data/var.declare.data'; -import { objGlobalScope, objFuncScope, objBlockScope } from '../../data/var.scope.data'; -import { objBlockScopeReassign } from '../../data/var.scope.reassign.data'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objRandom as objDeclare } from '../../../data/js/var.declare.data'; +import { objGlobalScope, objFuncScope, objBlockScope } from '../../../data/js/var.scope.data'; +import { objBlockScopeReassign } from '../../../data/js/var.scope.reassign.data'; import cors from 'cors'; export default class VarGeneral { diff --git a/apps/api/src/controllers/variables/var.declare.controller.ts b/apps/api/src/controllers/data/variables/var.declare.controller.ts similarity index 92% rename from apps/api/src/controllers/variables/var.declare.controller.ts rename to apps/api/src/controllers/data/variables/var.declare.controller.ts index c8c9865..2ff0125 100644 --- a/apps/api/src/controllers/variables/var.declare.controller.ts +++ b/apps/api/src/controllers/data/variables/var.declare.controller.ts @@ -1,11 +1,11 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../config/db'; -import { Question } from '../../classes/question'; -import { Q_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; -import { objRandom, objRandomVar, objRandomConst, objRandomLet } from '../../data/var.declare.data' +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objRandom, objRandomVar, objRandomConst, objRandomLet } from '../../../data/js/var.declare.data' export default class VarDeclare { public pathVarRandomDeclare = '/var/declare/all' diff --git a/apps/api/src/controllers/variables/var.scope.controller.ts b/apps/api/src/controllers/data/variables/var.scope.controller.ts similarity index 93% rename from apps/api/src/controllers/variables/var.scope.controller.ts rename to apps/api/src/controllers/data/variables/var.scope.controller.ts index c3d8635..5356987 100644 --- a/apps/api/src/controllers/variables/var.scope.controller.ts +++ b/apps/api/src/controllers/data/variables/var.scope.controller.ts @@ -1,11 +1,11 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../config/db'; -import { Question } from '../../classes/question'; -import { Q_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; -import { objBlockScope, objFuncScope, objGlobalScope } from '../../data/var.scope.data'; +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objBlockScope, objFuncScope, objGlobalScope } from '../../../data/js/var.scope.data'; export default class VarScope { public pathVarRandomScope = '/var/scope/all'; diff --git a/apps/api/src/controllers/variables/var.scope.reassign.controller.ts b/apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts similarity index 77% rename from apps/api/src/controllers/variables/var.scope.reassign.controller.ts rename to apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts index 9714d0e..f0dd6a0 100644 --- a/apps/api/src/controllers/variables/var.scope.reassign.controller.ts +++ b/apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts @@ -1,11 +1,11 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../config/db'; -import { Question } from '../../classes/question'; -import { Q_Type } from '../../types/types.question'; -import { getRandomInt } from '../../utils/index'; -import { objBlockScopeReassign } from '../../data/var.scope.reassign.data'; +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objBlockScopeReassign } from '../../../data/js/var.scope.reassign.data'; export default class VarScopeReassign { public pathVarReassignBlock = '/var/scope/reassign/block'; diff --git a/apps/api/src/data/comments.data.ts b/apps/api/src/data/java/comments.data.ts similarity index 96% rename from apps/api/src/data/comments.data.ts rename to apps/api/src/data/java/comments.data.ts index 24470c0..a1035a8 100644 --- a/apps/api/src/data/comments.data.ts +++ b/apps/api/src/data/java/comments.data.ts @@ -1,6 +1,6 @@ -import { Q_Type } from '../types/types.question'; +import { Q_Type } from '../../types/types.question'; import { faker } from '@faker-js/faker'; -import { getRandomInt } from '../utils/index'; +import { getRandomInt } from '../../utils/index'; export const objSingle = (): Q_Type => { const personName = faker.person.firstName(); diff --git a/apps/api/src/data/js/comments.data.ts b/apps/api/src/data/js/comments.data.ts new file mode 100644 index 0000000..a1035a8 --- /dev/null +++ b/apps/api/src/data/js/comments.data.ts @@ -0,0 +1,69 @@ +import { Q_Type } from '../../types/types.question'; +import { faker } from '@faker-js/faker'; +import { getRandomInt } from '../../utils/index'; + +export const objSingle = (): Q_Type => { + const personName = faker.person.firstName(); + const keyword = "SingleLine"; + const data = { + _QUESTION_LANGUAGE: "Javascript", + _QUESTION_ID: '', + _QUESTION_LEVEL: 1, + _QUESTION_POINTS: 1, + _QUESTION_TASK: `Using ${keyword} comments, comment the statement: Greeting User abouve the console.log('Hello ${personName}') method `, + _QUESTION_DATA: { keyword: keyword, value: personName, returnValue: `console.log('Hello ${personName})` }, + _QUESTION_RESULT: { + 0: { + all:true + }, + 1 : { + answer: `function greetingUser() {// Only change code bellow this line // Greeting User console.log(\'Hello ${personName}\');// Only change code abouve this line}greetingUser()`, + optional: false + } + }, + _QUESTION_HINTS: {}, + _QUESTION_BOILERPLATE: `function greetingUser() {\n// Only change code bellow this line \n\n Greeting User\nconsole.log(\'Hello ${personName}\');\n\n// Only change code abouve this line\n}\n\ngreetingUser()\n`, + _QUESTION_CONDITIONS: {}, + _QUESTION_CONSTRAINTS: {}, + _QUESTION_CATEGORY: 'Comments', + _QUESTION_CATEGORY_SUB: '', + _QUESTION_TAGS: [], + _QUESTION_REFS: { + "javascript.info/comments": "https://javascript.info/comments", + "javascript.info/structure": "https://javascript.info/structure" + } + } + return data; +}; + +export const objMulti = (): Q_Type => { + const personName = faker.person.firstName(); + const keyword = "MultiLine"; + const data = { + _QUESTION_LANGUAGE: "Javascript", + _QUESTION_ID: '', + _QUESTION_LEVEL: 1, + _QUESTION_POINTS: 1, + _QUESTION_TASK: `Using ${keyword} comments, comment the statement: "Hello ${personName}"`, + _QUESTION_DATA: { keyword: keyword, value: personName}, + _QUESTION_RESULT: { + 0: { + all:true + }, + 1 : { + answer: `/** Hello ${personName} */`, + completed: false, + optional: false + } + }, + _QUESTION_HINTS: {}, + _QUESTION_BOILERPLATE: '', + _QUESTION_CONDITIONS: {}, + _QUESTION_CONSTRAINTS: {}, + _QUESTION_CATEGORY: 'Comments', + _QUESTION_CATEGORY_SUB: '', + _QUESTION_TAGS: [], + _QUESTION_REFS: {} + } + return data; +}; diff --git a/apps/api/src/data/var.declare.data.ts b/apps/api/src/data/js/var.declare.data.ts similarity index 97% rename from apps/api/src/data/var.declare.data.ts rename to apps/api/src/data/js/var.declare.data.ts index 07a9151..29191ef 100644 --- a/apps/api/src/data/var.declare.data.ts +++ b/apps/api/src/data/js/var.declare.data.ts @@ -1,6 +1,6 @@ -import { Q_Type } from '../types/types.question'; +import { Q_Type } from '../../types/types.question'; import { faker } from '@faker-js/faker'; -import { getRandomInt } from '../utils/index'; +import { getRandomInt } from '../../utils/index'; export const objRandom = (): Q_Type => { const random = getRandomInt(3); diff --git a/apps/api/src/data/var.scope.data.ts b/apps/api/src/data/js/var.scope.data.ts similarity index 98% rename from apps/api/src/data/var.scope.data.ts rename to apps/api/src/data/js/var.scope.data.ts index 53c20f0..4ff0791 100644 --- a/apps/api/src/data/var.scope.data.ts +++ b/apps/api/src/data/js/var.scope.data.ts @@ -1,4 +1,4 @@ -import { Q_Type } from '../types/types.question'; +import { Q_Type } from '../../types/types.question'; import { faker } from '@faker-js/faker'; export const objGlobalScope = (): Q_Type => { diff --git a/apps/api/src/data/var.scope.reassign.data.ts b/apps/api/src/data/js/var.scope.reassign.data.ts similarity index 96% rename from apps/api/src/data/var.scope.reassign.data.ts rename to apps/api/src/data/js/var.scope.reassign.data.ts index 7776450..83d8e5e 100644 --- a/apps/api/src/data/var.scope.reassign.data.ts +++ b/apps/api/src/data/js/var.scope.reassign.data.ts @@ -1,4 +1,4 @@ -import { Q_Type } from '../types/types.question'; +import { Q_Type } from '../../types/types.question'; import { faker } from '@faker-js/faker'; export const objBlockScopeReassign = (): Q_Type => { diff --git a/apps/api/src/data/py/comments.data.ts b/apps/api/src/data/py/comments.data.ts new file mode 100644 index 0000000..a1035a8 --- /dev/null +++ b/apps/api/src/data/py/comments.data.ts @@ -0,0 +1,69 @@ +import { Q_Type } from '../../types/types.question'; +import { faker } from '@faker-js/faker'; +import { getRandomInt } from '../../utils/index'; + +export const objSingle = (): Q_Type => { + const personName = faker.person.firstName(); + const keyword = "SingleLine"; + const data = { + _QUESTION_LANGUAGE: "Javascript", + _QUESTION_ID: '', + _QUESTION_LEVEL: 1, + _QUESTION_POINTS: 1, + _QUESTION_TASK: `Using ${keyword} comments, comment the statement: Greeting User abouve the console.log('Hello ${personName}') method `, + _QUESTION_DATA: { keyword: keyword, value: personName, returnValue: `console.log('Hello ${personName})` }, + _QUESTION_RESULT: { + 0: { + all:true + }, + 1 : { + answer: `function greetingUser() {// Only change code bellow this line // Greeting User console.log(\'Hello ${personName}\');// Only change code abouve this line}greetingUser()`, + optional: false + } + }, + _QUESTION_HINTS: {}, + _QUESTION_BOILERPLATE: `function greetingUser() {\n// Only change code bellow this line \n\n Greeting User\nconsole.log(\'Hello ${personName}\');\n\n// Only change code abouve this line\n}\n\ngreetingUser()\n`, + _QUESTION_CONDITIONS: {}, + _QUESTION_CONSTRAINTS: {}, + _QUESTION_CATEGORY: 'Comments', + _QUESTION_CATEGORY_SUB: '', + _QUESTION_TAGS: [], + _QUESTION_REFS: { + "javascript.info/comments": "https://javascript.info/comments", + "javascript.info/structure": "https://javascript.info/structure" + } + } + return data; +}; + +export const objMulti = (): Q_Type => { + const personName = faker.person.firstName(); + const keyword = "MultiLine"; + const data = { + _QUESTION_LANGUAGE: "Javascript", + _QUESTION_ID: '', + _QUESTION_LEVEL: 1, + _QUESTION_POINTS: 1, + _QUESTION_TASK: `Using ${keyword} comments, comment the statement: "Hello ${personName}"`, + _QUESTION_DATA: { keyword: keyword, value: personName}, + _QUESTION_RESULT: { + 0: { + all:true + }, + 1 : { + answer: `/** Hello ${personName} */`, + completed: false, + optional: false + } + }, + _QUESTION_HINTS: {}, + _QUESTION_BOILERPLATE: '', + _QUESTION_CONDITIONS: {}, + _QUESTION_CONSTRAINTS: {}, + _QUESTION_CATEGORY: 'Comments', + _QUESTION_CATEGORY_SUB: '', + _QUESTION_TAGS: [], + _QUESTION_REFS: {} + } + return data; +}; diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 4bb7da9..44e52ef 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -2,12 +2,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import App from './server'; import Index from './controllers/index.controller'; -import Guest_Routes from './controllers/guest/guest.controller'; -import Comments from './controllers/comments/comments.controller'; -import VarGeneral from './controllers/variables/var.controller'; -import VarDeclare from './controllers/variables/var.declare.controller'; -import VarScope from './controllers/variables/var.scope.controller'; -import VarScopeReassign from './controllers/variables/var.scope.reassign.controller'; +import Guest_Routes from './controllers/auth/guest/guest.controller'; +import Comments from './controllers/data/comments/comments.controller'; +import VarGeneral from './controllers/data/variables/var.controller'; +import VarDeclare from './controllers/data/variables/var.declare.controller'; +import VarScope from './controllers/data/variables/var.scope.controller'; +import VarScopeReassign from './controllers/data/variables/var.scope.reassign.controller'; const app = new App( [], From 12a707d4cda26b5854d72e131206ec20652a04b5 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:41:57 -0400 Subject: [PATCH 09/12] added java and python routes --- apps/api/src/constants/java.routes.ts | 10 ++++++++++ ...egories.routes.ts => javascript.routes.ts} | 2 +- apps/api/src/constants/python.routes.ts | 10 ++++++++++ apps/api/src/controllers/index.controller.ts | 19 +++++++++++++++---- 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 apps/api/src/constants/java.routes.ts rename apps/api/src/constants/{categories.routes.ts => javascript.routes.ts} (93%) create mode 100644 apps/api/src/constants/python.routes.ts diff --git a/apps/api/src/constants/java.routes.ts b/apps/api/src/constants/java.routes.ts new file mode 100644 index 0000000..396f79b --- /dev/null +++ b/apps/api/src/constants/java.routes.ts @@ -0,0 +1,10 @@ +export const _ROUTES_JAVA = [ + { + "id": 1, + "category": ["comments", "comments/all"], + "subCategories": { + "singleLine": ['comments/single/all'], + "multiLine": ['comments/multi/all'], + }, + }, +] diff --git a/apps/api/src/constants/categories.routes.ts b/apps/api/src/constants/javascript.routes.ts similarity index 93% rename from apps/api/src/constants/categories.routes.ts rename to apps/api/src/constants/javascript.routes.ts index 03aa82d..3e3a63e 100644 --- a/apps/api/src/constants/categories.routes.ts +++ b/apps/api/src/constants/javascript.routes.ts @@ -1,4 +1,4 @@ -export const ROUTES = [ +export const _ROUTES_JAVASCRIPT = [ { "id": 1, "category": ["comments", "comments/all"], diff --git a/apps/api/src/constants/python.routes.ts b/apps/api/src/constants/python.routes.ts new file mode 100644 index 0000000..5ea5096 --- /dev/null +++ b/apps/api/src/constants/python.routes.ts @@ -0,0 +1,10 @@ +export const _ROUTES_PYTHON = [ + { + "id": 1, + "category": ["comments", "comments/all"], + "subCategories": { + "singleLine": ['comments/single/all'], + "multiLine": ['comments/multi/all'], + }, + }, +] diff --git a/apps/api/src/controllers/index.controller.ts b/apps/api/src/controllers/index.controller.ts index edd790a..3058b8b 100644 --- a/apps/api/src/controllers/index.controller.ts +++ b/apps/api/src/controllers/index.controller.ts @@ -1,10 +1,12 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { ROUTES } from '../constants/categories.routes' +import { _ROUTES_JAVASCRIPT } from '../constants/javascript.routes'; +import { _ROUTES_JAVA } from '../constants/java.routes'; +import { _ROUTES_PYTHON } from '../constants/python.routes'; class Index { public path = '/'; - public pathCategories = '/categories'; + public pathCategories = '/categories/:id'; public router = Router(); constructor() { this.initializeRoutes(); @@ -33,8 +35,17 @@ class Index { public categories = async (req: Request, res: Response) => { switch(req.method) { case('GET'): - try { - res.status(200).send({ data: ROUTES }); + try { + switch(req.params.id) { + case('javascript'): + return res.status(200).send({ data: _ROUTES_JAVASCRIPT }); + case('java'): + return res.status(200).send({ data: _ROUTES_JAVA }); + case('python'): + return res.status(200).send({ data: _ROUTES_PYTHON }); + default: + return res.status(200).send({ data: _ROUTES_JAVASCRIPT }); + } } catch { res.status(500).send({ error: "Something went wrong" }); } From 06403e049b4039ce95ee9c232197088b696dff2f Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:31:28 -0400 Subject: [PATCH 10/12] added java and python questions and routes --- .../constants/{ => categories}/java.routes.ts | 0 .../{ => categories}/javascript.routes.ts | 0 .../{ => categories}/python.routes.ts | 0 apps/api/src/constants/languages.ts | 5 + .../data/comments/comments.controller.ts | 63 ++++- .../variables/var.controller.ts | 77 +++--- .../variables/var.declare.controller.ts | 38 +-- .../variables/var.scope.controller.ts | 36 ++- .../var.scope.reassign.controller.ts | 16 +- apps/api/src/controllers/index.controller.ts | 29 +- .../{comments.data.ts => java.comments.ts} | 0 .../javascript.comments.ts} | 2 +- .../javascript.var.declare.ts} | 0 .../javascript.var.scope.reassign.ts} | 0 .../javascript.var.scope.ts} | 0 .../python.comments.ts} | 2 +- apps/api/src/index.ts | 8 +- apps/web/src/components/dashboard/D_Route.tsx | 83 ++++-- .../dashboard-categories/D_Category_Menu.tsx | 253 +++++++++++++++--- .../dashboard/dashboard-code/D_Editor.tsx | 23 +- .../dashboard/dashboard-code/D_Problem.tsx | 23 +- apps/web/src/components/dashboard/loading.tsx | 81 +++--- apps/web/src/layout/Layout.D_Categories.tsx | 51 ++-- apps/web/src/layout/Layout.D_Code.tsx | 27 +- apps/web/src/redux/slices/dashboardSlice.ts | 11 +- apps/web/src/redux/store.ts | 7 +- apps/web/src/utils/constants.ts | 13 +- 27 files changed, 595 insertions(+), 253 deletions(-) rename apps/api/src/constants/{ => categories}/java.routes.ts (100%) rename apps/api/src/constants/{ => categories}/javascript.routes.ts (100%) rename apps/api/src/constants/{ => categories}/python.routes.ts (100%) create mode 100644 apps/api/src/constants/languages.ts rename apps/api/src/controllers/data/{ => javascript}/variables/var.controller.ts (71%) rename apps/api/src/controllers/data/{ => javascript}/variables/var.declare.controller.ts (68%) rename apps/api/src/controllers/data/{ => javascript}/variables/var.scope.controller.ts (69%) rename apps/api/src/controllers/data/{ => javascript}/variables/var.scope.reassign.controller.ts (61%) rename apps/api/src/data/java/{comments.data.ts => java.comments.ts} (100%) rename apps/api/src/data/{py/comments.data.ts => javascript/javascript.comments.ts} (96%) rename apps/api/src/data/{js/var.declare.data.ts => javascript/javascript.var.declare.ts} (100%) rename apps/api/src/data/{js/var.scope.reassign.data.ts => javascript/javascript.var.scope.reassign.ts} (100%) rename apps/api/src/data/{js/var.scope.data.ts => javascript/javascript.var.scope.ts} (100%) rename apps/api/src/data/{js/comments.data.ts => python/python.comments.ts} (98%) diff --git a/apps/api/src/constants/java.routes.ts b/apps/api/src/constants/categories/java.routes.ts similarity index 100% rename from apps/api/src/constants/java.routes.ts rename to apps/api/src/constants/categories/java.routes.ts diff --git a/apps/api/src/constants/javascript.routes.ts b/apps/api/src/constants/categories/javascript.routes.ts similarity index 100% rename from apps/api/src/constants/javascript.routes.ts rename to apps/api/src/constants/categories/javascript.routes.ts diff --git a/apps/api/src/constants/python.routes.ts b/apps/api/src/constants/categories/python.routes.ts similarity index 100% rename from apps/api/src/constants/python.routes.ts rename to apps/api/src/constants/categories/python.routes.ts diff --git a/apps/api/src/constants/languages.ts b/apps/api/src/constants/languages.ts new file mode 100644 index 0000000..8c3f73a --- /dev/null +++ b/apps/api/src/constants/languages.ts @@ -0,0 +1,5 @@ +export const _LANGUAGES = [ + 'javascript', + 'java', + 'python' +] diff --git a/apps/api/src/controllers/data/comments/comments.controller.ts b/apps/api/src/controllers/data/comments/comments.controller.ts index b020524..b4cd687 100644 --- a/apps/api/src/controllers/data/comments/comments.controller.ts +++ b/apps/api/src/controllers/data/comments/comments.controller.ts @@ -5,12 +5,14 @@ import client from '../../../config/db'; import { Question } from '../../../classes/question'; import { Q_Type } from '../../../types/types.question'; import { getRandomInt } from '../../../utils/index'; -import { objSingle, objMulti } from '../../../data/js/comments.data'; +import { objSingle as objSingleJs, objMulti as objMultiJs } from '../../../data/javascript/javascript.comments'; +import { objSingle as objSingleJava, objMulti as objMultiJava } from '../../../data/java/java.comments'; +import { objSingle as objSinglePy, objMulti as objMultiPy } from '../../../data/python/python.comments'; export default class VarDeclare { - public pathCommentsRandom = '/comments/all'; - public pathCommentsSingle = '/comments/single/all'; - public pathCommentsMulti = '/comments/multi/all'; + public pathCommentsRandom = '/:id/comments/all'; + public pathCommentsSingle = '/:id/comments/single/all'; + public pathCommentsMulti = '/:id/comments/multi/all'; public router = Router(); constructor() { this.initializeRoutes(); @@ -23,9 +25,28 @@ export default class VarDeclare { } public commentsRandom = async (req: Request, res: Response) => { - const dataSingle = objSingle(); + let dataSingle + let dataMulti + + switch(req.params.id.toLowerCase()) { + case("javascript"): + dataSingle = objSingleJs(); + dataMulti = objMultiJs(); + break + case("java"): + dataSingle = objSingleJava(); + dataMulti = objMultiJava(); + break + case("python"): + dataSingle = objSinglePy(); + dataMulti = objMultiPy(); + break + default: + dataSingle = objSingleJs(); + dataMulti = objMultiJs(); + } + const questionSingle = new Question(dataSingle); - const dataMulti = objMulti(); const questionMulti = new Question(dataMulti); const random = getRandomInt(2); @@ -45,7 +66,20 @@ export default class VarDeclare { }; public commentsSingle = async (req: Request, res: Response) => { - const data = objSingle(); + let data; + switch(req.params.id.toLowerCase()) { + case("javascript"): + data = objSingleJs(); + break + case("java"): + data = objSingleJava(); + break + case("python"): + data = objSinglePy(); + break + default: + data = objSingleJs(); + } const question = new Question(data); switch(req.method) { case('GET'): @@ -61,7 +95,20 @@ export default class VarDeclare { }; public commentsMulti = async (req: Request, res: Response) => { - const data = objMulti(); + let data; + switch(req.params.id.toLowerCase()) { + case("javascript"): + data = objMultiJs(); + break + case("java"): + data = objMultiJava(); + break + case("python"): + data = objMultiPy(); + break + default: + data = objMultiJs(); + } const question = new Question(data); switch(req.method) { case('GET'): diff --git a/apps/api/src/controllers/data/variables/var.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.controller.ts similarity index 71% rename from apps/api/src/controllers/data/variables/var.controller.ts rename to apps/api/src/controllers/data/javascript/variables/var.controller.ts index d0bd0ec..fb12bac 100644 --- a/apps/api/src/controllers/data/variables/var.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.controller.ts @@ -1,29 +1,29 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import sql from '../../../config/db'; +import sql from '../../../../config/db'; import { faker } from '@faker-js/faker'; -import { Question } from '../../../classes/question'; -import { Q_Type } from '../../../types/types.question'; -import { getRandomInt } from '../../../utils/index'; -import { objRandom as objDeclare } from '../../../data/js/var.declare.data'; -import { objGlobalScope, objFuncScope, objBlockScope } from '../../../data/js/var.scope.data'; -import { objBlockScopeReassign } from '../../../data/js/var.scope.reassign.data'; +import { Question } from '../../../../classes/question'; +import { Q_Type } from '../../../../types/types.question'; +import { getRandomInt } from '../../../../utils/index'; +import { objRandom as objDeclare } from '../../../../data/javascript/javascript.var.declare'; +import { objGlobalScope, objFuncScope, objBlockScope } from '../../../../data/javascript/javascript.var.scope'; +import { objBlockScopeReassign } from '../../../../data/javascript/javascript.var.scope.reassign'; import cors from 'cors'; export default class VarGeneral { /**Public: Get random var */ - public pathRandom = '/var/all'; + public pathRandom = '/:id/var/all'; /**Public: Get All Var Category Questions*/ - public pathVar = '/var'; + public pathVar = '/:id/var'; /**Public: Get Var Category Question by ID*/ - public pathVarId = '/var/get/:id'; + public pathVarId = '/:id/var/get/:id'; /**Private: Create Var Question*/ - public pathVarNew = '/var/new'; + public pathVarNew = '/:id/var/new'; /**Private: Update Var Question*/ - public pathVarUpdate = '/var/update/:id'; + public pathVarUpdate = '/:id/var/update/:id'; /**Private: Delete Var Question';*/ - public pathVarDelete = '/var/delete/:id'; + public pathVarDelete = '/:id/var/delete/:id'; /**Express Router */ public router = Router(); /**Cors Options*/ @@ -59,7 +59,9 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: varRandom }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: varRandom }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -73,9 +75,12 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - const id = req.params.id; - const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTIONS_CATEGORY = 'variables'`; - return res.status(200).send({ data: results }); + if(req.params.id.toLowerCase() === 'javascript') { + const id = req.params.id; + const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTIONS_CATEGORY = 'variables'`; + + return res.status(200).send({ data: results }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -89,9 +94,12 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - const id = req.params.id; - const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; - return res.status(200).send({ data: results }); + if(req.params.id.toLowerCase() === 'javascript') { + const id = req.params.id; + const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; + + return res.status(200).send({ data: results }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -105,9 +113,12 @@ export default class VarGeneral { switch(req.method) { case('UPDATE'): try { - const id = req.params.id; - const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; - return res.status(200); + if(req.params.id.toLowerCase() === 'javascript') { + const id = req.params.id; + const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; + + return res.status(200); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -121,9 +132,10 @@ export default class VarGeneral { switch(req.method) { case('POST'): try { - const data: Q_Type = req.body; - const question = new Question(data); - const results = await sql`INSERT INTO _QUESTIONS ( + if(req.params.id.toLowerCase() === 'javascript') { + const data: Q_Type = req.body; + const question = new Question(data); + const results = await sql`INSERT INTO _QUESTIONS ( _QUESTION_CREATED_AT, _QUESTION_UPDATED_AT, _QUESTION_ID, @@ -160,7 +172,9 @@ export default class VarGeneral { ${question._QUESTION_TAGS}, ${question._QUESTION_REFS} )`; - return res.status(200); + + return res.status(200); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -174,9 +188,12 @@ export default class VarGeneral { switch(req.method) { case('DELETE'): try { - const id = req.params.id; - const results = await sql`DELETE * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; - return res.status(200); + if(req.params.id.toLowerCase() === 'javascript') { + const id = req.params.id; + const results = await sql`DELETE * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; + + return res.status(200); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/variables/var.declare.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts similarity index 68% rename from apps/api/src/controllers/data/variables/var.declare.controller.ts rename to apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts index 2ff0125..10e59d0 100644 --- a/apps/api/src/controllers/data/variables/var.declare.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts @@ -1,17 +1,17 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../../config/db'; -import { Question } from '../../../classes/question'; -import { Q_Type } from '../../../types/types.question'; -import { getRandomInt } from '../../../utils/index'; -import { objRandom, objRandomVar, objRandomConst, objRandomLet } from '../../../data/js/var.declare.data' +import client from '../../../../config/db'; +import { Question } from '../../../../classes/question'; +import { Q_Type } from '../../../../types/types.question'; +import { getRandomInt } from '../../../../utils/index'; +import { objRandom, objRandomVar, objRandomConst, objRandomLet } from '../../../../data/javascript/javascript.var.declare' export default class VarDeclare { - public pathVarRandomDeclare = '/var/declare/all' - public pathVarDeclareVar = '/var/declare/var'; - public pathVarDeclareConst = '/var/declare/const'; - public pathVarDeclareLet = '/var/declare/let'; + public pathVarRandomDeclare = '/:id/var/declare/all' + public pathVarDeclareVar = '/:id/var/declare/var'; + public pathVarDeclareConst = '/:id/var/declare/const'; + public pathVarDeclareLet = '/:id/var/declare/let'; public router = Router(); constructor() { this.initializeRoutes(); @@ -30,7 +30,9 @@ export default class VarDeclare { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -45,8 +47,10 @@ export default class VarDeclare { const question: Q_Type = new Question(data); switch(req.method) { case('GET'): - try { - return res.status(200).send({ data: question }); + try { + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -62,7 +66,9 @@ export default class VarDeclare { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -77,8 +83,10 @@ export default class VarDeclare { const question: Q_Type = new Question(data); switch(req.method) { case('GET'): - try { - return res.status(200).send({ data: question }); + try { + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/variables/var.scope.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts similarity index 69% rename from apps/api/src/controllers/data/variables/var.scope.controller.ts rename to apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts index 5356987..5ca57fa 100644 --- a/apps/api/src/controllers/data/variables/var.scope.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts @@ -1,17 +1,17 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../../config/db'; -import { Question } from '../../../classes/question'; -import { Q_Type } from '../../../types/types.question'; -import { getRandomInt } from '../../../utils/index'; -import { objBlockScope, objFuncScope, objGlobalScope } from '../../../data/js/var.scope.data'; +import client from '../../../../config/db'; +import { Question } from '../../../../classes/question'; +import { Q_Type } from '../../../../types/types.question'; +import { getRandomInt } from '../../../../utils/index'; +import { objBlockScope, objFuncScope, objGlobalScope } from '../../../../data/javascript/javascript.var.scope'; export default class VarScope { - public pathVarRandomScope = '/var/scope/all'; - public pathVarScopeBlock = '/var/scope/block'; - public pathVarScopeFunc = '/var/scope/func'; - public pathVarScopeGlobal = '/var/scope/global'; + public pathVarRandomScope = '/:id/var/scope/all'; + public pathVarScopeBlock = '/:id/var/scope/block'; + public pathVarScopeFunc = '/:id/var/scope/func'; + public pathVarScopeGlobal = '/:id/var/scope/global'; public router = Router(); constructor() { this.initializeRoutes(); @@ -31,7 +31,9 @@ export default class VarScope { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -47,7 +49,9 @@ export default class VarScope { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -58,12 +62,14 @@ export default class VarScope { }; public varFuncScope = async (req: Request, res: Response) => { - const obj =objFuncScope(); + const obj = objFuncScope(); const question = new Question(obj); switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -79,7 +85,9 @@ export default class VarScope { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts similarity index 61% rename from apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts rename to apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts index f0dd6a0..561a7fb 100644 --- a/apps/api/src/controllers/data/variables/var.scope.reassign.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts @@ -1,14 +1,14 @@ 'use strict'; import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import client from '../../../config/db'; -import { Question } from '../../../classes/question'; -import { Q_Type } from '../../../types/types.question'; -import { getRandomInt } from '../../../utils/index'; -import { objBlockScopeReassign } from '../../../data/js/var.scope.reassign.data'; +import client from '../../../../config/db'; +import { Question } from '../../../../classes/question'; +import { Q_Type } from '../../../../types/types.question'; +import { getRandomInt } from '../../../../utils/index'; +import { objBlockScopeReassign } from '../../../../data/javascript/javascript.var.scope.reassign'; export default class VarScopeReassign { - public pathVarReassignBlock = '/var/scope/reassign/block'; + public pathVarReassignBlock = '/:id/var/scope/reassign/block'; public router = Router(); constructor() { this.initializeRoutes(); @@ -24,7 +24,9 @@ export default class VarScopeReassign { switch(req.method) { case('GET'): try { - return res.status(200).send({ data: question }); + if(req.params.id.toLowerCase() === 'javascript') { + return res.status(200).send({ data: question }); + } } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/index.controller.ts b/apps/api/src/controllers/index.controller.ts index 3058b8b..3ec807f 100644 --- a/apps/api/src/controllers/index.controller.ts +++ b/apps/api/src/controllers/index.controller.ts @@ -1,11 +1,14 @@ import { Request, Response } from 'express'; import Router from 'express-promise-router'; -import { _ROUTES_JAVASCRIPT } from '../constants/javascript.routes'; -import { _ROUTES_JAVA } from '../constants/java.routes'; -import { _ROUTES_PYTHON } from '../constants/python.routes'; +import { _ROUTES_JAVASCRIPT } from '../constants/categories/javascript.routes'; +import { _ROUTES_JAVA } from '../constants/categories/java.routes'; +import { _ROUTES_PYTHON } from '../constants/categories/python.routes'; +import { _LANGUAGES } from '../constants/languages'; class Index { public path = '/'; + public pathLanguages = '/languages'; + public pathCategories = '/categories/:id'; public router = Router(); constructor() { @@ -14,6 +17,7 @@ class Index { public initializeRoutes() { this.router.get(this.path, this.helloWorld); + this.router.get(this.pathLanguages, this.languages); this.router.get(this.pathCategories, this.categories); } @@ -32,11 +36,26 @@ class Index { }; }; + public languages = async (req: Request, res: Response) => { + switch(req.method) { + case('GET'): + try { + const languages = _LANGUAGES + return await res.status(200).send({ data: languages }); + } catch { + res.status(500).send({ error: "Something went wrong" }); + } + break + default: + res.status(400).send({ error: `${req.method} Method Not Allowed` }); + } + }; + public categories = async (req: Request, res: Response) => { switch(req.method) { case('GET'): try { - switch(req.params.id) { + switch(req.params.id.toLowerCase()) { case('javascript'): return res.status(200).send({ data: _ROUTES_JAVASCRIPT }); case('java'): @@ -47,7 +66,7 @@ class Index { return res.status(200).send({ data: _ROUTES_JAVASCRIPT }); } } catch { - res.status(500).send({ error: "Something went wrong" }); + res.status(500).send({ error: "route not found" }); } break default: diff --git a/apps/api/src/data/java/comments.data.ts b/apps/api/src/data/java/java.comments.ts similarity index 100% rename from apps/api/src/data/java/comments.data.ts rename to apps/api/src/data/java/java.comments.ts diff --git a/apps/api/src/data/py/comments.data.ts b/apps/api/src/data/javascript/javascript.comments.ts similarity index 96% rename from apps/api/src/data/py/comments.data.ts rename to apps/api/src/data/javascript/javascript.comments.ts index a1035a8..cce6852 100644 --- a/apps/api/src/data/py/comments.data.ts +++ b/apps/api/src/data/javascript/javascript.comments.ts @@ -10,7 +10,7 @@ export const objSingle = (): Q_Type => { _QUESTION_ID: '', _QUESTION_LEVEL: 1, _QUESTION_POINTS: 1, - _QUESTION_TASK: `Using ${keyword} comments, comment the statement: Greeting User abouve the console.log('Hello ${personName}') method `, + _QUESTION_TASK: `Using ${keyword} comments, comment the statement: 'Greeting User' abouve the console.log('Hello ${personName}') method `, _QUESTION_DATA: { keyword: keyword, value: personName, returnValue: `console.log('Hello ${personName})` }, _QUESTION_RESULT: { 0: { diff --git a/apps/api/src/data/js/var.declare.data.ts b/apps/api/src/data/javascript/javascript.var.declare.ts similarity index 100% rename from apps/api/src/data/js/var.declare.data.ts rename to apps/api/src/data/javascript/javascript.var.declare.ts diff --git a/apps/api/src/data/js/var.scope.reassign.data.ts b/apps/api/src/data/javascript/javascript.var.scope.reassign.ts similarity index 100% rename from apps/api/src/data/js/var.scope.reassign.data.ts rename to apps/api/src/data/javascript/javascript.var.scope.reassign.ts diff --git a/apps/api/src/data/js/var.scope.data.ts b/apps/api/src/data/javascript/javascript.var.scope.ts similarity index 100% rename from apps/api/src/data/js/var.scope.data.ts rename to apps/api/src/data/javascript/javascript.var.scope.ts diff --git a/apps/api/src/data/js/comments.data.ts b/apps/api/src/data/python/python.comments.ts similarity index 98% rename from apps/api/src/data/js/comments.data.ts rename to apps/api/src/data/python/python.comments.ts index a1035a8..5c20559 100644 --- a/apps/api/src/data/js/comments.data.ts +++ b/apps/api/src/data/python/python.comments.ts @@ -6,7 +6,7 @@ export const objSingle = (): Q_Type => { const personName = faker.person.firstName(); const keyword = "SingleLine"; const data = { - _QUESTION_LANGUAGE: "Javascript", + _QUESTION_LANGUAGE: "Python", _QUESTION_ID: '', _QUESTION_LEVEL: 1, _QUESTION_POINTS: 1, diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 44e52ef..b2e8e3f 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -4,10 +4,10 @@ import App from './server'; import Index from './controllers/index.controller'; import Guest_Routes from './controllers/auth/guest/guest.controller'; import Comments from './controllers/data/comments/comments.controller'; -import VarGeneral from './controllers/data/variables/var.controller'; -import VarDeclare from './controllers/data/variables/var.declare.controller'; -import VarScope from './controllers/data/variables/var.scope.controller'; -import VarScopeReassign from './controllers/data/variables/var.scope.reassign.controller'; +import VarGeneral from './controllers/data/javascript/variables/var.controller'; +import VarDeclare from './controllers/data/javascript/variables/var.declare.controller'; +import VarScope from './controllers/data/javascript/variables/var.scope.controller'; +import VarScopeReassign from './controllers/data/javascript/variables/var.scope.reassign.controller'; const app = new App( [], diff --git a/apps/web/src/components/dashboard/D_Route.tsx b/apps/web/src/components/dashboard/D_Route.tsx index e2d4200..a3a3828 100644 --- a/apps/web/src/components/dashboard/D_Route.tsx +++ b/apps/web/src/components/dashboard/D_Route.tsx @@ -1,16 +1,17 @@ -import { useContext } from 'react'; +import { useContext, useState } from 'react'; import { ThemeContext } from '../../context/ThemeContext'; -import JS_Icon from "../../assets/tech/javascript/javascript-original.svg"; // hooks import useWindowSize from '../../hooks/useWindowSize'; // redux hooks import { useAppSelector } from '../../redux/reduxHooks.ts'; import type { RootState } from '../../redux/store.ts'; -// icons -import { IconSearch } from '@tabler/icons-react'; import { IconArrowBadgeRightFilled } from '@tabler/icons-react'; +/** Custom State Components*/ +import { LoadingDashboardXS } from '../../components/dashboard/loading'; +/**Constants */ +import { _LANGUAGES_ALL } from "../../utils/constants"; const D_Header = () => { const { state } = useContext(ThemeContext); @@ -20,44 +21,70 @@ const D_Header = () => { const routeEmpty = menuItem.length === 0; const routeArr = menuItem.split('/').filter(route => route !== 'random'); + /**Loading Screen */ + const [loading, setLoading] = useState(true); + + setTimeout(() => { + setLoading(false) + }, "600"); + + /**Language Menu */ + const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); + const transformLanguage = getMenuLanguage[0].toUpperCase() + getMenuLanguage.slice(1).toLowerCase(); + //console.log("transformLanguage", transformLanguage); + const picture = _LANGUAGES_ALL[getMenuLanguage.toLowerCase()]; + //console.log(picture); + + if(loading) { + return ( +
*]:tw-bg-neutral-700/50' : '[&>*]:tw-bg-neutral-300/50'} + tw-text-transparent tw-flex tw-flex-col tw-w-full tw-h-full tw-place-self-center tw-place-content-center tw-place-items-center`}> + +
+ ) + } + return ( {isMobile ?
      -
    • Javascript
    • +
    • + {transformLanguage} +
    • {!routeEmpty ? routeArr.map((route, i) => -
    • +
    • - { darkMode ? - : + { darkMode ? + + : + } {route}
    • - ) :
      Javascript
      } + ) :
      {transformLanguage}
      }
: -
    -
      -
    • Javascript
    • -
    • Javascript
    • - {!routeEmpty ? routeArr.map((route, i) => -
    • - - { darkMode ? - : - } - - {route} -
    • - ) :
      } -
    -
      -
    • { darkMode ? : }
    • -
    -
+
    +
  • + {transformLanguage} +
  • +
  • + {transformLanguage} +
  • + {!routeEmpty ? routeArr.map((route, i) => +
  • + + { darkMode ? + : + } + + {route} +
  • + ) :
    } +
}
) diff --git a/apps/web/src/components/dashboard/dashboard-categories/D_Category_Menu.tsx b/apps/web/src/components/dashboard/dashboard-categories/D_Category_Menu.tsx index 74c60f3..361d3b2 100644 --- a/apps/web/src/components/dashboard/dashboard-categories/D_Category_Menu.tsx +++ b/apps/web/src/components/dashboard/dashboard-categories/D_Category_Menu.tsx @@ -1,70 +1,232 @@ // Categories -import { useContext } from 'react' +import { useContext, useState, useRef, useCallback, useEffect } from 'react' import { ThemeContext } from '../../../context/ThemeContext' // hooks import Transition from '../../../hooks/useTransition'; -//import useWindowSize from '../../../hooks/useWindowSize'; +import useWindowSize from '../../../hooks/useWindowSize'; +import { LoadingDashboardMD } from '../loading'; // components import D_Category_Menu_Items from '../../../components/dashboard/dashboard-categories/D_Category_Menu_Items'; // import D_Languages from '../../../components/dashboard/dashboard-categories/D_Languages'; /** React Redux Hooks */ import { useAppSelector, useAppDispatch } from '../../../redux/reduxHooks.ts'; -import { - menuLanguage, +import type { RootState } from '../../../redux/store.ts'; +import { + menuLanguages, + menuLanguage, + menuCategoryInfo } from '../../../redux/slices/dashboardSlice.ts'; /** Icons */ -import JS_Icon from "../../../assets/tech/javascript/javascript-original.svg"; -//import JAVA_Icon from "../../../assets/tech/java/java-original.svg"; -//import PY_Icon from "../../../assets/tech/python/python-original.svg"; import { IconArrowBadgeDown } from '@tabler/icons-react'; +/**Constants */ +import { _LANGUAGES_ALL } from "../../../utils/constants"; +/**React Query */ +import { useQuery } from "@tanstack/react-query"; +/** API url | Custom env mandatory to begin with VITE + * https://vitejs.dev/guide/env-and-mode.html#env-files */ +const baseURL = import.meta.env.VITE_API_BASE_URL; -const D_Category_Menu = ({data}) => { +const filterLanguages = (userLanguages) => { + if( userLanguages === undefined || + userLanguages.length === 0) { + return ['Javascript'] + } else { + //console.log("userLanguages", userLanguages); + const filtered = {} + const languages = Object.assign(filtered, _LANGUAGES_ALL); + //console.log("pre-filtered:", filtered); + const languagesKeys = Object.keys(filtered); + //console.log("langkeys:", languagesKeys) + languagesKeys.map((language) => { + //console.log("language", language) + const filter = userLanguages.includes(language.toLowerCase()) + if(!filter) { + delete languages[language.toLowerCase()] + } + }); + //console.log("filtered:", languages) + return languages + } +} + +const D_Category_Menu = ({menuData}) => { /** Custom Hooks */ - //const { isDesktopMDXL, isDesktopXL } = useWindowSize(); + const { isMobile } = useWindowSize(); const { state } = useContext(ThemeContext); const darkMode = state.darkMode; const dispatch = useAppDispatch(); /** Retrieve Category From Redux State */ + const getMenuLanguages = useAppSelector((state:RootState) => state?.dashboard?.languages); + //console.log("getMenuLanguages", getMenuLanguages); const getMenuLanguageDefault = useAppSelector((state:RootState) => state?.dashboard?.languageDefault); const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); + const getMenuCategory = useAppSelector((state:RootState) => state?.dashboard?.category); + const getMenuCategoryInfo = useAppSelector((state:RootState) => state?.dashboard?.categoryInfo); + //const getMenuUser = useAppSelector((state:RootState) => state?.dashboard?.user); + const [languages, setLanguages] = useState(getMenuLanguages); + + /**Desktop Dropdown Menu */ + const [ menuDropdown, setMenuDropdown] = useState(false); + + function toggleMenuDropdown(e) { + e.preventDefault(); + setMenuDropdown(!menuDropdown); + //console.log(menuDropdown) + }; + + const ref = useRef(); + + useEffect(() => { + const checkIfClickedOutside = e => { + // If the menu is open and the clicked target is not within the menu, + // then close the menu + if (menuDropdown && ref.current && !ref.current.contains(e.target)) { + setMenuDropdown(!menuDropdown) + } + } + + document.addEventListener("mousedown", checkIfClickedOutside) + + return () => { + // Cleanup the event listener + document.removeEventListener("mousedown", checkIfClickedOutside) + } + }, [menuDropdown]); + + /** Retrieve Available Languages */ + const getLanguages = useCallback( async () => { + /** Retrieve Languages from API */ + try { + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/languages`; + } else { + url = `/api/languages`; + } + await fetch(url, { + method: 'GET', + headers: { + 'Accept' : 'application/json', + 'Content-Type': 'application/json', + }, + }).then( (res) => { + let response + if(res.ok) { + response = res.json() + //console.log(resJSON); + return response + } else { + response = {data: [getMenuLanguageDefault]} + return response + } + }).then((res) => { + //console.log("res.data", res.data) + if(res.data !== undefined) { + dispatch(menuLanguages(res.data)); + } + return res.data + }) + } catch(e) { + console.log(e); + } + },[dispatch, getMenuLanguageDefault]); + + useEffect(() => { + getLanguages(); + },[getLanguages]); + - async function setLanguage() { - if(getMenuLanguage === undefined || getMenuLanguage === '') { - dispatch(menuLanguage(getMenuLanguageDefault)); + useEffect(() => { + const result = filterLanguages(getMenuLanguages ); + if( result !== undefined ) { + setLanguages(result); } + },[getMenuLanguages]); + + const getCategories = async () => { + try { + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/categories/${getMenuLanguage}`; + } else { + url = `/api/categories/${getMenuLanguage}`; + } + const res = await fetch(url, { + method: 'GET', + headers: { + 'Accept' : 'application/json', + 'Content-Type': 'application/json', + }, + }); + const resJSON = res.json(); + return resJSON; + } catch(error) { + console.log(error); + } + }; + + /** Generate Categories */ + const { + data, + refetch, + } = useQuery({ + queryKey: ['categoriesData'], + queryFn: getCategories, + refetchOnWindowFocus: false, + staleTime: 100 * (60 * 1000), + cacheTime: 0, + }); + + /**Update categories */ + const refetchData = async (getLanguage) => { + //console.log(getLanguage) + await dispatch(menuLanguage(getLanguage)); + await refetch(); } - const categories = data.data; + useEffect(() => { + if(data !== undefined) { + //const results = data?.data; + let results; + data?.data.find((item) => { + if(item.category[0] === getMenuCategory) { + results = item; + } + }); + //console.log("results", results) + dispatch(menuCategoryInfo(results)) + } + },[data, dispatch, getMenuCategory, getMenuCategoryInfo]); + + /**Category Route */ + const categories = menuData.data; + + /**Language Menu */ + const transformLanguage = getMenuLanguage[0].toUpperCase() + getMenuLanguage.slice(1).toLowerCase(); + //console.log("transformLanguage", transformLanguage); + const picture = _LANGUAGES_ALL[getMenuLanguage.toLowerCase()]; + //console.log(picture); + + if(getMenuLanguage === undefined) { + return + } return ( -
+
-
+

+ tw-font-space_mono tw-justify-items-start tw-flex tw-flex-row `}> Language:
-

+ {menuDropdown && +
+
    + {Object.entries(languages).map(([key, value], index) => { + return ( +
  • + key + +
  • + ) + })} +
+
+ }
+ tw-text-lg tw-h-[36px] tw-w-full tw-pl-2 tw-font-space_mono tw-z-40 tw-relative`}> Categories: 
-
    +
      { categories !== undefined && categories.map((category, i) => { return (
    • ) diff --git a/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx b/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx index 527158d..d50e45b 100644 --- a/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx +++ b/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx @@ -40,27 +40,28 @@ const D_Editor = () => { /** Retrieve Category Route From Redux State */ const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); + const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); /** Retrieve Category Based Question */ const getQuestion = useCallback( async () => { /** Retrieve Question from API */ try { let res; - const prodURL = `${baseURL}/${getMenuRoute}`; - const devURL = `/api/${getMenuRoute}`; + const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; + const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + res = await fetch(prodURL); + const resJSON = res.json(); + return resJSON; + } else { + res = await fetch(devURL); + const resJSON = res.json(); + return resJSON; + } } catch(error) { console.log(error); } - }, [getMenuRoute]); + }, [getMenuLanguage, getMenuRoute]); /** Generate Question */ const { isSuccess, data } = useQuery({ diff --git a/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx b/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx index a075c8f..9870e7c 100644 --- a/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx +++ b/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx @@ -25,27 +25,28 @@ const D_Problem = () => { /** Retrieve Category From Redux State */ const dispatch = useAppDispatch(); const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); + const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); /** Retrieve Category Based Question */ const getQuestion = useCallback( async () => { /** Retrieve Question from API */ try { let res; - const prodURL = `${baseURL}/${getMenuRoute}`; - const devURL = `/api/${getMenuRoute}`; + const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; + const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + res = await fetch(prodURL); + const resJSON = res.json(); + return resJSON; + } else { + res = await fetch(devURL); + const resJSON = res.json(); + return resJSON; + } } catch(error) { console.log(error); } - }, [getMenuRoute]); + }, [getMenuLanguage, getMenuRoute]); /** Generate Question */ const { isSuccess, data, refetch } = useQuery({ diff --git a/apps/web/src/components/dashboard/loading.tsx b/apps/web/src/components/dashboard/loading.tsx index b63893c..8cebb86 100644 --- a/apps/web/src/components/dashboard/loading.tsx +++ b/apps/web/src/components/dashboard/loading.tsx @@ -1,7 +1,7 @@ // loading screen import { useContext } from 'react'; import { ThemeContext } from '../../context/ThemeContext'; -import { Loader, Center } from '@mantine/core'; +import { Loader } from '@mantine/core'; export const LoadingDashboardXS = () => { const { state } = useContext(ThemeContext); @@ -10,17 +10,14 @@ export const LoadingDashboardXS = () => { return ( <> {darkMode ? -
      -
      -
      -
      -
      +
      + +
      + : -
      -
      -
      -
      -
      +
      + +
      } ) @@ -33,17 +30,13 @@ export const LoadingDashboardSM = () => { return ( <> {darkMode ? - -
      - -
      - +
      + +
      : - -
      - -
      - +
      + +
      } ) @@ -55,13 +48,13 @@ export const LoadingDashboardMD = () => { return ( <> {darkMode ? -
      - -
      +
      + +
      : -
      - -
      +
      + +
      } ) @@ -73,17 +66,13 @@ export const LoadingDashboardLG = () => { return ( <> {darkMode ? - -
      - -
      - +
      + +
      : - -
      - -
      - +
      + +
      } ) @@ -95,18 +84,14 @@ export const LoadingDashboardXL = () => { return ( <> {darkMode ? - -
      - -
      - +
      + +
      : - -
      - -
      - +
      + +
      } ) diff --git a/apps/web/src/layout/Layout.D_Categories.tsx b/apps/web/src/layout/Layout.D_Categories.tsx index c70eb27..66db9c6 100644 --- a/apps/web/src/layout/Layout.D_Categories.tsx +++ b/apps/web/src/layout/Layout.D_Categories.tsx @@ -3,7 +3,7 @@ import { useContext, useEffect, useState } from 'react' import { ThemeContext } from '../context/ThemeContext' /*Custom Hooks*/ -//import Transition from '../hooks/useTransition'; +import Transition from '../hooks/useTransition'; import useWindowSize from '../hooks/useWindowSize'; /**Custom Components */ import ErrorDashboard from '../components/dashboard/error'; @@ -15,6 +15,7 @@ import D_Category_Menu from '../components/dashboard/dashboard-categories/D_Cate import { useQuery } from "@tanstack/react-query"; /** React Redux Hooks */ import { useAppSelector, useAppDispatch } from '../redux/reduxHooks.ts'; +import type { RootState } from '../redux/store.ts'; import { menuLanguage, menuCategoryInfo } from '../redux/slices/dashboardSlice.ts'; @@ -33,10 +34,16 @@ const Layout_D_Categories = () => { const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); const getMenuCategory = useAppSelector((state:RootState) => state?.dashboard?.category); const getMenuCategoryInfo = useAppSelector((state:RootState) => state?.dashboard?.categoryInfo); + const getMenuUser = useAppSelector((state:RootState) => state?.dashboard?.user); async function setLanguage() { - if(getMenuLanguage === undefined || getMenuLanguage === '') { - dispatch(menuLanguage(getMenuLanguageDefault)); + if(getMenuLanguage === undefined || getMenuLanguage.length === 0) { + if(getMenuUser._DEFAULT_LANGUAGE === undefined || getMenuUser._DEFAULT_LANGUAGE.length === 0) { + dispatch(menuLanguage(getMenuLanguageDefault)); + } else { + //console.log("getMenuUser._DEFAULT_LANGUAGE",getMenuUser._DEFAULT_LANGUAGE) + dispatch(menuLanguage(getMenuUser._DEFAULT_LANGUAGE)); + } } } @@ -45,9 +52,9 @@ const Layout_D_Categories = () => { await setLanguage(); let res; if(import.meta.env.PROD) { - res = await fetch(`${baseURL}/categories`); + res = await fetch(`${baseURL}/categories/${getMenuLanguage}`); } else { - res = await fetch(`api/categories`); + res = await fetch(`api/categories/${getMenuLanguage}`); } const resJSON = res.json(); return resJSON; @@ -59,10 +66,10 @@ const Layout_D_Categories = () => { /** Generate Categories */ const { isFetching, isLoading, isError, error, isSuccess, data} = useQuery({ queryKey: ['categoriesData'], - queryFn: getCategories, + queryFn: getCategories, refetchOnWindowFocus: false, staleTime: 100 * (60 * 1000), - cacheTime: 100 * (60 * 1000), + cacheTime: 0, }); useEffect(() => { @@ -109,23 +116,35 @@ const Layout_D_Categories = () => { [&>*]:tw-backdrop-blur-sm [&>*]:tw-rounded tw-border tw-border-transparent tw-w-full tw-h-full tw-grid tw-grid-rows-layout-dashboard-categories-container tw-gap-1 `}>
      -
      - +
      + + +
      -
      +
      + + + +
      : -
      *]:tw-backdrop-brightness-25 ' : '[&>*]:tw-backdrop-brightness-65'} + +
      *]:tw-backdrop-brightness-25 ' : '[&>*]:tw-backdrop-brightness-65'} tw-bg-transparent tw-pb-1 tw-w-full tw-h-full tw-grow [&>*]:tw-backdrop-blur-sm tw-grid tw-grid-rows-layout-dashboard-categories-mobile tw-gap-1 [&>*]:tw-rounded tw-border tw-border-transparent`}> -
      *]:tw-bg-campfire-neutral-300"} tw-col-start-1 tw-col-end-1 tw-row-start-1 tw-row-end-1 tw-p-2`}> - -
      -
      -
      +
      *]:tw-bg-campfire-neutral-300"} + tw-col-start-1 tw-col-end-1 tw-row-start-1 tw-row-end-1 tw-p-2 tw-z-50 tw-relative tw-h-full`}> + +
      +
      + +
      +
      + }
) diff --git a/apps/web/src/layout/Layout.D_Code.tsx b/apps/web/src/layout/Layout.D_Code.tsx index a7a0f75..6514e30 100644 --- a/apps/web/src/layout/Layout.D_Code.tsx +++ b/apps/web/src/layout/Layout.D_Code.tsx @@ -32,27 +32,28 @@ const Layout_D_Code = () => { /** Retrieve Category Route From Redux State */ const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); + const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); /** Retrieve Category Based Question */ const getQuestion = useCallback( async () => { /** Retrieve Question from API */ - try { + try { let res; - const prodURL = `${baseURL}/${getMenuRoute}`; - const devURL = `/api/${getMenuRoute}`; + const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; + const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + res = await fetch(prodURL); + const resJSON = res.json(); + return resJSON; + } else { + res = await fetch(devURL); + const resJSON = res.json(); + return resJSON; + } } catch(error) { console.log(error); } - }, [getMenuRoute]); + }, [getMenuLanguage, getMenuRoute]); /** Generate Question */ const { isLoading, isFetching, isError, error, isSuccess, data } = useQuery({ @@ -89,7 +90,7 @@ const Layout_D_Code = () => { if(isSuccess && loading) { return ( -
*]:tw-backdrop-brightness-25 ' : '[&>*]:tw-backdrop-brightness-85'} ${darkMode ? '[&>*]:tw-bg-neutral-700/50' : '[&>*]:tw-bg-neutral-300/50'} +
*]:tw-backdrop-brightness-25 ' : '[&>*]:tw-backdrop-brightness-85'} tw-text-transparent tw-flex tw-flex-col tw-w-full tw-h-full tw-place-self-center tw-place-content-center tw-place-items-center`}>
diff --git a/apps/web/src/redux/slices/dashboardSlice.ts b/apps/web/src/redux/slices/dashboardSlice.ts index 93065d0..66809d4 100644 --- a/apps/web/src/redux/slices/dashboardSlice.ts +++ b/apps/web/src/redux/slices/dashboardSlice.ts @@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit' // Define a type for the slice state interface DashboardState { + languages: string[], languageDefault: string, categoryDefault: string, categoryRouteDefault: string, @@ -18,10 +19,12 @@ interface DashboardState { // Define the initial state using that type const initialState: DashboardState = { + languages: ['javascript'], languageDefault: import.meta.env.VITE_DEFAULT_LANGUAGE, categoryDefault: import.meta.env.VITE_DEFAULT_CATEGORY, categoryRouteDefault: import.meta.env.VITE_DEFAULT_ROUTE, category: import.meta.env.VITE_DEFAULT_CATEGORY, + language: import.meta.env.VITE_DEFAULT_LANGUAGE, categoryInfo: {}, categoryRoute: import.meta.env.VITE_DEFAULT_ROUTE, question: {}, @@ -42,7 +45,7 @@ const initialState: DashboardState = { _EMAIL_CONFIRMED: false, _EMAIL_PASSCODE: '', _PASSWORD: '', - _DEFAULT_LANGUAGE: '', + _DEFAULT_LANGUAGE: 'javascript', _DEFAULT_ROUTE: '', _POINTS_TOTAL: 0, _POINTS_JAVASCRIPT: 0, @@ -58,6 +61,7 @@ export const dashboardSlice = createSlice({ // `createSlice` will infer the state type from the `initialState` argument reducers: { menu: (state) => { + state.languages; state.language; state.languageDefault; state.category; @@ -70,6 +74,9 @@ export const dashboardSlice = createSlice({ state.consoleMessage; state.user; }, + menuLanguages: (state, action) => { + state.languages = action.payload; + }, menuLanguage: (state, action) => { state.language = action.payload; }, @@ -98,7 +105,7 @@ export const dashboardSlice = createSlice({ }, }); -export const { menu, menuUser, menuLanguage, menuCategory, menuCategoryInfo, menuCategoryRoute, menuQuestion, menuPoints, menuConsoleMessage } = dashboardSlice.actions +export const { menu, menuUser, menuLanguages, menuLanguage, menuCategory, menuCategoryInfo, menuCategoryRoute, menuQuestion, menuPoints, menuConsoleMessage } = dashboardSlice.actions export default dashboardSlice.reducer; diff --git a/apps/web/src/redux/store.ts b/apps/web/src/redux/store.ts index df162b0..6c1efa5 100644 --- a/apps/web/src/redux/store.ts +++ b/apps/web/src/redux/store.ts @@ -1,12 +1,13 @@ -import { configureStore } from '@reduxjs/toolkit'; +import { configureStore} from '@reduxjs/toolkit'; //import { createStore, applyMiddleware, combineReducers } from 'redux'; // import monitorReducersEnhancer from './enhancers/monitorReducers' -// import thunkMiddleware from 'redux-thunk' +//import thunkMiddleware from 'redux-thunk' import { dashboardSlice } from './slices/dashboardSlice.ts' const store = configureStore({ reducer: { - dashboard: dashboardSlice.reducer + dashboard: dashboardSlice.reducer, + devTools: process.env.NODE_ENV !== 'production', }, }) diff --git a/apps/web/src/utils/constants.ts b/apps/web/src/utils/constants.ts index 05038d7..70fdbfe 100644 --- a/apps/web/src/utils/constants.ts +++ b/apps/web/src/utils/constants.ts @@ -1,3 +1,8 @@ +/** Icons */ +import JS_Icon from "../assets/tech/javascript/javascript-original.svg"; +import JAVA_Icon from "../assets/tech/java/java-original.svg"; +import PY_Icon from "../assets/tech/python/python-original.svg"; + export const DEFAULT_USER = { _ID: '', _CREATED_AT: new Date().toISOString(), @@ -20,4 +25,10 @@ export const DEFAULT_USER = { _POINTS_JAVA: 0 , _POINTS_PYTHON: 0, _COURSES: '', -} \ No newline at end of file +} + +export const _LANGUAGES_ALL = { + javascript: JS_Icon, + java: JAVA_Icon, + python: PY_Icon, +} From cd34e49268e5ae6424c8e05ec8e9ed7de833ae24 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Sat, 30 Sep 2023 06:56:26 -0400 Subject: [PATCH 11/12] fixed endpoints --- apps/api/src/classes/question.ts | 61 +++++++--- .../data/java/comments.controller.ts | 85 +++++++++++++ .../comments.controller.ts | 66 ++--------- .../javascript/variables/var.controller.ts | 112 ++++++++---------- .../variables/var.declare.controller.ts | 26 ++-- .../variables/var.scope.controller.ts | 24 ++-- .../var.scope.reassign.controller.ts | 6 +- .../data/python/comments.controller.ts | 80 +++++++++++++ apps/api/src/data/java/java.comments.ts | 27 +++-- apps/api/src/data/python/python.comments.ts | 2 +- apps/api/src/index.ts | 16 ++- 11 files changed, 317 insertions(+), 188 deletions(-) create mode 100644 apps/api/src/controllers/data/java/comments.controller.ts rename apps/api/src/controllers/data/{comments => javascript}/comments.controller.ts (57%) create mode 100644 apps/api/src/controllers/data/python/comments.controller.ts diff --git a/apps/api/src/classes/question.ts b/apps/api/src/classes/question.ts index ce52be2..8e1ca29 100644 --- a/apps/api/src/classes/question.ts +++ b/apps/api/src/classes/question.ts @@ -22,24 +22,49 @@ export class Question implements Q { _QUESTION_REFS!: object; constructor(data) { - this._QUESTION_CREATED_AT = new Date(); - this._QUESTION_UPDATED_AT = new Date(); - this._QUESTION_ID = data._QUESTION_ID || ''; - this._QUESTION_LANGUAGE = data._QUESTION_LANGUAGE; - this._QUESTION_LEVEL = data._QUESTION_LEVEL || 1; - this._QUESTION_POINTS = data._QUESTION_POINTS || 1; - this._QUESTION_TASK = data._QUESTION_TASK || ''; - this._QUESTION_DATA = data._QUESTION_DATA || {}; - this._QUESTION_RESULT = data._QUESTION_RESULT || {}; - this._QUESTION_HINTS = data._QUESTION_HINTS || {}; - this._QUESTION_BOILERPLATE = data._QUESTION_BOILERPLATE || ''; - this._QUESTION_CONDITIONS = data._QUESTION_CONDITIONS || {}; - this._QUESTION_CONSTRAINTS = data._QUESTION_CONSTRAINTS || {}; - this._QUESTION_CATEGORY = data._QUESTION_CATEGORY || ''; - this._QUESTION_CATEGORY_SUB = data._QUESTION_CATEGORY_SUB || ''; - this._QUESTION_TAGS = data._QUESTION_TAGS || []; - this._QUESTION_REFS = data._QUESTION_REFS || {}; - this.set_QUESTION_ID(data._QUESTION_LANGUAGE); + const defaults = { + _QUESTION_CREATED_AT: new Date(), + _QUESTION_UPDATED_AT: new Date(), + _QUESTION_ID: `js-${nanoid(10)}`, + _QUESTION_LANGUAGE: "Javascript", + _QUESTION_LEVEL: 1, + _QUESTION_POINTS: 1, + _QUESTION_TASK: "", + _QUESTION_DATA: {}, + _QUESTION_RESULT: {}, + _QUESTION_HINTS: {}, + _QUESTION_BOILERPLATE: "", + _QUESTION_CONDITIONS: {}, + _QUESTION_CONSTRAINTS: {}, + _QUESTION_CATEGORY: "", + _QUESTION_CATEGORY_SUB: "", + _QUESTION_TAGS: [], + _QUESTION_REFS: {}, + } + let opts = Object.assign({}, defaults, data); + // assign options to instance data (using only property names contained + // in defaults object to avoid copying properties we don't want) + // Object.keys(defaults).forEach(prop => { + // this[prop] = opts[prop]; + // }); + this._QUESTION_CREATED_AT = opts._QUESTION_CREATED_AT; + this._QUESTION_UPDATED_AT = opts._QUESTION_UPDATED_AT; + this._QUESTION_ID = opts._QUESTION_ID; + this._QUESTION_LANGUAGE = opts._QUESTION_LANGUAGE; + this._QUESTION_LEVEL = opts._QUESTION_LEVEL; + this._QUESTION_POINTS = opts._QUESTION_POINTS; + this._QUESTION_TASK = opts._QUESTION_TASK; + this._QUESTION_DATA = opts._QUESTION_DATA; + this._QUESTION_RESULT = opts._QUESTION_RESULT; + this._QUESTION_HINTS = opts._QUESTION_HINTS; + this._QUESTION_BOILERPLATE = opts._QUESTION_BOILERPLATE; + this._QUESTION_CONDITIONS = opts._QUESTION_CONDITIONS; + this._QUESTION_CONSTRAINTS = opts._QUESTION_CONSTRAINTS; + this._QUESTION_CATEGORY = opts._QUESTION_CATEGORY; + this._QUESTION_CATEGORY_SUB = opts._QUESTION_CATEGORY_SUB; + this._QUESTION_TAGS = opts._QUESTION_TAGS; + this._QUESTION_REFS = opts._QUESTION_REFS; + this.set_QUESTION_ID(opts._QUESTION_LANGUAGE); } public set_QUESTION_ID(_QUESTION_LANGUAGE) { diff --git a/apps/api/src/controllers/data/java/comments.controller.ts b/apps/api/src/controllers/data/java/comments.controller.ts new file mode 100644 index 0000000..7bd5fc2 --- /dev/null +++ b/apps/api/src/controllers/data/java/comments.controller.ts @@ -0,0 +1,85 @@ +'use strict'; +import { Request, Response } from 'express'; +import Router from 'express-promise-router'; +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objSingle, objMulti } from '../../../data/java/java.comments'; + +export default class VarDeclare { + public pathCommentsRandom = '/java/comments/all'; + public pathCommentsSingle = '/java/comments/single/all'; + public pathCommentsMulti = '/java/comments/multi/all'; + public router = Router(); + constructor() { + this.initializeRoutes(); + } + + public initializeRoutes() { + this.router.get(this.pathCommentsRandom, this.commentsRandom); + this.router.get(this.pathCommentsSingle, this.commentsSingle); + this.router.get(this.pathCommentsMulti, this.commentsMulti); + } + + public commentsRandom = async (req: Request, res: Response) => { + const dataSingle = objSingle(); + const dataMulti = objMulti(); + + const questionSingle = new Question(dataSingle); + const questionMulti = new Question(dataMulti); + const random = getRandomInt(2); + + const randomQuestion = [dataSingle, dataMulti][random]; + + switch(req.method) { + case('GET'): + try { + res.status(200).send({ data: randomQuestion }); + } catch { + res.status(500).send({ error: "Something went wrong" }); + } + break + default: + res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; + + public commentsSingle = async (req: Request, res: Response) => { + //console.log("hello") + const dataObj = objSingle(); + //console.log(dataObj) + const question = new Question(dataObj); + //console.log(question); + switch(req.method) { + case('GET'): + try { + res.status(200).send({ data: question }); + + } catch { + res.status(500).send({ error: "Something went wrong" }); + } + break + default: + res.status(400).send({ error: `${req.method} Method Not Allowed` }); + } + }; + + public commentsMulti = async (req: Request, res: Response) => { + const dataObj = objMulti(); + const question = new Question(dataObj); + switch(req.method) { + case('GET'): + try { + return res.status(200).send({ data: question }); + + } catch { + return res.status(500).send({ error: "Something went wrong" }); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + } + }; + +} diff --git a/apps/api/src/controllers/data/comments/comments.controller.ts b/apps/api/src/controllers/data/javascript/comments.controller.ts similarity index 57% rename from apps/api/src/controllers/data/comments/comments.controller.ts rename to apps/api/src/controllers/data/javascript/comments.controller.ts index b4cd687..29a685a 100644 --- a/apps/api/src/controllers/data/comments/comments.controller.ts +++ b/apps/api/src/controllers/data/javascript/comments.controller.ts @@ -6,13 +6,11 @@ import { Question } from '../../../classes/question'; import { Q_Type } from '../../../types/types.question'; import { getRandomInt } from '../../../utils/index'; import { objSingle as objSingleJs, objMulti as objMultiJs } from '../../../data/javascript/javascript.comments'; -import { objSingle as objSingleJava, objMulti as objMultiJava } from '../../../data/java/java.comments'; -import { objSingle as objSinglePy, objMulti as objMultiPy } from '../../../data/python/python.comments'; export default class VarDeclare { - public pathCommentsRandom = '/:id/comments/all'; - public pathCommentsSingle = '/:id/comments/single/all'; - public pathCommentsMulti = '/:id/comments/multi/all'; + public pathCommentsRandom = '/javascript/comments/all'; + public pathCommentsSingle = '/javascript/comments/single/all'; + public pathCommentsMulti = '/javascript/comments/multi/all'; public router = Router(); constructor() { this.initializeRoutes(); @@ -25,26 +23,8 @@ export default class VarDeclare { } public commentsRandom = async (req: Request, res: Response) => { - let dataSingle - let dataMulti - - switch(req.params.id.toLowerCase()) { - case("javascript"): - dataSingle = objSingleJs(); - dataMulti = objMultiJs(); - break - case("java"): - dataSingle = objSingleJava(); - dataMulti = objMultiJava(); - break - case("python"): - dataSingle = objSinglePy(); - dataMulti = objMultiPy(); - break - default: - dataSingle = objSingleJs(); - dataMulti = objMultiJs(); - } + const dataSingle = objSingleJs(); + const dataMulti = objMultiJs(); const questionSingle = new Question(dataSingle); const questionMulti = new Question(dataMulti); @@ -54,7 +34,7 @@ export default class VarDeclare { switch(req.method) { case('GET'): - try { + try { res.status(200).send({ data: randomQuestion }); } catch { res.status(500).send({ error: "Something went wrong" }); @@ -66,24 +46,11 @@ export default class VarDeclare { }; public commentsSingle = async (req: Request, res: Response) => { - let data; - switch(req.params.id.toLowerCase()) { - case("javascript"): - data = objSingleJs(); - break - case("java"): - data = objSingleJava(); - break - case("python"): - data = objSinglePy(); - break - default: - data = objSingleJs(); - } + const data = objSingleJs(); const question = new Question(data); switch(req.method) { case('GET'): - try { + try { res.status(200).send({ data: question }); } catch { res.status(500).send({ error: "Something went wrong" }); @@ -95,24 +62,11 @@ export default class VarDeclare { }; public commentsMulti = async (req: Request, res: Response) => { - let data; - switch(req.params.id.toLowerCase()) { - case("javascript"): - data = objMultiJs(); - break - case("java"): - data = objMultiJava(); - break - case("python"): - data = objMultiPy(); - break - default: - data = objMultiJs(); - } + const data = objMultiJs(); const question = new Question(data); switch(req.method) { case('GET'): - try { + try { return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); diff --git a/apps/api/src/controllers/data/javascript/variables/var.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.controller.ts index fb12bac..9d3af0b 100644 --- a/apps/api/src/controllers/data/javascript/variables/var.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.controller.ts @@ -13,17 +13,17 @@ import cors from 'cors'; export default class VarGeneral { /**Public: Get random var */ - public pathRandom = '/:id/var/all'; + public pathRandom = '/javascript/var/all'; /**Public: Get All Var Category Questions*/ - public pathVar = '/:id/var'; + public pathVar = '/javascript/var'; /**Public: Get Var Category Question by ID*/ - public pathVarId = '/:id/var/get/:id'; + public pathVarId = '/javascript/var/get/:id'; /**Private: Create Var Question*/ - public pathVarNew = '/:id/var/new'; + public pathVarNew = '/javascript/var/new'; /**Private: Update Var Question*/ - public pathVarUpdate = '/:id/var/update/:id'; + public pathVarUpdate = '/javascript/var/update/:id'; /**Private: Delete Var Question';*/ - public pathVarDelete = '/:id/var/delete/:id'; + public pathVarDelete = '/javascript/var/delete/:id'; /**Express Router */ public router = Router(); /**Cors Options*/ @@ -59,9 +59,7 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: varRandom }); - } + return res.status(200).send({ data: varRandom }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -75,11 +73,9 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - const id = req.params.id; - const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTIONS_CATEGORY = 'variables'`; + const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTIONS_CATEGORY = 'variables'`; - return res.status(200).send({ data: results }); + return res.status(200).send({ data: results }); } } catch { return res.status(500).send({ error: "Something went wrong" }); @@ -94,8 +90,6 @@ export default class VarGeneral { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - const id = req.params.id; const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; return res.status(200).send({ data: results }); @@ -113,8 +107,6 @@ export default class VarGeneral { switch(req.method) { case('UPDATE'): try { - if(req.params.id.toLowerCase() === 'javascript') { - const id = req.params.id; const results = await sql`SELECT * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; return res.status(200); @@ -132,49 +124,47 @@ export default class VarGeneral { switch(req.method) { case('POST'): try { - if(req.params.id.toLowerCase() === 'javascript') { - const data: Q_Type = req.body; - const question = new Question(data); - const results = await sql`INSERT INTO _QUESTIONS ( - _QUESTION_CREATED_AT, - _QUESTION_UPDATED_AT, - _QUESTION_ID, - _QUESTION_LANGUAGE, - _QUESTION_LEVEL, - _QUESTION_POINTS, - _QUESTION_TASK, - _QUESTION_DATA, - _QUESTION_RESULT, - _QUESTION_HINTS, - _QUESTION_BOILERPLATE, - _QUESTION_CONDITIONS, - _QUESTION_CONSTRAINTS, - _QUESTION_CATEGORY, - _QUESTION_CATEGORY_SUB, - _QUESTION_TAGS, - _QUESTION_REFS, - ) VALUES ( - ${question._QUESTION_CREATED_AT}, - ${question._QUESTION_UPDATED_AT}, - ${question._QUESTION_ID}, - ${question._QUESTION_LANGUAGE}, - ${question._QUESTION_LEVEL}, - ${question._QUESTION_POINTS}, - ${question._QUESTION_TASK}, - ${question._QUESTION_DATA}, - ${question._QUESTION_RESULT}, - ${question._QUESTION_HINTS}, - ${question._QUESTION_BOILERPLATE}, - ${question._QUESTION_CONDITIONS}, - ${question._QUESTION_CONSTRAINTS}, - ${question._QUESTION_CATEGORY}, - ${question._QUESTION_CATEGORY_SUB}, - ${question._QUESTION_TAGS}, - ${question._QUESTION_REFS} - )`; - - return res.status(200); - } + const data: Q_Type = req.body; + const question = new Question(data); + const results = await sql`INSERT INTO _QUESTIONS ( + _QUESTION_CREATED_AT, + _QUESTION_UPDATED_AT, + _QUESTION_ID, + _QUESTION_LANGUAGE, + _QUESTION_LEVEL, + _QUESTION_POINTS, + _QUESTION_TASK, + _QUESTION_DATA, + _QUESTION_RESULT, + _QUESTION_HINTS, + _QUESTION_BOILERPLATE, + _QUESTION_CONDITIONS, + _QUESTION_CONSTRAINTS, + _QUESTION_CATEGORY, + _QUESTION_CATEGORY_SUB, + _QUESTION_TAGS, + _QUESTION_REFS, + ) VALUES ( + ${question._QUESTION_CREATED_AT}, + ${question._QUESTION_UPDATED_AT}, + ${question._QUESTION_ID}, + ${question._QUESTION_LANGUAGE}, + ${question._QUESTION_LEVEL}, + ${question._QUESTION_POINTS}, + ${question._QUESTION_TASK}, + ${question._QUESTION_DATA}, + ${question._QUESTION_RESULT}, + ${question._QUESTION_HINTS}, + ${question._QUESTION_BOILERPLATE}, + ${question._QUESTION_CONDITIONS}, + ${question._QUESTION_CONSTRAINTS}, + ${question._QUESTION_CATEGORY}, + ${question._QUESTION_CATEGORY_SUB}, + ${question._QUESTION_TAGS}, + ${question._QUESTION_REFS} + )`; + + return res.status(200); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -188,8 +178,6 @@ export default class VarGeneral { switch(req.method) { case('DELETE'): try { - if(req.params.id.toLowerCase() === 'javascript') { - const id = req.params.id; const results = await sql`DELETE * FROM _QUESTIONS WHERE _QUESTION_ID = ${id}`; return res.status(200); diff --git a/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts index 10e59d0..f1635e8 100644 --- a/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.declare.controller.ts @@ -8,10 +8,10 @@ import { getRandomInt } from '../../../../utils/index'; import { objRandom, objRandomVar, objRandomConst, objRandomLet } from '../../../../data/javascript/javascript.var.declare' export default class VarDeclare { - public pathVarRandomDeclare = '/:id/var/declare/all' - public pathVarDeclareVar = '/:id/var/declare/var'; - public pathVarDeclareConst = '/:id/var/declare/const'; - public pathVarDeclareLet = '/:id/var/declare/let'; + public pathVarRandomDeclare = '/javascript/var/declare/all' + public pathVarDeclareVar = '/javascript/var/declare/var'; + public pathVarDeclareConst = '/javascript/var/declare/const'; + public pathVarDeclareLet = '/javascript/var/declare/let'; public router = Router(); constructor() { this.initializeRoutes(); @@ -30,9 +30,7 @@ export default class VarDeclare { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -48,9 +46,7 @@ export default class VarDeclare { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -65,10 +61,8 @@ export default class VarDeclare { const question: Q_Type = new Question(data); switch(req.method) { case('GET'): - try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + try { + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -84,9 +78,7 @@ export default class VarDeclare { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts index 5ca57fa..16ca0b7 100644 --- a/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.scope.controller.ts @@ -8,10 +8,10 @@ import { getRandomInt } from '../../../../utils/index'; import { objBlockScope, objFuncScope, objGlobalScope } from '../../../../data/javascript/javascript.var.scope'; export default class VarScope { - public pathVarRandomScope = '/:id/var/scope/all'; - public pathVarScopeBlock = '/:id/var/scope/block'; - public pathVarScopeFunc = '/:id/var/scope/func'; - public pathVarScopeGlobal = '/:id/var/scope/global'; + public pathVarRandomScope = '/javascript/var/scope/all'; + public pathVarScopeBlock = '/javascript/var/scope/block'; + public pathVarScopeFunc = '/javascript/var/scope/func'; + public pathVarScopeGlobal = '/javascript/var/scope/global'; public router = Router(); constructor() { this.initializeRoutes(); @@ -31,9 +31,7 @@ export default class VarScope { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -49,9 +47,7 @@ export default class VarScope { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -67,9 +63,7 @@ export default class VarScope { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } @@ -85,9 +79,7 @@ export default class VarScope { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts b/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts index 561a7fb..19ab19f 100644 --- a/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts +++ b/apps/api/src/controllers/data/javascript/variables/var.scope.reassign.controller.ts @@ -8,7 +8,7 @@ import { getRandomInt } from '../../../../utils/index'; import { objBlockScopeReassign } from '../../../../data/javascript/javascript.var.scope.reassign'; export default class VarScopeReassign { - public pathVarReassignBlock = '/:id/var/scope/reassign/block'; + public pathVarReassignBlock = '/javascript/var/scope/reassign/block'; public router = Router(); constructor() { this.initializeRoutes(); @@ -24,9 +24,7 @@ export default class VarScopeReassign { switch(req.method) { case('GET'): try { - if(req.params.id.toLowerCase() === 'javascript') { - return res.status(200).send({ data: question }); - } + return res.status(200).send({ data: question }); } catch { return res.status(500).send({ error: "Something went wrong" }); } diff --git a/apps/api/src/controllers/data/python/comments.controller.ts b/apps/api/src/controllers/data/python/comments.controller.ts new file mode 100644 index 0000000..312f5fa --- /dev/null +++ b/apps/api/src/controllers/data/python/comments.controller.ts @@ -0,0 +1,80 @@ +'use strict'; +import { Request, Response } from 'express'; +import Router from 'express-promise-router'; +import client from '../../../config/db'; +import { Question } from '../../../classes/question'; +import { Q_Type } from '../../../types/types.question'; +import { getRandomInt } from '../../../utils/index'; +import { objSingle as objSinglePy, objMulti as objMultiPy } from '../../../data/python/python.comments'; + +export default class VarDeclare { + public pathCommentsRandom = '/python/comments/all'; + public pathCommentsSingle = '/python/comments/single/all'; + public pathCommentsMulti = '/python/comments/multi/all'; + public router = Router(); + constructor() { + this.initializeRoutes(); + } + + public initializeRoutes() { + this.router.get(this.pathCommentsRandom, this.commentsRandom); + this.router.get(this.pathCommentsSingle, this.commentsSingle); + this.router.get(this.pathCommentsMulti, this.commentsMulti); + } + + public commentsRandom = async (req: Request, res: Response) => { + const dataSingle = objSinglePy(); + const dataMulti = objMultiPy(); + + const questionSingle = new Question(dataSingle); + const questionMulti = new Question(dataMulti); + const random = getRandomInt(2); + + const randomQuestion = [dataSingle, dataMulti][random]; + + switch(req.method) { + case('GET'): + try { + res.status(200).send({ data: randomQuestion }); + } catch { + res.status(500).send({ error: "Something went wrong" }); + } + break + default: + res.status(400).send({ error: `${req.method} Method Not Allowed` }); + }; + }; + + public commentsSingle = async (req: Request, res: Response) => { + const data = objSinglePy(); + const question = new Question(data); + switch(req.method) { + case('GET'): + try { + res.status(200).send({ data: question }); + } catch { + res.status(500).send({ error: "Something went wrong" }); + } + break + default: + res.status(400).send({ error: `${req.method} Method Not Allowed` }); + } + }; + + public commentsMulti = async (req: Request, res: Response) => { + const data = objMultiPy(); + const question = new Question(data); + switch(req.method) { + case('GET'): + try { + return res.status(200).send({ data: question }); + } catch { + return res.status(500).send({ error: "Something went wrong" }); + } + break + default: + return res.status(400).send({ error: `${req.method} Method Not Allowed` }); + } + }; + +} diff --git a/apps/api/src/data/java/java.comments.ts b/apps/api/src/data/java/java.comments.ts index a1035a8..9d87ae2 100644 --- a/apps/api/src/data/java/java.comments.ts +++ b/apps/api/src/data/java/java.comments.ts @@ -6,31 +6,42 @@ export const objSingle = (): Q_Type => { const personName = faker.person.firstName(); const keyword = "SingleLine"; const data = { - _QUESTION_LANGUAGE: "Javascript", + _QUESTION_LANGUAGE: "Java", _QUESTION_ID: '', _QUESTION_LEVEL: 1, _QUESTION_POINTS: 1, - _QUESTION_TASK: `Using ${keyword} comments, comment the statement: Greeting User abouve the console.log('Hello ${personName}') method `, - _QUESTION_DATA: { keyword: keyword, value: personName, returnValue: `console.log('Hello ${personName})` }, + _QUESTION_TASK: + `Using ${keyword} comments, comment the statement: 'Greeting User' abouve the 'System.out.println('Hello ' + user) method'.`, + _QUESTION_DATA: { keyword: keyword, value: personName, + returnValue: `System.out.println("Hello " + ${personName})` }, _QUESTION_RESULT: { 0: { all:true }, 1 : { - answer: `function greetingUser() {// Only change code bellow this line // Greeting User console.log(\'Hello ${personName}\');// Only change code abouve this line}greetingUser()`, + answer: `class Main { + public static void main(String[] args) { + String user = "${personName}"; + // Only change code bellow this line + // Greeting User + System.out.println("Hello " + user); + // Only change code abouve this line + } + }`, optional: false } }, _QUESTION_HINTS: {}, - _QUESTION_BOILERPLATE: `function greetingUser() {\n// Only change code bellow this line \n\n Greeting User\nconsole.log(\'Hello ${personName}\');\n\n// Only change code abouve this line\n}\n\ngreetingUser()\n`, + _QUESTION_BOILERPLATE: + `class Main {\n\tpublic static void main(String[] args) {\n\t\t// Only change code bellow this line\n\t\tString user = "${personName}";\n\n\t\tGreeting User\n\t\tSystem.out.println("Hello " + user);\n\t\t\n\t\t// Only change code abouve this line\n\t}\n}`, _QUESTION_CONDITIONS: {}, _QUESTION_CONSTRAINTS: {}, _QUESTION_CATEGORY: 'Comments', _QUESTION_CATEGORY_SUB: '', _QUESTION_TAGS: [], _QUESTION_REFS: { - "javascript.info/comments": "https://javascript.info/comments", - "javascript.info/structure": "https://javascript.info/structure" + "java comments": "https://www.w3schools.com/java/java_comments.asp", + "java syntax": "https://www.w3schools.com/java/java_syntax.asp" } } return data; @@ -40,7 +51,7 @@ export const objMulti = (): Q_Type => { const personName = faker.person.firstName(); const keyword = "MultiLine"; const data = { - _QUESTION_LANGUAGE: "Javascript", + _QUESTION_LANGUAGE: "Java", _QUESTION_ID: '', _QUESTION_LEVEL: 1, _QUESTION_POINTS: 1, diff --git a/apps/api/src/data/python/python.comments.ts b/apps/api/src/data/python/python.comments.ts index 5c20559..88d64e9 100644 --- a/apps/api/src/data/python/python.comments.ts +++ b/apps/api/src/data/python/python.comments.ts @@ -40,7 +40,7 @@ export const objMulti = (): Q_Type => { const personName = faker.person.firstName(); const keyword = "MultiLine"; const data = { - _QUESTION_LANGUAGE: "Javascript", + _QUESTION_LANGUAGE: "Python", _QUESTION_ID: '', _QUESTION_LEVEL: 1, _QUESTION_POINTS: 1, diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index b2e8e3f..88acc76 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -2,9 +2,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import App from './server'; import Index from './controllers/index.controller'; -import Guest_Routes from './controllers/auth/guest/guest.controller'; -import Comments from './controllers/data/comments/comments.controller'; -import VarGeneral from './controllers/data/javascript/variables/var.controller'; +import guestRoutes from './controllers/auth/guest/guest.controller'; +import jsComments from './controllers/data/javascript/comments.controller'; +import javaComments from './controllers/data/java/comments.controller'; +import pythonComments from './controllers/data/python/comments.controller'; +//import VarGeneral from './controllers/data/javascript/variables/var.controller'; import VarDeclare from './controllers/data/javascript/variables/var.declare.controller'; import VarScope from './controllers/data/javascript/variables/var.scope.controller'; import VarScopeReassign from './controllers/data/javascript/variables/var.scope.reassign.controller'; @@ -13,9 +15,11 @@ const app = new App( [], [ new Index(), - new Guest_Routes(), - new Comments(), - new VarGeneral(), + new guestRoutes(), + new jsComments(), + new javaComments(), + new pythonComments(), + //new VarGeneral(), new VarDeclare(), new VarScope(), new VarScopeReassign() From b348f17ffcc1084febd24a41c4269de7c43469e5 Mon Sep 17 00:00:00 2001 From: jazicorn <40859840+jazicorn@users.noreply.github.com> Date: Sat, 30 Sep 2023 07:26:31 -0400 Subject: [PATCH 12/12] fixed code editor to display different languages --- apps/web/package.json | 7 + .../dashboard/dashboard-code/D_Editor.tsx | 73 ++++---- .../dashboard/dashboard-code/D_Problem.tsx | 48 ++--- apps/web/src/layout/Layout.D_Code.tsx | 41 +++-- apps/web/src/utils/constants.ts | 16 ++ yarn.lock | 164 ++++++++++++++++++ 6 files changed, 284 insertions(+), 65 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 16b0f4e..fc02bc6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -43,7 +43,9 @@ }, "dependencies": { "@codemirror/commands": "^6.2.4", + "@codemirror/lang-java": "^6.0.1", "@codemirror/lang-javascript": "^6.1.9", + "@codemirror/lang-python": "^6.1.3", "@codemirror/view": "^6.16.0", "@dicebear/collection": "^7.0.1", "@dicebear/core": "^7.0.1", @@ -72,6 +74,11 @@ "@tiptap/extension-link": "^2.0.3", "@tiptap/pm": "^2.0.3", "@tiptap/react": "^2.0.3", + "@uiw/codemirror-theme-dracula": "^4.21.18", + "@uiw/codemirror-theme-github": "^4.21.18", + "@uiw/codemirror-theme-material": "^4.21.18", + "@uiw/codemirror-theme-quietlight": "^4.21.18", + "@uiw/codemirror-theme-xcode": "^4.21.18", "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.9", "add": "^2.0.6", diff --git a/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx b/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx index d50e45b..276bd95 100644 --- a/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx +++ b/apps/web/src/components/dashboard/dashboard-code/D_Editor.tsx @@ -19,10 +19,17 @@ import { notifications } from '@mantine/notifications'; import { IconX, IconCheck } from '@tabler/icons-react'; /** Codemirror */ import CodeMirror from '@uiw/react-codemirror'; -import { javascript } from '@codemirror/lang-javascript'; -import lightTheme from '../../../styles/style.codemirror.light'; -import darkTheme from '../../../styles/style.codemirror.dark'; -const extensions = [ javascript({ jsx: true })]; +/**CodeMirror Languages */ +//import lightTheme from '../../../styles/style.codemirror.light'; +//import darkTheme from '../../../styles/style.codemirror.dark'; +//const extensions = [ javascript({ jsx: true })]; +import { _LANGUAGES_CODE_MIRROR, _LANGUAGES_RAPID_API } from '../../../utils/constants'; +//import { dracula } from '@uiw/codemirror-theme-dracula'; +import { materialDark } from '@uiw/codemirror-theme-material'; +import { githubLight } from '@uiw/codemirror-theme-github' +//import { quietlight } from '@uiw/codemirror-theme-quietlight'; +//import { xcodeLight, xcodeLightInit, xcodeDark, xcodeDarkInit } from '@uiw/codemirror-theme-xcode'; + /** API url | Custom env mandatory to begin with VITE * https://vitejs.dev/guide/env-and-mode.html#env-files */ @@ -42,31 +49,38 @@ const D_Editor = () => { const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); + /**Get question url */ + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/${getMenuLanguage}/${getMenuRoute}` + } else { + url = `/api/${getMenuLanguage}/${getMenuRoute}` + } + /** Retrieve Category Based Question */ - const getQuestion = useCallback( async () => { + const getQuestion = useCallback(async (url) => { /** Retrieve Question from API */ - try { - let res; - const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; - const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; - if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + try { + const result = await fetch(url, { + method: 'GET', + headers: { + 'Accept' : 'application/json', + 'Content-Type': 'application/json', + }, + } + ); + const resJSON = await result.json(); + //console.log("resjson", resJSON) + return resJSON; } catch(error) { console.log(error); } - }, [getMenuLanguage, getMenuRoute]); + },[]); /** Generate Question */ const { isSuccess, data } = useQuery({ - queryKey: ['questionData'], - queryFn: getQuestion, + queryKey: ['questionData', url], + queryFn: () => getQuestion(url), refetchOnWindowFocus: false, staleTime: 100 * (60 * 1000), cacheTime: 100 * (60 * 1000), @@ -171,8 +185,6 @@ const D_Editor = () => { notifications.show({ id: 'correct', withCloseButton: true, - onClose: () => console.log('unmounted'), - onOpen: () => console.log('mounted'), autoClose: 2000, title: "Answer Correct", message: '', @@ -204,7 +216,8 @@ const D_Editor = () => { const resultsStrip = getMenuQuestion._QUESTION_RESULT[1].answer.replace(/\s+/g, ''); try { if( userCode === resultsStrip ) { - consoleTest(93, editor, ''); + const languageId = _LANGUAGES_RAPID_API[getMenuLanguage.toLowerCase()]; + consoleTest(languageId, editor, ''); setPoints(getMenuPoints + getMenuQuestion._QUESTION_POINTS); } } catch (e) { @@ -212,8 +225,6 @@ const D_Editor = () => { notifications.show({ id: 'incorrect', withCloseButton: true, - onClose: () => console.log('unmounted'), - onOpen: () => console.log('mounted'), autoClose: 2000, title: "Answer Incorrect", message: '', @@ -225,12 +236,16 @@ const D_Editor = () => { loading: false, }); } - }, [editor, getMenuQuestion._QUESTION_RESULT, getMenuQuestion._QUESTION_POINTS, consoleTest, setPoints, getMenuPoints]); + }, [editor, getMenuQuestion._QUESTION_RESULT, getMenuQuestion._QUESTION_POINTS, getMenuLanguage, consoleTest, setPoints, getMenuPoints]); useEffect(() => { dispatch(menuConsoleMessage(consoleMessage)); },[consoleMessage, dispatch]); + + const editorLanguage = _LANGUAGES_CODE_MIRROR[getMenuLanguage.toLowerCase()]; + //console.log(editorLanguage); + /** Render if Successful */ if (isSuccess) return (
@@ -261,8 +276,8 @@ const D_Editor = () => { value={editor} height={isMobile ? "250px" : "300px"} maxHeight="100%" - theme={darkMode ? darkTheme : lightTheme} - extensions={extensions} + theme={darkMode ? materialDark : githubLight } + extensions={editorLanguage} onChange={onChange} />
diff --git a/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx b/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx index 9870e7c..f2e37e5 100644 --- a/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx +++ b/apps/web/src/components/dashboard/dashboard-code/D_Problem.tsx @@ -27,31 +27,38 @@ const D_Problem = () => { const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); + /**Get question url */ + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/${getMenuLanguage}/${getMenuRoute}` + } else { + url = `/api/${getMenuLanguage}/${getMenuRoute}` + } + /** Retrieve Category Based Question */ - const getQuestion = useCallback( async () => { + const getQuestion = useCallback(async (url) => { /** Retrieve Question from API */ try { - let res; - const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; - const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; - if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + const result = await fetch(url, { + method: 'GET', + headers: { + 'Accept' : 'application/json', + 'Content-Type': 'application/json', + }, + } + ); + const resJSON = await result.json(); + //console.log("resJSON",resJSON); + return resJSON; } catch(error) { console.log(error); } - }, [getMenuLanguage, getMenuRoute]); + },[]); /** Generate Question */ const { isSuccess, data, refetch } = useQuery({ - queryKey: ['questionData'], - queryFn: getQuestion, + queryKey: ['questionData', url], + queryFn: () => getQuestion(url), refetchOnWindowFocus: false, staleTime: 100 * (60 * 1000), cacheTime: 100 * (60 * 1000), @@ -60,6 +67,7 @@ const D_Problem = () => { /** Save Question to Redux Store */ useEffect(() => { if(data !== undefined) { + //console.log(data.data) dispatch(menuQuestion(data.data)); } }, [dispatch, data]); @@ -108,11 +116,11 @@ const D_Problem = () => { const regex = /[""]/g; const wordStrip = word.replace(regex, ''); if(word.match(regex)) { - return + return ( - {wordStrip} -   - + {wordStrip}  + + ) } return {word} })} diff --git a/apps/web/src/layout/Layout.D_Code.tsx b/apps/web/src/layout/Layout.D_Code.tsx index 6514e30..6a2f78b 100644 --- a/apps/web/src/layout/Layout.D_Code.tsx +++ b/apps/web/src/layout/Layout.D_Code.tsx @@ -34,32 +34,40 @@ const Layout_D_Code = () => { const getMenuRoute = useAppSelector((state:RootState) => state?.dashboard?.categoryRoute); const getMenuLanguage = useAppSelector((state:RootState) => state?.dashboard?.language); + /**Get question url */ + let url; + if(import.meta.env.PROD) { + url = `${baseURL}/${getMenuLanguage}/${getMenuRoute}` + } else { + url = `/api/${getMenuLanguage}/${getMenuRoute}` + } + /** Retrieve Category Based Question */ - const getQuestion = useCallback( async () => { + const getQuestion = useCallback(async (url) => { /** Retrieve Question from API */ try { - let res; - const prodURL = `${baseURL}/${getMenuLanguage}/${getMenuRoute}`; - const devURL = `/api/${getMenuLanguage}/${getMenuRoute}`; - if(import.meta.env.PROD) { - res = await fetch(prodURL); - const resJSON = res.json(); - return resJSON; - } else { - res = await fetch(devURL); - const resJSON = res.json(); - return resJSON; - } + const result = await fetch(url, { + method: 'GET', + headers: { + 'Accept' : 'application/json', + 'Content-Type': 'application/json', + }, + } + ); + const resJSON = await result.json(); + //console.log("resjson", resJSON) + return resJSON; } catch(error) { console.log(error); } - }, [getMenuLanguage, getMenuRoute]); + },[]); /** Generate Question */ const { isLoading, isFetching, isError, error, isSuccess, data } = useQuery({ - queryKey: ['questionData'], - queryFn: getQuestion, + queryKey: ['questionData', url], + queryFn: () => getQuestion(url), refetchOnWindowFocus: false, + keepPreviousData: true, staleTime: 100 * (60 * 1000), cacheTime: 100 * (60 * 1000), }); @@ -67,6 +75,7 @@ const Layout_D_Code = () => { /** Save Question to Redux Store */ useEffect(() => { if(data !== undefined) { + //console.log(data.data) dispatch(menuQuestion(data.data)); } }, [dispatch, data]); diff --git a/apps/web/src/utils/constants.ts b/apps/web/src/utils/constants.ts index 70fdbfe..38fa17c 100644 --- a/apps/web/src/utils/constants.ts +++ b/apps/web/src/utils/constants.ts @@ -2,6 +2,10 @@ import JS_Icon from "../assets/tech/javascript/javascript-original.svg"; import JAVA_Icon from "../assets/tech/java/java-original.svg"; import PY_Icon from "../assets/tech/python/python-original.svg"; +/**CodeMirror Languages */ +import { javascript } from '@codemirror/lang-javascript'; +import { java } from '@codemirror/lang-java'; +import { python } from '@codemirror/lang-python'; export const DEFAULT_USER = { _ID: '', @@ -32,3 +36,15 @@ export const _LANGUAGES_ALL = { java: JAVA_Icon, python: PY_Icon, } + +export const _LANGUAGES_CODE_MIRROR = { + javascript: [ javascript({ jsx: true })], + java: [java()], + python: [python()], +} + +export const _LANGUAGES_RAPID_API = { + javascript: 93, + java: 91, + python: 92 +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 919b723..5905a64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2019,6 +2019,23 @@ __metadata: languageName: node linkType: hard +"@codemirror/autocomplete@npm:^6.3.2": + version: 6.9.1 + resolution: "@codemirror/autocomplete@npm:6.9.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.17.0 + "@lezer/common": ^1.0.0 + peerDependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + checksum: 96dad7a12429bf61e6f1bf75da731bf0dcbfeb56c33400b60a0de22049226e0926a53a174e84701812a235f8f144595ce53f0928054481bdf9cdc2ed3b8be20f + languageName: node + linkType: hard + "@codemirror/commands@npm:^6.0.0, @codemirror/commands@npm:^6.1.0, @codemirror/commands@npm:^6.2.4": version: 6.2.4 resolution: "@codemirror/commands@npm:6.2.4" @@ -2031,6 +2048,16 @@ __metadata: languageName: node linkType: hard +"@codemirror/lang-java@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-java@npm:6.0.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/java": ^1.0.0 + checksum: 4679104683cbffcd224ac04c7e5d144b787494697b26470b07017259035b7bb3fa62609d9a61bfbc566f1756d9f972f9f26d96a3c1362dd48881c1172f9a914d + languageName: node + linkType: hard + "@codemirror/lang-javascript@npm:^6.1.9": version: 6.1.9 resolution: "@codemirror/lang-javascript@npm:6.1.9" @@ -2046,6 +2073,17 @@ __metadata: languageName: node linkType: hard +"@codemirror/lang-python@npm:^6.1.3": + version: 6.1.3 + resolution: "@codemirror/lang-python@npm:6.1.3" + dependencies: + "@codemirror/autocomplete": ^6.3.2 + "@codemirror/language": ^6.8.0 + "@lezer/python": ^1.1.4 + checksum: 65a0276a4503e4e3b70dd28d1c93ef472632b6d2c4bf3ae92d305d14ee8cf60b0bbbf62d5ceb51294de9598d9e2d42eafcde26f317ee7b90d0a11dfa863c1d1a + languageName: node + linkType: hard + "@codemirror/language@npm:^6.0.0, @codemirror/language@npm:^6.6.0": version: 6.8.0 resolution: "@codemirror/language@npm:6.8.0" @@ -2060,6 +2098,20 @@ __metadata: languageName: node linkType: hard +"@codemirror/language@npm:^6.8.0": + version: 6.9.1 + resolution: "@codemirror/language@npm:6.9.1" + dependencies: + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.1.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + style-mod: ^4.0.0 + checksum: 62265f1042d2edfd3a091c408d9d0071f23889099b2f6ce8275fa910118bd2c45b8c4b29228c7be6e6d5f0e0812a522de902bc75ba8d8b2e62e42ade1692a49a + languageName: node + linkType: hard + "@codemirror/lint@npm:^6.0.0": version: 6.4.0 resolution: "@codemirror/lint@npm:6.4.0" @@ -2112,6 +2164,17 @@ __metadata: languageName: node linkType: hard +"@codemirror/view@npm:^6.17.0": + version: 6.20.2 + resolution: "@codemirror/view@npm:6.20.2" + dependencies: + "@codemirror/state": ^6.1.4 + style-mod: ^4.1.0 + w3c-keyname: ^2.2.4 + checksum: eaf47726bb94b40f12c6f1d3494b558addaa7cd98a4ff05bfea7439c03cca3967d73380346ea8b06021478c21ec336a74665c9acb44e2b0280d5e0da4714387b + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -3311,6 +3374,13 @@ __metadata: languageName: node linkType: hard +"@lezer/common@npm:^1.1.0": + version: 1.1.0 + resolution: "@lezer/common@npm:1.1.0" + checksum: 93c208a44d1c0bdf7407853ba7c4ddcedf1c52d1b82170813d83b9bd6301aa23587405ac54332fe39ce8bc37f706936ab237ceb4d3d535d1dead650153b6474c + languageName: node + linkType: hard + "@lezer/highlight@npm:^1.0.0, @lezer/highlight@npm:^1.1.3, @lezer/highlight@npm:^1.1.6": version: 1.1.6 resolution: "@lezer/highlight@npm:1.1.6" @@ -3320,6 +3390,16 @@ __metadata: languageName: node linkType: hard +"@lezer/java@npm:^1.0.0": + version: 1.0.4 + resolution: "@lezer/java@npm:1.0.4" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 97f5a2c2d733afba5dc57a0da9a97515b19b5e63bb5937717dac4e8c9baed74d15c0cb5c1580858b678931f11d517c56d89f903968fa48931f9c62e2ea67a107 + languageName: node + linkType: hard + "@lezer/javascript@npm:^1.0.0": version: 1.4.5 resolution: "@lezer/javascript@npm:1.4.5" @@ -3339,6 +3419,16 @@ __metadata: languageName: node linkType: hard +"@lezer/python@npm:^1.1.4": + version: 1.1.8 + resolution: "@lezer/python@npm:1.1.8" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: e4a4e0b0fd871acff25111d4f767944b5015479776504b85c4431859c8a2859fdfa6362f204f3027cf9858c7ea907fd57244852a18b67da9eba3b2fe38d31b03 + languageName: node + linkType: hard + "@linaria/core@npm:4.2.9": version: 4.2.9 resolution: "@linaria/core@npm:4.2.9" @@ -6090,6 +6180,66 @@ __metadata: languageName: node linkType: hard +"@uiw/codemirror-theme-dracula@npm:^4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-theme-dracula@npm:4.21.18" + dependencies: + "@uiw/codemirror-themes": 4.21.18 + checksum: 565893d01d5b7ca046cec9d628b6c1114480a832e9a8db874eec6a49905f79366257dc60862f72639e1cdcfd6b9215acfdceb280ec8ef0f4b7db240361c4091e + languageName: node + linkType: hard + +"@uiw/codemirror-theme-github@npm:^4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-theme-github@npm:4.21.18" + dependencies: + "@uiw/codemirror-themes": 4.21.18 + checksum: 549e589dab1ecd1c322211eb6813ec3fb05a1cce930e5bb592913a3d068d6858fcb327c4a89c928a19f786a559beef5c2265678ecf7cd084338f5f231ef05b8a + languageName: node + linkType: hard + +"@uiw/codemirror-theme-material@npm:^4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-theme-material@npm:4.21.18" + dependencies: + "@uiw/codemirror-themes": 4.21.18 + checksum: 8a0ded86b418036baf5ed87e2e0120be0760bd9691528d896a332967e04718b9cf782cd45e52c335831d80744f3192ebf691df592980a1d90b617c3c85753465 + languageName: node + linkType: hard + +"@uiw/codemirror-theme-quietlight@npm:^4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-theme-quietlight@npm:4.21.18" + dependencies: + "@uiw/codemirror-themes": 4.21.18 + checksum: 99ca2af837d14d7d0114de9e45288eb16aab9e4645111886e7482d55933155042afac119b77dafd5cd65403108ae5f862f3c94a54d6377f011f9598368ea4cec + languageName: node + linkType: hard + +"@uiw/codemirror-theme-xcode@npm:^4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-theme-xcode@npm:4.21.18" + dependencies: + "@uiw/codemirror-themes": 4.21.18 + checksum: 44e78b153b5178d4c31f516ba4c4873d45018d6d2d4efb1193db7e62429ebda81aad8f1cafe4caa17bfc1e23c5c8a76919e04e4e661dce4224cc55966e05d371 + languageName: node + linkType: hard + +"@uiw/codemirror-themes@npm:4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-themes@npm:4.21.18" + dependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + peerDependencies: + "@codemirror/language": ">=6.0.0" + "@codemirror/state": ">=6.0.0" + "@codemirror/view": ">=6.0.0" + checksum: 70f3e1cb5acdc47eff0a50aa3c70fc636e4122fa52471431fd7150910bf1ad6cb10c0913ab77faca343a550d550e37fac8a576e69b9eda1b1b48f121547365ca + languageName: node + linkType: hard + "@uiw/codemirror-themes@npm:^4.21.9": version: 4.21.9 resolution: "@uiw/codemirror-themes@npm:4.21.9" @@ -16382,6 +16532,13 @@ __metadata: languageName: node linkType: hard +"style-mod@npm:^4.1.0": + version: 4.1.0 + resolution: "style-mod@npm:4.1.0" + checksum: 8402b14ca11113a3640d46b3cf7ba49f05452df7846bc5185a3535d9b6a64a3019e7fb636b59ccbb7816aeb0725b24723e77a85b05612a9360e419958e13b4e6 + languageName: node + linkType: hard + "styled-components@npm:^6.0.3": version: 6.0.3 resolution: "styled-components@npm:6.0.3" @@ -17785,7 +17942,9 @@ __metadata: resolution: "web@workspace:apps/web" dependencies: "@codemirror/commands": ^6.2.4 + "@codemirror/lang-java": ^6.0.1 "@codemirror/lang-javascript": ^6.1.9 + "@codemirror/lang-python": ^6.1.3 "@codemirror/view": ^6.16.0 "@dicebear/collection": ^7.0.1 "@dicebear/core": ^7.0.1 @@ -17831,6 +17990,11 @@ __metadata: "@types/styled-components": ^5.1.26 "@typescript-eslint/eslint-plugin": ^5.59.0 "@typescript-eslint/parser": ^5.59.0 + "@uiw/codemirror-theme-dracula": ^4.21.18 + "@uiw/codemirror-theme-github": ^4.21.18 + "@uiw/codemirror-theme-material": ^4.21.18 + "@uiw/codemirror-theme-quietlight": ^4.21.18 + "@uiw/codemirror-theme-xcode": ^4.21.18 "@uiw/codemirror-themes": ^4.21.9 "@uiw/react-codemirror": ^4.21.9 "@vitejs/plugin-react": ^4.0.0