Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/csv #90

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions app/(api)/_actions/logic/ingestCSV.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
'use server';

import { CreateManyTeams } from '@datalib/teams/createTeams';
import csvAlgorithm from '@utils/csv-ingestion/csvAlgorithm';

export default async function ingestCSV() {
const parsedData = await (await csvAlgorithm()).json();

const res = await (await CreateManyTeams(parsedData.body)).json();
export default async function ingestCSV(parsedData: []) {
const res = await (await CreateManyTeams(parsedData)).json();
return { ok: res.ok, error: res.error };
}
28 changes: 6 additions & 22 deletions app/(api)/_actions/logic/uploadFile.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
'use server';
import fs from 'fs';

import csvAlgorithm from '@utils/csv-ingestion/csvAlgorithm';

export default async function uploadFile(formData: FormData) {
const file = formData.get('file') as File;
const data = await file.arrayBuffer();
return new Promise((resolve, rejects) => {
fs.writeFile(
'app/(api)/_data/2024_data.csv',
Buffer.from(data),
(error) => {
if (error) {
rejects({
ok: false,
body: null,
error: error?.message,
});
} else {
resolve({
ok: true,
body: `Successfully uploaded.`,
error: null,
});
}
}
);
});
const blob = new Blob([data], { type: file.type });

const res = await csvAlgorithm(blob);
return await res.json();
}
72 changes: 41 additions & 31 deletions app/(api)/_utils/csv-ingestion/csvAlgorithm.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import csv from 'csv-parser';
import { NextResponse } from 'next/server';
import trackData from '../../_data/tracks.json' assert { type: 'json' };
import { Readable } from 'stream';

interface parsedRecord {
name: string;
Expand All @@ -18,7 +18,8 @@ const validTracks: string[] = trackData
.filter((t) => t !== 'Best Hack for Social Good');

function sortTracks(track1: string, track2: string, chosentracks: string) {
const tracksInOrder: string[] = [track1, track2];
let tracksInOrder: string[] = [track1, track2];

if (chosentracks.length > 1) {
const otherTracks = chosentracks
.split(',')
Expand All @@ -28,47 +29,56 @@ function sortTracks(track1: string, track2: string, chosentracks: string) {
validTracks.includes(track) && !tracksInOrder.includes(track)
);

tracksInOrder.push(...otherTracks);
const uniqueTracks = [...new Set(otherTracks)];

tracksInOrder.push(...uniqueTracks);
}

if (tracksInOrder.length > 4) {
tracksInOrder.length = 4;
}

return tracksInOrder.filter((track) => track !== 'NA');
tracksInOrder = tracksInOrder.filter(
(track) => track !== 'NA' && validTracks.includes(track)
);
return tracksInOrder;
}

export default async function csvAlgorithm() {
const csvFilePath = 'app/(api)/_data/2024_data.csv';

export default async function csvAlgorithm(blob: Blob) {
try {
const parsePromise = new Promise<parsedRecord[]>((resolve, reject) => {
const output: parsedRecord[] = [];

fs.createReadStream(csvFilePath)
.pipe(csv())
.on('data', (data) => {
if (data['Table Number'] !== '') {
const track1 = data['Track #1'].trim();
const track2 = data['Track #2'].trim();

const tracksInOrder: string[] = sortTracks(
track1,
track2,
data['Opt-In Prizes']
);

output.push({
name: data['Project Title'],
number: parseInt(data['Table Number']),
tracks: tracksInOrder,
});
}
})
.on('end', () => {
resolve(output);
})
.on('error', (error) => reject(error));
const parseBlob = async () => {
const buffer = Buffer.from(await blob.arrayBuffer());
const stream = Readable.from(buffer.toString());

stream
.pipe(csv())
.on('data', (data) => {
if (data['Table Number'] !== '') {
const track1 = data['Track #1'].trim();
const track2 = data['Track #2'].trim();

const tracksInOrder: string[] = sortTracks(
track1,
track2,
data['Opt-In Prizes']
);

output.push({
name: data['Project Title'],
number: parseInt(data['Table Number']),
tracks: tracksInOrder,
});
}
})
.on('end', () => {
resolve(output);
})
.on('error', (error) => reject(error));
};
parseBlob().catch(reject);
});

const results = await parsePromise;
Expand Down
26 changes: 12 additions & 14 deletions app/(pages)/judges/admin/csv/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,29 @@ export default function CsvIngestion() {
const [response, setResponse] = useState('');
const [uploadRes, setUploadRes] = useState('');

const handleIngestion = async () => {
setPending(true);
const res = await ingestCSV();
setResponse(JSON.stringify(res));
setPending(false);
};

const handleUpload = async (event: React.FormEvent<HTMLFormElement>) => {
const handler = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const res = await uploadFile(formData);
setUploadRes(JSON.stringify(res));
const fileRes = await uploadFile(formData);
setUploadRes(JSON.stringify(fileRes.ok));

if (fileRes.ok) {
setPending(true);
const res = await ingestCSV(fileRes.body);
setResponse(JSON.stringify(res));
setPending(false);
}
};

return (
<div>
<div>
<h4>Upload CSV:</h4>
<form onSubmit={handleUpload} className={styles.form}>
<form onSubmit={handler} className={styles.form}>
<input type="file" accept=".csv" name="file" id="file" />
<button type="submit">Upload</button>
<p>{uploadRes}</p>
<p>Upload Successful: {uploadRes}</p>
</form>
<h4>Create Teams:</h4>
<button onClick={handleIngestion}>Start CSV Ingestion</button>
<p>{pending ? 'creating teams...' : response}</p>
</div>
</div>
Expand Down