diff --git a/Dockerfile b/Dockerfile index fd8f30c..6615438 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM denoland/deno:alpine WORKDIR /app COPY . . -RUN deno cache main.ts +RUN deno cache main.ts --allow-import flag RUN deno task build USER deno diff --git a/databases/init/students.sql b/databases/init/students.sql new file mode 100644 index 0000000..b503221 --- /dev/null +++ b/databases/init/students.sql @@ -0,0 +1,14 @@ +create table students ( + userId text primary key, + firstName text, + lastName text, + mail text, + promo integer, + foreign key(promo) references promo(id) +); + +create table promo ( + id integer, + endyear integer, + current integer +); \ No newline at end of file diff --git a/defaults/interfaces.ts b/defaults/interfaces.ts index 9b417e2..3189dfe 100644 --- a/defaults/interfaces.ts +++ b/defaults/interfaces.ts @@ -1,3 +1,5 @@ +import { type RegularTagNode, type TextNode } from "@melvdouc/xml-parser"; + export interface AppProperties { name: string; icon: string; @@ -6,4 +8,43 @@ export interface AppProperties { hint: string; } +export interface CasTagNode extends RegularTagNode { + children: [TextNode]; +} + +export interface CasGroupNode extends RegularTagNode { + children: CasTagNode[]; +} + +export interface CasResponse extends RegularTagNode { + children: [TextNode, CasGroupNode]; +} + +export interface CasContent { + amuCampus: string; + amuComposante: string; + amuDateValidation: string; + coGroup: string; + eduPersonPrimaryAffiliation: string; + eduPersonPrincipalName: string; + mail: string; + displayName: string; + givenName: string; + memberOf: string[]; + sn: string; + supannCivilite: string; + supannEntiteAffectation: string; + supannEtuAnneeInscription: string; + supannEtuEtape: string; + uid: string; +} + +export interface LoginJWT { + iss: "PolyMPR"; + iat: number; + exp: number; + aud: "PolyMPR"; + user: CasContent; +} + export type EmptyObject = Record; diff --git a/defaults/makeIndex.ts b/defaults/makeIndex.ts index 4205b03..f4ebd11 100644 --- a/defaults/makeIndex.ts +++ b/defaults/makeIndex.ts @@ -1,10 +1,12 @@ -import { EmptyObject } from "$root/defaults/interfaces.ts"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; -export default function makeIndex< - IndexProps = EmptyObject, ->(basePath: string) { - return async function Index(props: IndexProps) { +export default function makeIndex(basePath: string) { + return async function Index( + request: Request, + context: FreshContext, + ) { const index = (await import(`${basePath}/partials/index.tsx`)).Index; - return index(props); + return index(request, context); }; } diff --git a/defaults/makePartials.tsx b/defaults/makePartials.tsx index 783c20e..e6b81af 100644 --- a/defaults/makePartials.tsx +++ b/defaults/makePartials.tsx @@ -1,6 +1,7 @@ import { JSX } from "preact"; import { Partial } from "$fresh/runtime.ts"; -import { RouteConfig } from "$fresh/server.ts"; +import { FreshContext, RouteConfig } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; export function getPartialsConfig(): RouteConfig { return { @@ -9,14 +10,19 @@ export function getPartialsConfig(): RouteConfig { }; } -// deno-lint-ignore no-explicit-any -export function makePartials( - page: (props: Props) => JSX.Element, +export function makePartials( + page: ( + request: Request, + context: FreshContext, + ) => Promise, ) { - return function WrappedElements(props: Props): JSX.Element { + return async function WrappedElements( + request: Request, + context: FreshContext, + ): Promise { return ( - {page(props)} + {await page(request, context)} ); }; diff --git a/deno.json b/deno.json index e9dcaca..344187a 100644 --- a/deno.json +++ b/deno.json @@ -26,6 +26,7 @@ "@db/sqlite": "jsr:@db/sqlite@^0.12.0", "@melvdouc/xml-parser": "jsr:@melvdouc/xml-parser@^0.1.1", "@popov/jwt": "jsr:@popov/jwt@^1.0.1", + "@psych/sheet": "jsr:@psych/sheet@^1.0.6", "@std/cli": "jsr:@std/cli@^1.0.10", "preact": "https://esm.sh/preact@10.22.0", "preact/": "https://esm.sh/preact@10.22.0/", diff --git a/fresh.gen.ts b/fresh.gen.ts index 62756f9..a256829 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -3,13 +3,20 @@ // This file is automatically updated during development when running `dev.ts`. import * as $_apps_layout from "./routes/(apps)/_layout.tsx"; +import * as $_apps_mobility_api_insert_students from "./routes/(apps)/mobility/api/insert_students.ts"; import * as $_apps_mobility_index from "./routes/(apps)/mobility/index.tsx"; +import * as $_apps_mobility_partials_admin_mobility from "./routes/(apps)/mobility/partials/(admin)/mobility.tsx"; import * as $_apps_mobility_partials_index from "./routes/(apps)/mobility/partials/index.tsx"; +import * as $_apps_mobility_partials_overview from "./routes/(apps)/mobility/partials/overview.tsx"; +import * as $_apps_mobility_partials_students from "./routes/(apps)/mobility/partials/students.tsx"; import * as $_apps_notes_index from "./routes/(apps)/notes/index.tsx"; import * as $_apps_notes_partials_admin_courses from "./routes/(apps)/notes/partials/(admin)/courses.tsx"; import * as $_apps_notes_partials_admin_students from "./routes/(apps)/notes/partials/(admin)/students.tsx"; import * as $_apps_notes_partials_index from "./routes/(apps)/notes/partials/index.tsx"; import * as $_apps_notes_partials_notes from "./routes/(apps)/notes/partials/notes.tsx"; +import * as $_apps_students_api_example from "./routes/(apps)/students/api/example.ts"; +import * as $_apps_students_index from "./routes/(apps)/students/index.tsx"; +import * as $_apps_students_partials_index from "./routes/(apps)/students/partials/index.tsx"; import * as $_404 from "./routes/_404.tsx"; import * as $_app from "./routes/_app.tsx"; import * as $_middleware from "./routes/_middleware.ts"; @@ -20,14 +27,28 @@ import * as $login from "./routes/login.tsx"; import * as $logout from "./routes/logout.tsx"; import * as $_islands_AppNavigator from "./routes/(_islands)/AppNavigator.tsx"; import * as $_islands_Navbar from "./routes/(_islands)/Navbar.tsx"; +import * as $_apps_mobility_islands_ConsultMobility from "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx"; +import * as $_apps_mobility_islands_ConsultStudents from "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx"; +import * as $_apps_mobility_islands_EditMobility from "./routes/(apps)/mobility/(_islands)/EditMobility.tsx"; +import * as $_apps_mobility_islands_EditStudents from "./routes/(apps)/mobility/(_islands)/EditStudents.tsx"; +import * as $_apps_mobility_islands_ImportFile from "./routes/(apps)/mobility/(_islands)/ImportFile.tsx"; +import * as $_apps_mobility_islands_UploadStudents from "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx"; import type { Manifest } from "$fresh/server.ts"; const manifest = { routes: { "./routes/(apps)/_layout.tsx": $_apps_layout, + "./routes/(apps)/mobility/api/insert_students.ts": + $_apps_mobility_api_insert_students, "./routes/(apps)/mobility/index.tsx": $_apps_mobility_index, + "./routes/(apps)/mobility/partials/(admin)/mobility.tsx": + $_apps_mobility_partials_admin_mobility, "./routes/(apps)/mobility/partials/index.tsx": $_apps_mobility_partials_index, + "./routes/(apps)/mobility/partials/overview.tsx": + $_apps_mobility_partials_overview, + "./routes/(apps)/mobility/partials/students.tsx": + $_apps_mobility_partials_students, "./routes/(apps)/notes/index.tsx": $_apps_notes_index, "./routes/(apps)/notes/partials/(admin)/courses.tsx": $_apps_notes_partials_admin_courses, @@ -35,6 +56,10 @@ const manifest = { $_apps_notes_partials_admin_students, "./routes/(apps)/notes/partials/index.tsx": $_apps_notes_partials_index, "./routes/(apps)/notes/partials/notes.tsx": $_apps_notes_partials_notes, + "./routes/(apps)/students/api/example.ts": $_apps_students_api_example, + "./routes/(apps)/students/index.tsx": $_apps_students_index, + "./routes/(apps)/students/partials/index.tsx": + $_apps_students_partials_index, "./routes/_404.tsx": $_404, "./routes/_app.tsx": $_app, "./routes/_middleware.ts": $_middleware, @@ -47,6 +72,18 @@ const manifest = { islands: { "./routes/(_islands)/AppNavigator.tsx": $_islands_AppNavigator, "./routes/(_islands)/Navbar.tsx": $_islands_Navbar, + "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx": + $_apps_mobility_islands_ConsultMobility, + "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx": + $_apps_mobility_islands_ConsultStudents, + "./routes/(apps)/mobility/(_islands)/EditMobility.tsx": + $_apps_mobility_islands_EditMobility, + "./routes/(apps)/mobility/(_islands)/EditStudents.tsx": + $_apps_mobility_islands_EditStudents, + "./routes/(apps)/mobility/(_islands)/ImportFile.tsx": + $_apps_mobility_islands_ImportFile, + "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx": + $_apps_mobility_islands_UploadStudents, }, baseUrl: import.meta.url, } satisfies Manifest; diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx new file mode 100644 index 0000000..4ca3459 --- /dev/null +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from "preact/hooks"; + +interface Student { + id: number; + firstName: string; + lastName: string; + email: string; + promotion: string; +} + +export default function ConsultStudents() { + const [students, setStudents] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchStudents = async () => { + try { + const response = await fetch("/mobility/api/insert_students"); + + if (!response.ok) { + throw new Error(`Error fetching students: ${response.statusText}`); + } + + const data: Student[] = await response.json(); + setStudents(data); + } catch (err) { + console.error("Error fetching students:", err); + setError("Failed to load students. Please try again later."); + } + }; + + fetchStudents(); + }, []); + + return ( +
+

Consult Students

+ {error &&

{error}

} + {students.length === 0 ?

No students found.

: ( + + + + + + + + + + + + {students.map((student) => ( + + + + + + + + ))} + +
IDFirst NameLast NameEmailPromotion
{student.id}{student.firstName}{student.lastName}{student.email}{student.promotion}
+ )} +
+ ); +} diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/EditStudents.tsx b/routes/(apps)/mobility/(_islands)/EditStudents.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/ImportFile.tsx b/routes/(apps)/mobility/(_islands)/ImportFile.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx new file mode 100644 index 0000000..763cdc4 --- /dev/null +++ b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx @@ -0,0 +1,87 @@ +// @deno-types="https://cdn.sheetjs.com/xlsx-0.20.3/package/types/index.d.ts" +import * as XLSX from "https://cdn.sheetjs.com/xlsx-0.20.3/package/xlsx.mjs"; +import { useSignal } from "@preact/signals"; + +export default function UploadStudents() { + const statusMessage = useSignal(""); + const fileData = useSignal(null); + + const handleFileChange = (event: Event) => { + const input = event.target as HTMLInputElement; + if (input.files && input.files.length > 0) { + fileData.value = input.files[0]; + statusMessage.value = "File selected: " + input.files[0].name; + console.log("File selected:", input.files[0].name); + } else { + fileData.value = null; + statusMessage.value = "No file selected"; + } + }; + + const confirmUpload = () => { + console.log("Confirm Upload"); + if (!fileData.value) { + statusMessage.value = "Please select a file before confirming upload."; + console.error("Error: No file selected."); + return; + } + + try { + const reader = new FileReader(); + + reader.onload = async (e) => { + try { + const arrayBuffer = e.target?.result as ArrayBuffer; + const workbook = XLSX.read(arrayBuffer, { type: "array" }); + + for (const sheetName of workbook.SheetNames) { + const sheet = workbook.Sheets[sheetName]; + const data = XLSX.utils.sheet_to_json(sheet, { + header: ["Nom", "Prénom", "Mail"], + range: 1, // Ignorer les en-têtes + }); + + console.log(`Data from sheet ${sheetName}:`, data); + + const response = await fetch("/mobility/api/insert_students", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ promoName: sheetName, data }), + }); + + if (!response.ok) { + throw new Error( + `Failed to insert data for promotion ${sheetName}`, + ); + } + } + + statusMessage.value = "Data uploaded and inserted successfully!"; + } catch (error) { + console.error("Error processing the file:", error); + statusMessage.value = + "Error processing the file. Please check its format."; + } + }; + + reader.onerror = (e) => { + console.error("FileReader error:", e); + statusMessage.value = "Error reading the file."; + }; + + reader.readAsArrayBuffer(fileData.value); + } catch (error) { + console.error("Error uploading file:", error); + statusMessage.value = "An unexpected error occurred during upload."; + } + }; + + return ( +
+

Upload Students

+ + +

{statusMessage.value}

+
+ ); +} diff --git a/routes/(apps)/mobility/(_props)/props.ts b/routes/(apps)/mobility/(_props)/props.ts index f9c0b54..b324ead 100644 --- a/routes/(apps)/mobility/(_props)/props.ts +++ b/routes/(apps)/mobility/(_props)/props.ts @@ -3,9 +3,14 @@ import { AppProperties } from "$root/defaults/interfaces.ts"; const properties: AppProperties = { name: "PolyMobility", icon: "flight_takeoff", - hint: "Gestionnaire de mobilité", - pages: {}, - adminOnly: [], + hint: "Student mobility management", + pages: { + index: "Homepage", + overview: "Mobility overview", + mobility: "Mobility management", + students: "Students management", + }, + adminOnly: ["students"], }; export default properties; diff --git a/routes/(apps)/mobility/api/insert_students.ts b/routes/(apps)/mobility/api/insert_students.ts new file mode 100644 index 0000000..e8af2fe --- /dev/null +++ b/routes/(apps)/mobility/api/insert_students.ts @@ -0,0 +1,92 @@ +import { Handlers } from "$fresh/server.ts"; +import { Database } from "@db/sqlite"; + +export const handler: Handlers = { + // deno-lint-ignore require-await + async GET(_request, _context) { + try { + const db = new Database("databases/data/mobility.db"); + + db.prepare( + ` + CREATE TABLE IF NOT EXISTS students ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + firstName TEXT NOT NULL, + lastName TEXT NOT NULL, + email TEXT NOT NULL, + promotion TEXT NOT NULL + ); + `, + ).run(); + + const rows = db.prepare( + "SELECT id, firstName, lastName, email, promotion FROM students", + ).all(); + + db.close(); + + return new Response(JSON.stringify(rows), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + } catch (error) { + console.error("Error fetching students:", error); + return new Response("Failed to fetch students", { status: 500 }); + } + }, + + async POST(request) { + console.log("API /mobility/api/insert_students called"); + + try { + const body = await request.json(); + const { data, promoName } = body; + + console.log("Received data:", { promoName, data }); + + if (!promoName || !Array.isArray(data)) { + throw new Error("Invalid request body"); + } + + const db = new Database("databases/data/mobility.db"); + + console.log("Database opened successfully"); + + db.prepare( + ` + CREATE TABLE IF NOT EXISTS students ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + firstName TEXT NOT NULL, + lastName TEXT NOT NULL, + email TEXT NOT NULL, + promotion TEXT NOT NULL + ); + `, + ).run(); + + console.log("Table ensured successfully"); + + const insertQuery = db.prepare( + "INSERT INTO students (firstName, lastName, email, promotion) VALUES (?, ?, ?, ?)", + ); + + for (const student of data) { + console.log("Inserting student:", student); + insertQuery.run( + student.Nom, + student["Prénom"], + student.Mail, + promoName, + ); + } + + console.log("All students inserted successfully"); + db.close(); + + return new Response("Students inserted successfully", { status: 201 }); + } catch (error) { + console.error("Error inserting students:", error); + return new Response("Failed to insert students", { status: 500 }); + } + }, +}; diff --git a/routes/(apps)/mobility/partials/(admin)/mobility.tsx b/routes/(apps)/mobility/partials/(admin)/mobility.tsx new file mode 100644 index 0000000..a73c859 --- /dev/null +++ b/routes/(apps)/mobility/partials/(admin)/mobility.tsx @@ -0,0 +1,17 @@ +import { Partial } from "$fresh/runtime.ts"; +import { RouteConfig } from "$fresh/server.ts"; + +type ModulesProps = Record; + +export const config: RouteConfig = { + skipAppWrapper: true, + skipInheritedLayouts: true, +}; + +export default function Modules(_props: ModulesProps) { + return ( + + mobility + + ); +} diff --git a/routes/(apps)/mobility/partials/overview.tsx b/routes/(apps)/mobility/partials/overview.tsx new file mode 100644 index 0000000..a73c859 --- /dev/null +++ b/routes/(apps)/mobility/partials/overview.tsx @@ -0,0 +1,17 @@ +import { Partial } from "$fresh/runtime.ts"; +import { RouteConfig } from "$fresh/server.ts"; + +type ModulesProps = Record; + +export const config: RouteConfig = { + skipAppWrapper: true, + skipInheritedLayouts: true, +}; + +export default function Modules(_props: ModulesProps) { + return ( + + mobility + + ); +} diff --git a/routes/(apps)/mobility/partials/students.tsx b/routes/(apps)/mobility/partials/students.tsx new file mode 100644 index 0000000..f3c7cb9 --- /dev/null +++ b/routes/(apps)/mobility/partials/students.tsx @@ -0,0 +1,20 @@ +import { RouteConfig } from "$fresh/server.ts"; +import UploadStudents from "../(_islands)/UploadStudents.tsx"; +import ConsultStudents from "../(_islands)/ConsultStudents.tsx"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; + +export const config: RouteConfig = { + skipAppWrapper: false, + skipInheritedLayouts: false, +}; + +export default function Students() { + return ( +
+

Manage Promotions

+ +
+ +
+ ); +} diff --git a/routes/(apps)/students/(_props)/props.ts b/routes/(apps)/students/(_props)/props.ts new file mode 100644 index 0000000..0a7a522 --- /dev/null +++ b/routes/(apps)/students/(_props)/props.ts @@ -0,0 +1,14 @@ +import { AppProperties } from "$root/defaults/interfaces.ts"; + +const properties: AppProperties = { + name: "Students", + icon: "badge", + pages: { + index: "Homepage", + upload: "Upload students", + }, + adminOnly: ["upload"], + hint: "See student information", +}; + +export default properties; diff --git a/routes/(apps)/students/api/example.ts b/routes/(apps)/students/api/example.ts new file mode 100644 index 0000000..9f04cd1 --- /dev/null +++ b/routes/(apps)/students/api/example.ts @@ -0,0 +1,22 @@ +import { Handlers } from "$fresh/server.ts"; + +export const handler: Handlers = { + async POST(request, context) { + if (request.headers.get("content-type") != "application/json") { + return new Response(null, { + status: 400, + }); + } + + const responseBody = { + requestBody: await request.json(), + context, + }; + + return new Response(JSON.stringify(responseBody), { + headers: { + "content-type": "application/json", + }, + }); + }, +}; diff --git a/routes/(apps)/students/index.tsx b/routes/(apps)/students/index.tsx new file mode 100644 index 0000000..1d82f7f --- /dev/null +++ b/routes/(apps)/students/index.tsx @@ -0,0 +1,2 @@ +import makeIndex from "$root/defaults/makeIndex.ts"; +export default makeIndex(import.meta.dirname!); diff --git a/routes/(apps)/students/partials/index.tsx b/routes/(apps)/students/partials/index.tsx new file mode 100644 index 0000000..2971e0e --- /dev/null +++ b/routes/(apps)/students/partials/index.tsx @@ -0,0 +1,14 @@ +import { + getPartialsConfig, + makePartials, +} from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; + +// deno-lint-ignore require-await +export async function Index(_request: Request, context: FreshContext) { + return

Welcome to {context.state.session?.displayName}.

; +} + +export const config = getPartialsConfig(); +export default makePartials(Index); diff --git a/routes/_middleware.ts b/routes/_middleware.ts index 281a9c0..3601da1 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -1,7 +1,7 @@ import { FreshContext } from "$fresh/server.ts"; import { getCookies } from "$std/http/cookie.ts"; import { getJwtPayload, isJwtValid } from "@popov/jwt"; -import { LoginJWT } from "$root/routes/login.tsx"; +import { CasContent, LoginJWT } from "$root/defaults/interfaces.ts"; const PUBLIC_ROUTES = [ "/", @@ -16,6 +16,7 @@ const jwtKeyCache: Record = {}; export interface State { isAuthenticated: boolean; + session: CasContent; } function isRoutePublic(route: string) { @@ -44,12 +45,16 @@ export const handler = [ } const content = getJwtPayload(cookies["sessionToken"]) as LoginJWT; - const key = getKey(content.user.uid as string); + const key = getKey(content.user.uid); context.state.isAuthenticated = await isJwtValid( cookies["sessionToken"], key, ); + const session: CasContent = + (getJwtPayload(cookies["sessionToken"]) as LoginJWT).user; + + context.state.session = session; return await context.next(); }, diff --git a/routes/login.tsx b/routes/login.tsx index 284fc5e..66dfcb0 100644 --- a/routes/login.tsx +++ b/routes/login.tsx @@ -1,10 +1,12 @@ import { Handlers } from "$fresh/server.ts"; import { State } from "$root/routes/_middleware.ts"; +import { parse, type RegularTagNode } from "@melvdouc/xml-parser"; import { - parse, - type RegularTagNode, - type TextNode, -} from "@melvdouc/xml-parser"; + CasContent, + CasResponse, + CasTagNode, + LoginJWT, +} from "$root/defaults/interfaces.ts"; import { createJwt } from "@popov/jwt"; import { setCookie } from "$std/http/cookie.ts"; import { getKey } from "$root/routes/_middleware.ts"; @@ -12,26 +14,6 @@ import { getKey } from "$root/routes/_middleware.ts"; const SERVICE = "https://localhost/login"; const CAS = "https://ident.univ-amu.fr/cas"; -interface CasTagNode extends RegularTagNode { - children: [TextNode]; -} - -interface CasGroupNode extends RegularTagNode { - children: CasTagNode[]; -} - -interface CasResponse extends RegularTagNode { - children: [TextNode, CasGroupNode]; -} - -export interface LoginJWT { - iss: "PolyMPR"; - iat: number; - exp: number; - aud: "PolyMPR"; - user: Record; -} - function getTag(tag: CasTagNode): [string, string] { return [ tag.tagName.replace("cas:", ""), @@ -43,11 +25,13 @@ function createUserJWT(casResponse: CasResponse): Promise { const nodes = casResponse.children[1].children.map(getTag); const fullUserInfos: Record = {}; - nodes.forEach(([key, value]) => { - if (fullUserInfos[key] && Array.isArray(fullUserInfos[key])) { + nodes.forEach(([key, value]: [string, string]) => { + if (typeof fullUserInfos[key] == "string") { + fullUserInfos[key] = [fullUserInfos[key]]; + } + + if (Array.isArray(fullUserInfos[key])) { fullUserInfos[key].push(value); - } else if (fullUserInfos[key]) { - fullUserInfos[key] = [fullUserInfos[key], value]; } else { fullUserInfos[key] = value; } @@ -56,12 +40,12 @@ function createUserJWT(casResponse: CasResponse): Promise { const now = Math.floor(Date.now() / 1000); const oneHour = 60 * 60; - const payload = { + const payload: LoginJWT = { iss: "PolyMPR", iat: now, exp: now + oneHour, aud: "PolyMPR", - user: fullUserInfos, + user: fullUserInfos as unknown as CasContent, }; const key = getKey(fullUserInfos.uid as string); diff --git a/toolbox/module/create.ts b/toolbox/module/create.ts index f289d98..aa93463 100644 --- a/toolbox/module/create.ts +++ b/toolbox/module/create.ts @@ -77,15 +77,14 @@ function getIndexContent(_name: string) { function getPartialIndexContent(name: string) { return ` - import { EmptyObject } from "$root/defaults/interfaces.ts"; import { getPartialsConfig, makePartials, } from "$root/defaults/makePartials.tsx"; + import { FreshContext } from "$fresh/server.ts"; + import { State } from "$root/routes/_middleware.ts"; - type ${name}IndexProps = EmptyObject; - - export function Index(_props: ${name}IndexProps) { + export async function Index(request: Request, context: FreshContext) { return

Welcome to ${name}.

; }