diff --git a/README.md b/README.md index 46e1d166c3..6326002274 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![cOOPer](docs/userGuideImages/cooperLogo.png) -# What is COOPER? +# What is cOOPer? cOOPer is a **desktop application** developed to simplify administrative processes of **tech startups** such as **communication** and **finance management**. diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c1b9f92bdb..f18b85ffc6 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,5 +1,7 @@ ![cOOPer](userGuideImages/cooperLogo.png) + + # Developer Guide ## Introducing cOOPer @@ -166,10 +168,12 @@ cOOPer recognizes different sets of inputs at each layer. layerDiagram

-Upon launching the app, the user starts at the _**verification** layer_ where they can only [log in](UserGuide.md#login) or [register](UserGuide.md#user-registration). +Upon launching the app, the user starts at the _**verification** layer_ where they can only [log in](UserGuide.md#logging-in-login) or [register](UserGuide.md#registration). Entering valid credentials will then grant the user access to the _**features** layer_ where they can input commands to use cOOPer's features. At this layer, entering the `logout` command will bring the user back to the _verification layer_. +
+ ### Architecture

@@ -245,7 +249,7 @@ The `Ui` component:

- The `Parser` component consists of an abstract `ParserBase` class with its subclasses, `CommandParser` and `SignInDetailsParser`. -- To emphasize the different [layers](#overview) of cOOPer and to increase cohesiveness, different types of objects are constructed from user input at different layers. +- To emphasize the different [layers](#overview) of cOOPer, different types of objects are constructed from user input at different layers. User input at the _verification layer_ will be parsed to construct a `SignInProtocol` object while user input at the _features layer_ will be parsed to construct a `Command` object. - The `SignInProtocol` object executes the signing in of the user with details provided while the `Command` object executes the command input by the user. - `ParserBase` contains a reference to the `Parser` *interface* from the [dopsun chatbot-cli](https://github.com/dopsun/chatbot-cli) library used by cOOPer. @@ -267,8 +271,7 @@ The `Parser`component: verificationComponent

-- The `Verification` component consists of a `Verifier` class which verifies user credentials and performs the necessary action in granting access to the user. -- `Cooper` contains a reference to a `Verifier` object. +- The `Verification` component consists of a `Verifier` class which contains the list of registered users and methods to verify user credentials. - The `SignInProtocol` class is an abstract class representing one of the two sign in protocols, `Login` or `Registration`. - The `SignInProtocol` class contains a reference to a `SignInDetails` object which as a whole, represents a **sign in attempt** by the user using one of the two protocols, with the corresponding `SignInDetails`. For example, a `Login` object containing `SignInDetailsX` represents the user's login attempt with the details `SignInDetailsX`. @@ -280,6 +283,8 @@ The `Verification` component: [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Command Component **API**: [`Command.java`](https://github.com/AY2122S1-CS2113T-W13-4/tp/blob/master/src/main/java/cooper/command/Command.java) @@ -339,6 +344,7 @@ The `Resources` component: - Returns references of feature managers such as `MeetingManager`, `FinanceManager` or `ForumManager` based on `UserRole` of the request body. E.g. Only an *admin* is able to get `FinanceManager` successfully. - Returns references to `StorageManager` safely upon request. + #### Finance @@ -357,6 +363,8 @@ The `Finance` component: + Handles adding / listing / generating of balance sheets, cash flow statements, and free cash flow projections. + Assists the parser in identifying which function is being used at any given time. + + #### Meetings **API**: [`cooper.meetings`](https://github.com/AY2122S1-CS2113T-W13-4/tp/tree/master/src/main/java/cooper/meetings) @@ -367,7 +375,7 @@ The `Finance` component: The `Meetings` component contains the `MeetingManager` and `Meeting` classes. -`MeetingManager` stores **2** attributes: +`MeetingManager` stores **two** attributes: 1. the **timings** along with the **usernames** of the available users, which is a `TreeMap>` object, 2. the **list of meetings** scheduled, which is an `ArrayList` object. @@ -379,6 +387,8 @@ The `Meetings` component: + Assists in the **scheduling** of meetings + Lists the current availability and meetings + + #### Forum **API**: [`cooper.forum`](https://github.com/AY2122S1-CS2113T-W13-4/tp/tree/master/src/main/java/cooper/forum) @@ -397,6 +407,8 @@ The `Forum` component: [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Storage Component **API**: [`cooper.storage`](https://github.com/AY2122S1-CS2113T-W13-4/tp/tree/master/src/main/java/cooper/storage) @@ -419,6 +431,8 @@ The `Storage` component: [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Util Component **API**: [`Util.java`](https://github.com/AY2122S1-CS2113T-W13-4/tp/tree/master/src/main/java/cooper/util/Util.java) @@ -434,6 +448,8 @@ This method is used to convert the `.tex` template files (located in `src/main/r
+ + ## Implementation ### Parsing user input @@ -458,6 +474,8 @@ This gives great flexibility and extensibility to the `Parser` component as you [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Verifying user credentials The `Verifier` class facilitates the verification of the credentials of a user registering or logging in to cOOPer. @@ -503,12 +521,14 @@ This algorithm is recommended by the National Institute of Standards and Technol [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Requesting a resource -`Resources` manages the access rights to other manager components like the `FinanceManager`, `MeetingManager` and `ForumManager`. The following sequence diagram shows the two main operations of `ResourcesManager`: +The `Resources` component manages the access rights to other manager components like the `FinanceManager`, `MeetingManager` and `ForumManager`. The following sequence diagram shows the two main operations of `ResourcesManager`: -+ To get a feature manager, such as the `FinanceManager`, user needs to pass in his `userRole`. `ResourcesManager` will check if the user has the right accessibility and either return the requested object, or a null. -+ Storage class has "super privilege" to access internal data structure of `FinanceManager`, `MeetingManager` and `ForumManager`. Private members are passed safely using the *give-receive* pattern, instead of universal `getters`. ++ To get a feature manager, such as the `FinanceManager`, the user needs to pass in their `UserRole`. `ResourcesManager` will check if the user has the right access to the feature and returns the requested object if so, and `null` otherwise. ++ The `StorageManager` class has "super privilege" to access internal data structure of `FinanceManager`, `MeetingManager` and `ForumManager`. Private members are passed safely using the *give-receive* pattern, instead of universal `getters`.

resourcesSequenceDiagram
@@ -516,8 +536,10 @@ This algorithm is recommended by the National Institute of Standards and Technol [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Interacting with finance functions -`Finance` provides features such as **adding** and **listing** of financial statements, such as the Balance Sheet and Cash Flow Statement as well as **compounded projection** of Free Cash Flow growth. +The `Finance` component provides features such as **adding** and **listing** of financial statements, i.e. the balance sheet and cash flow statement as well as **compounded projection** of Free Cash Flow growth. #### Adding to the financial statement The sequence diagram below illustrates the process of **adding** to a given financial statement, in this case the balance sheet. @@ -531,11 +553,13 @@ When the user wants to add an entry to a financial statement, `FinanceManager` w #### Viewing the financial statement When the user wants to view a financial statement with `list`, `FinanceManager` will run a check that the net amounts of each section of the financial statement are calculated correctly before the statement is displayed to the output. -#### Generating cash flow projections +#### Projecting cash flow When the user wants to project free cash flow, `FinanceManager` will first help to calculate free cash flow by subtracting the CapEx (Capital Expenditure: a field of the cash flow statement) from the total cash from Operating Activities. Subsequently `FinanceManager` will compare this value to the previous year's value, and calculate the percentage increase. This percentage increase will then be used in a recursive [periodic compound interest](https://en.wikipedia.org/wiki/Compound_interest) formula to calculate the following year's free cash flow, at the same percentage increase. [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Generating a PDF from the financial statement The [`PdfGenerator`](https://github.com/AY2122S1-CS2113T-W13-4/tp/blob/master/src/main/java/cooper/finance/pdfgenerator/PdfGenerator.java) abstract class is responsible for the generation of the financial statement as a PDF via the `generate` command. It is inherited by the subclasses, `BalanceSheetGenerator` and `CashFlowStatementGenerator`, with each subclass containing different methods to add different sections to the PDF. @@ -581,6 +605,8 @@ This forms a long `String` which is then sent to the online LaTeX compiler via a [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Declaring an availability The `MeetingManager` class facilitates the storing of availability in cOOPer. @@ -604,13 +630,13 @@ The `MeetingManager` class facilitates the scheduling of meetings. #### Scheduling process When the user schedules a meeting `ScheduleCommand` checks if the `[date]` and `[time]` parameter is entered and calls `manualScheduleMeeting` in `MeetingManager` if it is and `autoScheduleMeeting` if it isn't. -The following sequence diagram shows the process of **auto** scheduling a meeting. `username` of the user scheduling is `Sebastian` and `userInput` is `schedule Project Meeting /with Eugene`. +The following sequence diagram shows the process of **automatically** scheduling a meeting. `username` of the user scheduling is `Sebastian` and `userInput` is `schedule Project Meeting /with Eugene`.

autoScheduleSequenceDiagram

-The following sequence diagram shows the process of **manual** scheduling a meeting. `username` of the user scheduling is `Sebastian` and `userInput` is `schedule Project Meeting /with Eugene /at 11-08-2021 14:00`. +The following sequence diagram shows the process of **manually** scheduling a meeting. `username` of the user scheduling is `Sebastian` and `userInput` is `schedule Project Meeting /with Eugene /at 11-08-2021 14:00`.

manualScheduleSequenceDiagram
@@ -618,9 +644,11 @@ The following sequence diagram shows the process of **manual** scheduling a meet [⬆️ Back to top](#whats-in-this-developer-guide) + + ### Interacting with the forum -The following sequence diagram shows three operations with the forum. `addPost`, `commentPost` and `deletePost`. +The following sequence diagram shows three operations with the forum, `addPost`, `commentPost` and `deletePost`. + For adding a post, `ForumManager` will create a new `ForumPost` object and store its username and content. @@ -637,6 +665,7 @@ The following sequence diagram shows three operations with the forum. `addPost`, [⬆️ Back to top](#whats-in-this-developer-guide) + ### Saving and loading data > ℹ️Due to the way the `Storage` component is implemented, the classes and methods used for storage have names which are quite similar. In order to generalize the explanations in this section for how data is saved and loaded, the term `XYZ` will be used as a placeholder where `XYZ` is `signInDetails`, `balanceSheet`, `cashFlowStatement`, `availability`, `meetings` and `forum`. @@ -655,9 +684,9 @@ The following sequence diagram shows the general procedure of saving data to the

#### Loading data -Data is loaded from cOOPer's storage files to the `Verification` and `Resources` component upon launching the app. The `StorageManager` constructor is first called and each subclass `XYZStorage` is initialized with the file paths of their storage files, `XYZ.txt`. +Data is loaded from cOOPer's storage files into the `Verification` and `Resources` component upon launching the app. The `StorageManager` constructor is first called and each subclass `XYZStorage` is initialized with the file paths of their storage files, `XYZ.txt`. The `loadAllData()` method of `StorageManager` is then called and this method in turn calls the `loadXYZ()` methods of the `XYZStorage` subclasses. If the storage files are not present upon launching cOOPer, the storage files will be created and any error in file creation will be made known to the user. -Since data in the storage files are of a specific format, any change to the storage format will throw an `InvalidFileDataException` and a message will be printed for the user specifying the file containing invalid data. +Since data in the storage files are of a specific format, any change to the storage format will throw an `InvalidFileDataException` and a message will be printed to specify the file containing invalid data. The following sequence diagram shows the general procedure of loading data from the storage file upon launching cOOPer. @@ -678,6 +707,8 @@ The following sequence diagram shows the general procedure of loading data from
+ + ## Appendix: Requirements ### Product scope @@ -728,6 +759,8 @@ Example Users:
+ + ### Glossary * *IDE* - Integrated Development Environment @@ -771,6 +804,8 @@ Example Users: 2. Enter `help`.
**Expected output:** A list of commands specific to your role is shown along with their formats. + + ### Finance actions 1. Creating the balance sheet 1. Ensure that you are logged in as an *admin*. @@ -804,6 +839,8 @@ Example Users: 3. Enter `proj [years]` to project up to your specified number of years.
**Expected output:** All the projected values of free cash flow will be displayed up to the specified year. + + ### Generating the PDF The `generate` command works regardless of whether the prompt label is showing `[Balance Sheet]`, `[Cash Flow]` or is not even present. @@ -820,6 +857,8 @@ The `generate` command works regardless of whether the prompt label is showing ` 4. Enter `generate cf`.
**Expected output**: A message informing you that the PDF has been successfully generated is shown. A PDF named 'CashFlowStatement.pdf' is created in a folder named 'output' in the folder containing the JAR file. + + ### Meetings actions 1. Declaring availability 1. Ensure that you are logged in to cOOPer. @@ -840,6 +879,8 @@ The `generate` command works regardless of whether the prompt label is showing ` 2. Enter `meetings`.
**Expected output:** A table with all your meetings, their date and time, and their attendees is shown. + + ### Forum actions 1. Adding a post 1. Ensure that you are logged in to cOOPer. @@ -861,11 +902,12 @@ The `generate` command works regardless of whether the prompt label is showing ` 3. Enter `post list all`.
**Expected output**: A box containing all posts and comments you have entered so far is shown. + + ### Logging out 1. Logging out 1. Ensure that you are logged in to cOOPer. 2. Enter `logout`. **Expected output**: A message informing you that you have logged out of cOOPer is shown along with the instructions on how to log in, register or exit. The label at the command prompt now shows `[Logged out]`. - [⬆️ Back to top](#whats-in-this-developer-guide) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 4cc8f1fcba..e7cb44b1e1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -34,17 +34,16 @@ This section helps you navigate the guide. - [Getting Started](#getting-started) - [How cOOPer is to be used](#how-cooper-is-to-be-used) - [Roles](#roles) - - [User registration](#user-registration) -- [Login](#login) + - [Registration](#registration) +- [Logging In: `login`](#logging-in-login) - [Features for All Users](#features-for-all-users) - [Adding a forum post: `post add`](#adding-a-forum-post-post-add) - [Viewing a post / posts in the forum: `post list`](#viewing-a-post--posts-in-the-forum-post-list) - [Commenting on a forum post: `post comment`](#commenting-on-a-forum-post-post-comment) - [Deleting a forum post: `post delete`](#deleting-a-forum-post-post-delete) - [Declaring available timings for meetings: `available`](#declaring-available-timing-for-meetings-available) - - [Viewing users available at different timings: `availability`](#viewing-users-available-at-different-timings-availability) + - [Viewing users available at different timings: `availability`](#viewing-which-users-are-available-at-different-timings-availability) - [Viewing scheduled meetings: `meetings`](#viewing-scheduled-meetings-meetings) - - [Logging out: `logout`](#logging-out-logout) - [Admin Features](#admin-features) - [Creating the balance sheet: `bs` → `add`](#creating-the-balance-sheet-bs--add) - [Creating the cash flow statement: `cf` → `add`](#creating-the-cash-flow-statement-cf--add) @@ -55,7 +54,8 @@ This section helps you navigate the guide. - [Scheduling meetings with different users: `schedule`](#scheduling-meetings-with-different-users-schedule) - [Employee Features](#employee-features) - [Viewing Help: `help`](#viewing-help-help) -- [Exiting the Program: `exit`](#exiting-the-program-exit) +- [Logging Out: `logout`](#logging-out-logout) +- [Exiting cOOPer: `exit`](#exiting-cooper-exit) - [cOOPer's Data Storage](#coopers-data-storage) - [Coming Soon](#coming-soon) - [FAQ](#faq) @@ -158,6 +158,7 @@ You are now ready to use cOOPer! Refer to the [Getting Started](#getting-started
## Getting Started + This section explains how you can register an account with cOOPer in order to gain access to cOOPer's features. ### How cOOPer is to be used @@ -173,7 +174,7 @@ This section explains how you can register an account with cOOPer in order to ga - cOOPer offers tailor-made functions and features specific to your role to ensure the correct level of administrative access within the company throughout cOOPer's usage. -### User registration +### Registration - Upon first-time use of cOOPer, ensure that all members of the startup are registered with the correct role. - Once a member has been registered, they will be able to log in to cOOPer to access its features. @@ -181,7 +182,7 @@ This section explains how you can register an account with cOOPer in order to ga - How to register a user: 1. When you see the `[Logged out]` label beside cOOPer's prompt, enter `register [username] /pw [password] /as [role]`. 2. Upon successful registration, you should see a message informing you of your successful registration. - 3. You can now log in to access cOOPer's features specific to your role. Refer to the [Login](#login) section to find out more about logging in. + 3. You can now log in to access cOOPer's features specific to your role. Refer to the [Logging In](#logging-in-login) section to find out more about logging in. > ℹ️`[username]` refers to your name, `[password]` refers to your password, while `[role]` refers to your role as determined [here](#roles). @@ -204,8 +205,11 @@ Sebastian is now successfully registered as an admin! [⬆️ Back to top](#whats-in-this-user-guide) -## Login -- Once you are successfully [registered](#user-registration), you can now log in to access cOOPer's features. +
+ +## Logging in: `login` +- Logs you in to cOOPer to access cOOPer's features. +- You must be [registered](#registration) in order to log in. - How to log in: 1. When you see the `[Logged out]` label beside cOOPer's prompt, enter `login [username] /pw [password] /as [role]`. 2. You should see a message informing you of your successful login. The `[Logged out]` label is no longer present beside the prompt. @@ -235,7 +239,7 @@ You are now logged in successfully as Sebastian! ## Features for All Users -This section explains cOOPer's features for all users, regardless of your role. These features are accessible to you only **after** you have successfully [logged in](#login). +This section explains cOOPer's features for all users, regardless of your role. These features are accessible to you only **after** you have successfully [logged in](#logging-in-login). @@ -464,33 +468,6 @@ Here are your meetings for today: [⬆️ Back to top](#whats-in-this-user-guide) - - -### Logging out: `logout` -- Logs you out of your account. -- You will now see the `[Logged out]` label beside cOOPer's prompt. - -- Example input: - -``` ->> logout -``` - -- Expected output: - -``` -========================================================================= -You are now logged out! -To log in, enter "login [yourUsername] /pw [password] /as [yourRole]". -To register, enter "register [yourUsername] /pw [password] /as [yourRole]". - -To exit, enter "exit". -========================================================================= ->> [Logged out] -``` - -[⬆️ Back to top](#whats-in-this-user-guide) -
## Admin Features @@ -693,7 +670,7 @@ Proceeds from Issuing Debt 300 Dividends Paid 200 Net Cash from Financing Activities: 500 -----FREE CASH FLOW----- -Free Cash Flow 3000 +Last year's Free Cash Flow 3000 ========================================================================= ``` @@ -717,7 +694,8 @@ Free Cash Flow 3000 ``` ========================================================================= -At your current rate of profitability growth in Free Cash Flow, these are future year's projections: +At your current rate of profitability growth in Free Cash Flow, these are +future year's projections: 1 year: 4083 2 year: 4763 3 year: 5557 @@ -745,7 +723,7 @@ After 3 years you can expect Free Cash Flow of 5558 ``` ========================================================================= -The pdf file has been successfully generated! +The PDF file has been successfully generated! ========================================================================= ``` @@ -784,7 +762,7 @@ The pdf file has been successfully generated! > ℹ️You do not have to enter your own `[username]` as cOOPer assumes you are in the meeting that you want to schedule.
> ℹ️There is no limit to the number of `[username]`s you can enter. cOOPer supports scheduling a meeting with a large number of users. However, a large number of users may **slow** cOOPer down.
-> 💡 Before you do a manual schedule, you may want to check the [`availability`](#viewing-users-available-at-different-timings-availability) table for better success rates.
+> 💡 Before you do a manual schedule, you may want to check the [`availability`](#viewing-which-users-are-available-at-different-timings-availability) table for better success rates.
> ⚠️`[date]` has a format of **dd-MM-yyyy**, similar to the format [`available`](#declaring-available-timing-for-meetings-available) uses. Any other format will **not** be accepted and will result in incorrect behaviour.
> ⚠️`[time]` has a format of **HH:mm**, in *24-hour clock*, similar to the format [`available`](#declaring-available-timing-for-meetings-available) uses. Any other format will **not** be accepted and may result in incorrect behaviour. @@ -792,7 +770,7 @@ The pdf file has been successfully generated! - Example input for **automatically** scheduling a meeting: ``` ->> schedule Progress Meeting /with Eugene +>> schedule PR /with Eugene ``` - Expected output: @@ -800,14 +778,15 @@ The pdf file has been successfully generated! ``` ========================================================================= Success! -You have scheduled a <> meeting at 08-11-2021 10:00 with attendees: Eugene, Sebastian +You have scheduled a <> meeting at 08-11-2021 10:00 +with attendees: Eugene, Sebastian ========================================================================= ``` - Example input for **manually** scheduling a meeting: ``` ->> schedule Progress Meeting /with Eugene /at 08-11-2021 14:00 +>> schedule PR /with Eugene /at 08-11-2021 14:00 ``` - Expected output: @@ -815,7 +794,8 @@ You have scheduled a <> meeting at 08-11-2021 10:00 with atten ``` ========================================================================= Success! -You have scheduled a <> meeting at 08-11-2021 14:00 with attendees: Eugene, Sebastian +You have scheduled a <> meeting at 08-11-2021 14:00 +with attendees: Eugene, Sebastian ========================================================================= ``` @@ -830,6 +810,8 @@ As of v2.1, cOOPer does not yet have features exclusive to employees 😥, these
+ + ## Viewing help: `help` - Shows you a list of commands **specific to your role**, along with their formats. Refer to the [Roles](#roles) section if you do not know how roles are determined. @@ -838,8 +820,33 @@ As of v2.1, cOOPer does not yet have features exclusive to employees 😥, these [⬆️ Back to top](#whats-in-this-user-guide) -## Exiting the program: `exit` -- Exits the program. +## Logging out: `logout` +- Logs you out of your account. +- You will now see the `[Logged out]` label beside cOOPer's prompt. + +- Example input: + +``` +>> logout +``` + +- Expected output: + +``` +========================================================================= +You are now logged out! +To log in, enter "login [yourUsername] /pw [password] /as [yourRole]". +To register, enter "register [yourUsername] /pw [password] /as [yourRole]". + +To exit, enter "exit". +========================================================================= +>> [Logged out] +``` + +[⬆️ Back to top](#whats-in-this-user-guide) + +## Exiting cOOPer: `exit` +- Exits cOOPer. - Example input: @@ -859,8 +866,6 @@ Bye, see you next time!
- - ## cOOPer's Data Storage This section explains how cOOPer stores the data you keyed in throughout cOOPer's usage. cOOPer's data is stored on your hard disk in a folder named 'cooperData'. This folder is created in the *home folder* upon starting cOOPer up for the first time. @@ -873,6 +878,7 @@ The contents of the folder are as shown in the diagram below. >⚠️The contents of these storage files are in a specific format comprehensible by cOOPer. **Do not** edit the content or read/write access of these files. +
### availability.txt - What it stores: The different timings and the users associated with each timing. @@ -896,7 +902,7 @@ The contents of the folder are as shown in the diagram below. ### signInDetails.txt - What it stores: The username, an encrypted hash of the user's password, the salt used to generate the password hash, and the user's role. -- When is the data stored: Immediately after you [register](#user-registration) successfully as a user of cOOPer. +- When is the data stored: Immediately after you [register](#registration) successfully as a user of cOOPer. [⬆️ Back to top](#whats-in-this-user-guide) @@ -912,10 +918,15 @@ In future versions, you will be able to: - Create more than one balance sheet / cash flow statement - View each balance sheet / cash flow statement individually - Calculate your loan repayment -- Generate the PDF for a specific balance sheet / cash flow statement. +- Generate the PDF for a specific balance sheet / cash flow statement - Specify the name of the PDF document you want to generate. - Delete your comment on a forum post - Edit your forum post +- Asynchronously give feedback to management as an employee, with weekly reviews + +[⬆️ Back to top](#whats-in-this-user-guide) + +
## FAQ This section contains some frequently asked questions you may have when using cOOPer. @@ -927,7 +938,7 @@ This section contains some frequently asked questions you may have when using cO > No, you do not. As long as the commands you enter follow the format specified by cOOPer, you will be able to use cOOPer's features with ease! You can refer to the [Command Summary](#command-summary) section to familiarise yourself with the format of each command. **Q**: How do I know which commands to enter when using cOOPer?
-> After you have successfully [logged in](#login) to cOOPer, you can either enter `help` or refer to the [Command Summary](#command-summary) section to know the commands recognised by cOOPer. +> After you have successfully [logged in](#logging-in-login) to cOOPer, you can either enter `help` or refer to the [Command Summary](#command-summary) section to know the commands recognised by cOOPer. **Q**: How do I transfer cOOPer's data from the current desktop to another desktop?
> Follow the steps below:
diff --git a/docs/developerGuideDiagrams/autoScheduleSequenceDiagram.png b/docs/developerGuideDiagrams/autoScheduleSequenceDiagram.png index cd4176d4fc..57943bcde5 100644 Binary files a/docs/developerGuideDiagrams/autoScheduleSequenceDiagram.png and b/docs/developerGuideDiagrams/autoScheduleSequenceDiagram.png differ diff --git a/docs/developerGuideDiagrams/availableSequenceDiagram.png b/docs/developerGuideDiagrams/availableSequenceDiagram.png index 451a0d607d..c6f6828026 100644 Binary files a/docs/developerGuideDiagrams/availableSequenceDiagram.png and b/docs/developerGuideDiagrams/availableSequenceDiagram.png differ diff --git a/docs/developerGuideDiagrams/financeSequenceDiagram.png b/docs/developerGuideDiagrams/financeSequenceDiagram.png index 58381f705d..42ee2a5dbe 100644 Binary files a/docs/developerGuideDiagrams/financeSequenceDiagram.png and b/docs/developerGuideDiagrams/financeSequenceDiagram.png differ diff --git a/docs/developerGuideDiagrams/forumSequenceDiagram.png b/docs/developerGuideDiagrams/forumSequenceDiagram.png index 753de96d45..b21a968b62 100644 Binary files a/docs/developerGuideDiagrams/forumSequenceDiagram.png and b/docs/developerGuideDiagrams/forumSequenceDiagram.png differ diff --git a/docs/developerGuideDiagrams/manualScheduleSequenceDiagram.png b/docs/developerGuideDiagrams/manualScheduleSequenceDiagram.png index fdcedc1faf..9aa7a2d850 100644 Binary files a/docs/developerGuideDiagrams/manualScheduleSequenceDiagram.png and b/docs/developerGuideDiagrams/manualScheduleSequenceDiagram.png differ diff --git a/docs/developerGuideDiagrams/meetingsComponent.png b/docs/developerGuideDiagrams/meetingsComponent.png index 4fa9a19460..bd9db9393c 100644 Binary files a/docs/developerGuideDiagrams/meetingsComponent.png and b/docs/developerGuideDiagrams/meetingsComponent.png differ diff --git a/docs/developerGuideDiagrams/resourcesSequenceDiagram.png b/docs/developerGuideDiagrams/resourcesSequenceDiagram.png index 100c7d6d81..9c1269651b 100644 Binary files a/docs/developerGuideDiagrams/resourcesSequenceDiagram.png and b/docs/developerGuideDiagrams/resourcesSequenceDiagram.png differ diff --git a/docs/team/fansxx.md b/docs/team/fansxx.md index e3a2fe0817..e78cc6c8b1 100644 --- a/docs/team/fansxx.md +++ b/docs/team/fansxx.md @@ -11,4 +11,123 @@ cOOPer was developed in Java following an **Object-Oriented Programming (OOP)** All the code I contributed for this project can be found at this [RepoSense Link](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabType=authorship&tabAuthor=fansxx&tabRepo=AY2122S1-CS2113T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false). #### Enhancements Implemented -- **Feature 1:** Implemented the \ No newline at end of file +I was in charge of the availability and meetings component of cOOPer, which I coded from scratch (from the parsing logic to the actual features). + +- **Feature 1:** Implemented the `available` and `availability` features + - This feature allows users to key in their available date and time, as well as view everyone's availability. + - The `available` feature comes with error-checking, to make sure the time and date entered are of the correct format. + - Viewing of `availability` generates a neatly formatted table, enhancing the user experience of cOOPer. + - Date and time are filtered chronologically when the table of availability is generated. + +
+ +- **Feature 2:** Implemented the `schedule` and `meetings` features + - The `schedule` feature allows admins to schedule meetings with an in-built algorithm, or with a timing manually inputted by the user. + - The `schedule` feature also comes with error-checking, to make sure the time and date entered are of the correct format. + - I made the algorithm that finds a common time for the meeting fast and efficient, such that it saves users' time. + - The `meetings` feature generates a table of meetings customized for the user. + +- **Feature 3:** Implemented the storage function for availability and meetings storage + - I built on the 'template' @theeugenechong came up with. + - This feature stores `availability` and `meetings` in their own custom format, and reads the storage files when cOOPer starts. + - This storage feature also does error checking of the `availability.txt` and `meetings.txt` files to make sure the content and times are correctly formatted, before loading into cOOPer. + +### Contributions to the User Guide +- **Contribution 1:** Documented the `available` and `availability` commands + - Provided detailed explanation to how to use these commands + - Provided example input and output to these commands + +- **Contribution 2:** Documented the `schedule` and `meetings` commands + - Provided detailed explanation to how to use these commands + - Provided example input and output to these commands + +- **Contribution 3:** Added some commands and their examples to the 'Command Summary' section + +### Contributions to the Developer Guide +- **Contribution 1:** Documented the `Meetings` component under the 'Design' section + - Came up with the class diagrams and explanations about the design of the component. + +- **Contribution 2:** Documented the 'Declaring an availability' and 'Scheduling a meeting' features under the 'Implementation' section + - Came up with explanations and sequence diagrams for the implementation of these features. + +- **Contribution 3:** Documented the `available`, `availability`, `schedule`, and `meetings` commands in the 'Instructions for Manual Testing' section + - Came up with step by step testing and test examples for the commands. + +
+ +### Contribution to Team-based Tasks +- Created tags in the issue tracker +- Helped with the maintenance of the issue tracker (added issues with their respective tags and milestones) +- Resolved merge conflicts when merging multiple pull requests. +- Contributed in team meetings to plan out the tasks to do. + +### Review/mentoring contributions +- Pull requests I reviewed: + 1. Pull request [#48](https://github.com/AY2122S1-CS2113T-W13-4/tp/pull/48) + 2. Pull request [#200](https://github.com/AY2122S1-CS2113T-W13-4/tp/pull/200) +- Reviewed the content and formatting of both the User Guide and Developer Guide. + +### Contributions beyond the project team +- [Reported bugs for the Practical Exam Dry Run](https://github.com/fansxx/ped/issues). + +
+ +## [Optional] Contribution to the User Guide + +Here is an extract of one of my contributions to the User Guide: + +> ### Declaring available timing for meetings: `available` +> - Enters your available timing for easier scheduling of meetings. +> - How to declare your available timing: +> 1. Enter `available [date] [time]`. +> 2. You will now have your name stored under the specified time in the system. +> +>> ℹ️`[time]` refers to the **start of the hour** that you are available at. For example, `available 14:00` means that you are available from **14:00** to **14:59**.
+>> ⚠️`[date]` has a format of **dd-MM-yyyy**. Any other format will **not** be accepted and your availability will not be stored.
+>> ⚠️`[time]` has a format of **HH:mm**, in *24-hour clock*. Any other format will **not** be accepted and your availability will not be stored.
+>> ⚠️Duplicate `[username]` in one timeslot will **not** be accepted. +> +> - Example input: +> +>``` +>>> available 08-11-2021 14:00 +>``` +> +> - Expected output: +> +>``` +>========================================================================= +>Success! +>Sebastian's availability has been added to 08-11-2021 14:00 +>========================================================================= +>``` +> +>[⬆️ Back to top](#whats-in-this-user-guide) + +
+ +## [Optional] Contribution to the Developer Guide + +Here is an extract of one of my contributions to the Developer Guide: + +> #### Meetings +> +>**API**: [`cooper.meetings`](https://github.com/AY2122S1-CS2113T-W13-4/tp/tree/master/src/main/java/cooper/meetings) +> +>

+> meetingsComponent
+>

+> +>The `Meetings` component contains the `MeetingManager` and `Meeting` classes. +> +>`MeetingManager` stores **2** attributes: +>1. the **timings** along with the **usernames** of the available users, which is a `TreeMap>` object, +>2. the **list of meetings** scheduled, which is an `ArrayList` object. +> +>The `MeetingManager` constructs the instances of `Meeting`, and stores it as an `ArrayList` in itself. +> +>The `Meetings` component: +> +>+ Handles the **declaration of availability** +>+ Assists in the **scheduling** of meetings +>+ Lists the current availability and meetings \ No newline at end of file diff --git a/docs/team/rrraaaeee.md b/docs/team/rrraaaeee.md index 6b614a5d3d..e60bc97c5c 100644 --- a/docs/team/rrraaaeee.md +++ b/docs/team/rrraaaeee.md @@ -2,5 +2,43 @@ ## Overview +cOOPer is a **desktop application** developed to simplify administrative processes of **tech startups** such as **communication** and **finance management**. + +If you are running a tech startup, cOOPer can help you with **accounting** and **communicative** tasks like: + +- **Generating** your company's **financial statements** +- **Forecasting** your company's **cash flow** +- **Scheduling meetings** with your employees +- Having **discussions on forum** with your colleagues + +## Summary of Contributions + +#### Code contributed + +[RepoSense link](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=w13-4&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabAuthor=Rrraaaeee&tabRepo=AY2122S1-CS2113T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&tabType=authorship) + +### Enhancements implemented + ++ Implemented the base software structure, i.e the `parser` and the `command`class ++ Integrated third-party `Dopsun chatbot-cli` library into cOOPer's parser. ++ Implemented the `forum` package ++ Implemented the base version of `invoice generator`, including the `tex` file generation and `pdf` file generation by interfacing with web API using `POST multipart/form-data`. ++ Implemented `CooperState` and integrated to commandline to prompt user of the current mode cOOPer is in. + +### Contributions to the UG + ++ Added explanations for `post add`, `post list`, `post comment`, `post delete` sections + +### Contributions to the DG + ++ Added `Resources component`, `Forum component` sections under design and their class diagrams ++ Addded `Parsing user input`, `Interacting with forum` and `Requesting a resource` sections under implementation and their sequence diagrams ++ Added `Forum actions` section under manual testing + +### Contributiosns to team-based tasks + ++ Set up `gradle` ++ Updated README on main page + + -### Summary of Contributions \ No newline at end of file diff --git a/docs/team/theeugenechong.md b/docs/team/theeugenechong.md index 8af8fcd6df..7dd21bf936 100644 --- a/docs/team/theeugenechong.md +++ b/docs/team/theeugenechong.md @@ -111,7 +111,8 @@ All the code I contributed for this project can be found at this [RepoSense link Here is an extract of one of my contributions to the User Guide: > ## Getting Started -> +> This section explains how you can register an account with cOOPer in order to gain access to cOOPer's features. +> > ### How cOOPer is to be used > - The **correct** way (as of v2.1) of using cOOPer is to run cOOPer on a **single** desktop with only **a single user** interacting with cOOPer at a time. > > ⚠️cOOPer's features **will not work** as described in this user guide if **multiple users** are interacting with cOOPer on **multiple desktops** at the same time. @@ -126,7 +127,7 @@ Here is an extract of one of my contributions to the User Guide: > - cOOPer offers tailor-made functions and features specific to your role to ensure the correct level of administrative access within the company throughout cOOPer's usage. > > ### User registration -> - Upon first-time use of cOOPer, an individual holding the admin role in the startup is in charge of ensuring all members of the startup are registered with the correct role. +> - Upon first-time use of cOOPer, ensure that all members of the startup are registered with the correct role. > > - Once a member has been registered, they will be able to log in to cOOPer to access its features. > diff --git a/src/main/java/cooper/command/AvailabilityCommand.java b/src/main/java/cooper/command/AvailabilityCommand.java index 2d3647ebc8..f74644df21 100644 --- a/src/main/java/cooper/command/AvailabilityCommand.java +++ b/src/main/java/cooper/command/AvailabilityCommand.java @@ -13,9 +13,8 @@ public class AvailabilityCommand extends Command { /** - * The override function for executing the 'add' command, calls for 'add' and subsequently - * printing the status to the command line if and only if - * the command is being accessed by an 'admin' level user. + * The override function for executing the 'availability' command, which all users have access to. + * * @param signInDetails Sign in details of user to provide correct access * @param resourcesManager Provides access to manipulate data in the cOOPer's {@code FinanceManager}, * {@code MeetingsManager} and {@code ForumManager} diff --git a/src/main/java/cooper/command/AvailableCommand.java b/src/main/java/cooper/command/AvailableCommand.java index 98626ffbda..89f77e66a4 100644 --- a/src/main/java/cooper/command/AvailableCommand.java +++ b/src/main/java/cooper/command/AvailableCommand.java @@ -22,9 +22,8 @@ public AvailableCommand(String time) { } /** - * The override function for executing the 'add' command, calls for 'add' and subsequently - * printing the status to the command line if and only if - * the command is being accessed by an 'admin' level user. + * The override function for executing the 'available' command, which all users have access to. + * * @param signInDetails Sign in details of user to provide correct access * @param resourcesManager Provides access to manipulate data in the cOOPer's {@code FinanceManager}, * {@code MeetingsManager} and {@code ForumManager} diff --git a/src/main/java/cooper/command/MeetingsCommand.java b/src/main/java/cooper/command/MeetingsCommand.java index 51adeefc28..4f9d433de1 100644 --- a/src/main/java/cooper/command/MeetingsCommand.java +++ b/src/main/java/cooper/command/MeetingsCommand.java @@ -13,9 +13,8 @@ public class MeetingsCommand extends Command { /** - * The override function for executing the 'add' command, calls for 'add' and subsequently - * printing the status to the command line if and only if - * the command is being accessed by an 'admin' level user. + * The override function for executing the 'meetings' command, which all users have access to. + * * @param signInDetails Sign in details of user to provide correct access * @param resourcesManager Provides access to manipulate data in the cOOPer's {@code FinanceManager}, * {@code MeetingsManager} and {@code ForumManager} diff --git a/src/main/java/cooper/command/ScheduleCommand.java b/src/main/java/cooper/command/ScheduleCommand.java index 8779e35459..0bf8c8381e 100644 --- a/src/main/java/cooper/command/ScheduleCommand.java +++ b/src/main/java/cooper/command/ScheduleCommand.java @@ -29,7 +29,7 @@ public ScheduleCommand(String meetingName, ArrayList usernames, String d } /** - * The override function for executing the 'add' command, calls for 'add' and subsequently + * The override function for executing the 'schedule' command, calls for 'schedule' and subsequently * printing the status to the command line if and only if * the command is being accessed by an 'admin' level user. * @param signInDetails Sign in details of user to provide correct access diff --git a/src/main/java/cooper/forum/ForumComment.java b/src/main/java/cooper/forum/ForumComment.java index f26d6dce83..1094cc3bc0 100644 --- a/src/main/java/cooper/forum/ForumComment.java +++ b/src/main/java/cooper/forum/ForumComment.java @@ -4,6 +4,11 @@ public class ForumComment extends ForumPostBase { + /** + * Constructor of ForumComment object. + * @param username username of the user who input the comment + * @param content content of the comment + */ public ForumComment(String username, String content) { super(username, content); } diff --git a/src/main/java/cooper/forum/ForumManager.java b/src/main/java/cooper/forum/ForumManager.java index 49991ab174..133e002aea 100644 --- a/src/main/java/cooper/forum/ForumManager.java +++ b/src/main/java/cooper/forum/ForumManager.java @@ -10,21 +10,45 @@ public class ForumManager { private final ArrayList forumPosts; + private static final Integer ID_UPPER_LIMIT = 300_000_000; public ForumManager() { forumPosts = new ArrayList<>(); } + /** + * This method creates and adds a post to the forumPost arraylist data structure. + * @param username username of the user who added the post + * @param content post content + */ public void addPost(String username, String content) { forumPosts.add(new ForumPost(username, content)); } + /** + * This method adds a comment to the specified post id. If the post id is invalid, + * Throw an invalidForumPostIdException. + * @param username username of the user who added the comment + * @param content comment content + * @param postId post id of where comment goes to + * @throws InvalidForumPostIdException post id is invalid or outside range + * @throws NumberFormatException post id is not a number + */ public void addComment(String username, String content, int postId) throws InvalidForumPostIdException, NumberFormatException { checkValidPostId(postId); forumPosts.get(postId).addComment(username, content); } + /** + * This method deletes a post to the specified post id. If the post id is invalid, + * Throw an invalidForumPostIdException. + * @param username username of the user who added the comment + * @return content of the post deleted + * @throws InvalidForumPostIdException post id is invalid or outside range + * @throws InvalidForumDeleteByNonOwnerException deletion is not done by the owner + * @throws NumberFormatException post id is not a number + */ public String deletePost(String username, int postId) throws InvalidForumPostIdException, InvalidForumDeleteByNonOwnerException, NumberFormatException { checkValidPostId(postId); @@ -38,7 +62,16 @@ public String deletePost(String username, int postId) throw new InvalidForumDeleteByNonOwnerException(); } } - + + /** + * This method adds a comment object to the arraylist stored under post object. + * @param username username of the user who added the comment + * @param content comment content + * @param postId post id of where comment goes to + * @return content of the comment for printing onto UI + * @throws InvalidForumPostIdException post id is invalid or outside range + * @throws NumberFormatException post id is not a number + */ public String commentPost(String username, String content, int postId) throws InvalidForumPostIdException, NumberFormatException { checkValidPostId(postId); @@ -55,9 +88,16 @@ public void listPost(int postId) throws InvalidForumPostIdException, NumberForma ForumUi.printForumPost(forumPosts, postId); } + /** + * This method does sanity check to make sure post Id keyed in is a valid id. + * Throws exceptions otherwise + * @param postId post id of where comment goes to + * @throws InvalidForumPostIdException post id is invalid or outside range + * @throws NumberFormatException post id is not a number + */ private void checkValidPostId(int postId) throws InvalidForumPostIdException, NumberFormatException { if (postId >= forumPosts.size() || postId < 0) { - if (postId > 300_000_000) { + if (postId > ID_UPPER_LIMIT) { throw new NumberFormatException(); } throw new InvalidForumPostIdException(); diff --git a/src/main/java/cooper/meetings/MeetingManager.java b/src/main/java/cooper/meetings/MeetingManager.java index b69f971a8b..28953f50b3 100644 --- a/src/main/java/cooper/meetings/MeetingManager.java +++ b/src/main/java/cooper/meetings/MeetingManager.java @@ -146,6 +146,13 @@ private boolean isMeetingTimeFull(String username, LocalDateTime timing) { return false; } + /** + * Checks if any of the users already has a meeting scheduled at a particular time. + * + * @param usernames the usernames to be checked + * @param timing the time that the user wants to schedule a meeting at + * @return true if all the users already have another meeting at the timing, false otherwise + */ private boolean isMeetingTimeFullForAll(ArrayList usernames, LocalDateTime timing) { for (Meeting meeting : meetingsList) { if (meeting.getDateTime().equals(timing) && isOneUserNotAvailable(usernames, meeting)) { @@ -155,6 +162,13 @@ private boolean isMeetingTimeFullForAll(ArrayList usernames, LocalDateTi return false; } + /** + * Checks if the particular meeting has at least one user in the usernames list. + * + * @param usernames the usernames to be checked if they have a meeting at a particular time + * @param meeting the meeting to be checked to see if any of the specified users are in + * @return true if there is at least one user in the usernames list in the meeting, false otherwise + */ private boolean isOneUserNotAvailable(ArrayList usernames, Meeting meeting) { for (String username : usernames) { if (meeting.getListOfAttendees().contains(username)) { @@ -191,6 +205,7 @@ public void autoScheduleMeeting(String meetingName, ArrayList usernames) * @param dateTime the date and time the user is trying to schedule a meeting at * @throws InvalidDateTimeFormatException if the format of the date and time is not the specified format * @throws InvalidTimeException if the time is not the start of the hour + * @throws TimeNotInAvailabilityException if the time does not have any available users * @throws CannotScheduleMeetingException if no meeting can be scheduled because one or more of the users entered * is unavailable * @throws DuplicateMeetingException if one or more user already has a meeting at the date and time @@ -213,6 +228,7 @@ public void manualScheduleMeeting(String meetingName, ArrayList username for (LocalDateTime ldt: availability.keySet()) { if (localDateTime.equals(ldt)) { dateTimeExist = true; + break; } } if (!dateTimeExist) { diff --git a/src/main/java/cooper/parser/CommandParser.java b/src/main/java/cooper/parser/CommandParser.java index e1e27e1331..25d9997b79 100644 --- a/src/main/java/cooper/parser/CommandParser.java +++ b/src/main/java/cooper/parser/CommandParser.java @@ -49,12 +49,27 @@ public class CommandParser extends ParserBase { private static final String BS = "bs"; private static final String CF = "cf"; private static final String DOCUMENT_HINT = "document-hint"; + private static final String PARSER_SCHEMA = "command-data.properties"; + private static final String LIST = "list"; + private static final String HELP = "help"; + private static final String AVAILABILITY = "availability"; + private static final String MEETINGS = "meetings"; + private static final String EXIT = "exit"; + private static final String LOGOUT = "logout"; + private static final String ADD = "add"; + private static final String AVAILABLE = "available"; + private static final String SCHEDULE = "schedule"; + private static final String POST = "post"; + private static final String GENERATE = "generate"; + private static final String PROJ = "proj"; + private static final String POSTADD = "postAdd"; + private static final String POSTDELETE = "postDelete"; + private static final String POSTCOMMENT = "postComment"; + private static final String POSTLIST = "postList"; + - /** - * Constructor. Initialise internal parser. - */ private CommandParser() { - super("command-data.properties"); + super(PARSER_SCHEMA); } public static boolean isLogout() { @@ -67,9 +82,9 @@ public static void setCooperState(CooperState state) { } /** - * API to parse a command in string. - * @param input command to be parsed - * @return a command object, to be passed into command handler + * API to parse a string input into a command object. + * @param input user input + * @return the command object */ public static Command parse(String input) throws UnrecognisedCommandException, NoSuchElementException, InvalidCommandFormatException, InvalidScheduleFormatException, NoTimeEnteredException, @@ -82,6 +97,11 @@ public static Command parse(String input) throws UnrecognisedCommandException, N return command; } + /** + * Impl for parse() method. + * @param input command to be parsed + * @return the command object + */ @Override public Command parseInput(String input) throws UnrecognisedCommandException, NoSuchElementException, InvalidCommandFormatException, InvalidScheduleFormatException, NoTimeEnteredException, @@ -90,43 +110,48 @@ public Command parseInput(String input) throws UnrecognisedCommandException, NoS String commandWord = input.split(WHITESPACE_SEQUENCE)[0].toLowerCase(); switch (commandWord) { - case "list": - case "help": - case "availability": - case "meetings": - case "exit": + case LIST: + case HELP: + case AVAILABILITY: + case MEETINGS: + case EXIT: case BS: case CF: - case "logout": + case LOGOUT: return parseSimpleInput(commandWord); - case "add": - case "available": - case "schedule": - case "post": - case "generate": - case "proj": + case ADD: + case AVAILABLE: + case SCHEDULE: + case POST: + case GENERATE: + case PROJ: return parseComplexInput(input); default: throw new UnrecognisedCommandException(); } } + /** + * Method to parse single-word input. + * @param commandWord single-word input string + * @return a command object + */ private Command parseSimpleInput(String commandWord) throws UnrecognisedCommandException { assert commandWord != null; switch (commandWord) { - case "list": + case LIST: return new ListCommand(FinanceCommand.getCommandFromState(cooperState)); - case "help": + case HELP: return new HelpCommand(); - case "availability": + case AVAILABILITY: cooperState = CooperState.LOGIN; return new AvailabilityCommand(); - case "meetings": + case MEETINGS: cooperState = CooperState.LOGIN; return new MeetingsCommand(); - case "logout": + case LOGOUT: return new LogoutCommand(); - case "exit": + case EXIT: return new ExitCommand(); case CF: return new CfCommand(); @@ -137,6 +162,11 @@ private Command parseSimpleInput(String commandWord) throws UnrecognisedCommandE } } + /** + * Method to parse a multi-word input. Using the Dopsun cli library + * @param input multi-word input + * @return a command object + */ private Command parseComplexInput(String input) throws UnrecognisedCommandException, NoSuchElementException, InvalidCommandFormatException, InvalidScheduleFormatException, NoTimeEnteredException, NoUsernameAfterCommaException, InvalidDocumentException, InvalidAddFormatException { @@ -146,29 +176,29 @@ private Command parseComplexInput(String input) throws UnrecognisedCommandExcept String command = result.allCommands().get(0).name(); List commandArgs = result.allCommands().get(0).arguments(); switch (command) { - case "add": + case ADD: return parseAddArgs(commandArgs); - case "available": + case AVAILABLE: cooperState = CooperState.LOGIN; return parseAvailableArgs(commandArgs); - case "schedule": + case SCHEDULE: cooperState = CooperState.LOGIN; return parseScheduleArgs(commandArgs); - case "postAdd": + case POSTADD: cooperState = CooperState.LOGIN; return parsePostAddArgs(commandArgs); - case "postDelete": + case POSTDELETE: cooperState = CooperState.LOGIN; return parsePostDeleteArgs(commandArgs); - case "postComment": + case POSTCOMMENT: cooperState = CooperState.LOGIN; return parsePostCommentArgs(commandArgs); - case "postList": + case POSTLIST: cooperState = CooperState.LOGIN; return parsePostListArgs(commandArgs); - case "generate": + case GENERATE: return parseGenerateArgs(commandArgs); - case "proj": + case PROJ: return parseProjectionArgs(commandArgs); default: throw new UnrecognisedCommandException(); @@ -250,6 +280,14 @@ private Command parseScheduleArgs(List commandArgs) throws InvalidComm return new ScheduleCommand(meetingName, usernames, time); } + /** + * Gets the usernames in the schedule command. + * + * @param args the arguments after the /with + * @return an ArrayList of usernames detected in the command argument + * @throws InvalidScheduleFormatException if there are no arguments after /with and before /at + * @throws NoUsernameAfterCommaException if there are no usernames after the last comma + */ private ArrayList parseUsernamesInSchedule(String args) throws InvalidScheduleFormatException, NoUsernameAfterCommaException { if (args.length() < 1) { @@ -279,6 +317,13 @@ private ArrayList parseUsernamesInSchedule(String args) throws InvalidSc return usernamesArrayList; } + /** + * Gets the last username in the schedule command. + * + * @param usernamesArrayList the list of usernames to add this last username to + * @param trimmedUsername the last argument of the schedule command (after the last comma) + * @throws NoUsernameAfterCommaException if there are no usernames after the last comma + */ private void getLastUsername(ArrayList usernamesArrayList, String trimmedUsername) throws NoUsernameAfterCommaException { if (trimmedUsername.contains("/at")) { @@ -293,6 +338,13 @@ private void getLastUsername(ArrayList usernamesArrayList, String trimme } } + /** + * Gets the time parameter in the schedule command. + * + * @param args thea argument after the /with + * @return a String that corresponds to the time. A null string is returned if there is no time + * @throws NoTimeEnteredException if there is no time entered after /at + */ private String parseTimeInSchedule(String args) throws NoTimeEnteredException { if (args.contains("/at")) { String[] argsArray = args.split("/at"); diff --git a/src/main/java/cooper/parser/ParserBase.java b/src/main/java/cooper/parser/ParserBase.java index 3089f84aa5..847afb563f 100644 --- a/src/main/java/cooper/parser/ParserBase.java +++ b/src/main/java/cooper/parser/ParserBase.java @@ -33,7 +33,8 @@ public abstract class ParserBase { protected static final String WHITESPACE_SEQUENCE = "\\s+"; /** - * Constructor. Initialise internal parser. + * Constructor to initialise the dopsun parser. + * @param schema the schema for dopsum parser to recognise patterns */ public ParserBase(String schema) { try { diff --git a/src/main/java/cooper/resources/ResourcesManager.java b/src/main/java/cooper/resources/ResourcesManager.java index 244bf25eba..7dfc3df2ef 100644 --- a/src/main/java/cooper/resources/ResourcesManager.java +++ b/src/main/java/cooper/resources/ResourcesManager.java @@ -20,7 +20,11 @@ public ResourcesManager() { cooperForumManager = new ForumManager(); } - + /** + * get a finance manager if the user role has access right. + * @param userRole user's role for checking access rights + * @return financeManager or null + */ public FinanceManager getFinanceManager(UserRole userRole) { if (checkFinanceAccessibility(userRole)) { return cooperFinanceManager; @@ -29,6 +33,11 @@ public FinanceManager getFinanceManager(UserRole userRole) { } } + /** + * get a meeting manager if the user role has access right. + * @param userRole user's role for checking access rights + * @return meetingManager or null + */ public MeetingManager getMeetingManager(UserRole userRole) { if (checkMeetingAccessibility(userRole)) { return cooperMeetingManager; @@ -41,6 +50,11 @@ public MeetingManager getMeetingManager() { return cooperMeetingManager; } + /** + * get a forum manager if the user role has access right. + * @param userRole user's role for checking access rights + * @return forumManager or null + */ public ForumManager getForumManager(UserRole userRole) { if (checkForumAccessibility(userRole)) { return cooperForumManager; @@ -61,12 +75,15 @@ private boolean checkForumAccessibility(UserRole userRole) { return (userRole.equals(UserRole.ADMIN) || userRole.equals(UserRole.EMPLOYEE)); } + /** * Storage class has "super privilege" to access private member in resources class. * Use this give-receive pattern to get private members from ResourcesManager (Similar to friend class) * Pattern adapted from: * https://stackoverflow.com/questions/14226228/implementation-of-friend-concept-in-javat - **/ + * @param storageManager storage manager object to pass private members to + * @return the private member object queried + */ public FinanceManager giveFinanceManager(StorageManager storageManager) { return storageManager.receiveFinanceManager(cooperFinanceManager); } diff --git a/src/main/java/cooper/ui/FinanceUi.java b/src/main/java/cooper/ui/FinanceUi.java index 38b799a074..960180a665 100644 --- a/src/main/java/cooper/ui/FinanceUi.java +++ b/src/main/java/cooper/ui/FinanceUi.java @@ -42,7 +42,7 @@ public class FinanceUi extends Ui { private static final String INPUT_VALID_PROJECTION = "Please key in a valid number of years (1 or more)"; private static final String AT_CURRENT_PROFITABILITY = "At your current rate of profitability growth "; - private static final String IN_FREE_CASH_FLOW = "in Free Cash Flow, these are\n future year's projections:"; + private static final String IN_FREE_CASH_FLOW = "in Free Cash Flow, these are\nfuture year's projections:"; private static final String YEARS_CAN_EXPECT = " years you can expect Free Cash Flow of "; private static final String MORE_THAN_ONE_BILLION = "1 Billion SGD or more "; diff --git a/src/main/java/cooper/ui/ForumUi.java b/src/main/java/cooper/ui/ForumUi.java index b36c5e46a3..eed17505f3 100644 --- a/src/main/java/cooper/ui/ForumUi.java +++ b/src/main/java/cooper/ui/ForumUi.java @@ -7,10 +7,17 @@ //@@author Rrraaaeee public class ForumUi extends Ui { + private static final String PROMPT_LIST = "Here is the list of forum posts:"; + private static final String PROMPT_POST = "Here is the forum post:"; + private static final String INVALID_DELETE = "You cannot delete a forum post that is not owned by you!."; + private static final String INVALID_INDEX = "The forum index you just keyed in is outside the valid range."; + private static final String RESPONSE_COMMENT = " has just commented on a post from the forum:"; + private static final String RESPONSE_DELETE = " has just deleted a post from the forum:"; + private static final String RESPONSE_POST = " has just posted to the forum:"; public static void printForumPosts(ArrayList forumPosts) { show(LINE); - show("Here is the list of forum posts:"); + show(PROMPT_LIST); show(TABLE_LINE); int cntPost = 1; for (var post : forumPosts) { @@ -29,7 +36,7 @@ public static void printForumPosts(ArrayList forumPosts) { public static void printForumPost(ArrayList forumPosts, int postId) { show(LINE); - show("Here is the forum post:"); + show(PROMPT_POST); show(TABLE_LINE); show("| " + forumPosts.get(postId).toString()); @@ -45,7 +52,7 @@ public static void printForumPost(ArrayList forumPosts, int postId) { public static void printNewPostCommand(String username, String content) { show(LINE); - show(username + " has just posted to the forum:"); + show(username + RESPONSE_POST); show(TABLE_LINE); show("| " + content); show(TABLE_LINE); @@ -54,7 +61,7 @@ public static void printNewPostCommand(String username, String content) { public static void printDeletePostCommand(String username, String content) { show(LINE); - show(username + " has just deleted a post from the forum:"); + show(username + RESPONSE_DELETE); show(TABLE_LINE); show("| " + content); show(TABLE_LINE); @@ -63,7 +70,7 @@ public static void printDeletePostCommand(String username, String content) { public static void printCommentPostCommand(String username, String content, String comment) { show(LINE); - show(username + " has just commented on a post from the forum:"); + show(username + RESPONSE_COMMENT); show(TABLE_LINE); show("| " + content); show("| - " + comment); @@ -73,13 +80,13 @@ public static void printCommentPostCommand(String username, String content, Stri public static void printInvalidForumPostIndexError() { show(LINE); - show("The forum index you just keyed in is outside the valid range."); + show(INVALID_INDEX); show(LINE); } public static void printInvalidForumDeleteByNonOwnerError() { show(LINE); - show("You cannot delete a forum post that is not owned by you!."); + show(INVALID_DELETE); show(LINE); } } diff --git a/src/main/java/cooper/ui/MeetingsUi.java b/src/main/java/cooper/ui/MeetingsUi.java index 6bbbffe287..a9a20d1264 100644 --- a/src/main/java/cooper/ui/MeetingsUi.java +++ b/src/main/java/cooper/ui/MeetingsUi.java @@ -120,8 +120,8 @@ public static void printSuccessfulScheduleCommand(String meetingName, LocalDateT show(SUCCESS_MESSAGE); show("You have scheduled a <<" + meetingName + ">> meeting at " + dateTime.toLocalDate().format(DateTimeFormatter.ofPattern(DATE_FORMAT)) + " " - + dateTime.toLocalTime().format(DateTimeFormatter.ofPattern(TIME_FORMAT)) - + " with attendees: " + listOfAvailabilities(usernames)); + + dateTime.toLocalTime().format(DateTimeFormatter.ofPattern(TIME_FORMAT))); + show("with attendees: " + listOfAvailabilities(usernames)); show(LINE); } diff --git a/src/test/java/cooper/meetings/MeetingManagerTest.java b/src/test/java/cooper/meetings/MeetingManagerTest.java index 017e9b9a2d..bc44e06790 100644 --- a/src/test/java/cooper/meetings/MeetingManagerTest.java +++ b/src/test/java/cooper/meetings/MeetingManagerTest.java @@ -94,4 +94,24 @@ void autoScheduleMeeting_noAvailability_expectException() { assertThrows(CannotScheduleMeetingException.class, () -> meetingManager.autoScheduleMeeting(meetingName, listOfAttendees)); } + + @Test + @Order(7) + void manualScheduleMeeting_timeNotInAvailability_expectException() { + String meetingName = "Project Meeting"; + ArrayList listOfAttendees = new ArrayList<>(); + listOfAttendees.add("shixi"); + listOfAttendees.add("fan"); + String time = "10-02-2021 12:00"; + assertThrows(TimeNotInAvailabilityException.class, () -> + meetingManager.manualScheduleMeeting(meetingName, listOfAttendees, time)); + } + + @Test + @Order(8) + void addAvailability_notStartOfHour_expectException() { + String inputTime = "12-02-2021 16:24"; + String inputName = "shixi"; + assertThrows(InvalidTimeException.class, () -> meetingManager.addAvailability(inputTime, inputName)); + } }