Skip to content

Commit

Permalink
Merge pull request #104 from comicalromance/import-csv
Browse files Browse the repository at this point in the history
Add Import Functionality
  • Loading branch information
Piyotato authored Oct 27, 2022
2 parents 3572335 + c902420 commit 5664401
Show file tree
Hide file tree
Showing 17 changed files with 291 additions and 22 deletions.
4 changes: 4 additions & 0 deletions src/main/java/seedu/studmap/logic/Logic.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package seedu.studmap.logic;

import java.io.File;
import java.nio.file.Path;

import javafx.collections.ObservableList;
import seedu.studmap.commons.core.GuiSettings;
import seedu.studmap.logic.commands.CommandResult;
import seedu.studmap.logic.commands.exceptions.CommandException;
import seedu.studmap.logic.imports.exceptions.ImportException;
import seedu.studmap.logic.parser.exceptions.ParseException;
import seedu.studmap.model.ReadOnlyStudMap;
import seedu.studmap.model.student.Student;
Expand Down Expand Up @@ -47,4 +49,6 @@ public interface Logic {
* Set the user prefs' GUI settings.
*/
void setGuiSettings(GuiSettings guiSettings);

String importFile(File file) throws ImportException;
}
10 changes: 10 additions & 0 deletions src/main/java/seedu/studmap/logic/LogicManager.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package seedu.studmap.logic;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
Expand All @@ -10,6 +11,8 @@
import seedu.studmap.logic.commands.Command;
import seedu.studmap.logic.commands.CommandResult;
import seedu.studmap.logic.commands.exceptions.CommandException;
import seedu.studmap.logic.imports.ImportCsv;
import seedu.studmap.logic.imports.exceptions.ImportException;
import seedu.studmap.logic.parser.StudMapParser;
import seedu.studmap.logic.parser.exceptions.ParseException;
import seedu.studmap.model.Model;
Expand All @@ -27,6 +30,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
private final StudMapParser studMapParser;
private final ImportCsv importer;

/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
Expand All @@ -35,6 +39,7 @@ public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
studMapParser = new StudMapParser();
importer = new ImportCsv();
}

@Override
Expand Down Expand Up @@ -78,4 +83,9 @@ public GuiSettings getGuiSettings() {
public void setGuiSettings(GuiSettings guiSettings) {
model.setGuiSettings(guiSettings);
}

@Override
public String importFile(File file) throws ImportException {
return importer.execute(model, file);
}
}
12 changes: 10 additions & 2 deletions src/main/java/seedu/studmap/logic/commands/CommandResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ public class CommandResult {
/** Help information should be shown to the user. */
private final boolean showHelp;

/** File browser should be shown to the user. */
private final boolean chooseFile;

/** The application should exit. */
private final boolean exit;

/**
* Constructs a {@code CommandResult} with the specified fields.
*/
public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
public CommandResult(String feedbackToUser, boolean showHelp, boolean chooseFile, boolean exit) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.chooseFile = chooseFile;
this.exit = exit;
}

Expand All @@ -31,7 +35,7 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
this(feedbackToUser, false, false);
this(feedbackToUser, false, false, false);
}

public String getFeedbackToUser() {
Expand All @@ -46,6 +50,10 @@ public boolean isExit() {
return exit;
}

public boolean isChooseFile() {
return chooseFile;
}

@Override
public boolean equals(Object other) {
if (other == this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ExitCommand extends Command {

@Override
public CommandResult execute(Model model) {
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, false, true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public class HelpCommand extends Command {

@Override
public CommandResult execute(Model model) {
return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
}
}
20 changes: 20 additions & 0 deletions src/main/java/seedu/studmap/logic/commands/ImportCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package seedu.studmap.logic.commands;

import seedu.studmap.model.Model;

/**
* Imports file using browser.
*/
public class ImportCommand extends Command {

public static final String COMMAND_WORD = "import";

public static final String MESSAGE_USAGE = "Opening Browser...";


@Override
public CommandResult execute(Model model) {
return new CommandResult(MESSAGE_USAGE, false, true, false);
}

}
187 changes: 187 additions & 0 deletions src/main/java/seedu/studmap/logic/imports/ImportCsv.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package seedu.studmap.logic.imports;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

import seedu.studmap.logic.imports.exceptions.ImportException;
import seedu.studmap.logic.parser.ParserUtil;
import seedu.studmap.logic.parser.exceptions.ParseException;
import seedu.studmap.model.Model;
import seedu.studmap.model.student.Student;
import seedu.studmap.model.student.StudentData;

/**
* Parses CSV file and loads it into the model.
*/
public class ImportCsv {

public static final String FILE_DOES_NOT_EXIST = "File does not exist!";

public static final String FILE_CANNOT_BE_READ = "File cannot be read!";

public static final String FILE_NOT_CSV = "File is not a CSV file!";

public static final String CSV_WRONG_FORMAT = "CSV template is wrongly formatted! "
+ "Please use the one in the UG strictly.";

public final String delimiter = "\\,";

public final String[] templateHeader = {
"name",
"studentid",
"module",
"phone",
"email",
"github",
"telegram",
};

public final Attributes[] enumList = {
Attributes.NAME,
Attributes.STUDENTID,
Attributes.MODULE,
Attributes.PHONE,
Attributes.EMAIL,
Attributes.GITHUB,
Attributes.TELEGRAM
};

private StringBuilder log;

private int rowNumber;

private enum Attributes {
NAME,
STUDENTID,
MODULE,
PHONE,
EMAIL,
GITHUB,
TELEGRAM
}

/**
* Executes the ImportCSV process, taking a model and file and updating the model with the imported students.
*
* @param model Model to update
* @param file CSV file containing import data
* @return Error message containing logs during import
* @throws ImportException
*/
public String execute(Model model, File file) throws ImportException {
log = new StringBuilder();
if (!file.exists()) {
throw new ImportException(FILE_DOES_NOT_EXIST);
} else if (!file.canRead()) {
throw new ImportException(FILE_CANNOT_BE_READ);
} else if (!checkIfCsv(file.getName())) {
throw new ImportException(FILE_NOT_CSV);
}

Scanner sc;

try {
sc = new Scanner(file);
} catch (FileNotFoundException e) {
throw new ImportException(FILE_DOES_NOT_EXIST);
}

if (!verifyFirstLine(sc.nextLine().split(delimiter, -1))) {
throw new ImportException(CSV_WRONG_FORMAT);
}

rowNumber = 2;
while (sc.hasNextLine()) {
processLine(sc.nextLine().split(delimiter, -1), model);
rowNumber++;
}
sc.close();
return log.toString();
}

/**
* Checks if the file is a CSV file.
* @param filename Filename to check
* @return Boolean if file is CSV
*/
public boolean checkIfCsv(String filename) {
String[] fileNameSplit = filename.split("\\.");

return fileNameSplit.length != 1 && fileNameSplit[fileNameSplit.length - 1].equals("csv");
}

/**
* Checks if the first line follows the proper header template
* @param firstLine First line of the CSV
* @return Boolean if first line correctly follows the template
*/
public boolean verifyFirstLine(String[] firstLine) {
if (firstLine.length != 7) {
return false;
}

for (int i = 0; i < 7; i++) {
if (!firstLine[i].equals(templateHeader[i])) {
return false;
}
}
return true;
}

/**
* Processes the CSV line input, creating a Student and updating the Model with it.
* @param inputLine Input from CSV
* @param model Model to update
*/
public void processLine(String[] inputLine, Model model) {
StudentData studentData = new StudentData();

for (int i = 0; i < inputLine.length; i++) {
Attributes currentAttribute = enumList[i];
String currentInput = inputLine[i];
try {
switch (currentAttribute) {
case NAME:
studentData.setName(ParserUtil.parseName(currentInput));
break;
case STUDENTID:
studentData.setId(ParserUtil.parseId(currentInput));
break;
case MODULE:
studentData.setModule(ParserUtil.parseModule(currentInput));
break;
case PHONE:
studentData.setPhone(ParserUtil.parsePhone(currentInput));
break;
case EMAIL:
studentData.setEmail(ParserUtil.parseEmail(currentInput));
break;
case GITHUB:
studentData.setGitUser(ParserUtil.parseGitName(currentInput));
break;
case TELEGRAM:
studentData.setTeleHandle(ParserUtil.parseHandle(currentInput));
break;
default:
break;
}
} catch (ParseException e) {
if (currentAttribute == Attributes.NAME || currentAttribute == Attributes.STUDENTID
|| currentAttribute == Attributes.MODULE) {
log.append(String.format("Row %d has missing compulsory attribute %s!\n",
rowNumber, currentAttribute));
return;
}
}
}

Student newStudent = new Student(studentData);
if (model.hasStudent(newStudent)) {
log.append(String.format("Row %d is a duplicate entry!\n", rowNumber));
return;
}
model.addStudent(newStudent);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package seedu.studmap.logic.imports.exceptions;

import seedu.studmap.logic.imports.ImportCsv;

/**
* Represents an error which occurs during execution of an {@link ImportCsv}.
*/
public class ImportException extends Exception {

public ImportException(String message) {
super(message);
}

/**
* Constructs a new {@code ImportException} with the specified detail {@code message} and {@code cause}.
*/
public ImportException(String message, Throwable cause) {
super(message, cause);
}
}
4 changes: 4 additions & 0 deletions src/main/java/seedu/studmap/logic/parser/StudMapParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import seedu.studmap.logic.commands.FindCommand;
import seedu.studmap.logic.commands.GradeCommand;
import seedu.studmap.logic.commands.HelpCommand;
import seedu.studmap.logic.commands.ImportCommand;
import seedu.studmap.logic.commands.ListCommand;
import seedu.studmap.logic.commands.MarkCommand;
import seedu.studmap.logic.commands.ParticipateCommand;
Expand Down Expand Up @@ -75,6 +76,9 @@ public Command parseCommand(String userInput) throws ParseException {
case ExitCommand.COMMAND_WORD:
return new ExitCommand();

case ImportCommand.COMMAND_WORD:
return new ImportCommand();

case TagCommand.COMMAND_WORD:
return new TagCommandParser().parse(arguments);

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/seedu/studmap/model/student/Student.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,16 @@ public int getAssignmentCount() {
}

/**
* Returns true if both students have the same name.
* Returns true if both students have the same name, studentID and module.
* This defines a weaker notion of equality between two students.
*/
public boolean isSameStudent(Student otherStudent) {
if (otherStudent == this) {
return true;
}

return otherStudent != null && otherStudent.getName().equals(getName());
return otherStudent != null && otherStudent.getName().equals(getName())
&& otherStudent.getId().equals(getId()) && otherStudent.getModule().equals(getModule());
}


Expand Down
Loading

0 comments on commit 5664401

Please sign in to comment.