Release Candidate : 1.0.0 #150
@@ -1,55 +1,36 @@
|
|||||||
import { Handlers } from "$fresh/server.ts";
|
import { Handlers } from "$fresh/server.ts";
|
||||||
import { Database } from "@db/sqlite";
|
import { db } from "$root/databases/db.ts";
|
||||||
|
import { mobility, promotions, students } from "$root/databases/schema.ts";
|
||||||
|
import { eq } from "npm:drizzle-orm";
|
||||||
|
|
||||||
export const handler: Handlers = {
|
export const handler: Handlers = {
|
||||||
// deno-lint-ignore require-await
|
|
||||||
async GET() {
|
async GET() {
|
||||||
try {
|
try {
|
||||||
console.log("Connecting to mobility database...");
|
const studentRows = await db
|
||||||
const connection = new Database("databases/data/mobility.db", {
|
.select({
|
||||||
create: false,
|
id: students.userId,
|
||||||
});
|
firstName: students.firstName,
|
||||||
connection.run(
|
lastName: students.lastName,
|
||||||
"ATTACH DATABASE 'databases/data/students.db' AS students",
|
promotionId: students.promotionId,
|
||||||
);
|
endyear: promotions.endyear,
|
||||||
console.log("Connected to databases.");
|
current: promotions.current,
|
||||||
|
})
|
||||||
|
.from(students)
|
||||||
|
.leftJoin(promotions, eq(students.promotionId, promotions.id));
|
||||||
|
|
||||||
const students = connection.prepare(
|
const mobilityRows = await db.select().from(mobility);
|
||||||
`SELECT
|
|
||||||
students.userId AS id,
|
|
||||||
students.firstName,
|
|
||||||
students.lastName,
|
|
||||||
students.promotionId AS promotionId,
|
|
||||||
promotions.name AS promotionName
|
|
||||||
FROM students.students
|
|
||||||
LEFT JOIN students.promotions ON students.promotionId = promotions.id`,
|
|
||||||
).all();
|
|
||||||
|
|
||||||
const mobilities = connection.prepare(
|
const promotionRows = await db
|
||||||
`SELECT
|
.select({ id: promotions.id, endyear: promotions.endyear, current: promotions.current })
|
||||||
mobility.id,
|
.from(promotions);
|
||||||
mobility.studentId,
|
|
||||||
mobility.startDate,
|
|
||||||
mobility.endDate,
|
|
||||||
mobility.weeksCount,
|
|
||||||
mobility.destinationCountry,
|
|
||||||
mobility.destinationName,
|
|
||||||
mobility.mobilityStatus
|
|
||||||
FROM mobility`,
|
|
||||||
).all();
|
|
||||||
|
|
||||||
const promotions = connection.prepare(
|
|
||||||
`SELECT id, name FROM students.promotions`,
|
|
||||||
).all();
|
|
||||||
|
|
||||||
connection.close();
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ mobilities, students, promotions }),
|
JSON.stringify({
|
||||||
{
|
mobilities: mobilityRows,
|
||||||
status: 200,
|
students: studentRows,
|
||||||
headers: { "Content-Type": "application/json" },
|
promotions: promotionRows,
|
||||||
},
|
}),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching mobility data:", error);
|
console.error("Error fetching mobility data:", error);
|
||||||
@@ -58,8 +39,6 @@ export const handler: Handlers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async POST(request) {
|
async POST(request) {
|
||||||
console.log("API /mobility/api/insert_mobility POST called");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { data } = body;
|
const { data } = body;
|
||||||
@@ -67,32 +46,8 @@ export const handler: Handlers = {
|
|||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
throw new Error("Invalid request body");
|
throw new Error("Invalid request body");
|
||||||
}
|
}
|
||||||
console.log("Connecting to mobility database...");
|
|
||||||
const connection = new Database("databases/data/mobility.db", {
|
|
||||||
create: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Attaching students database...");
|
for (const entry of data) {
|
||||||
connection.run(
|
|
||||||
"ATTACH DATABASE 'databases/data/students.db' AS students",
|
|
||||||
);
|
|
||||||
console.log("Students database attached successfully.");
|
|
||||||
|
|
||||||
const insertQuery = connection.prepare(
|
|
||||||
`INSERT INTO mobility (
|
|
||||||
id, studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus
|
|
||||||
)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
ON CONFLICT(id) DO UPDATE SET
|
|
||||||
startDate = excluded.startDate,
|
|
||||||
endDate = excluded.endDate,
|
|
||||||
weeksCount = excluded.weeksCount,
|
|
||||||
destinationCountry = excluded.destinationCountry,
|
|
||||||
destinationName = excluded.destinationName,
|
|
||||||
mobilityStatus = excluded.mobilityStatus`,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const mobility of data) {
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
studentId,
|
studentId,
|
||||||
@@ -102,19 +57,16 @@ export const handler: Handlers = {
|
|||||||
destinationCountry,
|
destinationCountry,
|
||||||
destinationName,
|
destinationName,
|
||||||
mobilityStatus = "N/A",
|
mobilityStatus = "N/A",
|
||||||
} = mobility;
|
} = entry;
|
||||||
|
|
||||||
console.log("Processing mobility data:", mobility);
|
const studentExists = await db
|
||||||
|
.select({ userId: students.userId })
|
||||||
|
.from(students)
|
||||||
|
.where(eq(students.userId, studentId))
|
||||||
|
.limit(1)
|
||||||
|
.then((rows) => rows.length > 0);
|
||||||
|
|
||||||
const studentExists = connection
|
if (!studentExists) {
|
||||||
.prepare(
|
|
||||||
`SELECT COUNT(*) AS count FROM students.students WHERE userId = ?`,
|
|
||||||
)
|
|
||||||
.get(studentId);
|
|
||||||
|
|
||||||
console.log(`Student ${studentId} exists:`, studentExists.count > 0);
|
|
||||||
|
|
||||||
if (studentExists.count === 0) {
|
|
||||||
console.warn(`Skipping mobility for unknown studentId: ${studentId}`);
|
console.warn(`Skipping mobility for unknown studentId: ${studentId}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -123,43 +75,39 @@ export const handler: Handlers = {
|
|||||||
if (startDate && endDate) {
|
if (startDate && endDate) {
|
||||||
const start = new Date(startDate);
|
const start = new Date(startDate);
|
||||||
const end = new Date(endDate);
|
const end = new Date(endDate);
|
||||||
if (start <= end) {
|
calculatedWeeksCount = start <= end
|
||||||
calculatedWeeksCount = Math.ceil(
|
? Math.ceil(
|
||||||
(end.getTime() - start.getTime()) / (7 * 24 * 60 * 60 * 1000),
|
(end.getTime() - start.getTime()) / (7 * 24 * 60 * 60 * 1000),
|
||||||
);
|
)
|
||||||
} else {
|
: null;
|
||||||
calculatedWeeksCount = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Executing SQL insert/update query for:", {
|
await db
|
||||||
|
.insert(mobility)
|
||||||
|
.values({
|
||||||
id,
|
id,
|
||||||
studentId,
|
studentId,
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
calculatedWeeksCount,
|
weeksCount: calculatedWeeksCount,
|
||||||
destinationCountry,
|
destinationCountry,
|
||||||
destinationName,
|
destinationName,
|
||||||
mobilityStatus,
|
mobilityStatus,
|
||||||
});
|
})
|
||||||
|
.onConflictDoUpdate({
|
||||||
insertQuery.run(
|
target: mobility.id,
|
||||||
id,
|
set: {
|
||||||
studentId,
|
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
calculatedWeeksCount,
|
weeksCount: calculatedWeeksCount,
|
||||||
destinationCountry,
|
destinationCountry,
|
||||||
destinationName,
|
destinationName,
|
||||||
mobilityStatus,
|
mobilityStatus,
|
||||||
);
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.close();
|
return new Response("Data inserted/updated successfully", { status: 200 });
|
||||||
console.log("Mobility data inserted/updated successfully.");
|
|
||||||
return new Response("Data inserted/updated successfully", {
|
|
||||||
status: 200,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error inserting mobility data:", error);
|
console.error("Error inserting mobility data:", error);
|
||||||
return new Response("Failed to insert/update data", { status: 500 });
|
return new Response("Failed to insert/update data", { status: 500 });
|
||||||
|
|||||||
@@ -1,150 +1,121 @@
|
|||||||
import { FreshContext, Handlers } from "$fresh/server.ts";
|
import { FreshContext, Handlers } from "$fresh/server.ts";
|
||||||
import connect from "$root/databases/connect.ts";
|
import { db } from "$root/databases/db.ts";
|
||||||
|
import { promotions, students } from "$root/databases/schema.ts";
|
||||||
import { AuthenticatedState } from "$root/defaults/interfaces.ts";
|
import { AuthenticatedState } from "$root/defaults/interfaces.ts";
|
||||||
import { Database } from "@db/sqlite";
|
import { eq, lt } from "npm:drizzle-orm";
|
||||||
|
|
||||||
/**
|
async function getItself(
|
||||||
* Gets itself from the database.
|
|
||||||
* @param database The database connection
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @returns Itself from the database.
|
|
||||||
*/
|
|
||||||
function getItself(
|
|
||||||
database: Database,
|
|
||||||
userId: string,
|
userId: string,
|
||||||
): { student: Student | null; promo: Promotion | null } {
|
): Promise<{ student: Student | null; promo: Promotion | null }> {
|
||||||
const studentQuery = "select * from students where userId = ?";
|
const student = await db
|
||||||
const student: Student | undefined = database.prepare(studentQuery).get(
|
.select()
|
||||||
userId,
|
.from(students)
|
||||||
);
|
.where(eq(students.userId, userId))
|
||||||
|
.limit(1)
|
||||||
|
.then((rows) => rows[0] ?? null);
|
||||||
|
|
||||||
if (!student) {
|
if (!student) {
|
||||||
return { student: null, promo: null };
|
return { student: null, promo: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
const promoQuery = "select * from promotions where id = ?";
|
const promo = await db
|
||||||
const promo: Promotion | undefined = database.prepare(promoQuery).get(
|
.select()
|
||||||
student.promotionId,
|
.from(promotions)
|
||||||
);
|
.where(eq(promotions.id, student.promotionId!))
|
||||||
|
.limit(1)
|
||||||
|
.then((rows) => rows[0] ?? null);
|
||||||
|
|
||||||
return { student, promo: promo ?? null };
|
return { student, promo };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function getAll(): Promise<
|
||||||
* Gets itself from the database.
|
{ students: Student[]; promos: Promotion[] }
|
||||||
* @param database The database connexion
|
> {
|
||||||
* @param userId The user ID.
|
const rows = await db
|
||||||
* @returns Itself from the database.
|
.select({
|
||||||
*/
|
userId: students.userId,
|
||||||
function getAll(
|
firstName: students.firstName,
|
||||||
database: Database,
|
lastName: students.lastName,
|
||||||
): { students: Student[]; promos: Promotion[] } {
|
mail: students.mail,
|
||||||
const studentsQuery = `
|
promotionId: students.promotionId,
|
||||||
select userId, firstName, lastName, mail, promotionId
|
})
|
||||||
from students inner join promotions
|
.from(students)
|
||||||
on students.promotionId = promotions.id
|
.innerJoin(promotions, eq(students.promotionId, promotions.id))
|
||||||
where promotions.current < 6`;
|
.where(lt(promotions.current, 6));
|
||||||
const students: Student[] = database.prepare(studentsQuery).all();
|
|
||||||
|
|
||||||
const promosQuery = "select * from promotions where promotions.current < 6";
|
const promos = await db
|
||||||
const promos: Promotion[] | undefined = database.prepare(promosQuery).all();
|
.select()
|
||||||
|
.from(promotions)
|
||||||
|
.where(lt(promotions.current, 6));
|
||||||
|
|
||||||
return { students, promos };
|
return { students: rows as Student[], promos };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function addStudents(
|
||||||
* Add users to the database.
|
studentList: Student[],
|
||||||
* @param database The database connexion
|
promoId: number,
|
||||||
* @param students The students to add
|
): Promise<void> {
|
||||||
* @param promoId The promotion id.
|
for (const student of studentList) {
|
||||||
*/
|
await db
|
||||||
function addStudents(database: Database, students: Student[], promoId: string) {
|
.insert(students)
|
||||||
const query = `
|
.values({
|
||||||
INSERT INTO students
|
userId: student.userId,
|
||||||
(userId, firstName, lastName, mail, promotionId)
|
firstName: student.firstName,
|
||||||
VALUES (?, ?, ?, ?, ?)`;
|
lastName: student.lastName,
|
||||||
|
mail: student.mail,
|
||||||
const statement = database.prepare(query);
|
promotionId: promoId,
|
||||||
|
})
|
||||||
for (const student of students) {
|
.onConflictDoNothing();
|
||||||
statement.run(
|
|
||||||
student.userId,
|
|
||||||
student.firstName,
|
|
||||||
student.lastName,
|
|
||||||
student.mail,
|
|
||||||
promoId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handler: Handlers<null, AuthenticatedState> = {
|
export const handler: Handlers<null, AuthenticatedState> = {
|
||||||
/**
|
|
||||||
* The students the user can see.
|
|
||||||
* @param _request The HTTP request.
|
|
||||||
* @param _context The context with authenticated state.
|
|
||||||
* @returns All students our user can see.
|
|
||||||
*/
|
|
||||||
// deno-lint-ignore require-await
|
|
||||||
async GET(
|
async GET(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
context: FreshContext<AuthenticatedState>,
|
context: FreshContext<AuthenticatedState>,
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
using connection = connect("students");
|
|
||||||
const database = connection.database;
|
|
||||||
|
|
||||||
if (context.state.session.eduPersonPrimaryAffiliation == "student") {
|
if (context.state.session.eduPersonPrimaryAffiliation == "student") {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify(getItself(database, context.state.session.uid)),
|
JSON.stringify(await getItself(context.state.session.uid)),
|
||||||
{
|
{ headers: { "content-type": "application/json" } },
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify(getAll(database)),
|
JSON.stringify(await getAll()),
|
||||||
{
|
{ headers: { "content-type": "application/json" } },
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Add students in the database.
|
|
||||||
* @param request The HTTP request.
|
|
||||||
* @param _context The Fresh context.
|
|
||||||
* @returns HTTP 201 on successful insert.
|
|
||||||
*/
|
|
||||||
async POST(
|
async POST(
|
||||||
request: Request,
|
request: Request,
|
||||||
_context: FreshContext<AuthenticatedState>,
|
_context: FreshContext<AuthenticatedState>,
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const { students, promo }: { students: Student[]; promo: string } =
|
const { students: studentList, promo }: {
|
||||||
await request.json();
|
students: Student[];
|
||||||
|
promo: string;
|
||||||
|
} = await request.json();
|
||||||
|
|
||||||
if (!promo || !promo.match(/^\d{4}-\dA$/) || !Array.isArray(students)) {
|
if (!promo || !promo.match(/^\d{4}-\dA$/) || !Array.isArray(studentList)) {
|
||||||
return new Response(null, { status: 400 });
|
return new Response(null, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
using connection = connect("students");
|
|
||||||
const database = connection.database;
|
|
||||||
|
|
||||||
const { endyear, current } = promo.match(
|
const { endyear, current } = promo.match(
|
||||||
/^(?<endyear>\d{4})-(?<current>\d)A$/,
|
/^(?<endyear>\d{4})-(?<current>\d)A$/,
|
||||||
)?.groups!;
|
)?.groups!;
|
||||||
|
|
||||||
database.prepare(
|
await db
|
||||||
"insert or ignore into promotions (endyear, current) values (?, ?)",
|
.insert(promotions)
|
||||||
).run(endyear, current);
|
.values({ endyear: Number(endyear), current: Number(current) })
|
||||||
|
.onConflictDoNothing();
|
||||||
|
|
||||||
const { id: promoId }: { id: string } = database
|
const promo_row = await db
|
||||||
.prepare("select id from promotions where endyear = ? and current = ?")
|
.select()
|
||||||
.get(endyear, current)!;
|
.from(promotions)
|
||||||
|
.where(eq(promotions.endyear, Number(endyear)))
|
||||||
|
.then((rows) => rows.find((r) => r.current === Number(current))!);
|
||||||
|
|
||||||
addStudents(database, students, promoId);
|
await addStudents(studentList, promo_row.id);
|
||||||
|
|
||||||
return new Response(null, { status: 201 });
|
return new Response(null, { status: 201 });
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user