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
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.
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.
To contribute to Codeducator, you will need the following software:
-
JDK
1.8.0_60
or laterℹ️Having 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
>Plugins
to re-enable them.You can download the latest Intellij IDE here.
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 Project
to 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.gradle
file and select it. ClickOK
-
Click
Open as Project
-
Click
OK
to accept the default settings -
Open a console and run the command
gradlew processResources
(Mac/Linux:./gradlew processResources
). It should finish with theBUILD SUCCESSFUL
message.
This will generate all resources required by the application and tests.
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.MainApp
and try a few commands -
Run the tests to ensure they all pass.
You will need to configure and set up some tools we use before you can start making meaningful contributions to Codeducator.
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
Imports
tab to set the order-
For
Class count to use import with '*'
andNames count to use static import with '*'
: Set to999
to 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.
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.
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) |
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].
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
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
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.
The Sequence Diagram below shows how the components interact for the scenario where the user issues the command delete 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.
ℹ️
|
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.
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
Logic
component. -
Binds itself to some data in the
Model
so that the UI can auto-update when data in theModel
change. -
Responds to events raised from various parts of the App and updates the UI accordingly.
XYZCommand
and Command
in Figure 6, “Structure of the Logic Component”API :
Logic.java
-
Logic
uses theAddressBookParser
class to parse the user command. -
This results in a
Command
object 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
CommandResult
object 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.
API : Model.java
The Model
,
-
stores a
UserPref
object 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.
API : Storage.java
The Storage
component,
-
can save
UserPref
objects in json format and read it back. -
can save the Address Book data in xml format and read it back.
This section describes some noteworthy details on how certain features are implemented.
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:
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. |
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
logLevel
setting in the configuration file (See Section 4.3, “Configuration”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
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
Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json
).
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.
The favourites feature allows users to remember/mark a student by adding them to favourites.
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
FavouriteCommandParser
parses the user input to obtain the target student index and constructs a newFavouriteCommand
with this index. -
The logic portion of the favourite command will be executed by the
FavouriteCommand
class. To mark aStudent
object 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 aStudent
object called "editedStudent". "editedStudent" will have the attributes of "studentToFavourite", except that itsFavourite
attribute 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.
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 |
Selecting a student using the select
command will render their location on google maps.
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:
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 |
The programmingLanguage
field is part of the student model and helps to keep track of what programming language he/she is being taught with.
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.
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 |
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.
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.moreInfo
Command
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.
As 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
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. |
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.
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
UniqueKey
field, which we will now use inLesson
to create a relation to Student objects. -
A
Lesson
object callednewLesson
will 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.
The 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.
|
The schedule
command displays of a student’s dashboard. The schedule
command is implemented this way:
From the following diagram,
-
InfoPanel
handles theshowScheduleEvent
event. It changes the view to theCalendarPanel
, hidingDashboardPanel
andBrowserPanel
. -
InfoPanel
raises theshowScheduleEvent
which is also handled byCalendarPanel
to display the lessons of the student in the schedule.
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. |
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
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'
}
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. |
Upload and download |
+ : Much more convenient for the user to sync his data to the cloud. |
The dashboard feature aims to help users keep track of their students' learning progress.
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();
}
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 aStudent
object called "editedStudent". "editedStudent" is created with the same attributes of "targetStudent", but with a newDashboard
object 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.
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 ShowDashboardCommand
As seen from the above diagram,
-
InfoPanel
handles theShowStudentInDashboard
event. -
InfoPanel
then raises theShowStudentNameInDashboard
which is handled byDashboardPanel
to display the name of the student in the dashboard. -
Finally,
InfoPanel
raises theShowMilestoneEvent
which is also handled byDashboardPanel
to display the milestones of the student in the dashboard.
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. |
Allows users to invoke features using free-form english, apart from keywords specific to each feature.
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.
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 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(); } }
Important
|
Every single input always has an intent, but that is not the case for entities! |
For further clarification, refer to the screenshot below:
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.
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. |
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. |
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.
See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.
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/docs
folder, right click on them and selectOpen with
→Google Chrome
. -
Within Chrome, click on the
Print
option in Chrome’s menu. -
Set the destination to
Save as PDF
, then clickSave
to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.
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/java
folder 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
)
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
systemtests
package. -
Unit tests that test the individual components. These are in
seedu.address.ui
package.
-
-
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
-
See UsingGradle.adoc to learn how to use Gradle for build automation.
We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.
We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.
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.
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.
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)
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
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.
-
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 |
(For all use cases below, the System is Codeducator
and the Actor is the user
, unless specified otherwise)
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.
-
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.
-
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.
-
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
editPicture
command.-
4a1. Profile picture on the profile page changes
Use case ends.
-
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
editMisc
command.-
4a1. The miscellaneous information portion is updated.
Use case ends.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
-
Should work on any mainstream OS as long as it has Java
1.8.0_60
or 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
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. |
-
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.
-
-
Deleting a student while all students are listed
-
Prerequisites: List all students using the
list
command. 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.
-
-
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
-
-
Adding a student to favourites while all students are listed
-
Prerequisites: List all students using the
list
command 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 -f
will 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
-
-
-
Removing a student from favourites while all students are listed
-
Prerequisites: List all students using the
list
command 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 -f
will 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 -f
command 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.
-
-
-
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
list
command and there are multiple students in the list. The schedule is being displayed on the right panel using theschedule
command. -
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
list
command 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 theselect
command. -
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.
-
-
-
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 1
command. -
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.
-
-
-
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 1
command. 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/1
Expected:-
Similar to the previous test case.
-
-
-
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 1
command. 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.
-
-
-
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 1
command. 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.
-
-
-
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 1
command. 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 1
command. 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.
-
-
-
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
,ProgrammingLanguage
andtags
. -
The student’s miscellaneous information is shown, including
Allergies
,Next Of Kin Name
,Next Of Kin Phone
andRemarks
. -
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 1
with 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
,ProgrammingLanguage
andtags
. -
The student’s miscellaneous information is shown, including
Allergies
,Next Of Kin Name
,Next Of Kin Phone
andRemarks
. -
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 1
with 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.
-
-
-
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/Naughty
Expected-
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.
-
-
-
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.jpg
given "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.jpg
given 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.jpg
given 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.exe
given the file path is a not a picture file but it does exist. Expected-
As the file does not end with an extension of
.jpg
orpng
, 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.
-
-
-
Adding a lesson while all students are listed.
-
Prerequisites: View schedule using
schedule
command. List all students using thelist
command. 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:00
oraddLesson 1 d/thu st/24:00 et/26:00
Expected:-
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:00
oraddLesson 1 d/mo st/10:00 et/15:00
Expected:-
No lesson added.
-
Error message shows invalid day format.
-
-
-
Adding a lesson for a filtered list after using
find
orfindTag
command.-
Prerequisites: List a filtered list of students using the
find
orfindTag
command. 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.
-
-
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
deleteLessons
commands to try:deleteLesson
,deleteLesson x
where x is larger than the index of the last lesson.
-
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
login
command.
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
-
-
Prerequisites: Valid Google account, you know your username and password, ending in @gmail.com. Already logged in
-
Test case: Successfully logging in after executing
logout
command-
Message shows logout success
-
Unable to sync data.
-
Unable to logout.
-
Able to login again.
-
-
Test case: Execute
logout
without logging in first.
Expected-
Error message shows not logged in
-
-
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
sync
again 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
sync
without logging in.
Expected:-
Error message shows not logged in
-