Skip to content

Commit

Permalink
fixed merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
DomiVesalius committed Jul 23, 2023
2 parents 2272160 + 2b13260 commit 40a1c55
Show file tree
Hide file tree
Showing 25 changed files with 2,387 additions and 919 deletions.
13 changes: 13 additions & 0 deletions backend/dev.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This dockerfile is meant to be used in a development to enable hot reloading

FROM node:18-alpine

WORKDIR /backend

COPY ./ ./

RUN npm install

EXPOSE 3000

CMD ["npm", "run", "dev"]
209 changes: 127 additions & 82 deletions backend/module/role/admin/upload.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,146 @@
const express = require("express");
const router = express.Router();
const multer = require('multer');
const csv = require('csvtojson');
const format = require('pg-format');
const path = require('path');
const multer = require("multer");
const csv = require("csvtojson");
const format = require("pg-format");
const path = require("path");
const client = require("../../../setup/db");
const helpers = require("../../../utilities/helpers");

const upload = multer({
dest: './tmp/upload/'
dest: "./tmp/upload/",
});

router.post("/", upload.single("file"), (req, res) => {
if (req.file === undefined) {
res.status(400).json({ message: "The file is missing or has invalid format." });
return;
}
if (path.extname(req.file.originalname) !== ".csv") {
res.status(200).json({ message: "The file must be a csv file." });
return;
}
if (!("course_id" in req.body) || helpers.number_validate(req.body["course_id"])) {
res.status(400).json({ message: "The course id is missing or has invalid format." });
return;
}
if (!("update_user_info" in req.body) || helpers.boolean_validate(req.body["update_user_info"])) {
res.status(400).json({ message: "The update user info property is missing or invalid." });
return;
}
router.post("/", upload.single("file"), async (req, res) => {
if (req.file === undefined) {
res
.status(400)
.json({ message: "The file is missing or has invalid format." });
return;
}
if (path.extname(req.file.originalname) !== ".csv") {
res.status(200).json({ message: "The file must be a csv file." });
return;
}
if (
!("course_id" in req.body) ||
helpers.number_validate(req.body["course_id"])
) {
res
.status(400)
.json({ message: "The course id is missing or has invalid format." });
return;
}
if (
!("update_user_info" in req.body) ||
helpers.boolean_validate(req.body["update_user_info"])
) {
res.status(400).json({
message: "The update user info property is missing or invalid.",
});
return;
}

let roles = ["instructor", "ta", "student"];
if (!("role" in req.body) || !roles.includes(req.body["role"])) {
res.status(400).json({ message: "The role is missing or invalid." });
return;
}

let roles = ["instructor", "ta", "student"];
if (!("role" in req.body) || !roles.includes(req.body["role"])) {
res.status(400).json({ message: "The role is missing or invalid." });
return;
}
if (
req.body["update_user_info"] === true ||
req.body["update_user_info"] === "true"
) {
var sql_register =
"INSERT INTO user_info (username, password, email) VALUES %L ON CONFLICT (username) DO UPDATE SET email = EXCLUDED.email";
} else {
var sql_register =
"INSERT INTO user_info (username, password, email) VALUES %L ON CONFLICT (username) DO NOTHING";
}

if (req.body["update_user_info"] === true || req.body["update_user_info"] === "true"){
var sql_register = "INSERT INTO user_info (username, password, email) VALUES %L ON CONFLICT (username) DO UPDATE SET email = EXCLUDED.email";
} else{
var sql_register = "INSERT INTO user_info (username, password, email) VALUES %L ON CONFLICT (username) DO NOTHING";
}

let sql_upload = "INSERT INTO course_role (username, course_id, role) VALUES %L ON CONFLICT (username, course_id) DO NOTHING; "
+ "INSERT INTO course_" + req.body["course_id"] + ".user (username) VALUES %L ON CONFLICT (username) DO NOTHING";
let sql_upload =
"INSERT INTO course_role (username, course_id, role) VALUES %L ON CONFLICT (username, course_id) DO NOTHING; " +
"INSERT INTO course_" +
req.body["course_id"] +
".user (username) VALUES %L ON CONFLICT (username) DO NOTHING";

const csv_path = req.file.destination + req.file.filename;
csv({
noheader: true,
output: "csv"
}).fromFile(csv_path).then((csv_row) => {
let invalid_username = 0;
let invalid_email = 0;
let upload_data_all = [];
let upload_data_users = [];
let register_data = [["test", "initial", "ibs-test@utoronto.ca"]];
const csv_path = req.file.destination + req.file.filename;
csv({
noheader: true,
output: "csv",
})
.fromFile(csv_path)
.then(async (csv_row) => {
let invalid_username = 0;
let invalid_email = 0;
let upload_data_all = [];
let upload_data_users = [];
let register_data = [["test", "initial", "ibs-test@utoronto.ca"]];
let totalRows = csv_row.length - 1;

for (let j = 1; j < csv_row.length; j++) {
if (csv_row[j].length >= 1 && !(helpers.name_validate(csv_row[j][0]))) {
upload_data_users.push([csv_row[j][0]]);
upload_data_all.push([csv_row[j][0], req.body["course_id"], req.body["role"]]);
if (csv_row[j].length >= 2 && csv_row[j][1] != "") {
if (helpers.email_validate(csv_row[j][1])) {
invalid_email += 1;
} else {
register_data.push([csv_row[j][0], 'initial', csv_row[j][1]]);
}
}
for (let j = 1; j < csv_row.length; j++) {
if (csv_row[j].length >= 1 && !helpers.name_validate(csv_row[j][0])) {
upload_data_users.push([csv_row[j][0]]);
upload_data_all.push([
csv_row[j][0],
req.body["course_id"],
req.body["role"],
]);
if (csv_row[j].length >= 2 && csv_row[j][1] !== "") {
if (helpers.email_validate(csv_row[j][1])) {
invalid_email += 1;
} else {
invalid_username += 1;
register_data.push([csv_row[j][0], "initial", csv_row[j][1]]);
}
}
} else {
invalid_username += 1;
}
if (upload_data_users.length === 0) {
res.status(200).json({ message: "The file must contain at least 1 valid username." });
}
}

client.query(format(sql_register, register_data), [], (err, pg_res_register) => {
if (err) {
res.status(404).json({ message: "Unknown error." });
console.log(err);
} else {
client.query(format(sql_upload, upload_data_all, upload_data_users), [], (err, pg_res_upload) => {
if (err) {
if (err.code === "23503" && err.constraint === "username") {
let username = err.detail.match(/Key \(username\)=\((.*)\) is not present in table "user_info"\./);
res.status(400).json({ message: "The username " + username[1] + " is not found in the database and a valid email is not provided." });
} else {
res.status(404).json({ message: "Unknown error." });
console.log(err);
}
} else {
let message = pg_res_upload[0].rowCount + " users are added to the course as " + req.body["role"] + ".";
res.status(200).json({ message: message, added: pg_res_upload[0].rowCount, registered: pg_res_register.rowCount, invalid_username: invalid_username, invalid_email: invalid_email });
}
});
}
let validRows =
totalRows === 0 ? 0 : totalRows - invalid_username - invalid_email;

if (upload_data_users.length === 0) {
res.status(200).json({
message: "The file must contain at least 1 valid username.",
});
}

try {
await client.query(format(sql_register, register_data), []);
await client.query(
format(sql_upload, upload_data_all, upload_data_users)
);
let message =
validRows +
" users are added to the course as " +
req.body["role"] +
".";
res.status(200).json({
message: message,
added: validRows,
registered: validRows,
invalid_username: invalid_username,
invalid_email: invalid_email,
});
} catch (err) {
if (err.code === "23503" && err.constraint === "username") {
let username = err.detail.match(
/Key \(username\)=\((.*)\) is not present in table "user_info"\./
);
res.status(400).json({
message:
"The username " +
username[1] +
" is not found in the database and a valid email is not provided.",
});
} else {
res.status(404).json({ message: "Unknown error." });
console.error(err);
}
}
});
})
});

module.exports = router;
module.exports = router;
4 changes: 4 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "app.js",
"scripts": {
"start": "node app",
"dev": "nodemon app.js --legacy-watch",
"deploy": "pm2 start --env production",
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down Expand Up @@ -33,5 +34,8 @@
"nodemailer": "^6.7.2",
"pg": "^8.7.1",
"pg-format": "^1.0.4"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}
6 changes: 5 additions & 1 deletion docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ services:
- postgres
build:
context: ./backend
dockerfile: Dockerfile
dockerfile: dev.Dockerfile
environment:
DATABASE_URL: postgres://ibs:password@postgres:5432/ibs?sslmode=disable
volumes:
- ./backend:/backend
env_file:
- backend/.env

frontend:
restart: always
Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,6 @@
```

### Note
For questions/issues regarding hot-reloading on the frontend read [this](frontend_hot_reloading.md)
For questions/issues regarding hot-reloading on the frontend read [this](hot_reloading.md)

**Written by Eric Ryu**
File renamed without changes.
24 changes: 9 additions & 15 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import SubmitMarks from './components/Page/Instructor/SubmitMarks';
import TaskGroupPage from './components/Page/Instructor/TaskGroupPage';
import AddTask from './components/Page/Instructor/AddTask';
import ModifyTask from './components/Page/Instructor/ModifyTask';

import InstructorTaskMarksPage from './components/Page/Instructor/InstructorTaskMarksPage';

function App() {
const theme = ThemeSettings();
Expand All @@ -46,7 +46,6 @@ function App() {
<Route path="/login" element={<LoginPage />}></Route>
<Route path="/reset" element={<ResetPasswordPage />}></Route>
<Route path="/home" element={<Home />}></Route>

<Route path="/course/:course_id/task" element={<StudentTaskPage />}></Route>
<Route
path="/course/:course_id/student-list"
Expand All @@ -68,24 +67,19 @@ function App() {
path="/course/:course_id/task/:task/file"
element={<StudentFilePage />}
></Route>

<Route path="/ta/course/:course_id/task" element={<TaTaskPage />}></Route>
<Route
path="/ta/course/:course_id/task/:task/interview"
element={<TaInterviewPage />}
></Route>

<Route
path="/instructor/course/:course_id/task"
element={<InstructorTaskPage />}
>
</Route>

></Route>
<Route
path="/instructor/course/:courseId/task/:taskId/groups"
element={<TaskGroupListPage />}
/>

<Route
path="/instructor/course/:course_id/impersonate"
element={<InstructorImpersonate />}
Expand All @@ -102,6 +96,13 @@ function App() {
path="/instructor/course/:course_id/task/:task/modify"
element={<ModifyTask />}
/>
path="/instructor/course/:course_id/task/:task_id/mark" element=
{<InstructorTaskMarksPage />}
/>
<Route
path="/instructor/course/:course_id/impersonate"
element={<InstructorImpersonate />}
></Route>
<Route
path="/instructor/course/:courseId/task-group"
element={<TaskGroupPage role="instructor" />}
Expand All @@ -110,24 +111,17 @@ function App() {
path="/instructor/course/:courseId/submit-marks"
element={<SubmitMarks />}
></Route>

<Route path="/admin" element={<AdminPage />}></Route>
<Route path="/admin/course/:course_id/task" element={<AdminCoursePage />} />
<Route path="/admin/impersonate" element={<AdminImpersonate />} />
<Route
path="/admin/course/:courseId/all-grades"
element={<AggregatedGrades role="admin" />}
/>
<Route
path="/admin/course/:course_id/task"
element={<AdminCoursePage />}
></Route>
<Route path="/admin/impersonate" element={<AdminImpersonate />}></Route>
<Route
path="/admin/course/:courseId/task-group"
element={<TaskGroupPage role="admin" />}
/>

<Route path="*" element={<Error />} />
</Routes>
</BrowserRouter>
Expand Down
Loading

0 comments on commit 40a1c55

Please sign in to comment.