Skip to content

Commit

Permalink
feat: add a import script to collection for JSON data
Browse files Browse the repository at this point in the history
  • Loading branch information
Gum-Joe committed Oct 21, 2024
1 parent 0b8eee9 commit 276789f
Show file tree
Hide file tree
Showing 2 changed files with 305 additions and 0 deletions.
196 changes: 196 additions & 0 deletions collection/emails/import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* This scrpt allows you to import a list of people into the database under one specific items and variant.
*
* Auto imports into current academic year.
*/
import { AcademicYear } from "@docsoc/eactivities";
import { createLogger } from "@docsoc/util";
import { PrismaClient } from "@prisma/client";
// Load .env file
import dotenv from "dotenv";

const logger = createLogger("collection.import");

dotenv.config();

/**
* ================================
* DEFINE THE ITEM BELOW
* ================================
*/

/** Used for the name of the {@link RootItem} */
const ROOT_ITEM_NAME = "Freshers Merch";

/** Used for the name of the {@link Variant} */
const VARIANT_NAME = "Freshers Merch 2024";

/** Used for the quantity of the {@link Variant} */
const VARIANT_QUANTITY = 1;

/**
* ================================
* DATA SOURCE
* ================================
*
* Data source must be a JSON file
*/
/**
* Data source must be a JSON file which is a list of records of this shape
*/
interface DataSource {
/** MUST be correct as it is used as the unique ID in the DB to link orders to a studnt */
shortcode: string;
/** Ideally make this right, but if not just use the shortcode */
cid: string;
firstName: string;
lastName: string;
email: string;
}

/** Path to the data source */
const DATA_SOURCE_PATH = "./data/freshers-2024.json";

// Start the script

// 0: init db
const prisma = new PrismaClient();

// 0.1: Find the current academic year
// from collection/lib/config.ts
async function getConfigValueFor(key: string) {
const config = await prisma.config.findFirst({
where: {
key,
},
});
return config?.value;
}
const ACADEMIC_YEAR_KEY = "academicYear";
export async function getAcademicYear(): Promise<AcademicYear> {
return (await getConfigValueFor(ACADEMIC_YEAR_KEY)) as string as AcademicYear;
}

async function main() {
const currentAcademicYear = await getAcademicYear();

if (!currentAcademicYear) {
throw new Error("No academic year found to import into");
}

// 1: Upsert the item

const item = await prisma.rootItem.upsert({
where: { name: ROOT_ITEM_NAME },
update: {},
create: {
name: ROOT_ITEM_NAME,
academicYear: currentAcademicYear,
Variant: {
create: {
variantName: VARIANT_NAME,
},
},
},
include: {
Variant: true,
},
});

// Load file
const data = (await import(DATA_SOURCE_PATH)).default as DataSource[];

// Valid data
if (!Array.isArray(data)) {
throw new Error("Data source is not an array");
}

// Make an import for it
const importName = `${ROOT_ITEM_NAME}, ${VARIANT_NAME} via import.ts @ ${new Date().toLocaleString(
"en-GB",
)}`;
const importItem = await prisma.orderItemImport.create({
data: {
name: importName,
},
});

// 2: Upsert the students
let index = 0;
for (const record of data) {
const { shortcode, cid, firstName, lastName, email } = record;

// If any null values, print warning and skip
if (!shortcode || !cid || !firstName || !lastName || !email) {
logger.warn(
`Skipping ${shortcode} due to missing values. Record was ${JSON.stringify(record)}`,
);
continue;
}

logger.debug(`Processing ${shortcode} <${email}> (CID: ${cid})`);
logger.debug(`Upserting ${shortcode}...`);
const student = await prisma.imperialStudent.upsert({
where: {
shortcode,
},
update: {},
create: {
cid,
shortcode,
firstName,
lastName,
email,
},
});

// Make order
// If they already have a merch order matching that item, skip
const existingOrder = await prisma.order.findFirst({
where: {
studentId: student.id,
OrderItem: {
some: {
variantId: item.Variant[0].id,
},
},
},
});

if (existingOrder) {
logger.warn(`Skipping ${shortcode} as they already have a ${VARIANT_NAME} order`);
continue;
}

// Create order
await prisma.order.create({
data: {
academicYear: currentAcademicYear,
orderDate: new Date(),
studentId: student.id,
orderNo: Math.floor(Math.random() * 100000) * 1000 + index,
OrderItem: {
create: {
quantity: VARIANT_QUANTITY,
variantId: item.Variant[0].id,
importId: importItem.id,
collected: false,
},
},
},
});

logger.info(`Imported ${shortcode} <${email}> (CID: ${cid})`);

index++;
}
}

main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(() => {
prisma.$disconnect();
});
109 changes: 109 additions & 0 deletions collection/emails/pride.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Import pride merch
// OLD Script, will not work with current codebase
import { PrismaClient } from "@prisma/client";
import { parse } from "csv-parse";
import { promises as fs } from "fs";

const prisma = new PrismaClient();

async function main(fileName: string) {
// Create pride
const lanyard = await prisma.rootItem.upsert({
where: { name: "Pride Lanyard" },
update: {},
create: {
name: "Pride Lanyard",
variants: {
create: {
variantName: "Pride Lanyard",
},
},
},
include: {
variants: true,
},
});

const fileContents = await fs.open(fileName, "r").then((f) => f.readFile("utf-8"));

const iter = parse(fileContents, {
columns: true,
});

for await (const record of iter) {
const email = record["Email"];
const name = record["Name"];
const dateWithTime = record["Start time"];

const shortcode = email.split("@")[0];

console.log(`Processing ${name} <${email}> (${shortcode})`);

// User
const user = await prisma.imperialStudent.upsert({
where: {
shortcode,
},
update: {},
create: {
cid: name,
shortcode,
firstName: name,
lastName: "",
email: email,
},
});

// Order
// Basically, if they already have an order containing a pride lanyard, skip
const lanyardOrders = await prisma.order.findFirst({
where: {
studentId: user.id,
orderItems: {
some: {
variantId: lanyard.variants[0].id,
},
},
},
relationLoadStrategy: "join",
include: {
orderItems: true,
},
});

if (lanyardOrders) {
console.log(`Skipping ${name} as they already have a lanyard order`);
continue;
}

// Add fake lanyard order
await prisma.order.create({
data: {
orderDate: new Date(dateWithTime),
student: {
connect: {
id: user.id,
},
},
orderNo: Math.floor(Math.random() * 100000),
orderItems: {
create: {
variantId: lanyard.variants[0].id,
quantity: 1,
collected: false,
},
},
},
});
}
}

main("./data/Pride Lanyard 26.06.24.csv")
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});

0 comments on commit 276789f

Please sign in to comment.