From 5bf8bb374a93e271cb1cfa1f0abb673ea3c3d861 Mon Sep 17 00:00:00 2001 From: Julian <32705562+macchazuki@users.noreply.github.com> Date: Sat, 23 Mar 2019 12:47:14 +0800 Subject: [PATCH 01/11] merge upstream (#6) * Update User Guide (#105) * Update use cases in developer guide * edit user guide * add encryption key skeleton * user guide edits * Update User Guide (#106) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update README.adoc and UserGuide.adoc: change table layouts (#110) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update UserGuide.adoc with feedback from peers * Update UserGuide.adoc with nicer tables * Update UserGuide.adoc: fix formatting issues * UserGuide.adoc Remove potential Netlify breaking code * README.adoc revert changes * UserGuide.adoc revert Netlify breakdown test code * Update User Guide (#108) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Enhance list and find functionality to include tags (#111) * Merge (#18) * FIx Bug in FindCommand (#97) Fix Bug in FindCommand * Update User Guide documentation (#98) * Update User Guide documentation (#99) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update UserGuide.adoc (#100) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide (#101) * Merge (#17) * FIx Bug in FindCommand (#97) Fix Bug in FindCommand * Update User Guide documentation (#98) * Update User Guide documentation (#99) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update UserGuide.adoc (#100) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Add config file for Reposense * Add config file for Reposense (#102) * Move config.json to _reposense folder * Move config.json to _reposense folder (#103) * Edit config file for reposense * Resolve conflicts * Merge (#19) * Resolve checkstyle errors * FIx Bug in FindCommand (#97) Fix Bug in FindCommand * Update User Guide documentation (#98) * Update User Guide documentation (#99) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update UserGuide.adoc (#100) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide (#101) * Merge (#17) * FIx Bug in FindCommand (#97) Fix Bug in FindCommand * Update User Guide documentation (#98) * Update User Guide documentation (#99) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update UserGuide.adoc (#100) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Update User Guide * Add config file for Reposense * Add config file for Reposense (#102) * Move config.json to _reposense folder * Move config.json to _reposense folder (#103) * Edit config file for reposense * Update User Guide (#105) * Update use cases in developer guide * edit user guide * add encryption key skeleton * user guide edits * Update User Guide (#106) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Update README.adoc and UserGuide.adoc: change table layouts (#110) * v1.1 * fix some errors and typos * Refactor entire project, remove all traces of Addressbook * Update developer guide for ExportCommandP (#80) * Update documentation for view command (#81) * Remove remaining Addressbook classes * Refactor some classes * fix missing files issue * Add test cases for add function, Utils and other code enhancements * fix codacy issues * fix codacy issues * Add tests for Utils * Add diagrams * Update Ui.png * fix issue with Ui.png * Update Codacy Badge link due to reinitialization. * Enhance ordering of slots printed * Update UserGuide.adoc with feedback from peers * Update UserGuide.adoc with nicer tables * Update UserGuide.adoc: fix formatting issues * UserGuide.adoc Remove potential Netlify breaking code * README.adoc revert changes * UserGuide.adoc revert Netlify breakdown test code * Update User Guide (#108) * Planner: Initialize weekType for each Day * Planner: Fix Codacy issue * Planner: Update code for initialisation of semester * Planner: Fix Codacy and checkstyle issues * Planner: Fix build error * Planner: Dynamic generation of semester from date * PlannerTest: Add JUnit test for generateSemester * Update documentation for view command * Add view command for monthly calendar view * Fix Codacy issue * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * UserGuide: Update user guide documentation * Enhance list and find functionality to include tags --- README.adoc | 8 +- docs/UserGuide.adoc | 471 ++++++++++++++-------- src/planmysem/commands/EditCommand.java | 11 +- src/planmysem/commands/FindCommand.java | 55 ++- src/planmysem/commands/ListCommand.java | 35 +- src/planmysem/common/Messages.java | 1 + src/planmysem/data/Planner.java | 9 + src/planmysem/data/semester/Semester.java | 19 + src/planmysem/parser/Parser.java | 16 +- src/planmysem/ui/DarkTheme.css | 2 +- test/java/planmysem/logic/LogicTest.java | 27 +- 11 files changed, 442 insertions(+), 212 deletions(-) diff --git a/README.adoc b/README.adoc index 95e0efca1..add67da75 100644 --- a/README.adoc +++ b/README.adoc @@ -7,13 +7,11 @@ https://ci.appveyor.com/project/seanieyap/main-r8jp5[image:https://ci.appveyor.c https://app.netlify.com/sites/planmysem/deploys[image:https://api.netlify.com/api/v1/badges/6c19b45b-dbdd-4eff-afe2-200356d6ebb4/deploy-status[Build Status]] https://coveralls.io/github/CS2113-AY1819S2-T08-3/main?branch=master[image:https://coveralls.io/repos/github/CS2113-AY1819S2-T08-3/main/badge.svg?branch=master[Coverage Status]] https://www.codacy.com/app/CS2113T-T08-3/main?utm_source=github.com&utm_medium=referral&utm_content=CS2113-AY1819S2-T08-3/main&utm_campaign=Badge_Grade[image:https://api.codacy.com/project/badge/Grade/90f57d16da5049858ef67b6eaaf692f2[Codacy Badge]] +https://opensource.org/licenses/MIT[image:https://img.shields.io/badge/License-MIT-yellow.svg[License: MIT]] image::Ui.png[] -PlanMySem is a CLI (Command Line Interface) scheduling/calendar application that targets NUS students and staff who prefer to use a desktop application for managing their schedule/calendar. -PlanMySem automatically creates a planner that is synchronised according to the NUS academic calendar for the current semester and enables easy creation, editing and deleting of items. -Special weeks such as recess week and reading week are taken into account within our unique recursion system. -Items can then be efficiently managed via the intuitive tagging system. +PlanMySem is a CLI (Command Line Interface) scheduling/calendar application that targets NUS students and staff who prefer to use a desktop application for managing their schedule/calendar. PlanMySem automatically creates a planner that is synchronised according to the NUS academic calendar for the current semester and enables easy creation, editing and deleting of items. Special weeks such as recess week and reading week are taken into account within our unique recursion system. Items can then be efficiently managed via the intuitive tagging system. PlanMySem is optimized for those who prefer to work with a Command Line Interface (CLI) and/or are learning to work more efficiently with CLI tools. Additionally, unlike traditional calendar/scheduling applications, PlanMySem utilizes minimal resources on the user’s machine while still allowing the user to view their schedules swiftly and efficiently. @@ -42,3 +40,5 @@ PlanMySem is optimized for those who prefer to work with a Command Line Interfac * *Bug reports, Suggestions* : Post in our https://github.com/CS2113-AY1819S2-T08-3/main/issues[issue tracker] if you noticed bugs or have suggestions on how to improve. * *Contributing* : We welcome pull requests. Follow the process described https://github.com/oss-generic/process[here] + +== Licence : link:LICENSE[MIT] \ No newline at end of file diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 3f02f2271..ca7198a46 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -1,4 +1,4 @@ -= PlanMySem - User Guide += PlanMySem - User Guide :site-section: UserGuide :toc: :toc-title: @@ -11,14 +11,16 @@ ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: +:important-caption: :heavy_exclamation_mark: +:caution-caption: :fire: +:warning-caption: :warning: endif::[] :repoURL: https://github.com/CS2113-AY1819S2-T08-3/main By: `Team T08-3` Since: `Jan 2019` Licence: `MIT` == Introduction - -Welcome to _PlanMySem_! Choose a topic from the table of contents to learn about available features with examples, find answers or view a summary of the commands. +Welcome to _PlanMySem_! _PlanMySem_ is a text-based (Command Line Interface) scheduling/calendar application that targets NUS students and staff who prefer to use a desktop application for managing their schedule/calendar. _PlanMySem_ automatically creates a planner that is synchronised according to the NUS academic calendar for the current semester and enables easy creation, editing and deleting of items. @@ -26,13 +28,37 @@ Special weeks such as recess week and reading week are taken into account within Items can then be efficiently managed via the intuitive tagging system. _PlanMySem_ is optimized for those who prefer to work with a Command Line Interface (CLI) and/or are learning to work more efficiently with CLI tools. Additionally, unlike traditional calendar/scheduling applications, _PlanMySem_ utilizes minimal resources on the user’s machine while still allowing the user to view their schedules swiftly and efficiently. +{zwsp} -This user guide provides a quick start guide for you to easily setup and install _PlanMySem_, documentation of all the various features _PlanMySem_ offers, frequently asked questions and a summary of the available commands. +{zwsp} + +== About this User Guide +This user guide provides a quick start guide for you to easily setup and install _PlanMySem_, documentation of all the various features _PlanMySem_ offers, frequently asked questions and a summary of the available commands. To navigate between the different sections, you could use the table of contents above. + +For ease of communication, this document will refer to lessons/activities/events/appointments that you might add into the planner as _slots_. + +Additionally, throughout this user guide, there will be various icons used as described below. + +[TIP] +This is a tip. Follow these suggested tips to make your life much simpler when using _PlanMySem_! + +[NOTE] +This is a note. These are things for you to take note of when using _PlanMySem_. + +[IMPORTANT] +This is a sign-post dictating important information. These are information that you will surely need to know to use _PlanMySem_ properly. + +[CAUTION] +This is a sign-post informing caution. Please take note of these items and exercise some care. + +[WARNING] +This is a rule. Ensure that you follow these rule to make your life using _PlanMySem_ a pleasant one. {zwsp} {zwsp} == Quick Start +This section guides you through the installation of _PlanMySem_ and provides a few example commands you may try. . Ensure you have Java version `9` or later installed in your Computer. . Download the latest `planmysem.jar` link:{repoURL}/releases[here]. @@ -44,14 +70,13 @@ This user guide provides a quick start guide for you to easily setup and install image::Start_Screen.png[width="790"] + . Type the command in the command box and press kbd:[Enter] to execute it. + -e.g. typing *`help`* and pressing kbd:[Enter] will open the help window. +E.g. typing *`help`* and pressing kbd:[Enter] will open the help window. . Some example commands you can try: - * **`add`**`n/CS2113T d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T t/Tutorial` : + -Add a slot, named "CS2113T" on the coming monday, from 0800hrs to 0900hrs with the tags "CS2113T" and "Tutorial". -* *`list`*`n/CS2113T` : list all slots named "CS2113T" -* **`delete`**`3` : delete the 3rd slot shown in the current list +Add a _slot_, named "CS2113T" on the coming monday, from 0800hrs to 0900hrs with the tags "CS2113T" and "Tutorial". +* *`list`*`n/CS2113T` : list all _slots_ named "CS2113T" +* **`delete`**`3` : delete the 3rd _slot_ shown in the current list * *`exit`* : exit the app . Refer to <> for details of each command. @@ -61,83 +86,134 @@ Add a slot, named "CS2113T" on the coming monday, from 0800hrs to 0900hrs with t [[Features]] == Features - -This section displays the current implemented features as well as features that will be implemented in the future. - -[NOTE] -*For ease of communication, this document will refer to lessons/activities/events/appointments that you might add into the Planner as _slots_.* - -==== +This section displays the available features of _PlanMySem_ together with examples for you to refer to. *Tagging System* -Unlike other commercial calendar/scheduling/planner software, PlanMySem makes use of a tagging system to manage slots. +Unlike other commercial calendar/scheduling/planner software, _PlanMySem_ makes use of a tagging system to manage _slots_. -Using tags to tag slots will make tasks easier for you in the future. Tasks such as viewing, deleting and editing slots will be more efficient and performed quicker. +Using tags to tag _slots_ will make tasks easier for you in the future. Performing tasks such as viewing, deleting and editing _slots_ will be more efficient. Recommended uses for tags: -1. Tag modules. e.g. "CS2113T", "CS2101". -2. Tag type of lesson. e.g. "Lecture", "Tutorial", "Lab". -3. Tag type of activities. e.g. "Sports", "Seminar", "Talk" -4. Tag difficulty of task. e.g. "Tough", "Simple", "Trivial" +1. Tag modules. E.g. "CS2113T", "CS2101". +2. Tag type of lesson. E.g. "Lecture", "Tutorial", "Lab". +3. Tag type of activities. E.g. "Sports", "Seminar", "Talk". +4. Tag difficulty of task. E.g. "Tough", "Simple", "Trivial". *Recursion System* -Recursion facilitates quick addition of multiple slots, similar to Microsoft Outlook's series of appointments. - -In NUS, academic semesters are split into weeks of several types. Recursion allows you to add slots to these types of weeks with ease through the use of the `r/`(recursion) parameter. - -*Parameters* +Recursion facilitates quick addition of multiple _slots_, similar to Microsoft Outlook's series of appointments. -Parameters in _PlanMySem_ are designed to be, short and easy to memorise. Once you are familarised with them, they should be intuitive to use. -The table of parameters and their descriptions (Table 1) below is useful for your reference as you jump right into grasping the system. +In NUS, academic semesters are split into weeks of several types. Recursion allows you to add _slots_ to these types of weeks with ease through the use of the `r/`(recursion) parameter. *Command Format* * Words in UPPER_CASE are the parameters to be supplied by the user. E.g. in `t/TAG`, `TAG` is a parameter which can be used as the name of the tag. -* Items in square brackets are optional. e.g in `add [l/LOCATION]`, `LOCATION` is a parameter that may be omited. -* Items with `…` after them can be used multiple times including zero times e.g. `[t/TAG]…` can be used as (i.e. 0 times), `t/lab`, `t/lecture`, `t/tutorial` etc. -* Parameters can be in any order e.g. if the command specifies `st/START_TIME et/END_TIME d/DATE`, then both `et/09:00 st/08:00 d/2-13-2019` and `et/09:00 d/2-13-2019 st/08:00` is also acceptable. - -[horizontal] -*Parameter*:: *Description* -`n/`:: *Name of a _slot_.* -`d/`:: *Date / Day of week.* + - Format: + - * Dates: `01-01`, `2019-01-02` - * Day of Week: `Monday`, `mon`, `1` -`st/`:: *Start Time.* + - Format: + - * 24-Hour in the form of “hh:mm”. e.g. `23:00` - * 12-Hour in the form of `hh:mm+AM|PM`. e.g. `12:30 AM` -`et/`:: *End Time / duration.* + - Format: + - * 24-Hour in the form of “hh:mm”. e.g. `23:00` - * 12-Hour in the form of `hh:mm+AM|PM`. e.g. `12:30 AM` - * Duration of the event in minutes. e.g. `60` represents 60 minutes -`r/`:: *Specify recurrence of a _slot_.* + - Format: + - * Select normal weeks: `normal` - * Select recess week: `recess` - * Select reading week: `reading` - * Select examination weeks: `exam` - * Select past dates: `past` -`l/`:: *Location.* -`des/`:: *Description.* -`t/`:: *Tag.* -`nn/`:: *New name of a _slot_.* -`nd/`:: *New Date.* -`nst/`:: *New Start Time.* -`net/`:: *New End Time.* -`nl/`:: *New Location.* -`ndes/`:: *New Description.* -==== -Table 1. Parameters and their descriptions -{zwsp} +* Items in square brackets are optional. e.g in `add [l/LOCATION]`, `LOCATION` is a parameter that may be omitted. +* Items with `…` after them can be used multiple times including zero times. E.g. `[t/TAG]…` can be used 0 times, or as `t/lab`, `t/lecture`, `t/tutorial` etc. +* Parameters can be in any order. E.g. if the command specifies `st/START_TIME et/END_TIME d/DATE`, then both `et/09:00 st/08:00 d/2-13-2019` and `et/09:00 d/2-13-2019 st/08:00` are acceptable. -{zwsp} +[TIP] +You can save time by utilizing the alternate and shortcut commands. E.g. instead of using `delete`, you may also use `del` or simply `d`. + +*Identifiers and Parameters* + +Identifiers in _PlanMySem_ are designed to be, short and easy to memorise. +Once you are familiarised with them, they should be intuitive to use to add your parameters. +The table of Identifiers and Parameters and their descriptions (Table 1) below is useful for your reference as you jump right into grasping the system. + +.Identifiers and their Parameters and descriptions. +[width="100%",cols="5%,<10%,<30%,<30%,<25",options="header"] +|======================================================================= +|Identifier |Parameter |Description |Format |Example + +.2+|`n/` + |`NAME` |Name of a _slot_ |Text |`n/CS2113T` + |`KEYWORD` |Text that are part of the name of a _slot_ |Text |`n/CS` +|`l/` |`LOCATION` |Location of a _slot_ |Text |`l/COM2 04-22` +|`des/` |`DESCRIPTION` |Description of a _slot_ |Text |`des/Topic: Abstraction` +|`t/` |`TAG` |Tag of a _slot_ |Text |`t/Lab` + +.4+|`d/` + .2+|`DATE` .2+|Date + |`dd-mm-yyyy` |`d/01-02-2019` + |`dd-mm` |`d/01-02` + .2+|`DAY` .2+|Day of week + |Name of day |`d/Monday` + |Name of day (short-form) |`d/mon` + +.2+|`st/` .2+|`START_TIME` .2+|Start time + |Time in 24-Hour format, `hh:mm` |`st/23:00` + |Time in 12-Hour format, form of `hh:mm+AM\|PM` |`st/11:00 PM` + +.3+|`et/` + .2+|`END_TIME` .2+|End Time + |Time in 24-Hour format, `hh:mm` |`et/23:00` + |Time 12-Hour format, `hh:mm+AM\|PM` |`et/11:00 PM` + |`DURATION` |Duration from Start Time |Number of minutes |`et/60` + +.5+|`r/` .5+|`RECURRENCE` + |Recurse _slot_ on normal academic weeks |`normal` |`r/normal` + |Recurse _slot_ on recess week |`recess` |`r/recess` + |Recurse _slot_ on reading week |`reading` |`r/reading` + |Recurse _slot_ on examination weeks |`exam` |`r/exam` + |Recurse _slot_ on past dates |`past` |`r/past` +|======================================================================= +[TIP] +You may order identifiers and parameters in any fashion and you will still be able to achieve what you want! +So, do not bother thinking about where to place parameters as ordering does not matter, instead become more efficient and save your time! + +[IMPORTANT] +Identifiers may be appended with a `n` to dictate "new". + +E.g. `nt/NEW_TAG` signifies new tags in which you want to replace existing tags with. + +[CAUTION] +While table 1 shows you all the identifiers and parameters that _PlanMySem_ uses, there are some commands that do not make use of identifiers nor parameters. +The view command is one such exception that make use of keywords that must be typed in a specific order. + +// +//[horizontal] +//==== +//*Parameter*:: *Description* +//`n/`:: *Name of a _slot_.* +//`d/`:: *Date / Day of week.* + +// Format: + +// * Dates: `01-01`, `2019-01-02` +// * Day of Week: `Monday`, `mon`, `1` +//`st/`:: *Start Time.* + +// Format: + +// * 24-Hour in the form of “hh:mm”. E.g. `23:00` +// * 12-Hour in the form of `hh:mm+AM|PM`. E.g. `12:30 AM` +//`et/`:: *End Time / duration.* + +// Format: + +// * 24-Hour in the form of “hh:mm”. E.g. `23:00` +// * 12-Hour in the form of `hh:mm+AM|PM`. E.g. `12:30 AM` +// * Duration of the event in minutes. E.g. `60` represents 60 minutes +//`r/`:: *Specify recurrence of a _slot_.* + +// Format: + +// * Select normal weeks: `normal` +// * Select recess week: `recess` +// * Select reading week: `reading` +// * Select examination weeks: `exam` +// * Select past dates: `past` +//`l/`:: *Location.* +//`des/`:: *Description.* +//`t/`:: *Tag.* +//`nn/`:: *New name of a _slot_.* +//`nd/`:: *New Date.* +//`nst/`:: *New Start Time.* +//`net/`:: *New End Time.* +//`nl/`:: *New Location.* +//`ndes/`:: *New Description.* +//==== +//Table 1. Parameters and their descriptions +{zwsp} + +{zwsp} + +[[help]] === Viewing help : `help` Displays all the available commands with the syntax and examples. + Format: `help` @@ -149,8 +225,8 @@ image::Help_Command_Output.png[width="790"] {zwsp} +[[add]] === Adding Slots : `add` / `a` - Add _slot(s)_ to the planner. + Format: `add n/NAME d/DATE_OR_DAY_OF_WEEK st/START_TIME et/END_TIME_OR_DURATION + [l/LOCATION] [des/DESCRIPTION] [r/normal] [r/recess] [r/reading] [r/exam] [r/past] [t/TAG]...` @@ -165,21 +241,19 @@ Add a _slot_, named "CS2113T Tutorial" on the coming monday, from 0800hrs to 090 image::Add_Command_Output_1.png[width="790"] * `add n/CS2113T Tutorial d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T t/Tutorial r/recess r/reading` + -Do the same but additionally, recurse the slot on recess and reading week. +Do the same but additionally, recurse the _slot_ on recess and reading week. * `add n/CS2113T Tutorial d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T t/Tutorial r/normal` + -Do the same but recurse the slot on "normal", instructional, weeks. +Do the same but recurse the _slot_ on "normal", instructional, weeks. [TIP] -==== -You may add single _slots_ by omitting the recurrence parameter. -==== +You may add single _slots_ by omitting the `r/` identifiers and its parameters. {zwsp} {zwsp} +[[edit]] === Editing Slots: `edit` / `e` - Edit _slot(s)_. 1. Edit _slot(s)_ which contains certain _tag_(s). + @@ -187,16 +261,14 @@ Format: `edit t/TAG... [nn/NEW_NAME] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURA 2. Edit specific _slot_ via the `list` command. + Format: `edit INDEX [nn/NEW_NAME] [nd/NEW_DATE] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURATION] [nl/NEW_LOCATION] [nd/NEW_DESCRIPTION] [nt/NEW_TAG]...` -[WARNING] -==== -You are not able to edit a slot's date when editing via _tags_. +[NOTE] +You will not be able to edit a _slot_'s date when editing via _tags_. + To edit a _slot_'s date, you may use the `list` or `find` command and edit specific _slot(s)_ via index. -==== Examples: * `edit t/CS2113T t/Tutorial nl/COM2 04-01` + -Edit slots that contain tags "CS2113T" and "Tutorial", set these _slot's_ location to "COM2 04-01". +Edit _slots_ that contain tags "CS2113T" and "Tutorial", set these _slot's_ location to "COM2 04-01". [#img-edit] .[.underline]#Output after entering `edit t/CS2113T t/Tutorial nl/COM2 04-01`# @@ -208,17 +280,15 @@ Edit the first item from the previous result of the `list` or `find` command. {zwsp} +[[delete]] === Delete Slots: `delete` / `del` / `d` - 1. Delete _slot(s)_ which contains certain _tag_(s). + Format: `delete t/TAG...` 2. Delete _slot_ via the `list` command. + Format: `delete INDEX` [TIP] -==== -You may delete a specific slot by using the `list` or `find` command and select the specific _slot_ via index. -==== +You may delete a specific _slot_ by using the `list` or `find` command and select the specific _slot_ via index. Examples: @@ -235,9 +305,9 @@ Delete the second _slot_ shown via the `list` command. {zwsp} +[[list]] === Listing Slots: `list` / `l` - -Lists all slots whose name directly matches the specified keyword (not case-sensitive). + +Lists all _slots_ whose name directly matches the specified keyword (not case-sensitive). + Format: `list n/NAME` Examples: @@ -252,8 +322,8 @@ image::List_Command_Output_1.png[width="790"] {zwsp} +[[find]] === Locating Slots: `find` / `f` - Find all _slots_ whose part of their name contains the specified keyword and displays them as a list. + Format: `find n/KEYWORD` @@ -269,8 +339,8 @@ image::Find_Command_Output_1.png[width="790"] {zwsp} +[[view]] === View the Planner : `view` / `v` - View the planner in a month/week/day view. 1. View the monthly calendar view of the current academic semester. + @@ -282,10 +352,9 @@ Format: `view day [DATE]` 4. View all the details in the planner. + Format: `view all` -[NOTE] -==== -If MONTH/WEEK/DATE is not specified, the current date is assumed. -==== +[TIP] +You may omit `[MONTH]`/`[WEEK]`/`[DATE]` to view the format chosen in respect to the current day! + +E.g. `view month` will allow you to view the current month and `view day` will allow you to view the current day! Examples: @@ -297,168 +366,222 @@ View planner for the first of March. View planner for week 7 of the academic calendar. * `view week recess` + View planner for recess week of the academic calendar. -* `view month March` + -View planner for the month of March. -* `view all` + -View all the details in the planner. +* `view month` + +View planner for the months of the current academic semester. [#img-view] .[.underline]#Output after entering `view month`# image::Ui.png[width="790"] + +* `view all` + +View all the details in the planner. {zwsp} {zwsp} +[[history]] === Listing previous input commands : `history` `[coming in v2.0]` - Lists all the commands that you have entered in reverse chronological order. + Format: `history` {zwsp} {zwsp} +[[undo]] === Undoing previous command : `undo` `[coming in v2.0]` - Restores the planner to the state before the previous command was executed. + Format: `undo` -[WARNING] -==== +[TIP] The `clear` command cannot be undone. -==== {zwsp} {zwsp} +[[redo]] === Redoing the previously undone command : `redo` `[coming in v2.0]` - Reverses the most recent `undo` command. + Format: `redo` {zwsp} {zwsp} -=== Clear all data : `clear` +[[encrypt]] +=== Encrypting/decrypting data files +Planner data is automatically encrypted before saving and decrypted before loading. You do not need to encrypt or decrypt he data manually. +{zwsp} + +{zwsp} +[[import]] +=== Importing .ics formatted files `[coming in v2.0]` +You can import an .ics file into the planner. +Format: `import FILENAME` +{zwsp} + +{zwsp} + +[[export]] +=== Exporting .ics formatted files: `export` +You can export the planner as a .ics file. + +[#img-export] +.[.underline]#Output after entering `export`# +image::Export_Command_Output_1.png[width="420"] + +[NOTE] +==== +The exported file is named "PlanMySem.ics" and is saved in the main directory. +The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. + + +[#img-exportFile] +.[.underline]#Location of PlanMySem.ics file# +image::Export_Command_Directory_1.png[width="790"] +==== + +[TIP] +A file with the ICS file extension is an iCalendar file. +These are plain text files that include calendar event details like a description, beginning and ending times, location, etc. +{zwsp} + +{zwsp} + +[[clear]] +=== Clear all data : `clear` Clear all data stored on the planner. + Format: `clear` [#img-find] .[.underline]#Output after entering `clear`# image::Clear_Command_Output_1.png[width="790"] -{zwsp} -[WARNING] -==== +[NOTE] The `clear` command cannot be undone! Your data will be permanently removed once `clear` is executed. -==== {zwsp} {zwsp} +[[exit]] === Exiting the program : `exit` - Exits the program. + Format: `exit` {zwsp} {zwsp} +[[save]] === Saving the data - Planner data is saved in the hard disk automatically after any command that changes the data is executed. + There is no need to save manually. {zwsp} {zwsp} -=== Encrypting/decrypting data files +== FAQ +*Q*: How do I transfer my data to another Computer? + +*A*: In order to transfer your data to another Computer, you should: -Planner data is automatically encrypted before saving and decrypted before loading. You do not need to encrypt or decrypt he data manually. -{zwsp} +1. Install the app on the other computer + +2. Copy _PlanMySem.txt_ from your old _PlanMySem_ folder and paste it into the new _PlanMySem_ folder. + +This will overwrite the empty data file it creates with the file that contains the data of your previous _PlanMySem_ folder. {zwsp} -=== Importing .ics formatted files `[coming in v2.0]` - -You can import an .ics file into the planner. -Format: `import FILENAME` {zwsp} -{zwsp} +== Command Summary -=== Exporting .ics formatted files: `export` +//* *Add Slot* : `add n/NAME d/DATE_OR_DAY_OF_WEEK st/START_TIME et/END_TIME_OR_DURATION [l/LOCATION] [des/DESCRIPTION] [r/normal] [r/recess] [r/reading] [r/exam] [r/past] [t/TAG]…​` + +//E.g. `add n/CS2113T Tutorial d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T t/Tutorial` + +//* *List Slot(s)* : `list n/NAME` + +//eg. `list n/CS2113T` +//* *Edit Slot* : `edit` + +//1. Via tags: `edit t/TAG... [nn/NEW_NAME] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURATION] [nl/NEW_LOCATION] [nd/NEW_DESCRIPTION] [nt/NEW_TAG]...` + +//E.g. `edit t/CS2113T t/Tutorial nl/COM2 04-01` +//2. Via `list` command: `edit INDEX [nn/NEW_NAME] [nd/NEW_DATE] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURATION] [nl/NEW_LOCATION] [nd/NEW_DESCRIPTION] [nt/NEW_TAG]...` + +//E.g. `edit 1 des/Topic: Sequence Diagram` +//* *Delete Slot* : `delete` + +//1. Via tags: `delete t/TAG…​` + +//eg. `delete t/CS2113T t/Tutorial` +//2. Via `list` command: `delete INDEX` + +//eg. `delete 2` +//* *Find Slots* : `find [KEYWORD]…​` + +//E.g. `find CS` +//* *View planner* : `view day [DATE] | view week [WEEK] | view month [MONTH]` + +//E.g.`view month` +//* *View all details* : `view all` +//* *Clear all data* : `clear` +//* *Exit the program* : `exit` +//* *Export .ics file* : `export` +//* *Import .ics file* : `import FILENAME` -You can export the planner as a .ics file. +=== General Commands +General commands that you might find useful in helping you to navigate and configure _PlanMySem_: +[width="100%",cols="20%,<30%,<20%,<30",options="header"] +|======================================================================= +|Task |Purpose |Command |Example -[#img-export] -.[.underline]#Output after entering `export`# -image::Export_Command_Output_1.png[width="420"] +|_<>_ |Shows you the user guide |`help` | `help` -{zwsp} +|_<>_ |Shows you a history of all commands used |`history` | `history` -{zwsp} +|_<>_ |Undo your previous command |`undo` | `undo` -[NOTE] -==== -The exported file is named "PlanMySem.ics" and is saved in the main directory. -The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. + +|_<>_ |Redo your undo | `redo` | `redo` -[#img-exportFile] -.[.underline]#Location of PlanMySem.ics file# -image::Export_Command_Directory_1.png[width="790"] -==== -{zwsp} -[TIP] -==== -A file with the ICS file extension is an iCalendar file. -These are plain text files that include calendar event details like a description, beginning and ending times, location, etc. -==== -{zwsp} +|_<>_ |Clear your planner | `clear` | `clear` +|_<>_ |Exit the _PlanMySem_ | `exit` | `exit` +|======================================================================= {zwsp} +{zwsp} +=== Manipulating the Planner +Commands to manage _slots_: +[width="100%",cols="20%,<30%,<20%,<30",options="header"] +|======================================================================= +|Task |Purpose |Command |Example -== FAQ +|_<>_ |Add _slot(s)_ into the planner +|`add` | `add n/CS2113T Tutorial d/mon st/08:00 et/09:00 t/CS2113T` +|_<>_ |Edit _slot(s)_ +|`edit` | `edit t/CS2113T nl/COM2 04-01` +|_<>_ |Delete _slot(s)_ +|`delete` | `delete t/CS2113T` +|======================================================================= +{zwsp} -*Q*: How do I transfer my data to another Computer? + -*A*: In order to transfer your data to another Computer, you should: +{zwsp} -1. Install the app on the other computer + -2. Copy _PlanMySem.txt_ from your old _PlanMySem_ folder and paste it into the new _PlanMySem_ folder. + +=== Viewing the Planner +Commands to view _slots_: +[width="100%",cols="20%,<30%,<20%,<30",options="header"] +|======================================================================= +|Task |Purpose |Command |Example -This will overwrite the empty data file it creates with the file that contains the data of your previous _PlanMySem_ folder. +|_<>_ |view the planner in a chosen format/layout | +`view` | `view month` +|_<>_ |list _slot(s)_ of a certain name | +`list` | `list n/CS2113T` +|_<>_ |find _slot(s)_ containing certain keywords | +`find` | `find CS` +|======================================================================= {zwsp} {zwsp} -== Command Summary +=== Import/Exporting the Planner +Commands to view _slots_: +[width="100%",cols="20%,<30%,<20%,<30",options="header"] +|======================================================================= +|Task |Purpose |Command |Example + +|_<>_ |Export all your slots into a .ics file| +`export` | `export` +|_<>_ |Import into your planner from a .ics file | +`import` | `import` +|======================================================================= +{zwsp} -* *View help* : `help` + -* *Add Slot* : `add n/NAME d/DATE_OR_DAY_OF_WEEK st/START_TIME et/END_TIME_OR_DURATION [l/LOCATION] [des/DESCRIPTION] [r/normal] [r/recess] [r/reading] [r/exam] [r/past] [t/TAG]…​` + -e.g. `add n/CS2113T Tutorial d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T t/Tutorial` + -* *List Slot(s)* : `list n/NAME` + -eg. `list n/CS2113T` -* *Edit Slot* : `edit` + -1. Via tags: `edit t/TAG... [nn/NEW_NAME] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURATION] [nl/NEW_LOCATION] [nd/NEW_DESCRIPTION] [nt/NEW_TAG]...` + -e.g. `edit t/CS2113T t/Tutorial nl/COM2 04-01` -2. Via `list` command: `edit INDEX [nn/NEW_NAME] [nd/NEW_DATE] [nst/NEW_START_TIME] [net/NEW_END_TIME|DURATION] [nl/NEW_LOCATION] [nd/NEW_DESCRIPTION] [nt/NEW_TAG]...` + -e.g. `edit 1 des/Topic: Sequence Diagram` -* *Delete Slot* : `delete` + -1. Via tags: `delete t/TAG…​` + -eg. `delete t/CS2113T t/Tutorial` -2. Via `list` command: `delete INDEX` + -eg. `delete 2` -* *Find Slots* : `find [KEYWORD]…​` + -e.g. `find CS` -* *View planner* : `view day [DATE] | view week [WEEK] | view month [MONTH]` + -e.g.`view month` -* *View all details* : `view all` -* *View history* : `history` -* *Undo previous command* : `undo` -* *Redo previously undone command* : `redo` -* *Clear all data* : `clear` -* *Exit the program* : `exit` -* *Export .ics file* : `export` -* *Import .ics file* : `import FILENAME` +{zwsp} \ No newline at end of file diff --git a/src/planmysem/commands/EditCommand.java b/src/planmysem/commands/EditCommand.java index 8ac80eea6..7857c4894 100644 --- a/src/planmysem/commands/EditCommand.java +++ b/src/planmysem/commands/EditCommand.java @@ -12,10 +12,8 @@ import planmysem.common.Messages; import planmysem.common.Utils; import planmysem.data.exception.IllegalValueException; -import planmysem.data.semester.Day; import planmysem.data.semester.Semester; import planmysem.data.slot.ReadOnlySlot; -import planmysem.data.slot.Slot; import planmysem.data.tag.Tag; /** @@ -95,13 +93,8 @@ public CommandResult execute() { Map selectedSlots = new TreeMap<>(); if (getTargetIndex() == -1) { - for (Map.Entry day : planner.getSemester().getDays().entrySet()) { - for (Slot slot : day.getValue().getSlots()) { - if (slot.getTags().containsAll(tags)) { - selectedSlots.put(LocalDateTime.of(day.getKey(), slot.getStartTime()), slot); - } - } - } + planner.getSlots(tags); + if (selectedSlots.size() == 0) { return new CommandResult(String.format(MESSAGE_SUCCESS_NO_CHANGE, Messages.craftSelectedMessage(tags))); diff --git a/src/planmysem/commands/FindCommand.java b/src/planmysem/commands/FindCommand.java index 28c3bcee6..027f718fb 100644 --- a/src/planmysem/commands/FindCommand.java +++ b/src/planmysem/commands/FindCommand.java @@ -4,12 +4,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import javafx.util.Pair; import planmysem.data.semester.Day; import planmysem.data.slot.ReadOnlySlot; import planmysem.data.slot.Slot; +import planmysem.data.tag.Tag; /** @@ -23,16 +25,18 @@ public class FindCommand extends Command { private static final String MESSAGE_SUCCESS = "%1$s Slots listed.\n%2$s"; private static final String MESSAGE_SUCCESS_NONE = "0 Slots listed.\n"; public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + "Finds all slots whose name " - - + "contains the specified keywords (not case-sensitive).\n\t" + + "contains the specified keywords (case-sensitive).\n\t" + "Parameters: KEYWORD [MORE_KEYWORDS]...\n\t" + "Example: " + COMMAND_WORD + "n/CS"; private final String keyword; + private final boolean isFindByName; - public FindCommand(String keyword) { - this.keyword = keyword; + public FindCommand(String name, String tag ) { + this.keyword = (name == null) ? tag.trim() : name.trim(); + this.isFindByName = (name != null); } + @Override public CommandResult execute() { final List> relevantSlots = new ArrayList<>(); @@ -41,10 +45,21 @@ public CommandResult execute() { for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { for (Slot slots : entry.getValue().getSlots()) { - if (Pattern.matches(".*" + keyword + ".*", slots.getName().value)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + if (isFindByName) { + if (Pattern.matches(".*" + keyword + ".*", slots.getName().value)) { + matchedSlots.add(slots); + date = entry.getKey(); + relevantSlots.add(new Pair<>(date, slots)); + } + } else { + Set tagSet = slots.getTags(); + for (Tag tag : tagSet) { + if (Pattern.matches(".*" + keyword + ".*", tag.value)) { + matchedSlots.add(slots); + date = entry.getKey(); + relevantSlots.add(new Pair<>(date, slots)); + } + } } } } @@ -56,6 +71,27 @@ public CommandResult execute() { return new CommandResult(String.format(MESSAGE_SUCCESS, matchedSlots.size(), craftSuccessMessage(relevantSlots))); +// final List> relevantSlots = new ArrayList<>(); +// List matchedSlots = new ArrayList<>(); +// LocalDate date; +// +// for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { +// for (Slot slots : entry.getValue().getSlots()) { +// if (Pattern.matches(".*" + keyword + ".*", slots.getName().value)) { +// matchedSlots.add(slots); +// date = entry.getKey(); +// relevantSlots.add(new Pair<>(date, slots)); +// } +// } +// } +// +// if (matchedSlots.isEmpty()) { +// return new CommandResult(MESSAGE_SUCCESS_NONE); +// } +// setData(this.planner, relevantSlots); +// +// return new CommandResult(String.format(MESSAGE_SiUCCESS, matchedSlots.size(), +// craftSuccessMessage(rele } /** @@ -76,6 +112,9 @@ private String craftSuccessMessage(List> sb.append(",\n\t"); sb.append("Start Time: "); sb.append(pair.getValue().getStartTime()); + sb.append("\n\t"); + sb.append("Tags: "); + sb.append(pair.getValue().getTags()); sb.append("\n"); count++; } diff --git a/src/planmysem/commands/ListCommand.java b/src/planmysem/commands/ListCommand.java index 6df29b376..3f898693d 100644 --- a/src/planmysem/commands/ListCommand.java +++ b/src/planmysem/commands/ListCommand.java @@ -4,11 +4,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import javafx.util.Pair; import planmysem.data.semester.Day; import planmysem.data.slot.ReadOnlySlot; import planmysem.data.slot.Slot; +import planmysem.data.tag.Tag; /** * Displays a list of all slots in the planner whose name matches the argument keyword. @@ -22,15 +24,17 @@ public class ListCommand extends Command { public static final String MESSAGE_SUCCESS_NONE = "0 Slots listed.\n"; public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists all slots whose name " - + "directly matches the specified keyword (not case-sensitive)." + + "directly matches the specified keyword (case-sensitive)." //+ "\n\tOptional Parameters: [past] [next] [all]" //+ "\n\tDefault: list all" + "\n\tExample: " + COMMAND_WORD + " n/CS1010"; - private final String name; + private final String keyword; + private final boolean isListByName; - public ListCommand(String name) { - this.name = name; + public ListCommand(String name, String tag) { + this.keyword = (name == null) ? tag.trim() : name.trim(); + this.isListByName = (name != null); } @Override public CommandResult execute() { @@ -40,10 +44,21 @@ public CommandResult execute() { for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { for (Slot slots : entry.getValue().getSlots()) { - if (slots.getName().value.equalsIgnoreCase(name)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + if (isListByName) { + if (slots.getName().value.equalsIgnoreCase(keyword)) { + matchedSlots.add(slots); + date = entry.getKey(); + relevantSlots.add(new Pair<>(date, slots)); + } + } else { + Set tagSet = slots.getTags(); + for (Tag tag : tagSet) { + if (tag.value.equalsIgnoreCase(keyword)) { + matchedSlots.add(slots); + date = entry.getKey(); + relevantSlots.add(new Pair<>(date, slots)); + } + } } } } @@ -57,6 +72,7 @@ public CommandResult execute() { craftSuccessMessage(relevantSlots))); } + /** * Craft success message. */ @@ -75,6 +91,9 @@ private String craftSuccessMessage(List> sb.append(",\n\t"); sb.append("Start Time: "); sb.append(pair.getValue().getStartTime()); + sb.append("\n\t"); + sb.append("Tags: "); + sb.append(pair.getValue().getTags()); sb.append("\n"); count++; } diff --git a/src/planmysem/common/Messages.java b/src/planmysem/common/Messages.java index cd9046f37..e338992e5 100644 --- a/src/planmysem/common/Messages.java +++ b/src/planmysem/common/Messages.java @@ -12,6 +12,7 @@ public class Messages { public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; public static final String MESSAGE_INVALID_COMMAND_FORMAT_ADDITIONAL = "Invalid command format! \n%1$s\n\n%2$s"; public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; + public static final String MESSAGE_INVALID_MULTIPLE_PARAMS = "Either search by NAME or by TAG only, not both."; public static final String MESSAGE_INVALID_SLOT_DISPLAYED_INDEX = "The slot index provided is invalid"; public static final String MESSAGE_PERSON_NOT_IN_ADDRESSBOOK = "Person could not be found in address book"; public static final String MESSAGE_SLOT_NOT_IN_PLANNER = "Slot could not be found in Planner"; diff --git a/src/planmysem/data/Planner.java b/src/planmysem/data/Planner.java index 473f92451..843b6ca4b 100644 --- a/src/planmysem/data/Planner.java +++ b/src/planmysem/data/Planner.java @@ -2,6 +2,7 @@ import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; import java.time.temporal.TemporalAdjusters; import java.time.temporal.WeekFields; @@ -291,6 +292,14 @@ public void addDay(LocalDate date, Day day) throws Semester.DuplicateDayExceptio semester.addDay(date, day); } + /** + * Get set of slots which contain all specified tags. + */ + public Map getSlots(Set tags) { + return semester.getSlots(tags); + } + + /** * Adds a slot to the Planner. * diff --git a/src/planmysem/data/semester/Semester.java b/src/planmysem/data/semester/Semester.java index dd1565747..3c18db98e 100644 --- a/src/planmysem/data/semester/Semester.java +++ b/src/planmysem/data/semester/Semester.java @@ -1,12 +1,14 @@ package planmysem.data.semester; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeMap; import planmysem.data.exception.DuplicateDataException; import planmysem.data.exception.IllegalValueException; @@ -92,6 +94,23 @@ public void addDay(LocalDate date, Day day) throws DuplicateDayException { days.put(date, day); } + /** + * Get set of slots which contain all specified tags. + */ + public Map getSlots(Set tags) { + Map selectedSlots = new TreeMap<>(); + + for (Map.Entry day : days.entrySet()) { + for (Slot slot : day.getValue().getSlots()) { + if (slot.getTags().containsAll(tags)) { + selectedSlots.put(LocalDateTime.of(day.getKey(), slot.getStartTime()), slot); + } + } + } + + return selectedSlots; + } + /** * Adds a Slot to the Semester. * diff --git a/src/planmysem/parser/Parser.java b/src/planmysem/parser/Parser.java index 7e451b6a6..408c2c9ee 100644 --- a/src/planmysem/parser/Parser.java +++ b/src/planmysem/parser/Parser.java @@ -3,6 +3,7 @@ import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT_ADDITIONAL; import static planmysem.common.Messages.MESSAGE_INVALID_DATE; +import static planmysem.common.Messages.MESSAGE_INVALID_MULTIPLE_PARAMS; import static planmysem.common.Messages.MESSAGE_INVALID_TIME; import java.time.LocalDate; @@ -322,10 +323,14 @@ private Command prepareDelete(String args) { private Command prepareFind(String args) { HashMap> arguments = getParametersWithArguments(args); String name = getFirstInSet(arguments.get(PARAMETER_NAME)); - if (name == null || name.trim().isEmpty()) { + String tag = getFirstInSet(arguments.get(PARAMETER_TAG)); + if (name == null && tag == null) { return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } else if (name != null && tag != null) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_MULTIPLE_PARAMS, FindCommand.MESSAGE_USAGE)); + } - return new FindCommand(name); + return new FindCommand(name, tag); } /** @@ -337,10 +342,13 @@ private Command prepareFind(String args) { private Command prepareList(String args) { HashMap> arguments = getParametersWithArguments(args); String name = getFirstInSet(arguments.get(PARAMETER_NAME)); - if (name == null || name.trim().isEmpty()) { + String tag = getFirstInSet(arguments.get(PARAMETER_TAG)); + if (name == null && tag == null) { return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE)); + } else if (name != null && tag != null) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_MULTIPLE_PARAMS, ListCommand.MESSAGE_USAGE)); } - return new ListCommand(name); + return new ListCommand(name, tag); } /** diff --git a/src/planmysem/ui/DarkTheme.css b/src/planmysem/ui/DarkTheme.css index 1c619d1de..bc2968ca0 100644 --- a/src/planmysem/ui/DarkTheme.css +++ b/src/planmysem/ui/DarkTheme.css @@ -10,7 +10,7 @@ .text-area { -fx-background-color: black; -fx-control-inner-background: black; - -fx-font-family: "Lucida Console"; + -fx-font-family: "Monospace"; -fx-font-size: 10pt; -fx-padding: 5 5 5 5; } diff --git a/test/java/planmysem/logic/LogicTest.java b/test/java/planmysem/logic/LogicTest.java index d1c19631e..d72c5fdfd 100644 --- a/test/java/planmysem/logic/LogicTest.java +++ b/test/java/planmysem/logic/LogicTest.java @@ -2,10 +2,7 @@ import static junit.framework.TestCase.assertEquals; -import static planmysem.common.Messages.MESSAGE_INVALID_DATE; -import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT_ADDITIONAL; -import static planmysem.common.Messages.MESSAGE_INVALID_TIME; +import static planmysem.common.Messages.*; import java.time.LocalDate; import java.time.LocalTime; @@ -27,6 +24,8 @@ import planmysem.commands.ClearCommand; import planmysem.commands.CommandResult; import planmysem.commands.DeleteCommand; +import planmysem.commands.FindCommand; +import planmysem.commands.ListCommand; import planmysem.commands.EditCommand; import planmysem.commands.ExitCommand; import planmysem.commands.HelpCommand; @@ -206,6 +205,26 @@ public void execute_delete_invalidArgsFormat() throws Exception { "d wrong", expectedMessage); } + @Test + public void execute_find_invalidArgsFormat() throws Exception { + String expectedMessageSingle = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); + String expectedMessageMultipleParams = String.format(MESSAGE_INVALID_MULTIPLE_PARAMS, FindCommand.MESSAGE_USAGE); + assertCommandBehavior( + "find wrong args wrong args", expectedMessageSingle); + assertCommandBehavior( + "find n/CS2113T t/Tutorial", expectedMessageMultipleParams); + } + + @Test + public void execute_list_invalidArgsFormat() throws Exception { + String expectedMessageSingle = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE); + String expectedMessageMultipleParams = String.format(MESSAGE_INVALID_MULTIPLE_PARAMS, ListCommand.MESSAGE_USAGE); + assertCommandBehavior( + "list wrong args wrong args", expectedMessageSingle); + assertCommandBehavior( + "list n/CS2113T t/Tutorial", expectedMessageMultipleParams); + } + /** * Executes the command and confirms that the result message is correct. * Both the 'planner' and the 'last shown list' are expected to be empty. From 5f238c9b88c915e1b45da505375e21055ce80ba3 Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Sat, 23 Mar 2019 13:07:21 +0800 Subject: [PATCH 02/11] Update docs --- docs/DeveloperGuide.adoc | 4 +++- docs/UserGuide.adoc | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index 15583e3f7..0f87ed8fe 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -439,7 +439,9 @@ The storage file "PlanMySem.txt" is encrypted to prevent easy access of the user We are encrypting and decrypting the data using the Java Cypher class. This feature is implemented through creating a Encryptor that contains encrypt and decrypt methods. The encrypt method takes a String object as an argument and returns a encrypted String object. The decrypt method takes in a String object as an argument and returns the decrypted message as a String object. -Currently, the encryption is done using AES/ECB/PKCS5Padding. The key used for encryption is a placeholder key and the encrption mode is Electronic Codebook(ECB). In future updates, the key will be generated uniquely and Cipher Block Chaining(CBC) with a Initialization Vector(IV) will be used instead to improve security. +The encryption is done using AES/CBC/PKCS5Padding. The key used for encryption/decryption is generated randomly and stored in a file named "KeyStorage.jceks". No password is required from the user to retrieve this key, but a password input can be added in the KeyStorage.java class to improve security. + + +A initialization vector (IV) is required for the Cipher Block Chain (CBC) mode of encryption. A random IV is generated and appended at the beginning of the data before being stored. The IV is then retrieved from the same file to decrypt the data. Encryption of the data is done automatically before the file is saved. In the implmentation, the AdaptedPlanner object is first marshalled into a StringWriter before being encrypted and written into the file. This is to ensure that the data is JAXB formatted and the save algorithm is unaffected. Similarly, decryption of the data is done automatically before it is loaded. In the implementation, the file is read and decrypted and parsed into a StringReader object. The StringReader object is then unmarshalled and loaded. This is to ensure that the file is converted back into a JAXB object before being loaded and the load algorithm is unaffected. diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index ca7198a46..83d8a4828 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -1,4 +1,4 @@ -= PlanMySem - User Guide += PlanMySem - User Guide :site-section: UserGuide :toc: :toc-title: @@ -410,6 +410,10 @@ Format: `redo` === Encrypting/decrypting data files Planner data is automatically encrypted before saving and decrypted before loading. You do not need to encrypt or decrypt he data manually. {zwsp} +[NOTE] +==== +The key used for encryption and decryption is saved as a file named "KeyStorage.jceks". Deleting this file will prevent the data from being decrypted. +==== {zwsp} From 8da0076c18e25d50125848f95b35fb61422025c2 Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Sun, 31 Mar 2019 03:28:15 +0800 Subject: [PATCH 03/11] Add import command --- src/planmysem/commands/ImportCommand.java | 136 ++++++++++++++++++++++ src/planmysem/parser/Parser.java | 4 + 2 files changed, 140 insertions(+) create mode 100644 src/planmysem/commands/ImportCommand.java diff --git a/src/planmysem/commands/ImportCommand.java b/src/planmysem/commands/ImportCommand.java new file mode 100644 index 000000000..5ce1435d4 --- /dev/null +++ b/src/planmysem/commands/ImportCommand.java @@ -0,0 +1,136 @@ +package planmysem.commands; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import planmysem.common.Utils; +import planmysem.data.exception.IllegalValueException; +import planmysem.data.recurrence.Recurrence; +import planmysem.data.semester.Day; +import planmysem.data.semester.Semester; +import planmysem.data.slot.Description; +import planmysem.data.slot.Location; +import planmysem.data.slot.Name; +import planmysem.data.slot.Slot; + +/** + * Imports a .ics file into the Planner. + */ +public class ImportCommand extends Command { + public static final String COMMAND_WORD = "import"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Imports a .ics file into the Planner." + + "\n\tParameters: " + + "\n\t\tFILENAME"; + + public static final String MESSAGE_SUCCESS = "File imported.\n"; + public static final String MESSAGE_FILE_NOT_FOUND = "File not found.\n"; + public static final String MESSAGE_ERROR_IN_READING_FILE = "Error in reading file.\n"; + + private final String fileName; + private int failedImports = 0; + + public ImportCommand(String fileName) { + this.fileName = fileName.replaceAll("\\s", ""); + } + + @Override + public CommandResult execute() { + FileReader fileReader; + try { + fileReader = new FileReader(this.fileName); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return new CommandResult(MESSAGE_FILE_NOT_FOUND); + } + BufferedReader br = new BufferedReader(fileReader); + + + try { + String sCurrentLine = br.readLine(); + while (!(sCurrentLine.equals("END:VCALENDAR"))) { + sCurrentLine = br.readLine(); + if (sCurrentLine.equals("BEGIN:VEVENT")) { + LocalDate date = null; + String name = null; + String location = null; + String description = null; + LocalTime startTime = null; + int duration = 0; + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); + + while (!(sCurrentLine.equals("END:VEVENT"))) { + sCurrentLine = br.readLine(); + String[] sSplit = sCurrentLine.split(":"); + switch (sSplit[0]) { + case "SUMMARY": + name = sSplit[1]; + break; + + case "DTSTART": + date = LocalDate.parse(sSplit[1], dateFormat); + startTime = LocalTime.parse(sSplit[1], dateFormat); + break; + + case "DTEND": + LocalDateTime startDateTime = LocalDateTime.of(date, startTime); + LocalDateTime endDateTime = LocalDateTime.parse(sSplit[1], dateFormat); + duration = (int) startDateTime.until(endDateTime, ChronoUnit.MINUTES); + break; + + case "LOCATION": + location = sSplit[1]; + break; + + case "DESCRIPTION": + description = sSplit[1]; + break; + + default: + break; + + } + } + try { + Slot slot = new Slot(new Name(name), new Location(location), new Description(description), + startTime, duration, Utils.parseTags(null)); + Recurrence recurrence = new Recurrence(null, date); + Set dates = recurrence.generateDates(planner.getSemester()); + Map days = new TreeMap<>(); + + for (LocalDate singleDate : dates) { + try { + days.put(singleDate, planner.addSlot(date, slot)); + System.out.println("pass"); + } catch (Semester.DateNotFoundException dnfe) { + this.failedImports++; + } + } + } catch (IllegalValueException e) { + return new CommandResult(MESSAGE_ERROR_IN_READING_FILE); + } + + + } + } + } catch (IOException e) { + return new CommandResult(MESSAGE_ERROR_IN_READING_FILE); + } + if (this.failedImports == 0) { + return new CommandResult(MESSAGE_SUCCESS); + } else { + return new CommandResult(MESSAGE_SUCCESS + this.failedImports + " events failed to import.\n"); + } + } +} + + diff --git a/src/planmysem/parser/Parser.java b/src/planmysem/parser/Parser.java index 408c2c9ee..a8e269a1a 100644 --- a/src/planmysem/parser/Parser.java +++ b/src/planmysem/parser/Parser.java @@ -24,6 +24,7 @@ import planmysem.commands.ExportCommand; import planmysem.commands.FindCommand; import planmysem.commands.HelpCommand; +import planmysem.commands.ImportCommand; import planmysem.commands.IncorrectCommand; import planmysem.commands.ListCommand; import planmysem.commands.ViewCommand; @@ -92,6 +93,9 @@ public Command parseCommand(String userInput) { case FindCommand.COMMAND_WORD_SHORT: return prepareFind(arguments); + case ImportCommand.COMMAND_WORD: + return new ImportCommand(arguments); + case ListCommand.COMMAND_WORD: case ListCommand.COMMAND_WORD_SHORT: return prepareList(arguments); From 64d370633f55a37a35a63fab15cbf285f440364b Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Sun, 31 Mar 2019 23:44:12 +0800 Subject: [PATCH 04/11] checkstyle fix --- src/planmysem/logic/parser/ParserManager.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/planmysem/logic/parser/ParserManager.java b/src/planmysem/logic/parser/ParserManager.java index d2da2d49c..d478e5e1b 100644 --- a/src/planmysem/logic/parser/ParserManager.java +++ b/src/planmysem/logic/parser/ParserManager.java @@ -5,7 +5,19 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import planmysem.logic.commands.*; +import planmysem.logic.commands.AddCommand; +import planmysem.logic.commands.ClearCommand; +import planmysem.logic.commands.Command; +import planmysem.logic.commands.DeleteCommand; +import planmysem.logic.commands.EditCommand; +import planmysem.logic.commands.ExitCommand; +import planmysem.logic.commands.ExportCommand; +import planmysem.logic.commands.FindCommand; +import planmysem.logic.commands.HelpCommand; +import planmysem.logic.commands.HistoryCommand; +import planmysem.logic.commands.ImportCommand; +import planmysem.logic.commands.ListCommand; +import planmysem.logic.commands.ViewCommand; import planmysem.logic.parser.exceptions.ParseException; /** From ef2862bcdf42e293650d40d7a974fd1cb900f216 Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Sun, 31 Mar 2019 23:56:30 +0800 Subject: [PATCH 05/11] codacy edits --- src/planmysem/logic/commands/ImportCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/planmysem/logic/commands/ImportCommand.java b/src/planmysem/logic/commands/ImportCommand.java index 19a2070b1..fdbd8c5a8 100644 --- a/src/planmysem/logic/commands/ImportCommand.java +++ b/src/planmysem/logic/commands/ImportCommand.java @@ -56,9 +56,9 @@ public CommandResult execute(Model model, CommandHistory commandHistory) { try { String sCurrentLine = br.readLine(); - while (!(sCurrentLine.equals("END:VCALENDAR"))) { + while (!("END:VCALENDAR".equals(sCurrentLine))) { sCurrentLine = br.readLine(); - if (sCurrentLine.equals("BEGIN:VEVENT")) { + if ("BEGIN:VEVENT".equals(sCurrentLine)) { LocalDate date = null; String name = null; String location = null; @@ -67,7 +67,7 @@ public CommandResult execute(Model model, CommandHistory commandHistory) { int duration = 0; DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); - while (!(sCurrentLine.equals("END:VEVENT"))) { + while (!("END:VEVENT".equals(sCurrentLine))) { sCurrentLine = br.readLine(); String[] sSplit = sCurrentLine.split(":"); switch (sSplit[0]) { From 1d8994e0a52891f43470844d7e923af4c228f46b Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Mon, 1 Apr 2019 23:43:58 +0800 Subject: [PATCH 06/11] add tests for encryptor and export --- docs/UserGuide.adoc | 17 +++++++-- src/planmysem/storage/StorageFile.java | 2 +- .../logic/Commands/ExportCommandTest.java | 35 +++++++++++++++++++ .../logic/parser/ParserManagerTest.java | 14 ++++++++ .../java/planmysem/storage/EncryptorTest.java | 9 +++-- 5 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 test/java/planmysem/logic/Commands/ExportCommandTest.java diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 145fe938e..e64390823 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -411,7 +411,7 @@ Format: `redo` [[encrypt]] === Encrypting/decrypting data files -Planner data is automatically encrypted before saving and decrypted before loading. You do not need to encrypt or decrypt he data manually. +Planner data is automatically encrypted before saving and decrypted before loading. You do not need to encrypt or decrypt the data manually. {zwsp} {zwsp} @@ -419,7 +419,16 @@ Planner data is automatically encrypted before saving and decrypted before loadi [[import]] === Importing .ics formatted files `[coming in v2.0]` You can import an .ics file into the planner. -Format: `import FILENAME` +Format: `import filename` +[NOTE] +==== +The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. The file to be imported has to be located in the PlanMySem main directory.+ +{zwsp} +==== +[WARNING] +For .ics files that are created from other calendar applications, events with recurrence will not be recursed in our +application. Events that are outside of the current school semester will also not be imported. + {zwsp} {zwsp} @@ -437,6 +446,10 @@ image::Export_Command_Output_1.png[width="420"] The exported file is named "PlanMySem.ics" and is saved in the main directory. The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. + +==== +[WARNING] +Exporting will REMOVE all tags in the planner. + [#img-exportFile] .[.underline]#Location of PlanMySem.ics file# image::Export_Command_Directory_1.png[width="790"] diff --git a/src/planmysem/storage/StorageFile.java b/src/planmysem/storage/StorageFile.java index bf3734ef4..60d22a2a7 100644 --- a/src/planmysem/storage/StorageFile.java +++ b/src/planmysem/storage/StorageFile.java @@ -35,7 +35,7 @@ public class StorageFile implements Storage { */ public final Path path; private final JAXBContext jaxbContext; - private final boolean isEncrypted = false; //set to true to encrypt model + private final boolean isEncrypted = true; //set to true to encrypt model /** * @throws InvalidStorageFilePathException if the default path is invalid diff --git a/test/java/planmysem/logic/Commands/ExportCommandTest.java b/test/java/planmysem/logic/Commands/ExportCommandTest.java new file mode 100644 index 000000000..76cbfbcb5 --- /dev/null +++ b/test/java/planmysem/logic/Commands/ExportCommandTest.java @@ -0,0 +1,35 @@ +package planmysem.logic.Commands; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import planmysem.common.Clock; +import planmysem.model.Model; +import planmysem.model.ModelManager; +import planmysem.model.semester.IcsSemester; + +public class ExportCommandTest { + private Model model = new ModelManager(); + + @Before + public void setup() { + Clock.set("2019-01-14T10:00:00Z"); + } + + @Test + public void execute_export_success() throws IOException { + IcsSemester semester = new IcsSemester(model.getPlanner().getSemester()); + String expectedIcs = readFile("test/data/ImportExportTest/exportTest.ics"); + String actualIcs = semester.toString(); + Assert.assertEquals(actualIcs, expectedIcs); + } + + static String readFile(String path) throws IOException { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded); + } +} diff --git a/test/java/planmysem/logic/parser/ParserManagerTest.java b/test/java/planmysem/logic/parser/ParserManagerTest.java index 5f38ec9fe..4975ff5a9 100644 --- a/test/java/planmysem/logic/parser/ParserManagerTest.java +++ b/test/java/planmysem/logic/parser/ParserManagerTest.java @@ -16,7 +16,10 @@ import planmysem.logic.commands.DeleteCommand; import planmysem.logic.commands.EditCommand; import planmysem.logic.commands.ExitCommand; +import planmysem.logic.commands.ExportCommand; import planmysem.logic.commands.HelpCommand; +import planmysem.logic.commands.ImportCommand; +import planmysem.logic.commands.ListCommand; import planmysem.model.recurrence.Recurrence; import planmysem.model.slot.Slot; @@ -163,6 +166,17 @@ public void parseCommand_exit() throws Exception { assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand); assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand); } + + @Test + public void parseCommand_export() throws Exception { + assertTrue(parser.parseCommand(ExportCommand.COMMAND_WORD) instanceof ExportCommand); + assertTrue(parser.parseCommand(ExportCommand.COMMAND_WORD + " 3") instanceof ExportCommand); + } + + @Test + public void parseCommand_import() throws Exception { + assertTrue(parser.parseCommand(ImportCommand.COMMAND_WORD + " /test/data/ImportExportTest/importTest.ics\"") instanceof ImportCommand); + } // // @Test // public void parseCommand_find() throws Exception { diff --git a/test/java/planmysem/storage/EncryptorTest.java b/test/java/planmysem/storage/EncryptorTest.java index 3811741a5..b2c3ff8a2 100644 --- a/test/java/planmysem/storage/EncryptorTest.java +++ b/test/java/planmysem/storage/EncryptorTest.java @@ -1,4 +1,4 @@ -/*package planmysem.storage; +package planmysem.storage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -8,15 +8,14 @@ public class EncryptorTest { @Test - public void encrypt_Valid() { + public void encrypt_valid() { String testString = Encryptor.encrypt("Hello World!"); assertNotEquals(testString, "HellO World!"); - } + } @Test - public void decrypt_Valid() { + public void decrypt_valid() { String testString = Encryptor.encrypt("Hello World!"); assertEquals(Encryptor.decrypt(testString), "Hello World!"); } } -*/ From ec4838b209599587d17256052a09bbc34b011507 Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Tue, 2 Apr 2019 00:02:50 +0800 Subject: [PATCH 07/11] junit test bug fix --- test/java/planmysem/logic/Commands/ExportCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/java/planmysem/logic/Commands/ExportCommandTest.java b/test/java/planmysem/logic/Commands/ExportCommandTest.java index 76cbfbcb5..8a179fb26 100644 --- a/test/java/planmysem/logic/Commands/ExportCommandTest.java +++ b/test/java/planmysem/logic/Commands/ExportCommandTest.java @@ -23,7 +23,7 @@ public void setup() { @Test public void execute_export_success() throws IOException { IcsSemester semester = new IcsSemester(model.getPlanner().getSemester()); - String expectedIcs = readFile("test/data/ImportExportTest/exportTest.ics"); + String expectedIcs = new String("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nEND:VCALENDAR\r\n"); String actualIcs = semester.toString(); Assert.assertEquals(actualIcs, expectedIcs); } From 56012661d98161a1bea891dc81999eb216439862 Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Tue, 2 Apr 2019 21:55:51 +0800 Subject: [PATCH 08/11] code cleanup --- src/planmysem/storage/Encryptor.java | 12 ++----- src/planmysem/storage/KeyStorage.java | 49 ++++++++++++++++---------- src/planmysem/storage/StorageFile.java | 6 ++-- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/planmysem/storage/Encryptor.java b/src/planmysem/storage/Encryptor.java index 17b0ced41..24836e4d3 100644 --- a/src/planmysem/storage/Encryptor.java +++ b/src/planmysem/storage/Encryptor.java @@ -45,10 +45,8 @@ public static String encrypt(String toEncrypt) { return DatatypeConverter.printBase64Binary(encryptedIvAndText); } catch (Exception ex) { - ex.printStackTrace(); + return null; } - - return null; } /** @@ -80,13 +78,9 @@ public static String decrypt(String toDecrypt) { cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec); byte[] decryptedData = cipher.doFinal(encryptedBytes); - return new String(decryptedData); - - } catch (Exception ex) { - ex.printStackTrace(); + } catch (Exception e) { + return null; } - - return null; } } diff --git a/src/planmysem/storage/KeyStorage.java b/src/planmysem/storage/KeyStorage.java index eae620f2a..110c76a58 100644 --- a/src/planmysem/storage/KeyStorage.java +++ b/src/planmysem/storage/KeyStorage.java @@ -1,10 +1,12 @@ package planmysem.storage; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.security.KeyStore; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; @@ -14,12 +16,13 @@ */ public class KeyStorage { + private static char[] password = "password".toCharArray(); + /** * Loads the secret key from the key store. */ public static SecretKey load () throws Exception { - char[] password = "password".toCharArray(); //Initialize keystore. KeyStore ks = KeyStore.getInstance("JCEKS"); SecretKey secretKey; @@ -27,27 +30,35 @@ public static SecretKey load () throws Exception { ks.load(new FileInputStream("KeyStorage.jceks"), password); secretKey = (SecretKey) ks.getKey("secret-key", password); - } catch (FileNotFoundException ex) { + } catch (IOException | CertificateException | UnrecoverableKeyException ex) { + secretKey = generateSecretKey(); + } + return secretKey; + } - //Generates key. - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - secretKey = keyGen.generateKey(); + /** + * Generates a SecretKey and saves it into a KeyStorage.jceks file. + */ + private static SecretKey generateSecretKey() throws Exception { + //Initialize keystore. + KeyStore ks = KeyStore.getInstance("JCEKS"); - //Save key. - KeyStore.SecretKeyEntry secret = new KeyStore.SecretKeyEntry(secretKey); - KeyStore.ProtectionParameter passwordParam = new KeyStore.PasswordProtection(password); - ks.load(null, null); - ks.setEntry("secret-key", secret, passwordParam); + //Generates key. + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + SecretKey secretKey = keyGen.generateKey(); - FileOutputStream fos = new FileOutputStream("KeyStorage.jceks"); - ks.store(fos, password); + //Save key. + KeyStore.SecretKeyEntry secret = new KeyStore.SecretKeyEntry(secretKey); + KeyStore.ProtectionParameter passwordParam = new KeyStore.PasswordProtection(password); + ks.load(null, null); + ks.setEntry("secret-key", secret, passwordParam); + + FileOutputStream fos = new FileOutputStream("KeyStorage.jceks"); + ks.store(fos, password); - } catch (Exception ex) { - ex.printStackTrace(); - return null; - } return secretKey; } - } + + diff --git a/src/planmysem/storage/StorageFile.java b/src/planmysem/storage/StorageFile.java index 60d22a2a7..40e094798 100644 --- a/src/planmysem/storage/StorageFile.java +++ b/src/planmysem/storage/StorageFile.java @@ -12,6 +12,8 @@ import java.nio.file.Path; import java.nio.file.Paths; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -120,8 +122,8 @@ public Planner load() throws StorageOperationException { * 'normal' situation (i.e. not truly exceptional) we should not use an exception to handle it. */ - // create empty file if not found or is empty - } catch (FileNotFoundException | NullPointerException ex) { + // create empty planner if not found or is empty. + } catch (FileNotFoundException | NullPointerException e) { final Planner empty = new Planner(); save(empty); return empty; From 6eb0d67a319d627dda634a429bc01f6713f1958c Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Tue, 2 Apr 2019 21:56:24 +0800 Subject: [PATCH 09/11] update documentation and PPP --- docs/UserGuide.adoc | 6 +- docs/team/macchazuki.adoc | 141 +++++++++++++++++++++++++++++--------- 2 files changed, 111 insertions(+), 36 deletions(-) diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index e64390823..bd4dada9f 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -417,7 +417,7 @@ Planner data is automatically encrypted before saving and decrypted before loadi {zwsp} [[import]] -=== Importing .ics formatted files `[coming in v2.0]` +=== Importing .ics formatted files 'import filename' You can import an .ics file into the planner. Format: `import filename` [NOTE] @@ -588,7 +588,7 @@ Commands to view _slots_: {zwsp} === Import/Exporting the Planner -Commands to view _slots_: +Commands: [width="100%",cols="20%,<30%,<20%,<30",options="header"] |======================================================================= |Task |Purpose |Command |Example @@ -596,7 +596,7 @@ Commands to view _slots_: |_<>_ |Export all your slots into a .ics file| `export` | `export` |_<>_ |Import into your planner from a .ics file | -`import` | `import` +`import` | `import PlanMySem.ics` |======================================================================= {zwsp} diff --git a/docs/team/macchazuki.adoc b/docs/team/macchazuki.adoc index 744b1f181..70d2ecd9b 100644 --- a/docs/team/macchazuki.adoc +++ b/docs/team/macchazuki.adoc @@ -7,47 +7,92 @@ --- -== Overview +== About the project -AddressBook - Level 4 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. +My team and I were tasked with enhancing a basic command line interface addressbook for our +Software Engineering project. We chose to morph it into a student planner for NUS students. This planner is automatically synchronised according to the NUS academic calendar for the current semester and enables easy creation, editing and deleting of items. -== Summary of contributions +Special weeks such as recess week and reading week are taken into account within our unique recursion system. +This allows NUS students to easily keep track of school related matters such as classes, deadlines and examinations. +Items can also be efficiently managed via the intuitive tagging system. +{zwsp} -* *Major enhancement*: added *the ability to undo/redo previous commands* -** What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. -** Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. -** Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. -** Credits: _{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}_ +{zwsp} -* *Minor enhancement*: added a history command that allows the user to navigate to previous commands using up/down keys. +== Summary of contributions -* *Code contributed*: [https://github.com[Functional code]] [https://github.com[Test code]] _{give links to collated code files}_ +* *Major enhancement 1*: I added the ability to *import .ics files* +** What it does: allows the user to import .ics files obtained from this or other applications. +[NOTE] +.ics stands for a iCalendar file format. .ics files are one of the most commonly used calendar formats in applications such as Google Calendar and Outlook. +** Justification: This feature improves the product significantly because the user can import existing appointments on other calendar applications into PlanMySem, allowing him to combine external appointments with his school schedule. +** Highlights: This enhancement works with existing as well as future commands. In particular, this enhancement works hand-in-hand with 2 features that I will go into detail later: exporting and data and encryption. +An in-depth analysis of the add command was necessary to understand how slots are added into our planner as I had to add multiple slots into the planner at once. +* *Code contributed*: [https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/src/planmysem/logic/commands/ImportCommand.java] +{zwsp} + +* *Major enhancement 2*: I added the ability to *export .ics files* +** What it does: allows the user to export .ics files from the planner ** What it does: allows the user to export .ics files from the planner +** Justification: This feature improves the product because the user can export current slots in the planner and merge them into other calendar applications. The user can also export the .ics file to be imported across devices. +** Highlights: This enhancement works with existing as well as future commands. In particular, this enhancement works hand-in-hand with the import feature described above. This allows the user to export a file that can be imported into PlanMySem on another device. +This enhancement also allows the user to obtain a readable file as the data will be encrypted (discussed later). + +An in-depth analysis of how the planner stores slots was necessary in order to extract their details to be exported. +* *Code contributed*: [https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/src/planmysem/logic/commands/ExportCommand.java] +{zwsp} + +* *Major enhancement 3*: I added data encryption of the storage file. +** What it does: the planner automatically encrypts the data before saving it into a .txt file. This data is then decrypted before being loaded by the application. +** Justification: This feature improves the product because the user's schedule data will not be able to easily obtained by others. +** Highlights: This enhancement works with existing as well as future commands. In particular, this enhancement works hand-in-hand with the import and export functions. As we have decided to encrypt the raw data file, the user will not be able to obtain the raw data of his planner. + +As a result, the export function allows the user to obtain a read-able text file when he wishes to. + +This enhancement also allows the user to obtain a readable file as the data will be encrypted (discussed later). + +An in-depth analysis of how the planner data is stored was necessary to identify where encryption and decryption should be done on the data. Also, a general understanding of ciphers and data encryption was necessary in implementation of this enhancement. + +* *Code contributed*: [https://github.com/CS2113-AY1819S2-T08-3/main/tree/master/src/planmysem/storage] * *Other contributions*: -** Project management: -*** Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub -** Enhancements to existing features: -*** Updated the GUI color scheme (Pull requests https://github.com[#33], https://github.com[#34]) -*** Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests https://github.com[#36], https://github.com[#38]) ** Documentation: -*** Did cosmetic tweaks to existing contents of the User Guide: https://github.com[#14] -** Community: -*** PRs reviewed (with non-trivial review comments): https://github.com[#12], https://github.com[#32], https://github.com[#19], https://github.com[#42] -*** Contributed to forum discussions (examples: https://github.com[1], https://github.com[2], https://github.com[3], https://github.com[4]) -*** Reported bugs and suggestions for other teams in the class (examples: https://github.com[1], https://github.com[2], https://github.com[3]) -*** Some parts of the history feature I added was adopted by several other class mates (https://github.com[1], https://github.com[2]) -** Tools: -*** Integrated a third party library (Natty) to the project (https://github.com[#42]) -*** Integrated a new Github plugin (CircleCI) to the team repo - -_{you can add/remove categories in the list above}_ +*** Wrote Use Cases on the Developer Guide: [https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/DeveloperGuide.adoc] == Contributions to the User Guide |=== -|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/UserGuide.adoc#encrypt + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/UserGuide.adoc#import + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/UserGuide.adoc#export + + +Below is an example of my contributions for the import and export features. + + +{zwsp} +[[import]] +Importing .ics formatted files 'import filename' + +You can import an .ics file into the planner. +Format: `import filename` + +[NOTE] + +The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. The file to be imported has to be located in the PlanMySem main directory. + + +{zwsp} +[WARNING] + +For .ics files that are created from other calendar applications, events with recurrence will not be recursed in our +application. Events that are outside of the current school semester will also not be imported. + +{zwsp} + +[[export]] +Exporting .ics formatted files: `export` + +You can export the planner as a .ics file. + + +[NOTE] + +The exported file is named "PlanMySem.ics" and is saved in the main directory. +The .ics file can be imported into other calendar apps that support .ics files such as Google Calendar. + + +[WARNING] + +Exporting will REMOVE all tags in the planner. + + |=== include::../UserGuide.adoc[tag=importICS] @@ -57,16 +102,46 @@ include::../UserGuide.adoc[tag=dataencryption] == Contributions to the Developer Guide |=== -|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/DeveloperGuide.adoc#data-encryption-decryption-feature + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/DeveloperGuide.adoc#data-exporting-exporting-feature + +- https://github.com/CS2113-AY1819S2-T08-3/main/blob/master/docs/DeveloperGuide.adoc#use-cases + + +Below is an example of my contributions in design considerations. + +Data Exporting / Exporting feature + +The user can export the current planner into a .ics file to use in external calendar applications. The .ics file will contain the names of the slots in the SUMMARY field and the descriptions in the DESCRIPTION field. This command automatically exports into the main directory and names the file “PlanMySem.ics”. Future updates can include user input to allow saving the file in another directory and naming the file. + +We have chosen to use the iCalendar format due to its popularity and it’s use in applications such as Google Calendar, Microsoft Outlook and NUSmods. + +In our implementation, we have chosen not to export the tags into the .ics file. This is because iCalendar does not have in-built tag fields. This means that other other applications that import .ics will not be able to use the tags. +{zwsp} + +{zwsp} + +**Aspect: Exporting tags into .ics file.** + +**Alternative 1 (current choice):** Ignore tags when exporting. + +** Pros: Easier to implement as iCalendar does not have in-built tag fields.** + +Cons: Not all the information about the slots will be retained. + +**Reason for choice: We do not have much control over other applications, and importing and exporting .ics within *PlanMySem* can be done using the storageFile .txt file.** + +**Alternative 2:** Use the notes field and a tag identifier to save the tags. + +** Pros: All the information from the semester will be exported.** + +Cons: Requires other applications to be coded to read these tag identifiers and also to store and use the tags in their functions. |=== -include::../DeveloperGuide.adoc[tag=importICS] +include::../DeveloperGuide.adoc[tag=import] include::../DeveloperGuide.adoc[tag=dataencryption] -== PROJECT: PowerPointLabs - ---- +== PROJECT: PlanMySem -_{Optionally, you may include other projects in your portfolio.}_ +--- \ No newline at end of file From 421213d127412ebee7649a65c6224a65870e224d Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Tue, 2 Apr 2019 22:04:58 +0800 Subject: [PATCH 10/11] formatting changes --- docs/team/macchazuki.adoc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/team/macchazuki.adoc b/docs/team/macchazuki.adoc index 70d2ecd9b..392af826b 100644 --- a/docs/team/macchazuki.adoc +++ b/docs/team/macchazuki.adoc @@ -95,10 +95,6 @@ Exporting will REMOVE all tags in the planner. |=== -include::../UserGuide.adoc[tag=importICS] - -include::../UserGuide.adoc[tag=dataencryption] - == Contributions to the Developer Guide |=== @@ -137,11 +133,6 @@ Cons: Not all the information about the slots will be retained. Cons: Requires other applications to be coded to read these tag identifiers and also to store and use the tags in their functions. |=== -include::../DeveloperGuide.adoc[tag=import] - -include::../DeveloperGuide.adoc[tag=dataencryption] - - == PROJECT: PlanMySem --- \ No newline at end of file From f3d341598f44ab2ebb13ba4d5da83a5d3719556e Mon Sep 17 00:00:00 2001 From: Macchazuki Date: Tue, 2 Apr 2019 22:19:01 +0800 Subject: [PATCH 11/11] checkstyle fix --- src/planmysem/storage/StorageFile.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/planmysem/storage/StorageFile.java b/src/planmysem/storage/StorageFile.java index 40e094798..a9bf7828a 100644 --- a/src/planmysem/storage/StorageFile.java +++ b/src/planmysem/storage/StorageFile.java @@ -12,8 +12,6 @@ import java.nio.file.Path; import java.nio.file.Paths; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller;