By: Team W10-03      Since: Aug 2018      Licence: MIT

1. Setting up

1.1. Prerequisites

  1. JDK 9 or later

    JDK 10 on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK 9.
  2. IntelliJ IDE

    IntelliJ by default has Gradle and JavaFx plugins installed.
    Do not disable them. If you have disabled them, go to File > Settings > Plugins to re-enable them.

1.2. Setting up the project in your computer

  1. Fork this repo, and clone the fork to your computer

  2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)

  3. Set up the correct JDK version for Gradle

    1. Click Configure > Project Defaults > Project Structure

    2. Click New…​ and find the directory of the JDK

  4. Click Import Project

  5. Locate the build.gradle file and select it. Click OK

  6. Click Open as Project

  7. Click OK to accept the default settings

  8. Open a console and run the command gradlew processResources (Mac/Linux: ./gradlew processResources). It should finish with the BUILD SUCCESSFUL message.
    This will generate all resources required by the application and tests.

  9. Open XmlAdaptedPerson.java and MainWindow.java and check for any code errors

    1. Due to an ongoing issue with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully

    2. To resolve this, place your cursor over any of the code section highlighted in red. Press ALT+ENTER, and select Add '--add-modules=…​' to module compiler options for each error

  10. Repeat this for the test folder as well (e.g. check XmlUtilTest.java and HelpWindowTest.java for code errors, and if so, resolve it the same way)

1.3. Verifying the setup

  1. Run the seedu.address.MainApp and try a few commands

  2. Run the tests to ensure they all pass.

1.4. Configurations to do before writing code

1.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,

  1. Go to File > Settings…​ (Windows/Linux), or IntelliJ IDEA > Preferences…​ (macOS)

  2. Select Editor > Code Style > Java

  3. Click on the Imports tab to set the order

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements

    • For Import Layout: The order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.

1.4.2. Updating documentation to match your fork

After forking the repo, the documentation will still have the SE-EDU branding and refer to the se-edu/addressbook-level4 repo.

If you plan to develop this fork as a separate product (i.e. instead of contributing to se-edu/addressbook-level4), you should do the following:

  1. Configure the site-wide documentation settings in build.gradle, such as the site-name, to suit your own project.

  2. Replace the URL in the attribute repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.

1.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)

1.4.4. Getting started with coding

When you are ready to start coding,

  1. Get some sense of the overall design by reading Section 2.1, “Architecture”.

  2. Take a look at [GetStartedProgramming].

2. Design

2.1. Architecture

Architecture
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is 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.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

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.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

Events-Driven nature of the design

The Sequence Diagram below shows how the components interact for the scenario where the user issues the command deleteUser. It is assumed that the user has already logged in to his/her account EventOrganiser.

SDforDeletePerson
Figure 3. Component interactions for deleteUser 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.

SDforDeletePersonEventHandling
Figure 4. Component interactions for deleteUser 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.

2.2. UI component

UiClassDiagram
Figure 5. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, EventDetailsPanel, 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 the Model change.

  • Responds to events raised from various parts of the App and updates the UI accordingly.

2.3. Logic component

LogicClassDiagram
Figure 6. Structure of the Logic Component

API : Logic.java

  1. Logic uses the AddressBookParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a person) and/or raise events.

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("deleteUser") API call. Once again, note that we have assumed that the user has already logged in to his/her account in EventOrganiser.

DeletePersonSdForLogic
Figure 7. Interactions Inside the Logic Component for the deleteUser Command.

2.4. Model component

ModelClassDiagramUpdated
Figure 8. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the EventOrganiser data.

  • exposes an unmodifiable ObservableList<Person> and ObservableList<Event> 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.

The Event class contains attributes which depend on the Person and UniquePersonList classes. These are the event organiser (Person), the list of participants (a UniquePersonList). Each event also contains a list of polls, which contains a voter list for each option, which is a UniquePersonList.

As a more OOP model, we can store a Tag list in Address Book, which Person can reference. This would allow Address Book to only require one Tag object per unique Tag, instead of each Person needing their own Tag object. An example of how such a model may look like is given below.

ModelClassBetterOopDiagram

2.5. Storage component

StorageClassDiagram
Figure 9. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save EventOrganiser data in xml format and read it back.

Each event contains references to persons in the list of persons in the EventOrganiser. The storage component stores these people in the form of XmlPersonIndex objects, which are constructed from the index of the person as it is stored in EventOrganiser. When converting XmlAdaptedEvent objects back to a model type Event object, the XmlPersonIndex must be converted to the corresponding person in the EventOrganiser person list.

2.6. Common classes

Classes used by multiple components are in the seedu.addressbook.commons package.

3. Implementation

This section describes some noteworthy details on how certain features are implemented.

3.1. Login/Logout feature

3.1.1. Current Implementation

The goal of this section is to explain the implementation of the login/logout feature.

LoginFeature SequenceDiagram includes Logic
Figure 10. Sequence Diagram for the Logic component when the user issues a login n/Alice pass/password command.

We have assumed that a user with name as "Alice" and password as "password" already exists in Event Organiser. If such an user does not already exist before the login command is issued, login will not be successful. In this implementation, we define the uniqueness of a user by its tuple of NAME and PASSWORD. No two users can have the same NAME and PASSWORD pair. If two users have the same name, then they will have to use different passwords.

When the execute() method of the Login command is called, the login command authenticates the user using the autheneticateUser() method from the model component i.e. checks that the user that is trying to logging actually exists in EventOrganiser. A CommandException will be thrown in the following 2 scenarios:

  • When the user does not exist in EventOrganiser.

  • When there is already a user that is logged in.

On the other hand, when the execute() method of the Logout command is called, a CommandException will be thrown when there isn’t any user that is logged in.

width:"50%"
Figure 11. Sequence Diagram for the Model component when the user issues a login n/Alice pass/password command.

After a user logs in or logs out, the modelManager will raise an UserIsLoginStatusChangedEvent to update the UI.

LoginFeature SequenceDiagram includes Model EventsCenter UI
Figure 12. Sequence Diagram for the Model, EventsCenter, and UI component when the user issues a login n/Alice pass/password command.

There are 2 indications that login was successful. First, a welcome message will be shown with the a message in the format: "Welcome back [NAME]!" where [NAME] is replaced by the full name of the user. For example, if the user, Alex Yeoh, successfully logs in to his account, he should see the welcome message: "Welcome back Alex Yeoh!". Second, upon successful login the colour of the name of the user will change from white to green. The two images below attempts to illustrate the effects of a successful login on the UI. Again, we will use the scenario that a user, Alex Yeoh, wants to login to his account. Alex enters his name and password as required by the login command.

LoginFeatureBeforeLogin
Figure 13. UI before Alex Yeoh logs in.

Once Alex Yeoh successfully logs in, the UI will automatically be updated as shown below

LoginFeatureAfterLogin
Figure 14. UI after Alex Yeoh successfully logs in.

Note that some minute details for the Logic component where omitted for the sake of simplicity.

LoginFeature ClassDiagram Logic 1
Figure 15. Class Diagram for the Logic component of the Login Command

3.1.2. Design Considerations

Aspect: Security
  • Alternative 1(Current implementation) : In the current implementation, we need to uniquely identify an user using both their name and password. If two users have different names, they will be different users. Even if two users have the same name, they can simply choose different passwords for both users to use EventOrganiser.

    • Pros: Fairly easy to implement

    • Cons: Fairly easy for a malicious user to login to another user’s account. However, the problem arises when a malicious user wants to login to other user’s account. This can be achieved fairly simply using the login command. The malicious user can look for the name of the user that already has an account, and brunt force their way in, especially if the password is weak. Similar technique can be used using the EditUser command to comprise the integrity of another users account.

  • Alternative 2 : Implement login command with one-time passwords.

    • Pros: High level of security

    • Cons: Highly difficult to implement

3.2. Poll feature

3.2.1. Current implementation

This section explains the implementation of the features associated with the Poll class of each Event while detailing some implementation details of the Event class. The relevant commands which are callable by the user to be discussed are:

  • AddPollCommand - adds a new Poll to the event given the name of the poll to be created.

  • AddPollOptionCommand - adds a new poll option to the poll given the poll index and the name of the option to be added.

  • VoteCommand - adds the current user as a voter to the voter list of the given option.

  • AddTimePollCommand - creates a new TimePoll automatically populated with options based on the schedules of the event participants.

For all the above commands, the event must first be selected using the selectEvent command, which will set the currentEvent through the Model#setSelectedEvent() method. This is done to ensure that users do not have to continually specify the event for which the Poll commands are called for every command. This is on top of the currentUser in the Model which was already selected through the LoginCommand.

There are two types of Polls which extends from the abstract class AbstractPoll: Poll and TimePoll. Each AbstractPoll object contains a pollData attribute which is stored as a HashMap<String, UniquePersonList>. The pollData stores each option as a string and the list of voters to that particular option as a UniquePersonList. As can be seen in the class diagram, AbstractPolls also include a unique ID to identify the poll and a poll name. They also support the adding of votes by participants who have joined the event, and the display of the poll details, including the most popular options.

PollClassDiagram

The TimePoll class extends from the abstract AbstractPoll class which is constructed by calling the AddTimePollCommand. This command automatically generates a list of 30 minute time slots based on the schedules of the persons on the event invite list, and a specified date range in the user input. The two dates must not be more than a month apart.

The TimePoll shares most of its functionality with Poll, except that users may not add new options. The TimePoll does not automatically update when new event participants join the event. This is done in order to present existing votes for certain options being removed when additional participants join the event. Hence, the event organiser must wait for all participants to be confirmed before adding a TimePoll.

When storing the Poll object in the Storage component, since the XML format does not support the HashMap format, each entry of the HashMap must be converted to a XmlAdaptedPollEntry. Each XmlAdaptedPollEntry contains the option as a String as well as a list of XmlPersonIndex objects, which serve as pointers to the actual Person objects stored in EventOrganiser. Hence, when the EventOrganiser data is retrieved from storage, the Persons in the list of voters for each option, as well as the Persons in the event participant list, refer to the same Person objects in the list of users of the EventOrganiser. This ensures that when a user is edited or deleted, they are updated or deleted in the poll details accordingly. This functionality is supported by the AbstractPoll#updatePerson() and AbstractPoll#deletePerson() methods.

As an example, the following sequence diagram illustrates the workings of the VoteCommand.

VoteSequenceDiagram

As stated above, since Model already stores the current user and the selected event from prior user commands, the Model can call the correct Event e and currently logged-in user in the addVoteToPoll method. If there is no logged-in user, a NoUserLoggedInException is thrown, and if there is no selected event, a NoEventSelectedException is thrown.

In addition, four other possible exceptions might be thrown by the VoteCommand:

  • A user must have already joined the event as a participant, or be on the invite list in order to vote, failing which, a UserNotJoinedEventException is thrown.

  • A user must not already have voted for that particular option in the poll already. This is enforced by the UniquePersonList, which throws a DuplicatePersonException if someone tries to vote twice.

  • A poll must exist at the given poll index for the selected event, else, an IndexOutOfBoundsException is thrown.

  • The given option must exist in the selected poll, else, an IllegalArgumentException is thrown.

The other commands AddPollCommand and AddPollOptionCommand follow a very similar structure. The sequence diagram within the model for the AddPollCommand is illustrated here:

AddPollSequenceDiagram

In all cases, the contents of the poll is returned to the calling Command object as String through the Poll#displayPoll() method. The displayed details of the poll contains the most popular options, computed using the Poll#getPopularOptions() method. This method returns an empty list if no user has voted for any option yet, i.e. if the most popular option has no voters. A new DisplayPollEvent is then posted to the EventsCenter, which is handled by the PollDisplayPanel in the UI component.

3.2.2. Design considerations

Aspect: The relationship between Poll and TimePoll
  • Alternative 1 (Current implementation): Design them as separate classes which both inherit from an abstract AbstractPoll class.

    • Pros: Allows for future extendability from the AbstractPoll class eg additional types of Polls (location, date) which constrain the option types and include additional features to recommend the best option eg most convenient location by distance for participants.

  • Alternative 2: Allow TimePoll to extend from the Poll class.

    • Pros: The two classes differ only in that TimePoll has the augmented feature of generating options from the schedule of event participants.

    • Cons: Unable to constrain the input and prevent users from adding the wrong format for options into TimePoll, since this would violate the Liskov Substitution Principle.

Aspect: Storage of voters in Poll
  • Alternative 1 (Current implementation): Store the voters as Persons.

    • Pros: All information about the voters are stored. This also allows the application to distinguish between two users of the same name. Future extensions to the application might also require additional details about the voters.

    • Cons: Need for complete reference to the actual person via the XmlPersonIndex class in storage, rather than duplicating the person details. The voter list must also be manually updated every time the person details are updated.

  • Alternative 2: Store only the names of voters.

    • Pros: No need for complete reference to the actual person via the XmlPersonIndex class in storage.

    • Cons: Some persons might share the same name. It is also not extendable for future versions where the data/attributes of the voters might be relevant to computing the best option.

3.3. Schedule feature

3.3.1. Current implementation

This section explains the implementation of the features associated with the Schedule class of each schedule while detailing some implementation details of the Schedule class. The relevant commands which are callable by the user to be discussed are:

EditUserCommand - The base Edit command for person with one additions - Schedule Update parameter

MaxScheduleCommand - Compare two or more persons' schedules and return the common free time.

3.3.2. Design considerations

For EditCommand, despite the fact that schedule piggybacks off the original edit command, the original person did not include a schedule object, and so adjustments have to be made. Firstly, if the person does not have the schedule object, a new schedule object would be created by the logic layer. This is to ensure backwards compatibility with past test cases without schedule objects. Next, the schedule needs to be stored in the xml file in a concise way so that it would not be bloated. As the persons in the applications are students, we can be certain that their schedules will be likely the same through the week, thus only the weekly schedule is stored.

Aspect: Storage of schedule in person
  • Alternative 1 Store all schedule as a slot just like how a calendar does, which includes day, time, etc.

    • Pros: All information about the schedule are stored.

    • Cons: Expensive storage as a lot of data needs to be stored. Management of schedule may become an issue here if the schedule needs to store for more than a year worth.

  • Alternative 2: (current implementation) Store weekly schedule

    • Pros: Cheap storage as only a subset of schedule needs to be stored. Possible O(1) access times.

    • Cons: Explicit details of the schedule may be lost such as an event that appears only once a year.

We have chosen the second option for the ease of storage management and low access times. To store the schedule, a unique approach of using bit counters is used. Each bit stores a 30 minute block, totalling to 24 hours * 2 30-mins * 7 days = 336 bits. 1-bit signifies an occupied slot while a 0-bit signifies an empty slot. This 336 bit-string is then stored as a string in the xml. However, in the application, it will stored as a two-dimensional array [7][48]. This allows O(1) access times for each slot, while only requiring O(n) on startup to reload the bit-string into an array.

Each bit string is then translated into a Slot, detailing its time of the day and the day of the week, to be used by the application

ScheduleDiagram

As manipulating bit strings may be complicated, getter, setter and merger methods are provided for any external access to the schedule. This allows easy use of the specific slots in the schedule without heavy calculation and memorisation of bits.

  • Schedule has a copy constructor to create duplicates for the schedule objects. Useful for any commands that manipulate schedule objects.

  • Note that schedule only takes in Slots as an argument for its methods. Slot consists of a Time object and a Day object. This is to ensure Separation of Concerns in the schedule manipulation as schedule does not need to be ensure that the argument input is valid; The Time and Day objects will ensure the validity of values.

  • All commands that feed input into schedule should also validate the data input. In the event such data is not sanitised, defensive programming has been employed in Day and Time to deny the data.

Aspect: Schedule Update

To effect a schedule update, a pair of strings representing the time of the day and the day of the week are to be entered. The strings are then converted into a Slot(which contains Time and Day objects). The setter methods of schedule is then called to effect the change. Note that this is a "bit flip" operation, so it will set a free Slot to an occupied Slot and vice versa.

Aspect: MaxSchedule Command

Similarly, as bitwise operations are allowed, two or more persons' schedule are or-ed together to form a new schedule object. This Schedule object is then translated into slots and print back to the application.

Noted that we have 336 Slots thus it is highly possible that maxSchedule command will return a large number of free time slots. Thus the sl/ tag is used to limit the range of free time displayed. It is implemented in the format of XXXX-XXXX where XXXX is the time slot in 24 hour format.

The sequence diagram of MaxSchedule command is illustrated below.

MaxScheduleDiagram

As noted from the schedule component, MaxSchedule command passes a Time object into the schedule. This abstraction of Time/Day objects reduces the possibility of invalid input resulting from the user input in MaxSchedule command.

3.4. TimeTable feature

3.4.1. Current implementation

This section explains the implementation of the features associated with the TimeTableUtil and Timetable class of each TimeTable while detailing some implementation details of the TimeTable and TimeTableUtil class. The relevant commands which are callable by the user to be discussed are:

3.4.2. Design considerations

EditUserCommand - The base Edit command for person with one addition - Timetable parameter

AddUserCommand - The base Add command for person with one addition - Timetable parameter

TimeTable is a collection of data downloaded from an external source, detailing the students' weekly schedule for the semester. This is to allow ease of access for the students, without having them to enter their schedules manually using schedule update parameters in the EditCommand. This timetable is also not stored inside the xml, but rather immediately translated into a schedule object to be passed back to the application, which would store the object inside the model.

Aspect: Timetable Source
  • Alternative 1 Google Calendar

    • Pros: Academic and non-academic calendar events can be downloaded.

    • Cons: Not tailored for NUS students - students must acquire their academic events from their own CORS (NUS module slot bidding) result to populate their own google calendar. Google authorization token (per user) will have to stored securely.

  • Alternative 2: (current implementation) NusMod

    • Pros: Academic events can be downloaded. Many students are already using this platform to store their academic events.

    • Cons: Non-academic events cannot be downloaded from this source.

NusMods will be used to provide academic events for the student. As for their non-academic events, he can use schedule update to manually update those slots. This way, we will be able to provide the most convenient way for the student to populate the schedule.

Aspect: Timetable Download

As nusmods.com is an external web server, internet access needs to be checked first. Following up, the nusmods.com gives the user a modsn.com shortlink which can translated back to a nusmods.com/…​ full link, if he wants to share his timetable with himself or others. Finally, a valid nusmods.com timetable would include json data in its GET parameters. All of these must be fulfilled or else a Invalid Nusmods link will be returned to the application.

The sequence diagram for the timetable download is illustrated below.

TimeTableScheduleDiagram

This is the valid short link of the nusmod timetable.

http://modsn.us/H4v8s

The above short link will be parsed into the full nusmods link as followed:

https://nusmods.com/timetable/sem-1/share?CS2102=LEC:1,TUT:11&CS2103=LEC:1,TUT:01&CS2105=LEC:1,TUT:16&CS2106=LAB:09,LEC:1,TUT:09&MA1521=LEC:1,TUT:4&UCV2209=SEM:01

Breakdown on how to obtain the full timetable and convert it into a Schedule.

Step 1. We can easily obtain the person’s timetable by splitting the GET parameters by ';' delimiter. The resulting array would contain Module Code /=/ Lesson Type /:/ Number Slot.

Step 2. Then, to obtain the full details of the module (including all lessons and all slots), we can use the NUSMODS API detailed here https://github.com/nusmodifications/nusmods-api.

Step 3. We will then filter out the lessons obtained in step 1 from the full detail in step 2.

Step 4. The filtered lessons is then converted into a list of Slot.

Step 5. The list of Slot will be passed in a Schedule constructor to generate a new Schedule.

Step 6. The new Schedule object is returned to the application.

3.5. Add/Delete Friend feature

3.5.1. Current implementation

This section explains the implementation of the addition/deletion of friends feature associated with each user in EventOrganiser. The relevant commands which are callable by the user to be discussed are:

  • AddFriendCommand - takes in an INDEX, and adds the person specified at the INDEX to the logged-in person’s friend list.

  • DeleteFriendCommand - takes in an INDEX, and deletes the person specified at the INDEX from the logged-in person’s friend list.

  • ListFriendsCommand - takes in an INDEX, and displays all friends of the person specified at the INDEX.

The following sequence diagram for AddFriendCommand is illustrated below:

AddFriendCommand

3.5.2. Design considerations

Aspect: Unilateral friendships

Friendships are unilateral, so if person A is a friend of person B, then person B may not be a friend of person A.

In EventOrganiser, adding a user into the friend list is similar to following someone on Instagram. This is because having a person in your friend list will make it easier for you to be kept updated of his/her details, such as viewing his/her personal particulars or viewing the events that he/she had joined. This is because of the ListFriendsCommand which can display all the friends of the particular user and their details in the display panel as shown below.

ListAllFriendsExample

To specify the addition of a user into the logged-in user’s friend list (AddFriendCommand), the index of the user has to be provided. The command format is addFriend INDEX, where INDEX has to be a positive number that is greater than 0, less than or equals to the current greatest index. The INDEX should also not be the current logged-in user himself/herself or someone who is already in his/her friend list. Whereas for DeleteFriendCommand, the INDEX should not be a user who is not currently in his/her friend list.

Aspect: Friend class

Like other attributes, we represents a friend of a Person using a Friend class. The Friend class has a constructor which takes in a Person object, and initializes the string field friendAttributes that combines the 2 attributes that define the uniqueness of a Person (name and password) in string form using a vertical bar(|). Example: For a person with name Alex Yeoh, password password123, the Friend object’s friendAttributes string field will be Alex Yeoh|password123.

In the Person class, his/her friends will be represented using a Set of Friend objects as the friend list. In the example below, we will describe the procedures when Person A (logged-in user) wants to add Person B (user specified by INDEX) into his/her friend list.

When AddFriendCommand is executed by Person A, once the checking is done (as described in the next aspect), a copy of Person A object will be created. Then the addFriendInList() method from Person class will be called, which creates a Friend object using Person B (as described by the paragraph above) and adds the newly created Friend object into the copy of Person A object’s Set of friends. Finally, the copy of Person A object will replace the original Person A object in the Model using the updatePerson() method from the Model class.

In the display panel where the friend list of a user is displayed, the friend of that user will be identified by the first token of the string field in the Friend object separated by the delimiter '|' (due to the toString() method in Friend class), which is the actual name of the friend.

Aspect: User can only be added as friend once. User can only be deleted as friend if he/she is in the friend list of the logged-in user.

Each person can only be added as a friend once by another person. If Person B is already in the friend list of Person A (logged-in user) and AddFriendCommand is called again Person B, the friend list of Person A will be checked using the hasFriendInList() method in Person class to confirm that Person B is already in the list, thus Person B will not be added into the list again.

Similarly, if Person B is not yet in Person A’s (logged-in user) friend list, and DeleteFriendCommand is called on Person B, the friend list of Person A will be checked using the hasFriendInList() method to confirm that Person B is not in the list, thus no one will be deleted from the list.

Aspect: Deletion/Modification of attributes of a person who is currently on the friend list of another person

The friend lists of each user have to be constantly updated when a user is deleted from the EventOrganiser or his/her attributes are modified (such as change of name).

The following scenario describes what happens if Person B is already on the friend list of Person A.

Person B gets deleted from the Event Organizer: This triggers the updateFriendListsDueToDeletedPerson() function in the DeleteUserCommand class, which searches through the friend lists of all the other persons. If someone has Person B in their friend list (such as Person A), then Person B will be removed from Person A’s friend list.

Person B’s attributes gets modified (eg change of name): This triggers the updateFriendListsDueToEditedPerson() function in the EditUserCommand class, which searches through the friend lists of all the other persons. If someone has Person B in their friend list (such as Person A), the original Friend object in Person A’s friend list will be replaced by the new Friend object created using the new attributes of Person B.

3.6. 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 logLevel setting in the configuration file (See Section 3.7, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.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

3.7. Configuration

Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json).

4. 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.

4.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.

4.2. Publishing Documentation

See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.

4.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.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open withGoogle Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 16. Saving documentation as PDF files in Chrome

4.4. Site-wide Documentation Settings

The build.gradle file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.

Attributes left unset in the build.gradle file will use their default value, if any.
Table 1. List of site-wide attributes
Attribute name Description Default value

site-name

The name of the website. If set, the name will be displayed near the top of the page.

not set

site-githuburl

URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar.

not set

site-seedu

Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items.

not set

4.5. Per-file Documentation Settings

Each .adoc file may also specify some file-specific asciidoc attributes which affects how the file is rendered.

Asciidoctor’s built-in attributes may be specified and used as well.

Attributes left unset in .adoc files will use their default value, if any.
Table 2. List of per-file attributes, excluding Asciidoctor’s built-in attributes
Attribute name Description Default value

site-section

Site section that the document belongs to. This will cause the associated item in the navigation bar to be highlighted. One of: UserGuide, DeveloperGuide, LearningOutcomes*, AboutUs, ContactUs

* Official SE-EDU projects only

not set

no-site-header

Set this attribute to remove the site navigation bar.

not set

4.6. Site Template

The files in docs/stylesheets are the CSS stylesheets of the site. You can modify them to change some properties of the site’s design.

The files in docs/templates controls the rendering of .adoc files into HTML5. These template files are written in a mixture of Ruby and Slim.

Modifying the template files in docs/templates requires some knowledge and experience with Ruby and Asciidoctor’s API. You should only modify them if you need greater control over the site’s layout than what stylesheets can provide. The SE-EDU team does not provide support for modified template files.

5. Testing

5.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/java folder and choose Run '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)

5.2. Types of tests

We have two types of tests:

  1. GUI Tests - These are tests involving the GUI. They include,

    1. System Tests that test the entire App by simulating user actions on the GUI. These are in the systemtests package.

    2. Unit tests that test the individual components. These are in seedu.address.ui package.

  2. Non-GUI Tests - These are tests not involving the GUI. They include,

    1. Unit tests targeting the lowest level methods/classes.
      e.g. seedu.address.commons.StringUtilTest

    2. 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

    3. 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

5.3. Troubleshooting Testing

Problem: HelpWindowTest fails with a NullPointerException.

  • Reason: One of its dependencies, HelpWindow.html in src/main/resources/docs is missing.

  • Solution: Execute Gradle task processResources.

6. Dev Ops

6.1. Build Automation

See UsingGradle.adoc to learn how to use Gradle for build automation.

6.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.

6.3. Coverage Reporting

We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.

6.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.

6.5. Making a Release

Here are the steps to create a new release.

  1. Update the version number in MainApp.java.

  2. Generate a JAR file using Gradle.

  3. Tag the repo with the version number. e.g. v0.1

  4. Create a new release using GitHub and upload the JAR file you created.

6.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)

Appendix A: Product Scope

Target user profile:

  • Busy NUS students.

  • Need to organise group project meetings.

  • Need to organise interest group meet-ups and encourage new participants to attend.

  • Need to find the best time to meet-up based on the schedules of participants and addresses.

  • Some level of tech-savviness to appreciate CLI apps.

  • Have a schedule that works on a weekly basis.

Value proposition:

  • Key concept: Semi-automate the coordination of meeting time/venue based on participant’s schedule.

  • What customers want: Students want to organize all kinds of meetups in a fast and efficient way, eg project meetups, interests groups etc.

  • Limitations of what customers can do now: Hard to coordinate the meetups as they are unable to locate people of available time slots or contact people with similar interests. They have to resort to use platforms such as WhatsApp to advertise their events through friends, and coordinate similar time slots through very manual means such as Google Docs and Doodle.

  • Benefits customers seek to achieve: Students want to do all the scheduling, inviting and finalizing of a meetup in a fast and effective way.

  • How value proposition is delivered: EventOrganiser provides a large database of all the contacts and information of NUS students, which allows the organizers to search by name, availability, interests etc.

Feature

Division of work

Keng Ji : Add event feature with polls and time, location features

  • V1.1: EventOrganiser able to create a basic event with date, time, organiser, participant and poll features.

  • V1.2: Users able to search for events by attributes (date, time, location, interest) and time range.

  • V1.3: Application able to generate poll options based on participants' schedules.

Yao Feng : Add login function and improve on search functions

  • V1.1: Basic login command.

  • V1.2: Search for users based on phone number, interests, friendships, schedule, and address.

  • V1.3: Improved login command with password.

Zhang Cheng : Add additional attributes for networking among users

  • V1.1: Users able to specify their interests.

  • V1.2: Users able to specify friendships with other people.

  • V1.3: Users able to search for friends and become more connected.

  • V1.1: Add feature of nearest MRT for each individual.

  • V1.2: Implement recommendation of best meet-up location via MRT lines.

  • V1.3: Implement Google maps visualisation.

Jason : Event Management/Recommendation

  • V1.1: Pull schedule from NUS Mods and convert to a timetable. Allow Unions of timetable.

  • V1.2: Create, Update, Delete individual slots in timetable. Find best possible time for events using timetables.

  • V1.3: Visualize timetables of multiple friends.

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

Event Organiser

Find people that might be interested in the event that I am organising.

Find potentially interested individuals to join my event.

* * *

Event Organiser

Allow my participants to vote for their most preferred time and location.

Organise an event at a time and location based on popular vote.

* * *

Event Organiser

Automate the task of sieving through the schedules of all my participants for the ideal meet-up location and meet-up time.

Do not have to worry about the hassle of finding the best time and location for my event.

* * *

Event Organiser

Have a specialised platform to post events aimed at a tech-savvy audience.

Promote my event to an audience that I am interested in.

* * *

Busy User

Have a platform to search for all the events that occur during my free time.

Easily find a event that I have time to go for.

* * *

Tech-savvy User

Have a platform that supports CLI.

Easily write scripts to automatic the task that I want to accomplish on a regular basis.

* * *

User

Keep track of all the events that I can gone to.

Have a record of the events that I have been to.

* * *

User

[Coming in v2.0] Visualise the event location on Google maps.

Find out exactly how to get to that location.

* * *

User

Have a social media kind of platform which specialises on organising events.

Know the events that my friends are going to and let my friends know about the events that I am going to.

* * *

User

Easily find other users based on their particulars.

Find my friends or anyone that might be of interest to me.

* * *

User

Create an individual profile with some security features.

I can access and make changes to my own profile easily, but other people will not have access to it.

* * *

NUS student

Have a platform that utilises NUSMODS’s schedule.

Conveniently update my schedule using NUSMODS’s schedule.

* * *

NUS student

Have a platform that can facilitate the task of finding the ideal time and location for project group meet-ups.

Easily organise project group meet-ups instead of asking each individual group mates one by one.

* *

User

Find mutual friends in among my social circle and people with similar interests as me.

I can widen my social circle and meet like minded people.

Appendix C: Use Cases

(For all use cases below, the System is the EventOrganiser, unless specified otherwise)

Use case: U01 - Create new user

Actor: New user

MSS:

  1. User creates new user profile.

  2. System checks that the details are valid.

  3. System informs the user that the profile has been successfully created.

    Use case ends.

Extensions:

  • 2a. User enters invalid detail.

    • 2a1. System will prompt user to re-enter their details.

    • 2a2. User enters profile details again.

      Steps 2a1 - 2a2 are repeated until the details entered are valid.

      Use case resumes from step 3.

Use case: U02 - Log in to a user account

Actor: User

MSS:

  1. User creates enters his credentials.

  2. System checks that the details are valid.

  3. System informs the user that he/she has successfully logged in.

    Use case ends.

Extensions:

  • 2a. User enters invalid details.

    • 2a1. System will prompt user to re-enter their details.

    • 2a2. User enters profile details again.

      Steps 2a1 - 2a2 are repeated until the details entered are valid.

      Use case resumes from step 3.

Use case: U03 – Delete a user

Actor: User

MSS:

  1. User chooses to delete his/her user profile.

  2. System checks that the profile that will be deleted corresponds to the profile of the current user.

  3. System informs the user that the profile has been successfully deleted.

  4. System deletes the user profile within its storage.

    Use case ends.

Extensions:

  • 2a. The profile to be deleted does not correspond to the profile of the current user.

    • 2a1. System informs user that the profile cannot be deleted.

    • 2a2. User either change his profile or change the profile that he/she wants to delete.

      Steps 2a1 – 2a2 are repeated until the current user and the user profile that will be deleted matches.

      Use case resumes from step 3.

Use case: U04 – Create new event

Actor: Event organiser

Precondition: Event organiser has logged himself/herself in

MSS:

  1. Event organiser creates a new event by specifying the name, location and tags of the event.

  2. System checks that the details are valid.

  3. System informs the event organiser that the event has been successfully created.

    Use case ends.

Extensions:

  • 2a. Event organiser enters invalid details.

    • 2a1. System will prompt event organiser to re-enter the event details.

    • 2a2. Event organiser enters event details again.

      Steps 2a1 - 2a2 are repeated until the details entered are valid.

      Use case resumes from step 3.

Use case: U05 – Delete an event

Actor: Event organiser

Precondition: Event organiser has identified himself/herself

MSS:

  1. Event organiser chooses to delete an event.

  2. System checks that the event belongs to the user.

  3. System informs the event organiser that the event has been successfully deleted.

    Use case ends.

Extensions:

  • 2a. The event that will be deleted does not belong to the user.

    • 2a1. System will inform the user that the event cannot be deleted.

    • 2a2. User either change his profile or change the event that he/she wants to delete.

    • Steps 2a1 – 2a2 are repeated until the event belongs to the current user.

      Use case resumes from step 3.

Use case: U06 - User joins an event

Actor: User

Precondition: User has logged in

MSS:

  1. User searches for available events.

  2. System shows user all the events that are available.

  3. User chooses an event that he wants to join.

  4. System informs the user that he/she has been successfully joined the event.

    Use case ends.

Extensions:

  • 1a. User may specify extra details to filter out search results.

    Use case resumes at step 2.

Use case: U07 – Event organiser creates a poll

Actor: Event organiser

Precondition: Event organiser has logged in and created an event

MSS:

  1. Event organiser selects an event.

  2. Event organiser creates a new poll.

  3. Event organiser creates options for the poll.

  4. System informs the event organiser’s options has been successfully updated.

  5. System updates polling information in its storage.

    Use case ends.

Use case: U08 – User votes in a poll

Actor: User who is keen to join an event

Precondition: User has logged in and has joined an event

MSS:

  1. User selects a poll from the poll list of the event.

  2. System displays the poll selected by the user.

  3. User looks at the options given in the poll and votes for his/her preferred options.

  4. System adds the user to the voter list of that option.

  5. System updates the list of most popular options in the poll.

  6. System updates polling information in its storage.

    Use case ends.

Use case: U09 – Event organiser confirms the event details

Actor: Event organiser

Precondition: Event organiser has logged in, event participants have all joined and voted in polls

MSS:

  1. Event organiser looks at the poll results.

  2. System shows the top options for each of the polls.

  3. Event organiser decides on the ideal time, date and location for the event and sets them accordingly.

  4. System informs the user’s options has been successfully updated.

  5. System updates event information in its storage.

    Use case ends.

Appendix D: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 9 or higher installed.

  2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.

  3. 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.

  4. Commands should be intuitive for users to pick up easily.

  5. Allows a limited form of security by ensuring that users are only able to log in to their own accounts.

Appendix E: Glossary

Unique user

Refers to an user which has an unique tuple of NAME and PASSWORD.

User / Person

Refers to a person who uses EventOrganiser.

User Profile

Refers to an account that is recorded in EventOrganiser.

New User

Refers to a person who does not own a user profile in EventOrganiser.

Current User

Refers to the user currently identified by the system.

Event Organiser

Refers to a user who has created an event.

Appendix F: Product Survey

  • NIL

Appendix G: 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. The result of the test cases under each command is assumed to not persist to the next test case unless otherwise stated

G.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

G.2. Add a user

  1. Note: The states of each test case is continued in the next test case.

  2. Prerequisites: EventOrganiser has no users currently.

  3. Test case: addUser n/Alex Yeoh pass/password Expected: Invalid command format.

  4. Test case: addUser n/Alex Yeoh e/alex@exmple.com a/Blk 12 John Street, #10-11 pass/password p/91234567 Expected: New person added.

G.3. Login a user

  1. Note: The states of each test case is continued in the next test case.

  2. Prerequisites: EventOrganiser already has a user with name as "Alex Yeoh" and password as "password". No user is currently logged in. EventOrganiser does not have a user with name as "Michael Lim" and password as "password".

  3. Test case: login Expected: Login unsuccessful.

  4. Test case: login n/Michael Lim pass/password Expected: Login unsuccessful.

  5. Test case login n/Alex Yeoh pass/password Expected: Login successful.

G.4. Logout a user

  1. Note: The states of each test case is continued in the next test case.

  2. Prerequisites: A user with name as "Alex Yeoh" and password as "password" is currently logged in.

  3. Test case logout Expected: Logout successful.

  4. Test case: logout Expected: Logout unsuccessful.

G.5. Find users

  1. Prerequisites: EventOrganiser currently has two user accounts. The first user has name as "Alex Yeoh" and interests as "study". The second user has name as "Bernice Yu" and interest as "play".

  2. Test case findUser n/Alex Yeoh Expected: Only user "Alex Yeoh" is listed.

  3. Test case: findUser i/play Expected: Only user "Bernice Yu" is listed.

  4. Test case: findUser n/Alex Yeoh i/play Expected: No user is listed.

G.6. Edit a user

  1. Prerequisites: EventOrganiser has a user with name as "Alex Yeoh" and user "Alex Yeoh" is currently logged in.

  2. Test case editUser n/Alex Tan Expected: Name of user successfully changed to "Alex Tan".

G.7. Delete a user

  1. Prerequisites: EventOrganiser has a user with name as "Alex Yeoh" and user "Alex Yeoh" is currently logged in.

  2. Test case deleteUser Expected: user "Alex Yeoh" successfully deleted.

G.8. Populate a user schedule via Timetable

  1. Prerequisites: EventOrganiser has a user with name as "Alex Yeoh" and user "Alex Yeoh" is currently logged in.

  2. Test case editUser tt/http://modsn.us/H4v8s Expected: Schedule of user successfully overwritten to 100000000000000011110000000011110000000000 000000000000000000000000000000111111110000000000000000000000000000000000001100000011110000000000 000000000000000000000000000000111100001111000000000000000000000000000000111100001111111111000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000.

  3. Test case editUser tt/http://modsn.us/H Expected: Invalid NUSmods Link

G.9. Edit a user schedule

  1. Prerequisites: EventOrganiser has a user with name as "Alex Yeoh", no existing schedule and user "Alex Yeoh" is currently logged in.

  2. Test case editUser su/monday 0000 Expected: Schedule of user "Alex Yeoh" successfully changed. First bit of the schedule is now 1.

  3. Test case editUser su/monday 0030 Expected: Schedule of user "Alex Yeoh" successfully changed. Second bit of the schedule is now 1.

G.10. Find free time between two users

  1. Prerequisites: EventOrganiser has 2 users A and B on index 1 and 2. Both A and B has no existing schedule.

  2. Test case maxSchedule 1 2 sl/0000-0000 Expected: Free time of 0000 from Monday to Sunday is displayed.

  3. Test case maxSchedule 1 2 sl/0800-0900 Expected: Free time of 0800, 0830, 0900 and 0930 from Monday to Sunday are displayed.

G.11. Add a friend

  1. Prerequisites: Event Organiser has users with name "Alex Yeoh"(index 1) and "Bernice Yu"(index 2), and "Bernice Yu" is not currently in "Alex Yeoh"'s friend list, and user "Alex Yeoh" is currently logged in.

  2. Test case addFriend 2 Expected: "Bernice Yu" is added to "Alex Yeoh" friend list.

G.12. Delete a friend

  1. Prerequisites: Event Organiser has users with name "Alex Yeoh"(index 1) and "Bernice Yu"(index 2), and "Bernice Yu" is currently in "Alex Yeoh"'s friend list, and user "Alex Yeoh" is currently logged in.

  2. Test case deleteFriend 2 Expected: "Bernice Yu" is deleted from "Alex Yeoh" friend list.

G.13. Add an event

  1. Prerequisites: EventOrganiser has a user with name as "Alex Yeoh" and user "Alex Yeoh" is currently logged in.

  2. Test case addEvent n/CS1234 Group Meeting a/SoC Canteen t/URGENT Expected: new event with details CS1234 Group Meeting Location: SoC Canteen Tags: [URGENT] is added and selected. "Alex Yeoh" is the event organiser. Event details are displayed in the event details panel, and "Alex Yeoh" is a participant of the event under "People attending".

  3. Test case addEvent n/CS1234 Group Meeting t/URGENT Expected: Add event unsuccessful.

G.14. Add a poll

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected the first event in the event list, created by him.

  2. Test case addPoll n/Meeting date Expected: a new poll with name "Meeting date" is created and displayed in the event details panel.

G.15. Add a time poll

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected the first event in the list, created by him.

  2. Test case addTimePoll d1/19-12-2018 d2/20-12-2018 Expected: a new poll with name "Time Poll" is created and displayed in the event details panel. It is populated by 30 minute slots based on the schedules of the participants.

G.16. Add poll options

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected an event created by him.

  2. Test case addOption i/1 o/12 December Expected: a new poll option with name "12 December" is created and displayed in the event details panel.

  3. Test case addOption i/1 o/13 December Expected: a new poll option with name "13 December" is created and displayed in the event details panel.

G.17. Delete an event

  1. Prerequisites: Event organiser "David Li" is logged in and "David Li" is the organiser of event at index 2 but not event at index 1.

  2. Test case deleteEvent 2 Expected: Event at index 2 is deleted

  3. Test case deleteEvent 1 Expected: Event 1 is not deleted, an error message "You are not the organiser of this event." is returned.

G.18. Select an event

  1. Prerequisites: The event list is not empty.

  2. Test case selectEvent 1 Expected: The event details panel displays the details of the event at index 1.

G.19. Display poll

  1. Prerequisites: The event at index 1 has been selected and there is a poll in the event.

  2. Test case displayPoll 1 Expected: Poll at index 1 of the poll list of the first event is displayed.

G.20. Edit an event

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected an event created by him.

  2. Test case editEvent n/CS2100 Discussion a/NUS UTown Expected: The selected event is edited to have the name "CS2100 Discussion" and the location "NUS UTown".

  3. Test case editEvent t/URGENT Expected: The selected event is edited to have only one tag "URGENT"

G.21. Find an event by attributes

  1. Prerequisites: The event list is not empty.

  2. Test case findEvent e/Linguistics Reading Group Expected: all and only events with name "Linguistics Reading Group" are displayed in the event list.

  3. Test case findEvent t1/17:30 on/Charlotte Oliveiro Expected: all and only events starting at 17:30 and organised by "Charlotte Oliveiro" are displayed in the event list.

G.22. Find event by time

  1. Prerequisites: The event list is not empty.

  2. Test case findEventByTime d/01-12-2018 t1/07:30 t2/17:30 Expected: all and only events held between 07:30 and 17:30 on 01-12-2018 are displayed.

G.23. List all events

  1. Prerequisites: NIL

  2. Test case listEvent Expected: All events in the event organiser are displayed in the events list.

G.24. Set date

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected an event created by him.

  2. Test case setDate d/12-12-2018 Expected: the date "12-12-2018" is set and appears in the event card of the event.

G.25. Set time

  1. Prerequisites: Event organiser "Alex Yeoh" is logged in and has selected an event created by him.

  2. Test case setTime t1/12:30 t2/14:30 Expected: the times "12:30 - 14:30" are set and appear in the event card of the event.

G.26. Join event

  1. Prerequisites: A user "Charlotte Oliveiro" is logged in and has yet to join the first event in the list.

  2. Test case joinEvent 1 Expected: The user "Charlotte Oliveiro" is added to the participants list of the first event. The new event details are displayed in the event details panel.

G.27. Vote in poll

  1. Prerequisites: User "Charlotte Oliveiro" is logged in and joined the first event in the list, to which the event organiser has added a poll "Meeting Date" at poll index 1. In the poll, there are the options 12 December and 13 December with no voters.

  2. Test case vote i/1 o/12 December Expected: The user "Charlotte Oliveiro" is added to the voter list of the option "12 December" The most popular options list updates to include "12 December"

G.28. Saving data

  1. Dealing with missing/corrupted data files

    1. Corrupted XML file: the application would not run to prevent unexpected responses.

    2. Missing XML file: the application will re-generate the sample xml, and save it as data/addressbook.xml when a change in the sample data.