By: Team W09-B3 Since: Mar 2018 Licence: MIT
- 1. Introduction
- 2. Setting up
- 3. Design
- 4. Implementation
- 5. Features Implementation
- 6. Documentation
- 7. Testing
- 8. Dev Ops
- 9. Product Scope
- Appendix A: User Stories
- Appendix B: Use Cases
- Appendix C: Non Functional Requirements
- Appendix D: Glossary
- Appendix E: Instructions for Manual Testing
- E.1. Launch and Shutdown
- E.2. Deleting a student
- E.3. Saving data
- E.4. Adding a student to favourites
- E.5. Removing a student from favourites
- E.6. Showing the dashboard of a student
- E.7. Adding a milestone to a student’s dashboard
- E.8. Deleting a milestone from a student’s dashboard
- E.9. Adding a task to a milestone
- E.10. Deleting a task from a milestone
- E.11. Marking a task as completed
- E.12. Displaying the profile page of a student
- E.13. Editing the miscellaneous information of a student
- E.14. Editing the profile picture of a student
- E.15. Adding a lesson
- E.16. Deleting a Lesson
- E.17. Logging in to Google Accounts
- E.18. Logging out of Google Accounts.
- E.19. Syncing data
1. Introduction
1.1. About Codeducator
Codeducator is an open source Command Line Interface (CLI) address book and scheduling desktop application. We aim to provide a solution for private programming tutors to better manage their student contacts, tutoring schedule and track their students' learning progress.
1.2. How to Contribute
There are lots of ways to contribute to Codeducator: coding, testing or improving our build process and tools. This developer’s guide provides information that will help you get started as a Codeducator contributor. Even if you are an experienced Codeducator developer, you will still find this guide to be useful to refer to.
If you are ready to contribute, simply create a Pull Request (PR) on our main repository.
If you have found any bugs or have ideas to improve Codeducator, create an issue here or contact us directly.
2. Setting up
2.1. Prerequisites
To contribute to Codeducator, you will need the following software:
-
JDK
1.8.0_60or laterHaving any Java 8 version is not enough.
This app will not work with earlier versions of Java 8.You can download the latest Java version here.
-
IntelliJ IDE
IntelliJ by default has Gradle and JavaFx plugins installed.
Do not disable them. If you have disabled them, go toFile>Settings>Pluginsto re-enable them.You can download the latest Intellij IDE here.
2.2. Setting up the project in your computer
To set up the project in your computer, follow the steps below:
-
Fork this repo, and clone the fork to your computer
-
Open IntelliJ (if you are not in the welcome screen, click
File>Close Projectto close the existing project dialog first) -
Set up the correct JDK version for Gradle
-
Click
Configure>Project Defaults>Project Structure -
Click
New…and find the directory of the JDK
-
-
Click
Import Project -
Locate the
build.gradlefile and select it. ClickOK -
Click
Open as Project -
Click
OKto accept the default settings -
Open a console and run the command
gradlew processResources(Mac/Linux:./gradlew processResources). It should finish with theBUILD SUCCESSFULmessage.
This will generate all resources required by the application and tests.
2.3. Verifying the setup
You will need to verify if your environment is set up correctly before you can start working on Codeducator.
In Intellij,
-
Run the
seedu.address.MainAppand try a few commands -
Run the tests to ensure they all pass.
2.4. Configurations to do before writing code
You will need to configure and set up some tools we use before you can start making meaningful contributions to Codeducator.
2.4.1. Configuring the coding style
This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,
-
Go to
File>Settings…(Windows/Linux), orIntelliJ IDEA>Preferences…(macOS) -
Select
Editor>Code Style>Java -
Click on the
Importstab to set the order-
For
Class count to use import with '*'andNames count to use static import with '*': Set to999to prevent IntelliJ from contracting the import statements -
For
Import Layout: The order isimport static all other imports,import java.*,import javax.*,import org.*,import com.*,import all other imports. Add a<blank line>between eachimport
-
Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.
2.4.2. Updating documentation to match your fork
After forking the repo, links in the documentation will still point to the se-edu/addressbook-level4 repo. If you plan to develop this as a separate product (i.e. instead of contributing to the se-edu/addressbook-level4) , you should replace the URL in the variable repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.
2.4.3. Setting up CI
Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.
After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).
| Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork. |
Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).
| Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based) |
2.4.4. Getting started with coding
When you are ready to start coding,
-
Get some sense of the overall design by reading Section 3.1, “Architecture”.
-
Take a look at [GetStartedProgramming].
3. Design
3.1. Architecture
The Architecture Diagram given below explains the high-level design of the App. Given below is also a quick overview of each component.
The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.
|
Main has only one class called MainApp. It is responsible for,
-
At app launch: Initializes the components in the correct sequence, and connects them up with each other.
-
At shut down: Shuts down the components and invokes cleanup method where necessary.
Commons represents a collection of classes used by multiple other components. Two of those classes play important roles at the architecture level.
-
EventsCenter: This class (written using Google’s Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design) -
LogsCenter: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
-
Defines its API in an
interfacewith the same name as the Component. -
Exposes its functionality using a
{Component Name}Managerclass.
For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.
Events-Driven nature of the design
The Sequence Diagram below shows how the components interact for the scenario where the user issues the command delete 1.
delete 1 command (part 1)
Note how the Model simply raises a AddressBookChangedEvent when the Address Book data are changed, instead of asking the Storage to save the updates to the hard disk.
|
The diagram below shows how the EventsCenter reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
delete 1 command (part 2)
Note how the event is propagated through the EventsCenter to the Storage and UI without Model having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.
|
The sections below give more details of each component.
3.2. UI component
API : Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, StudentListPanel, StatusBarFooter, BrowserPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.
The UI component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
The UI component,
-
Executes user commands using the
Logiccomponent. -
Binds itself to some data in the
Modelso that the UI can auto-update when data in theModelchange. -
Responds to events raised from various parts of the App and updates the UI accordingly.
3.3. Logic component
XYZCommand and Command in Figure 6, “Structure of the Logic Component”API :
Logic.java
-
Logicuses theAddressBookParserclass to parse the user command. -
This results in a
Commandobject which is executed by theLogicManager. -
The command execution can affect the
Model(e.g. adding a student) and/or raise events. -
The result of the command execution is encapsulated as a
CommandResultobject which is passed back to theUi.
Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.
delete 1 Command3.4. Model component
API : Model.java
The Model,
-
stores a
UserPrefobject that represents the user’s preferences. -
stores the Address Book data.
-
exposes an unmodifiable
ObservableList<Student>that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -
does not depend on any of the other three components.
3.5. Storage component
API : Storage.java
The Storage component,
-
can save
UserPrefobjects in json format and read it back. -
can save the Address Book data in xml format and read it back.
3.6. Common classes
Classes used by multiple components are in the seedu.addressbook.commons package.
4. Implementation
This section describes some noteworthy details on how certain features are implemented.
4.1. Undo/Redo feature
4.1.1. Current Implementation
The undo/redo mechanism is facilitated by an UndoRedoStack, which resides inside LogicManager. It supports undoing and redoing of commands that modifies the state of the address book (e.g. add, edit). Such commands will inherit from UndoableCommand.
UndoRedoStack only deals with UndoableCommands. Commands that cannot be undone will inherit from Command instead. The following diagram shows the inheritance diagram for commands:
As you can see from the diagram, UndoableCommand adds an extra layer between the abstract Command class and concrete commands that can be undone, such as the DeleteCommand. Note that extra tasks need to be done when executing a command in an undoable way, such as saving the state of the address book before execution. UndoableCommand contains the high-level algorithm for those extra tasks while the child classes implements the details of how to execute the specific command. Note that this technique of putting the high-level algorithm in the parent class and lower-level steps of the algorithm in child classes is also known as the template pattern.
Commands that are not undoable are implemented this way:
public class ListCommand extends Command {
@Override
public CommandResult execute() {
// ... list logic ...
}
}
With the extra layer, the commands that are undoable are implemented this way:
public abstract class UndoableCommand extends Command {
@Override
public CommandResult execute() {
// ... undo logic ...
executeUndoableCommand();
}
}
public class DeleteCommand extends UndoableCommand {
@Override
public CommandResult executeUndoableCommand() {
// ... delete logic ...
}
}
Suppose that the user has just launched the application. The UndoRedoStack will be empty at the beginning.
The user executes a new UndoableCommand, delete 5, to delete the 5th student in the address book. The current state of the address book is saved before the delete 5 command executes. The delete 5 command will then be pushed onto the undoStack (the current state is saved together with the command).
As the user continues to use the program, more commands are added into the undoStack. For example, the user may execute add n/David … to add a new student.
If a command fails its execution, it will not be pushed to the UndoRedoStack at all.
|
The user now decides that adding the student was a mistake, and decides to undo that action using undo.
We will pop the most recent command out of the undoStack and push it back to the redoStack. We will restore the address book to the state before the add command executed.
If the undoStack is empty, then there are no other commands left to be undone, and an Exception will be thrown when popping the undoStack.
|
The following sequence diagram shows how the undo operation works:
The redo does the exact opposite (pops from redoStack, push to undoStack, and restores the address book to the state after the command is executed).
If the redoStack is empty, then there are no other commands left to be redone, and an Exception will be thrown when popping the redoStack.
|
The user now decides to execute a new command, clear. As before, clear will be pushed into the undoStack. This time the redoStack is no longer empty. It will be purged as it no longer make sense to redo the add n/David command (this is the behavior that most modern desktop applications follow).
Commands that are not undoable are not added into the undoStack. For example, list, which inherits from Command rather than UndoableCommand, will not be added after execution:
The following activity diagram summarize what happens inside the UndoRedoStack when a user executes a new command:
4.1.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Implementation of |
Add a new abstract method |
+ : We will not lose any undone/redone functionality as it is now part of the default behaviour. Classes that deal with |
Just override |
+ : Does not involve the template pattern, easier for new developers to understand. |
|
How undo & redo executes |
Saves the entire address book. (current choice): |
+ : Easy to implement. |
Individual command knows how to undo/redo by itself. |
+ : Will use less memory (e.g. for |
|
Type of commands that can be undone/redone |
Only include commands that modifies the address book ( |
+ : We only revert changes that are hard to change back (the view can easily be re-modified as no data are * lost). |
Include all commands. |
+ : Might be more intuitive for the user. |
|
Data structure to support the undo/redo commands |
Use separate stack for undo and redo (current choice) |
+ : Easy to understand for new Computer Science student undergraduates to understand, who are likely to be * the new incoming developers of our project.
- : Logic is duplicated twice. For example, when a new command is executed, we must remember to update * both |
Use |
+ : We do not need to maintain a separate stack, and just reuse what is already in the codebase. |
4.2. Logging
We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevelsetting in the configuration file (See Section 4.3, “Configuration”) -
The
Loggerfor a class can be obtained usingLogsCenter.getLogger(Class)which will log messages according to the specified logging level -
Currently log messages are output through:
Consoleand to a.logfile.
Logging Levels
-
SEVERE: Critical problem detected which may possibly cause the termination of the application -
WARNING: Can continue, but with caution -
INFO: Information showing the noteworthy actions by the App -
FINE: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
4.3. Configuration
Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json).
4.4. [Proposed] Data Encryption
A password must be implemented, used as secret key. Using Java Cryptography Extension (JCE) library, we can encrypt text in the xml files.
First we save as XML files, then we encrypt the text data in the XML to encrypted text, storing it somewhere, then deleting the XML file.
The reverse process is decrypting the encrypted data to XML, then reading data from there.
5. Features Implementation
5.1. Favourites feature
The favourites feature allows users to remember/mark a student by adding them to favourites.
5.1.1. Current Implementation
To facilitate the favourite/unfavourite feature, an association with a new Favourite class is added to the Student class:
Student in the Model component. The diagram shows that the Student class is associated with the Favourite class.Since the implementation of the favourite and unfavourite command are similar, we will describe the implementation of the favourite command only.
The following sequence diagram shows how the favourite command works:
-
The
FavouriteCommandParserparses the user input to obtain the target student index and constructs a newFavouriteCommandwith this index. -
The logic portion of the favourite command will be executed by the
FavouriteCommandclass. To mark aStudentobject called "studentToFavourite" as favourite:-
The
preprocessUndoableCommand()method callssetTargetStudent()which will set the "studentToFavourite" object based on the provided student index. -
preprocessUndoableCommand()will then call thecreateEditedStudent()method which will create aStudentobject called "editedStudent". "editedStudent" will have the attributes of "studentToFavourite", except that itsFavouriteattribute will be set to "true".
createEditedStudent()is implemented as such:
-
private void createEditedStudent() {
assert targetStudent != null;
editedStudent = new StudentBuilder(target).withFavourite(true).build();
}
-
In the
executeUndoableCommand()method,Model.updateStudent(Student, Student)is called to replace "studentToFavourite" with "editedStudent" in the Address Book in-memory.
5.1.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Implementation of 'FavouriteCommand' |
Add a |
+ : It is easy to mark a student as favourite since we can make use of the current |
Create a new |
+ : Students that are currently in favourites can be managed more easily since there is a direct overview of which student is in favourites |
5.2. Location feature
Selecting a student using the select command will render their location on google maps.
5.2.1. Current Implementation
The address of the student is extracted and converted in a string to be appended to the end of the SEARCH_PAGE_URL in the following function
private void loadStudentPage(Student student) {
Address location = student.getAddress();
String append = location.urlstyle();
loadPage(SEARCH_PAGE_URL + append);
}
An example is provided below when select 1 is entered as a command:
5.2.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Implementation of displaying student locations |
Display it on the embedded browser (current choice) |
+ : Easy to implement, simply alter the default webpage |
Creating a new window to display the location |
+ : This would allow concurrent display of locations of many students |
5.3. Programming Language Feature
The programmingLanguage field is part of the student model and helps to keep track of what programming language he/she is being taught with.
5.3.1. Current Implementation
The programming language feature involves having an additional class to the student model called ProgrammingLanguage.
It stores the name of the programming language currently being taught to each student as a string.
The string for ProgrammingLanguage must contain visible characters.
|
As can be seen from the diagram, the field ProgrammingLanuage has been added to the student model.
Concerning the Logic component, when the add command or edit command is called,
a Student object with attributes including ProgrammingLanguage will be created/edited depending on which command was entered.
For example, adding a student would have the command string parsed for arguments in such a way:
public AddCommand parse(String args) throws ParseException {
// ...Tokenize the String Input...
// ...Check if prefixes are present...
try {
// ...Parses the other fields required of a Student...
ProgrammingLanguage programmingLanguage = ParserUtil.parseSubject(argMultimap
.getValue(PREFIX_PROGRAMMING_LANGUAGE)).get();
Student student = new Student(name, phone, email, address, programmingLanguage, tagList);
return new AddCommand(student);
} catch (IllegalValueException ive) {
throw new ParseException(ive.getMessage(), ive);
}
}
A new student would then be added. On the other hand, editing a student’s programming language will be done by creating an edited student in such a way:
private static Student createEditedStudent(Student studentToEdit, EditStudentDescriptor editStudentDescriptor) {
assert studentToEdit != null;
// ...Set other attributes of the prospective newly edited student...
ProgrammingLanguage updatedProgrammingLanguage = editStudentDescriptor.getProgrammingLanguage();
return new Student(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedProgrammingLanguage,
updatedTags);
}
The editedStudent will have the new programming language attribute and will hence be used to replace in the Address Book in-memory.
5.3.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
How to store |
Store as an attribute of Student. (current choice) |
+ : Easy to keep track of as well as modify. |
Store as a separate list and have each student index in the UniqueStudentsList be mapped to each item in the list. |
+ : Less coupling so less need to refactor code |
|
What command to add |
Implement it through the existing |
+ : Intuitive and the user does not have to learn an additional command |
Implement it as a new command. |
+ : User will be able to add or modify |
5.4. Profile Page feature
The profile page feature allows the user to view the full information of contacts(students) kept in their data. This page has each student’s main info, miscellaneous info, and their profle picture.
5.4.1. Current Implementation
Users will also be able to edit the miscellaneous information of a student as well as his/her profile picture. The profile picture is changed by providing a file path to the actual picture file.
The picture file to be changed to must be a valid and existing file with extensions of .png or .jpg
|
The following diagram shows the student model including the primary attributes as well as the miscellaneous information attributes.
When a student is added by the addCommand, the MiscellaneousInfo and ProfilePicturePath of the student will be set to these default values:
-
Allergies, NextOfKinName, Remarks will be set to
Not updated. -
NextOfKinPhone will be set to
000. -
ProfilePicturePath will be set to the path of a profile photo placeholder within the app.
This feature revolves mainly around 3 commands:
-
moreInfo: Shows the actual profile page on the web browser. -
editMisc: Edits the miscellaneous information of a student. -
editPicture: Edits the profile picture of a student with a valid picture file(refer to note above). The user will have to provide the filepath to this file.moreInfoCommand
For the command moreInfo, the model manager calls upon the data storage (addressbook) to raise an event for the Browser Panel to display the profile page of a student.
The moreInfo command cannot function if there is no real existing XML data of students. Thus, the sample student data provided at the initial start up will not work with this command. A warning will be mentioned if the command is called without existing data.
|
The code below shows how the the method is called with the parameter of the required Student functions:
public void displayStudentDetailsOnBrowserPanel(Student target) throws StudentNotFoundException,
StorageFileMissingException {
addressBook.checkForStudentInAddressBook(target);
checkIfStorageFileExists();
indicateRequiredStudentIndexChange(filteredStudents.indexOf(target));
indicateBrowserPanelToDisplayStudent(target);
}
The method checkIfStorageFileExists() checks if there is any real XML data of students at the moment. If none exists, then an exception is thrown and the command will not perform (as mentioned in the note above).
The method indicateRequiredStudentIndexChange(Index indexOfStudent) calls the modifying of XML data of which student is needed to display his/her profile page. This is because the HTML files
can only read data from XML files and hence, an external XML file containing the index of the student whose profile page is required to be shown is needed.
Lastly, indicating the browser panel to display a student will raise a StudentInfoDisplayEvent which is handled in the BrowserPanel with the following code:
private void handleStudentInfoDisplayEvent(StudentInfoDisplayEvent event) {
//... logging process...
loadStudentInfoPage();
//... raising event to switch panels...
}
The diagram below shows how the event is handled in the BrowserPanel :
editMisc Command
For the command editMisc, this is similar to the edit function, except it takes on different optional parameters. These are [ALLERGIES], [NEXTOFKINNAME], [NEXTOFKINPHONE], [REMARKS].
The code snippet below shows how the studentToEdit is created when the editMisc command is called.
private static Student createEditedStudent(Student studentToEdit, EditMiscDescriptor editMiscDescriptor) {
assert studentToEdit != null;
//... main information of the student is copied over...
Allergies allergies = editMiscDescriptor.getAllergies()
.orElse(studentToEdit.getMiscellaneousInfo().getAllergies());
NextOfKinName nextOfKinName = editMiscDescriptor.getNextOfKinName()
.orElse(studentToEdit.getMiscellaneousInfo().getNextOfKinName());
NextOfKinPhone nextOfKinPhone = editMiscDescriptor.getNextOfKinPhone()
.orElse(studentToEdit.getMiscellaneousInfo().getNextOfKinPhone());
Remarks remarks = editMiscDescriptor.getRemarks()
.orElse(studentToEdit.getMiscellaneousInfo().getRemarks());
MiscellaneousInfo miscellaneousInfo = new MiscellaneousInfo(allergies, nextOfKinName, nextOfKinPhone, remarks);
return new Student(uniqueKey, name, phone, email, address,
programmingLanguage, tags, isFavourite, dashboard, profilePicturePath, miscellaneousInfo);
}
After that, the student will be updated with the new details for his/her miscellaneous information.
editPicture Command
For the command editPicture, the student’s index will have to be provided by the user again. The next parameter for this is the required file path of the picture file.
This can be in the form of an absolute file path (starting from a hardrive like C:/Users/…/picture.png) or relative to the folder that the jar application is in.
This command uses the similar method of the edit command and the editMisc command where a new Student with the edited details is created to overwrite the current existing student.
In this case, the ProfilePicturePath of the student is edited. When this command is called, a ProfilePictureChangeEvent will be raised and the Storage Manager will call a method to save the data of the profile picture from its original location to a location in the jar folder.
The code below shows how the saving of the file is done:
public void saveProfilePicture(ProfilePicturePath pathToChangeTo, Student student) throws IOException {
//... ensuring that the picture's filepath exists
//... getting the extension of the provided filepath of the picture
deleteExistingProfilePicture(studentPictureFilePath);
Path studentPictureFilePathWithExtension = Paths.get(studentPictureFilePath.toString() + extension);
logger.fine("Attempting to write to data file: data/" + student.getUniqueKey().toString());
Files.copy(newPath, studentPictureFilePathWithExtension);
}
Thus, the HTML file for displaying the student’s profile page will be able to show the new image, which is copied to the local jar folder.
The following sequence diagram illustrates the process of calling the editPicture command.
editPicture commandAs seen from the above diagram, the createFinalEditedStudent() method ensures that the correct profile picture path is saved onto the student’s XML data in order to be read by the HTML file which displays the student profile page.
The method createEditedStudent creates the student wi
5.4.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Displaying and styling the profile page of a student |
*Have it as a JavaScript function in the HTML file of the student’s profile page. |
+ Able to directly read the XML data of students from the file. (current choice)* |
Have it as a JavaFX file. |
+ : Able to read the student’s data from the UniqueStudentList. |
|
Editing the profile picture |
Copy the picture file into the local jar directory. (current choice) |
+ : Ensures that the picture can still be loaded even when the original picture file is deleted. |
Read from the direct location of the original picture file. |
+ : Less code of copying is required and any modifications to the original photo is immediately updated. |
5.5. Schedule feature
5.5.1. Current Implementation
To get better control of one’s weekly schedule, we will now attach a component called Schedule to Model.
At startup, a new Schedule object is instantiated in ModelManager.
A Schedule has a LessonList, it contains an ObservableList<Lesson> internalList attribute, which stores all the Lesson objects that describes your schedule.
The UI is bounded to this LessonList so that it can automatically update when data changes.
A Lesson has a UniqueKey attribute, a Day attribute, a starting TIME START_TIME and an ending TIME END_TIME attribute.
Lesson objects are created by the addLesson command.
Implementation of commands that edit your Schedule
Commands that modify the schedule are addLesson and deleteLesson.
Editing a student’s name will edit the name of the event in the schedule.
Deleting a student will also delete all his lessons in the schedule.
-
Students have the
UniqueKeyfield, which we will now use inLessonto create a relation to Student objects. -
A
Lessonobject callednewLessonwill be created byModelManager.addLesson(UniqueKey key, Day day, Time startTime, Time endTime), which is implemented as such:
public void addLesson(Student studentToAddLesson, Day day, Time startTime, Time endTime) {
requireAllNonNull(studentToAddLesson, day, startTime, endTime);
UniqueKey studentKey = studentToAddLesson.getUniqueKey();
Lesson newLesson = new Lesson(studentKey, day, startTime, endTime);
schedule.addLesson(newLesson);
indicateScheduleChanged();
}
A sequence diagram of the result can be seen from the below diagram.
addLesson commandThe student will be selected by the Index of the last seen list of students.
The UniqueKey is then retrieved from the Student. A new Lesson will now be added for that student at the specific Day, startTime and endTime, associated with the Student by the key
No Lesson objects can be created for students not in contact list.
If you have a future implementation that requires the addition of a new attribute in the Schedule class, you must take note of updating the Model.addLesson(Student, Day, Time START_TIME, Time END_TIME) method to reflect the new attribute.
|
Implementation of viewing your Schedule
The schedule command displays of a student’s dashboard. The schedule command is implemented this way:
schedule commandFrom the following diagram,
-
InfoPanelhandles theshowScheduleEventevent. It changes the view to theCalendarPanel, hidingDashboardPanelandBrowserPanel. -
InfoPanelraises theshowScheduleEventwhich is also handled byCalendarPanelto display the lessons of the student in the schedule.
5.5.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Implementation of |
|
+ : It is easier implement, just add |
|
+ : Less coupling and more cohesive design |
|
Data structure of |
Relational database related by a uniquekey attribute (current choice) |
+ : Much better normalised design. Modifying contacts list in any way will not affect the Schedule database. |
Adding Student objects to lessons in schedule |
+ : Easier implementation. |
5.6. Google Service Integration
To sync with Google Contacts and Google Calendar, a GServiceManager class is implemented to handle the 2 services.
GServiceManager contains a GContactsService and GCalendarService objects. GServiceManager.synchronize calls GContactsService.synchronize and
GCalendarService.synchronize
5.6.1. Prerequisites/Dependencies
Google Contacts and Calendar APIs require an external libaries. Remember to add the following to your dependencies
dependencies {
compile 'com.google.api-client:google-api-client:1.23.0'
compile 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
compile 'com.google.apis:google-api-services-oauth2:v1-rev139-1.23.0'
compile 'com.google.apis:google-api-services-calendar:v3-rev305-1.23.0'
compile group: 'com.google.gdata', name: 'core', version: '1.47.1'
}
5.6.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Implementation of |
Separate out 2 Google Services into two classes (current choice) |
+ : Less coupling |
All services are in |
+ : Fewer files and code to read |
|
Implementation of flow of data for a sync |
Only Upload (current choice) |
As we have to store the IDs of contacts and events created offline, that would create a massive database issue.
+ : Reduces the complexity of the implementation of syncing data. + - : User cannot download updated data that he synced from another Codeducator instance |
Upload and download |
+ : Much more convenient for the user to sync his data to the cloud. |
5.7. Dashboard feature
The dashboard feature aims to help users keep track of their students' learning progress.
5.7.1. Current Implementation
To have a dashboard for each student, an association with a new Dashboard class is added to the Student class. We have also created new classes associated with the Dashboard class to facilitate the different capabilities of the dashboard.
The following diagram shows the class diagram of the components that facilitate the dashboard feature:
Both UniqueMilestoneList and UniqueTaskList contain an attribute called "internalList" which are ObservableList<Milestone> and ObservableList<Task> respectively.
This means that the UI can be bound to both of the lists so that it can automatically update when the data in any of the lists change.
A new Dashboard object is created every time a new Student is being created. The Dashboard object will contain an empty milestone list until the user adds new milestones to the dashboard.
This enforces 1-to-1 association between Student and Dashboard, as well as between Dashboard and UniqueMilestoneList.
For example, the constructor for Student is implemented this way:
public Student(Name name, Phone phone, Email email, Address address, ProgrammingLanguage programmingLanguage, Set<Tag> tags) {
requireAllNonNull(name, phone, email, address, tags);
this.name = name;
this.phone = phone;
// ... initialise the rest of the attributes ...
this.dashboard = new Dashboard();
}
The constructor for Dashboard is implemented this way:
public Dashboard() {
milestoneList = new UniqueMilestoneList();
}
Implementation for commands that modify the Dashboard
The AddMilestoneCommand, AddTaskCommand, CheckTaskCommand and ShowDashboardCommand commands facilitate operations to the dashboard.
A common implementation for commands that modify the dashboard (e.g. AddMilestoneCommand) is that a new copy of Dashboard is created with the new modification.
For example, in the AddMilestoneCommand, to add a new milestone object to the dashboard of a Student Object called "targetStudent":
-
AddMilestoneCommand.preprocessUndoableCommand()calls theAddMilestoneCommand.createEditedStudent()method which will create aStudentobject called "editedStudent". "editedStudent" is created with the same attributes of "targetStudent", but with a newDashboardobject containing the new milestone.
AddMilestoneCommand.createEditedStudent()is implemented as such:
private void createEditedStudent() throws DuplicateMilestoneException {
requireAllNonNull(studentToEdit, newMilestone);
editedStudent = new StudentBuilder(targetStudent).withNewMilestone(newMilestone).build();
}
-
In the
AddMilestoneCommand.executeUndoableCommand()method,Model.updateStudent(Student, Student)is called to replace "targetStudent" with "editedStudent" in the Address Book in-memory.
Implementation for displaying the dashboard
The ShowDashboardCommand facilitates the displaying of a student’s dashboard. The ShowDashboardCommand.execute() method is implemented this way:
public CommandResult execute() throws CommandException {
// ... check whether targetIndex is valid ...
EventsCenter.getInstance().post(new ShowStudentDashboardEvent(lastShownList.get(targetIndex.getZeroBased())));
// ... return command result ...
}
As seen from the above code snippet, ShowDashboardCommand.execute() raises a ShowStudentDashboardEvent. The sequence diagram below shows how the EventsCenter reacts to that event.
EventsCenter and the Ui components react to the ShowDashboardCommandAs seen from the above diagram,
-
InfoPanelhandles theShowStudentInDashboardevent. -
InfoPanelthen raises theShowStudentNameInDashboardwhich is handled byDashboardPanelto display the name of the student in the dashboard. -
Finally,
InfoPanelraises theShowMilestoneEventwhich is also handled byDashboardPanelto display the milestones of the student in the dashboard.
5.7.2. Design Considerations
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Aspect: Data structure to support the dashboard feature |
Add a |
+ : Able to access the dashboard of a student easily. |
Add a new |
+ : Able to modify the dashboard easily if it is not made immutable. |
5.8. Natural Language Processing capabilities
Allows users to invoke features using free-form english, apart from keywords specific to each feature.
5.8.1. Current implementation
An AI bot(agent) that is trained to process sentences based on the features integrated is into the application. Its primary goal is to identify the user’s intention of the input and match it with a corresponding feature which the user wishes to use.
A new class ConversationCommand is written to process sentences that do not match the syntax of any features.
Making API calls via the REST API
The method below, written using the IBM Watson™ Assistant service API, is used to make the API call to the agent.
The userInput field contains the sentence that the user inputs.
public static MessageResponse getMessageResponse(String userInput) {
MessageResponse response = null;
InputData input = new InputData.Builder(userInput).build();
MessageOptions option = new MessageOptions.Builder("19f7b6f4-7944-419d-83a0-6bf9837ec333").input(input).build();
response = service.message(option).execute();
return response;
}
Intents and Entities
Intents refers to the intention behind the input of the user and entities refer to objects of interest e.g. name, address, location
The agent is integrated into the AddressBookParser class and the following code snippet deciphers the intents
and the entity embedded in the user’s input.
//processes the userInput
response = ConversationCommand.getMessageResponse(userInput);
intents = response.getIntents();
entities = response.getEntities();
for (int i = 0; i < intents.size(); i++) {
intention = intents.get(i).getIntent();
}
if (entities.size() != 0) {
for (int i = 0; i < intents.size(); i++) {
entity = entities.get(i).getValue();
}
}
| Every single input always has an intent, but that is not the case for entities! |
For further clarification, refer to the screenshot below:
Select and the entity refers to the name of a person, which takes on a value of Jason in this particular case.Matching the desired command
After identifying the intent and entities (if present) in the user’s input, the corresponding features matching intent is called, passing any entities as parameters to the feature’s method.
select command is invoked, passing Jason as a parameter, after the intent and entity is identified.5.8.2. Design Consideration
| Aspect | Alternatives | Pros (+)/ Cons(-) |
|---|---|---|
Aspect: Selection of an appropriate third-party APIs to implement NLP |
IBM Watson™ Assistant service (current choice) |
+ : Offers extensive NLP functions which are easy to implement. User-friendly interface allows ease of training of the model, which has high scalability |
Stanford CoreNLP |
+ : Possesses a powerful and comprehensive API, comprising of a set of stable and well-tested natural language processing tools, widely used by various groups in academia, industry, and government. |
|
Google Cloud Natural Language |
+ : Offers a variety of functions (Syntax Analysis, Entity Recognition, Sentiment Analysis etc.) and integrates REST API,
powerful enough to analyse texts properly and texts can be uploaded in the request or integrated with Google Cloud Storage. |
6. Documentation
We use asciidoc for writing documentation.
| We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting. |
6.1. Editing Documentation
See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits.
Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.
6.2. Publishing Documentation
See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.
6.3. Converting Documentation to PDF format
We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.
Here are the steps to convert the project documentation files to PDF format.
-
Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the
docs/directory to HTML format. -
Go to your generated HTML files in the
build/docsfolder, right click on them and selectOpen with→Google Chrome. -
Within Chrome, click on the
Printoption in Chrome’s menu. -
Set the destination to
Save as PDF, then clickSaveto save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.
7. Testing
7.1. Running Tests
There are three ways to run tests.
| The most reliable way to run tests is the 3rd one. The first two methods might fail some GUI tests due to platform/resolution-specific idiosyncrasies. |
Method 1: Using IntelliJ JUnit test runner
-
To run all tests, right-click on the
src/test/javafolder and chooseRun 'All Tests' -
To run a subset of tests, you can right-click on a test package, test class, or a test and choose
Run 'ABC'
Method 2: Using Gradle
-
Open a console and run the command
gradlew clean allTests(Mac/Linux:./gradlew clean allTests)
| See UsingGradle.adoc for more info on how to run tests using Gradle. |
Method 3: Using Gradle (headless)
Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.
To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests)
7.2. Types of tests
We have two types of tests:
-
GUI Tests - These are tests involving the GUI. They include,
-
System Tests that test the entire App by simulating user actions on the GUI. These are in the
systemtestspackage. -
Unit tests that test the individual components. These are in
seedu.address.uipackage.
-
-
Non-GUI Tests - These are tests not involving the GUI. They include,
-
Unit tests targeting the lowest level methods/classes.
e.g.seedu.address.commons.StringUtilTest -
Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
e.g.seedu.address.storage.StorageManagerTest -
Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
e.g.seedu.address.logic.LogicManagerTest
-
7.3. Troubleshooting Testing
Problem: HelpWindowTest fails with a NullPointerException.
-
Reason: One of its dependencies,
UserGuide.htmlinsrc/main/resources/docsis missing. -
Solution: Execute Gradle task
processResources.
8. Dev Ops
8.1. Build Automation
See UsingGradle.adoc to learn how to use Gradle for build automation.
8.2. Continuous Integration
We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.
8.3. Coverage Reporting
We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.
8.4. Documentation Previews
When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.
8.5. Making a Release
Here are the steps to create a new release.
-
Update the version number in
MainApp.java. -
Generate a JAR file using Gradle.
-
Tag the repo with the version number. e.g.
v0.1 -
Create a new release using GitHub and upload the JAR file you created.
8.6. Managing Dependencies
A project often depends on third-party libraries. For example, Address Book depends on the Jackson library for XML parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)
9. Product Scope
Target user profile:
-
has a need to plan tuition slots for large number of students
-
wants to store students' profile information and pictures
-
wants to keep a progress log for students
-
is able to reference common important student details like contact number
-
prefer desktop apps over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: improve the planning process for scheduling time slots for all tutees
9.1. Feature Contribution
Samuel Loh:
-
(Minor) Added programmingLanguage field to student model and modified add/edit commands to fit enhancement
-
This helps the tutor to identify what programming language is being used by each student to learn coding.
-
-
(Major) Create a profile page storing other important details of the students including a profile picture.
-
This helps the tutor store more information about students, which are not referenced as often, in another portion and thus are not displayed on the student card. E.g. Next of kin contact and an optional profile picture
-
Tan Wei Hao:
-
(Minor) Added a findTag command
-
This allows the tutor to find a student by tag labels.
-
-
(Major) Syncing timetable with Google calendar
-
This helps the tutor keep track of lessons better by syncing with his Google calendar. It also allows the use of Google calendar features.
-
Tan Chee Wee:
-
(Minor) Selecting a student via 'select' commands renders their location on google maps
-
This allows the tutor to easily plan a route to the student’s home.
-
-
(Major) Add a functionality that enables tutor to use free-form english to execute commands instead of conforming to the specific syntax
-
This makes the app more user-friendly without the need to memorise the syntax of respective commands and able to execute them more intuitively.
-
Yap Ni:
-
(Minor) Favourites feature where tutors can add or remove students from favourites and list students that are in their favourites
-
This helps the tutor to remember or view the list of prominent students they want to take note of easily.
-
-
(Major) Dashboard feature where each student has their own dashboard
-
This helps the tutor to better plan out lessons for each student and track their learning progress.
-
Appendix A: User Stories
Priorities: High (must have) - * * , Medium (nice to have) - , Low (unlikely to have) -
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
|
tutor |
add a new student |
|
|
tutor |
be able to edit the miscellaneous information of a student |
have the most updated version of a student’s information |
|
tutor |
delete a student |
remove entries that I no longer need |
|
tutor |
find a student by name |
locate details of students without having to go through the entire list |
|
tutor |
find a student by programming language |
locate details of students of a certain programming language |
|
new user |
see usage instructions |
refer to instructions when I forget how to use the App |
|
tutor |
search a student by label/tag |
so I can easily categorize my students as per my personal preferences |
|
tutor |
indicate a student’s programming language when adding one |
so I can know which programming language to prepare before my lesson |
|
tutor |
view the address of a student in the maps |
know where the student lives |
|
tutor |
add a student to favourites |
keep track of that student |
|
tutor |
list students added to favourites |
view students I’m keeping tack |
|
tutor |
upload my contacts to Google Contacts |
sync my contacts list with Google Contacts, being able to easily view my data across devices |
|
tutor |
be able to view misc info of my students on a different page |
have an easier viewing of them |
|
tutor |
view the profile pictures of each student(if it exists) |
learn to recognise them |
|
tutor |
be able to add/change a profile picture for my students |
|
|
tutor |
have a remarks column included in the misc info for each student |
add specific remarks for each particular student that may be important to note |
|
tutor |
view timetable of lessons by week |
easily view my schedule |
|
tutor |
add a lesson for a student |
|
|
tutor |
delete a lesson for a student |
remove lessons that the student cancels |
|
tutor who adds lessons in odd hours(very early or very late) |
see my schedule resize |
can view my lessons in full and have a better user experience. |
|
tutor |
check free slot |
easily find a free timeslot to allocate to students |
|
tutor |
edit a lesson for a student |
make changes to lessons when required |
|
tutor |
upload my lessons to Google Calendars |
easily sync my schedule with Google Calendars, being able to view them across all my devices |
|
tutor |
get an overview of my student’s progress |
can see what they don’t know and tutor them better |
|
tutor |
type little but get the command I want |
to save time |
|
tutor |
sort the contact list by programming language |
easily recognise which and how many students are taking a particular programming language |
|
tutor |
send emails to my student |
to send reminders for upcoming lessons or payments owed |
|
tutor |
submit feedback to the developers |
to improve my user experience |
|
tutor with many students in the address book |
sort students by name |
locate a student easily |
Appendix B: Use Cases
(For all use cases below, the System is Codeducator and the Actor is the user, unless specified otherwise)
Use case: Delete student
MSS
-
User requests to list students
-
Codeducator shows a list of students
-
User requests to delete a specific student in the list
-
Schedule deletes the student
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use case: Adding a lesson
MSS
-
Schedule panel shows lessons and timeslots
-
User requests to add a lesson
-
Codeducator adds that lesson to that slot
Use case ends.
Extensions
-
2a. The schedule is empty.
Use case ends.
-
2b. The schedule is full. (Any attempt to add lessons will result in clashes)
-
3b1. Codeducator shows an error message.
-
-
3a. The given student index is invalid.
-
3a1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use Case: View a student’s profile page
MSS
-
User requests to list students.
-
Student list panel shows a list of students.
-
User requests to view profile page of a student.
-
Browser panel shows profile page of student.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Error message shown.
-
3a2. User enters another index.
Use case resumes at step 3.
-
-
3b. There is no XML data currently.
-
3b1. Error message shown.
Use case ends.
-
Use Case: Edit a student’s profile picture
MSS
-
User requests to list students.
-
Student list panel shows a list of students.
-
User requests to edit a student’s profile picture.
-
Command box shows updated picture.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends
-
3a. The given index is invalid.
-
3a1. Error message shown.
-
3a2. User enters another index.
Use case resumes at step 3.
-
-
3b. The file path of the picture does not exist.
-
3b1. Error message shown.
-
3b2. User can enter another file path to the desired picture file.
Use case resumes at step 3.
-
-
3c The file path does not end with an extension of '.png' or '.jpg'.
-
3c1. Error message shown.
-
3c2. User can enter another file path to the desired picture file.
Use case resumes at step 3.
-
-
4a User is at the profile page while entering
editPicturecommand.-
4a1. Profile picture on the profile page changes
Use case ends.
-
Use Case: Edit a student’s miscellaneous information
MSS
-
User requests to list students.
-
Student list panel shows a list of students.
-
User requests to edit a student’s miscellaneous information.
-
Command box shows command success.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends
-
3a. The given index is invalid.
-
3a1. Error message shown.
-
3a2. User enters another index.
Use case resumes at step 3.
-
-
3b. No fields are entered.
-
3b1. Error message shown.
-
3b2. User enters command with specific fields which are desired to edit.
Use case resumes at step 3.
-
-
3c The prefixes are wrong.
-
3c1. Error message shown.
-
3c2. User enters command with proper prefixes to changes desired
Use case resumes at step 3.
-
-
4a User is at the profile page while entering
editMisccommand.-
4a1. The miscellaneous information portion is updated.
Use case ends.
-
Use case: Deleting a lesson
MSS
-
Schedule panel shows lessons and timeslots.
-
User requests to delete a lesson identified by index.
-
Codeducator deletes that lesson from that slot.
Use case ends.
Extensions
-
2a. The schedule is empty.
Use case ends.
-
2b. The given lesson index is invalid.
-
2b1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use case: Logging in
MSS
-
User requests to log in to Google Accounts.
-
A window opens in user’s default browser.
-
User logs in to Google Accounts.
-
User authorizes Codeducator.
-
Codeducator shows login success message
Use case ends.
Extensions
-
3a. User enters wrong password too many times.
-
3a1. Codeducator goes into timeout after 45 seconds.
Use case ends.
-
-
3b. User closes his browser window.
-
3b1. Codeducator goes into timeout after 45 seconds.
-
-
4a. User does not authorise Codeducator.
-
4a1. Codeducator shows authentication denied error.
Use case ends.
-
Use case: Logging out
MSS
-
User requests to log out of Google accounts in Codeducator
-
Codeducator shows logout success message
Use case ends.
Extensions
-
1a. User was not logged in
-
1a1. Codeducator goes into timeout after 45 seconds.
Use case ends.
-
-
3a. User closes his browser window
-
3a1. Codeducator goes into timeout after 45 seconds.
-
-
4a. User does not authorise Codeducator
-
4a1. Codeducator shows authentication denied error
Use case ends.
-
Use case: Syncing data
MSS
-
User requests to sync data with Google services.
-
Codeducator uploads data through network connection.
-
Codeducator shows data sync success
Use case ends.
Extensions
-
2a. User’s internet get cut
-
2a1. Codeducator goes into timeout after losing connection.
Use case ends.
-
Use case: Show a student’s dashboard
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
Use case ends.
Extensions
-
1a. The student index is invalid
-
1a1. Codeducator shows an error message.
-
Use case: Add a milestone to a dashboard
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
-
User requests to add a specific milestone to the dashboard of that student.
-
Codeducator adds the milestone to the dashboard of that student.
Use case ends.
Extensions
-
3a. The milestone is a duplicate of an existing milestone in the dashboard.
-
3a1. Codeducator shows an error message.
-
Use case: Add a task to a milestone in a dashboard
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
-
User requests to add a specific task to a milestone in the dashboard of that student.
-
Codeducator adds the task to the milestone in the dashboard of that student.
Use case ends.
Extensions
-
3a. The task is a duplicate of an existing task in the milestone.
-
3a1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use case: Delete a milestone in a dashboard
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
-
User requests to delete a milestone in the dashboard of that student.
-
Codeducator deletes the milestone in the dashboard of that student.
Use case ends.
Extensions
-
3a. The given student index is invalid
-
3a1. Codeducator shows an error message.
-
-
3b. The given milestone index is invalid
-
3b1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use case: Delete a task in a milestone in the dashboard
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
-
User requests to delete a task in a milestone in the dashboard of that student.
-
Codeducator deletes the task in the milestone in the dashboard of that student.
Use case ends.
Extensions
-
3a. The given student index is invalid
-
3a1. Codeducator shows an error message.
-
-
3b. The given milestone index is invalid
-
3b1. Codeducator shows an error message.
Use case resumes at step 2.
-
-
3c. The given task index is invalid
-
3c1. Codeducator shows an error message.
Use case resumes at step 2.
-
Use case: Mark a task in a milestone as completed
MSS
-
User requests view the dashboard of a student.
-
Codeducator shows the dashboard the student.
-
User requests to mark a task in a milestone in the dashboard of that student as completed.
-
Codeducator marks the task in the milestone in the dashboard of that student as completed.
Use case ends.
Extensions
-
3a. The given student index is invalid
-
3a1. Codeducator shows an error message.
-
-
3b. The given milestone index is invalid
-
3b1. Codeducator shows an error message.
Use case resumes at step 2.
-
-
3c. The given task index is invalid
-
3c1. Codeducator shows an error message.
Use case resumes at step 2.
-
Appendix C: Non Functional Requirements
-
Should work on any mainstream OS as long as it has Java
1.8.0_60or higher installed. -
Should be able to hold up to 1000 students without a noticeable sluggishness in performance for typical usage.
-
A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
-
Should receive feedback after executing commands.
-
Should have correct error handling and not crash from unexpected behavior.
-
Should have its functions and commands easily understood and readable for first time users.
-
Should be able to sync with any Google account ending with @gmail.com
Appendix E: Instructions for Manual Testing
Given below are instructions to test the app manually.
| These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
E.1. Launch and Shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
E.2. Deleting a student
-
Deleting a student while all students are listed
-
Prerequisites: List all students using the
listcommand. Multiple students in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No student is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete,delete x(where x is larger than the list size) {give more}
Expected: Similar to previous.
-
E.3. Saving data
-
Dealing with missing/corrupted data files
-
Delete the contents of /data.
Expected: Codeducator will start off with sample contacts and empty schedule, empty dashboards, empty moreinfo pages
-
E.4. Adding a student to favourites
-
Adding a student to favourites while all students are listed
-
Prerequisites: List all students using the
listcommand and there are multiple students in the list. The first student contact is not in favourites. -
Test case:
fav 1
Expected:-
The name of the first student contact in the student list will turn orange in color.
-
The name of the first student contact will be shown in the result box.
-
Timestamp in the status bar is updated.
-
Executing the command
list -fwill show the student in the favourites list.
-
-
Test case:
fav 0
Expected:-
No student is added to favourites due to the invalid student index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect favourite commands to try:
fav,fav x(where x is larger than the list size)
Expected:-
Similar to the previous test case
-
-
E.5. Removing a student from favourites
-
Removing a student from favourites while all students are listed
-
Prerequisites: List all students using the
listcommand and there are multiple students in the list. The first student contact is in favourites. -
Test case:
unfav 1
Expected:-
The name of the first student contact in the student list will no longer be orange in color.
-
The name of the first student contact will be shown in the result box.
-
Timestamp in the status bar is updated.
-
Executing the command
list -fwill no longer show the student in the favourites list.
-
-
Test case:
unfav 0
Expected:-
No student is removed from favourites due to the invalid student index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect unfavourite commands to try:
unfav,unfav x(where x is larger than the list size)
Expected:-
Similar to the previous test case
-
-
-
Removing a student from favourites while only students in favourites are listed
-
Prerequisites: List only students in favourites using the
list -fcommand and there are multiple students in the list. -
Test case:
unfav 1
Expected:-
First student contact in the favourites list will be removed.
-
The name of the first student contact will be shown in the result box.
-
Timestamp in the status bar is updated.
-
-
E.6. Showing the dashboard of a student
-
Showing the dashboard of a student while all students are listed and the right panel is showing the schedule
-
Prerequisites: List all students using the
listcommand and there are multiple students in the list. The schedule is being displayed on the right panel using theschedulecommand. -
Test case:
showDB 1
Expected:-
The dashboard of the first student contact in the student list replaces the schedule in the right panel.
-
The index 1 is shown in the result box.
-
-
Test case:
showDB 0
Expected:-
The schedule remains in the right panel due to the invalid student index.
-
Error details will be shown in the result box.
-
-
Other incorrect show dashboard commands to try:
showDB,showDB x(where x is larger than the list size)
Expected:-
Similar to the previous test case.
-
-
-
Showing the dashboard of a student while all students are listed and the right panel is showing the browser panel
-
Prerequisites: List all students using the
listcommand and there are multiple students in the list. The 1st student in the list is being selected and the browser is being displayed on the right panel using theselectcommand. -
Test case:
showDB 1
Expected:-
The dashboard of the first student contact in the student list replaces the browser in the right panel.
-
The index 1 is shown in the result box.
-
-
E.7. Adding a milestone to a student’s dashboard
-
Adding a milestone to a student’s dashboard while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. -
Test case:
addMS i/1 d/23/05/2018 23:59 o/Learn Arrays
Expected:-
A milestone with the due date "23/05/2018 23:59" and description "Learn Arrays" is added to the dashboard.
-
The milestone details is shown in the result box.
-
Timestamp in the status bar is updated.
-
-
Test case:
addMS i/0 d/23/05/2018 23:59 o/Learn Arrays-
Milestone is not added to the dashboard due to the invalid student index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Test case:
addMS i/1 d/31/02/2018 23:59 o/Learn Arrays-
Milestone is not added to the dashboard due to the invalid date.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect add milestone commands to try:
addMS,addMS i/1,addMS d/23/05/2018,addMS o/Learn Arrays,addMS i/1 d/23/05/2018 23:59,addMS i/1 d/23/05/2018 o/Learn Arrays
Expected:-
Similar to the previous test case.
-
-
E.8. Deleting a milestone from a student’s dashboard
-
Deleting a milestone from a student’s dashboard while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. The dashboard contains at least 1 milestone. -
Test case:
deleteMS i/1 m/1
Expected:-
The 1st milestone in the dashboard is being deleted.
-
The milestone details is shown in the result box.
-
Timestamp in the status bar is updated.
-
-
Test case:
deleteMS i/1 m/x(where x is larger than the size of the milestone list)
Expected:-
No milestone is deleted due to the invalid milestone index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect delete milestone commands to try:
deleteMS,deleteMS i/1,deleteMS m/1,deleteMS i/0 m/1Expected:-
Similar to the previous test case.
-
-
E.9. Adding a task to a milestone
-
Adding a task to a milestone in a student’s dashboard while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. The dashboard contains at least 1 milestone. -
Test case:
addTask i/1 m/1 n/Learn Array Syntax o/Student to refer to the textbook
Expected:-
A task with the name "Learn Array Syntax" and description "Student to refer to the textbook" is added to the 1st milestone in the dashboard.
-
The task details are shown in the result box.
-
Timestamp in the status bar is updated.
-
-
Test case:
addTask i/1 m/x n/Learn Array Syntax o/Student to refer to the textbook(where x larger than the size of the milestone list)
Expected:-
Task is not added to the milestone due to the invalid milestone index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect add task commands to try:
addTask,addTask i/1 m/1,addTask i/1 m/1 n/Learn Array Syntax,addTask n/Learn Array Syntax o/Student to refer to the textbook
Expected:-
Similar to the previous test case.
-
-
E.10. Deleting a task from a milestone
-
Deleting a task from a milestone in a student’s dashboard while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. The dashboard contains at least 1 milestone with at least 1 task. -
Test case:
deleteTask i/1 m/1 tk/1
Expected:-
The 1st task in the 1st milestone is being deleted.
-
The task details are shown in the result box.
-
Timestamp in the status bar is updated.
-
-
Test case:
deleteTask i/1 m/1 tk/x(where x is larger than the size of the task list)
Expected:-
No task is deleted due to the invalid task index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect delete task commands to try:
deleteTask,deleteTask tk/1,deleteTask m/1 tk/1,deleteTask i/0 m/1 tk/1,deleteTask i/1 m/0 tk/1
Expected:-
Similar to the previous test case.
-
-
E.11. Marking a task as completed
-
Marking an incomplete task from a milestone in a student’s dashboard as completed while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. The dashboard contains at least 1 milestone with the 1st task not marked as completed. -
Test case:
checkTask i/1 m/1 tk/1
Expected:-
The 1st task in the 1st milestone is marked as completed with the "Completed" field turning from "No" to "Yes".
-
The progress of the 1st milestone is updated.
-
The task index and milestone index are shown in the result box.
-
Timestamp in the status bar is updated.
-
-
Test case:
checkTask i/1 m/1 tk/x(where x is larger than the size of the task list)
Expected:-
No task is marked as completed due to the invalid task index.
-
Error details will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
Other incorrect marking task as completed command to try:
checkTask,checkTask tk/1,checkTask m/1 tk/1,checkTask i/0 m/1 tk/1,checkTask i/1 m/0 tk/1
Expected:-
Similar to the previous test case.
-
-
-
Marking a completed task from a milestone in a student’s dashboard as completed while the dashboard is being shown
-
Prerequisites: The dashboard of the 1st student in the list is being shown with the
showDB 1command. The dashboard contains at least 1 milestone with the 1st task already marked as completed. -
Test case:
checkTask i/1 m/1 tk/1
Expected:-
The 1st task in the 1st milestone remains marked as completed with the "Completed" field being "Yes".
-
The progress in the 1st milestone remains the same.
-
A message saying that the task is already marked as completed will be shown in the result box.
-
Timestamp in the status bar remains the same.
-
-
E.12. Displaying the profile page of a student
-
Showing the profile page of a student with the student list on the left and the browser panel is showing currently.
-
Prerequisites: There is at least 1 student in the contacts data and the last shown filtered list. There exists XML data of that particular student.
-
Test case:
moreInfo 1
Expected:-
The profile page of a student is shown.
-
The student’s main information is shown, including
Name,Phone,Address,Email,ProgrammingLanguageandtags. -
The student’s miscellaneous information is shown, including
Allergies,Next Of Kin Name,Next Of Kin PhoneandRemarks. -
The student’s profile picture is displayed. Note: if he/she does not have a custom profile picture, they are assigned a placeholder picture in its place.
-
-
Test case:
moreInfo 0
Expected:-
There is no student whose index is 0. Thus the main panel on the right remains unchanged.
-
An error message is shown in the command box.
-
-
Test case:
moreInfo 1with no XML data of Students
Expected:-
No profile page will be shown as this command only works when there is existing XML data( as mentioned in the prerequisites)
-
An error message is shown in the command box.
-
-
-
Showing the profile page of a student with the student list on the left and the dashboard panel is showing currently
-
Test case:
moreInfo 1
Expected:-
The dashboard panel is switched with the browser panel.
-
The profile page of a student is loaded.
-
The student’s main information is shown, including
Name,Phone,Address,Email,ProgrammingLanguageandtags. -
The student’s miscellaneous information is shown, including
Allergies,Next Of Kin Name,Next Of Kin PhoneandRemarks. -
The student’s profile picture is displayed. Note: if he/she does not have a custom profile picture, they are assigned a placeholder picture in its place.
-
-
Test case:
moreInfo 0
Expected:-
There is no student whose index is 0. Thus, the dashboard panel will still be on display and will not switch with the browser panel.
-
An error message is shown in the command box.
-
-
Test case:
moreInfo 1with no XML data of Students
Expected:-
No profile page will be shown as this command only works when there is existing XML data( as mentioned in the prerequisites)
-
The dashboard panel will still be on display and will not switch with the browser panel.
-
An error message is shown in the command box.
-
-
E.13. Editing the miscellaneous information of a student
-
Editing the miscellaneous information of a student while the student’s profile page is being shown on the main browser panel.
-
Test case:
editMisc 1 al/Nuts
Expected-
The student’s allergies portion of his/her miscellaneous information is overwritten with the string "Nuts".
-
The profile page refreshes and displays the latest updated information of the student.
-
Timestamp in the status bar is updated.
-
-
Test case:
editMisc 1 al/Nuts r/NaughtyExpected-
The student’s allergies portion, as well as the remarks portion, of his/her miscellaneous information is overwritten with "Nuts" and "Naughty" respectively.
-
The profile page refreshes and displays the latest updated information of the student.
-
Timestamp in the status bar is updated.
-
-
Test case:
editMisc 0 al/Nuts
Expected-
There is no student whose index is 0. Thus, the miscellaneous information of the student is not changed.
-
Information of the student on the browser panel is not changed.
-
An error message is shown in the command box.
-
Timestamp in the status bar remains the same.
-
-
Test case: `editMisc 1 al/ ` Expected
-
Fields entered cannot take in empty values. Thus, the miscellaneous information of the student is not changed.
-
Information of the student on the browser panel is not changed.
-
An error message is shown in the command box.
-
Timestamp in the status bar remains the same.
-
-
E.14. Editing the profile picture of a student
-
Editing the profile picture of a student while his/her profile page is on display on the browser panel.
-
Test case:
editPicture i/1 pa/test.jpggiven "test.jpg" is a valid picture file that exists Expected-
The student’s profile picture is overwritten with the new profile picture.
-
The picture from the filepath indicated by the user is copied onto the local data folder.
-
The profile page refreshes and displays the latest updated information of the student.
-
Timestamp in the status bar is updated.
-
-
Test case:
editPicture i/1 pa/C:/Users/User/Desktop/test.jpggiven the file path is a valid picture file that exists Expected-
The student’s profile picture is overwritten with the new profile picture.
-
The picture from the filepath indicated by the user is copied onto the local data folder.
-
The profile page refreshes and displays the latest updated information of the student.
-
Timestamp in the status bar is updated.
-
-
Test case:
editPicture i/1 pa/missingFile.jpggiven the file path is a picture file that does not exists Expected-
As the file does not exist, the profile picture of the student will not be modified.
-
The profile picture of the student displayed on the browser panel is not changed.
-
An error message is shown in the command box.
-
Timestamp in the status bar remains the same.
-
-
Test case:
editPicture i/1 pa/wrongFile.exegiven the file path is a not a picture file but it does exist. Expected-
As the file does not end with an extension of
.jpgorpng, the profile picture of the student will not be modified. -
The profile picture of the student displayed on the browser panel is not changed.
-
An error message is shown in the command box.
-
Timestamp in the status bar remains the same.
-
-
E.15. Adding a lesson
-
Adding a lesson while all students are listed.
-
Prerequisites: View schedule using
schedulecommand. List all students using thelistcommand. Multiple students in the list. Your current schedule would preferably have no lessons starting before 7am or ending after 10pm. -
Test case:
addLesson 1 d/mon st/10:00 et/12:00
Expected:-
A lesson will be added for student at index 1, starting at 10:00am, ending at 12:00pm.
-
-
Test case:
addLesson 1 d/wed st/00:00 et/23:59
Expected:-
A lesson will be added for student at index 1, on Wednesday, starting at 00:00pm, ending at 23:59pm (whole day).
-
The schedule should resize (change start and end times) to show the lesson in the whole day.
-
-
Test case:
addLesson 0 d/mon st/10:00 et/12:00
Expected:-
No lesson added.
-
Error message showing invalid student index.
-
-
-
Adding a lesson with invalid time.
-
Test case:
addLesson 1 d/thu st/10:90 et/15:00oraddLesson 1 d/thu st/24:00 et/26:00Expected:-
No lesson added.
-
Error message shows invalid time format.
-
-
-
Adding a lesson with invalid day
-
Test case:
addLesson 1 d/monday st/10:00 et/15:00oraddLesson 1 d/mo st/10:00 et/15:00Expected:-
No lesson added.
-
Error message shows invalid day format.
-
-
-
Adding a lesson for a filtered list after using
findorfindTagcommand.-
Prerequisites: List a filtered list of students using the
findorfindTagcommand. Single or multiple students in the list. Your current schedule would preferably have no lessons starting before 7am or ending after 10pm. -
Same test cases as when all students are listed, but should work for a smaller index range due to a smaller list of filtered students.
-
E.16. Deleting a Lesson
-
Deleting a lesson from schedule
-
Prerequisites: Add a few lessons into the schedule. Take note of display lesson indexes of your lessons.
-
Test case:
deleteLesson 1
Expected:-
The lesson with displayed lesson index 1 will be deleted.
-
Schedule will resize to between 07:00 and 22:00 if no lesson on any day ends later than that.
-
Message shows lesson deleted.
-
-
Test case:
deleteLesson 0
Expected:-
No lesson will be added due to invalid student index. Error details shown in results screen.
-
-
Other incorrect
deleteLessonscommands to try:deleteLesson,deleteLesson xwhere x is larger than the index of the last lesson.
-
E.17. Logging in to Google Accounts
The testing will only include interactions with Codeducator. Login procedure to Google Accounts is handled by Google
-
Prerequisites: Valid Google account, you know your username and password, ending in @gmail.com
-
Test case: Successfully logging in after executing
logincommand.
Expected:-
Message shows login success
-
Now able to sync data.
-
Now able to logout.
-
Trying to login again results in error message that you are already logged in.
-
-
Test case: Unable to login successfully to Google Accounts within 45 seconds.
Expected-
Error message shows timeout.
-
Unable to sync data.
-
Unable to logout.
-
Able to login again.
-
-
Test case: Ignoring the login screen for 45 seconds.
Expected-
Same as unable to login successfully
-
-
Test case: Wrong Google account username and password.
Expected-
Same as unable to login successfully
-
E.18. Logging out of Google Accounts.
-
Prerequisites: Valid Google account, you know your username and password, ending in @gmail.com. Already logged in
-
Test case: Successfully logging in after executing
logoutcommand-
Message shows logout success
-
Unable to sync data.
-
Unable to logout.
-
Able to login again.
-
-
Test case: Execute
logoutwithout logging in first.
Expected-
Error message shows not logged in
-
E.19. Syncing data
-
Prerequisites:
-
Valid Google account, you know your username and password, ending in @gmail.com.
Expected: -
Already logged in
-
Some contact data and schedule data
-
-
Test case: executing
sync
Expected:-
May take some time to sync
-
In contacts.google.com, you can see your contacts data synced. Codeducator contacts are grouped under the label "Students".
-
In calendar.google.com, you can see your schedule synced. Codeducator events are grouped under the calendar "Student lessons"
-
Message shows sync success.
-
Message
-
-
Test case: executing
syncagain after editing some data e.g.add,edit,delete,addLesson,deleteLesson
Expected:-
May take some time to sync
-
In contacts.google.com, you can see your contacts data synced. Updated Codeducator contacts are grouped under the label "Students".
-
In calendar.google.com, you can see your schedule synced. Updated Codeducator events are grouped under the calendar "Student lessons"
-
Message shows sync success.
-
-
Test case: Executing
syncwithout logging in.
Expected:-
Error message shows not logged in
-