diff --git a/doc/Note App Class Diagram.png b/doc/Note App Class Diagram.png new file mode 100644 index 0000000..76db85f Binary files /dev/null and b/doc/Note App Class Diagram.png differ diff --git a/doc/NoteAppPrjReview.smproj b/doc/NoteAppPrjReview.smproj new file mode 100644 index 0000000..f5387d6 Binary files /dev/null and b/doc/NoteAppPrjReview.smproj differ diff --git a/doc/Project Review.pdf b/doc/Project Review.pdf new file mode 100644 index 0000000..4289785 Binary files /dev/null and b/doc/Project Review.pdf differ diff --git a/pom.xml b/pom.xml index dd48a91..4a2bbfa 100644 --- a/pom.xml +++ b/pom.xml @@ -10,6 +10,11 @@ 21 + + com.itextpdf + itextpdf + 5.5.13.3 + com.mailjet mailjet-client diff --git a/src/main/java/com/noteapp/common/service/CausedBySystemException.java b/src/main/java/com/noteapp/common/service/CausedBySystemException.java new file mode 100644 index 0000000..028ec01 --- /dev/null +++ b/src/main/java/com/noteapp/common/service/CausedBySystemException.java @@ -0,0 +1,22 @@ +package com.noteapp.common.service; + +/** + * Đại diện cho các ngoại lệ gây ra bởi hệ thống NoteApp + * @author Nhóm 17 + */ +public class CausedBySystemException extends NoteAppServiceException { + protected static final String DEFAULT_NOTIFY = "Caused by NoteApp System"; + + public CausedBySystemException(String message) { + super(DEFAULT_NOTIFY + message); + } + + public CausedBySystemException(String message, Throwable cause) { + super(DEFAULT_NOTIFY + message, cause); + } + + public CausedBySystemException(Throwable cause) { + super(DEFAULT_NOTIFY, cause); + } + +} diff --git a/src/main/java/com/noteapp/common/service/CausedByUserException.java b/src/main/java/com/noteapp/common/service/CausedByUserException.java new file mode 100644 index 0000000..922c5e6 --- /dev/null +++ b/src/main/java/com/noteapp/common/service/CausedByUserException.java @@ -0,0 +1,21 @@ +package com.noteapp.common.service; + +/** + * Đại diện cho các ngoại lệ gây ra bởi người dùng khi sử dụng hệ thống NoteApp + * @author Nhóm 17 + */ +public class CausedByUserException extends NoteAppServiceException { + + public CausedByUserException(String message) { + super(message); + } + + public CausedByUserException(String message, Throwable cause) { + super(message, cause); + } + + public CausedByUserException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/noteapp/common/service/NoteAppService.java b/src/main/java/com/noteapp/common/service/NoteAppService.java new file mode 100644 index 0000000..2ef3601 --- /dev/null +++ b/src/main/java/com/noteapp/common/service/NoteAppService.java @@ -0,0 +1,102 @@ +package com.noteapp.common.service; + +import com.noteapp.note.service.INoteService; +import com.noteapp.note.service.IShareNoteService; +import com.noteapp.note.service.io.FileIOService; +import com.noteapp.user.service.IAdminService; +import com.noteapp.user.service.IUserService; +import com.noteapp.user.service.security.VerificationMailService; + +/** + * Cung cấp các service ở mức tổng quan của NoteApp System + * @author Nhóm 17 + * @see IUserService + * @see IAdminService + * @see INoteService + * @see IShareNoteService + * @see VerificationMailService + * @see FileIOService + */ +public class NoteAppService { + private IUserService userService; + private IAdminService adminService; + private INoteService noteService; + private IShareNoteService shareNoteService; + private VerificationMailService verificationMailService; + private FileIOService fileIOService; + + public NoteAppService() { + userService = null; + adminService = null; + noteService = null; + shareNoteService = null; + verificationMailService = null; + fileIOService = null; + } + + public IUserService getUserService() throws NoteAppServiceException { + if (userService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return userService; + } + + public void setUserService(IUserService userService) { + this.userService = userService; + } + + public IAdminService getAdminService() throws NoteAppServiceException { + if (adminService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return adminService; + } + + public void setAdminService(IAdminService adminService) { + this.adminService = adminService; + } + + public INoteService getNoteService() throws NoteAppServiceException { + if (noteService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return noteService; + } + + public void setNoteService(INoteService noteService) { + this.noteService = noteService; + } + + public IShareNoteService getShareNoteService() throws NoteAppServiceException { + if (shareNoteService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return shareNoteService; + } + + public void setShareNoteService(IShareNoteService shareNoteService) { + this.shareNoteService = shareNoteService; + } + + public VerificationMailService getVerificationMailService() throws NoteAppServiceException { + if (verificationMailService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return verificationMailService; + } + + public void setVerificationMailService(VerificationMailService verificationMailService) { + this.verificationMailService = verificationMailService; + } + + public FileIOService getFileIOService() throws NoteAppServiceException { + if (fileIOService == null) { + throw new CausedBySystemException("Service has not inited!"); + } + return fileIOService; + } + + public void setFileIOService(FileIOService fileIOService) { + this.fileIOService = fileIOService; + } +} diff --git a/src/main/java/com/noteapp/common/service/NoteAppServiceException.java b/src/main/java/com/noteapp/common/service/NoteAppServiceException.java new file mode 100644 index 0000000..50e0037 --- /dev/null +++ b/src/main/java/com/noteapp/common/service/NoteAppServiceException.java @@ -0,0 +1,22 @@ +package com.noteapp.common.service; + +/** + * Đại diện cho tất cả các ngoại lệ có thể xảy ra khi sử dụng dịch vụ + * của hệ thống NoteApp + * @author Nhóm 17 + */ +public class NoteAppServiceException extends Exception { + + public NoteAppServiceException(String message) { + super(message); + } + + public NoteAppServiceException(String message, Throwable cause) { + super(message, cause); + } + + public NoteAppServiceException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/noteapp/controller/AdminDashboardController.java b/src/main/java/com/noteapp/controller/AdminDashboardController.java new file mode 100644 index 0000000..5371505 --- /dev/null +++ b/src/main/java/com/noteapp/controller/AdminDashboardController.java @@ -0,0 +1,144 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.AdminDAO; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.service.AdminService; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +/** + * Controller cho view Dashboard của Admin + * @author admin + */ +public class AdminDashboardController extends RequestServiceController implements Initable { + @FXML + private Button viewUsersButton; + @FXML + private TextField searchUserField; + @FXML + private VBox userCardLayout; + @FXML + private Button closeButton; + @FXML + private Button logoutButton; + + private Map lockedStatusOfUsers; + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setAdminService(new AdminService(UserDAO.getInstance(), AdminDAO.getInstance())); + initView(); + closeButton.setOnAction((ActionEvent event) -> { + close(); + }); + logoutButton.setOnAction((ActionEvent event) -> { + LoginController.open(stage); + }); + viewUsersButton.setOnAction((ActionEvent event) -> { + initView(); + }); + searchUserField.setOnAction((ActionEvent event) -> { + searchUser(); + }); + } + + protected void initView() { + try { + lockedStatusOfUsers = noteAppService.getAdminService().getAllLockedStatus(); + loadUsers(lockedStatusOfUsers); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + private void saveLockedStatus(String username, boolean lockedStatus) { + try { + noteAppService.getAdminService().updateLockedStatus(username, lockedStatus); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Tải thông tin về các User và trạng thái Locked của họ vào + * một danh sách có thể hiển thị trên màn hình + * @param lockedStatusOfUsers Một Map lưu giữ trạng thái Locked của mỗi User + * @see userCardLayout + * @see UserItemController + */ + protected void loadUsers(Map lockedStatusOfUsers) { + userCardLayout.getChildren().clear(); + if (lockedStatusOfUsers.isEmpty()) { + return; + } + String filePath = Controller.DEFAULT_FXML_RESOURCE + "UserItemView.fxml"; + //Load từng user vào UserItemController + for (Map.Entry entry: lockedStatusOfUsers.entrySet()) { + String username = entry.getKey(); + boolean isLocked = entry.getValue(); + try { + UserItemController controller = new UserItemController(); + HBox box = controller.loadFXML(filePath); + controller.setData(username, isLocked); + //Thêm action cho nút đổi trạng thái lock + controller.getChangeLockStatusButton().setOnAction((ActionEvent event) -> { + controller.changeLockedStatus(); + String thisUsername = controller.getUsername(); + boolean thisLockedStatus = controller.isLocked(); + this.lockedStatusOfUsers.put(thisUsername, thisLockedStatus); + saveLockedStatus(thisUsername, thisLockedStatus); + }); + userCardLayout.getChildren().add(box); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can load user items"); + } + } + } + + /** + * Thực hiện tìm kiếm user có username chứa chuỗi được nhập vào + * {@link searchUserField} và load lại danh sách hiển thị những + * user khớp với yêu cầu + */ + protected void searchUser() { + String searchText = searchUserField.getText(); + Map searchUsers = new HashMap<>(); + for (Map.Entry entry: lockedStatusOfUsers.entrySet()) { + String username = entry.getKey(); + boolean isLocked = entry.getValue(); + if (username.contains(searchText)) { + searchUsers.put(username, isLocked); + } + } + loadUsers(searchUsers); + } + + /** + * Mở một giao diện Dashboard cho Admin + * @param stage Stage được truyền vào để chứa giao diện này + */ + public static void open(Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "AdminDashboardView.fxml"; + AdminDashboardController controller = new AdminDashboardController(); + controller.setStage(stage); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open admin dashboard"); + } + } +} diff --git a/src/main/java/com/noteapp/controller/DashboardController.java b/src/main/java/com/noteapp/controller/DashboardController.java new file mode 100644 index 0000000..8b2f213 --- /dev/null +++ b/src/main/java/com/noteapp/controller/DashboardController.java @@ -0,0 +1,678 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.dao.NoteBlockDAO; +import com.noteapp.note.dao.NoteDAO; +import com.noteapp.note.dao.NoteFilterDAO; +import com.noteapp.note.dao.ShareNoteDAO; +import com.noteapp.note.dao.SurveyBlockDAO; +import com.noteapp.note.dao.TextBlockDAO; +import com.noteapp.user.model.Email; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.NoteBlock; +import com.noteapp.note.model.NoteFilter; +import com.noteapp.note.model.ShareNote; +import com.noteapp.note.model.TextBlock; +import com.noteapp.note.service.NoteService; +import com.noteapp.user.model.User; +import com.noteapp.note.service.ShareNoteService; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.service.UserService; +import java.io.IOException; +import java.sql.Date; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ChoiceDialog; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextField; +import javafx.scene.control.TextInputDialog; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +/** + * FXML Controller class cho Dashboard của User + * @author Nhóm 17 + */ +public class DashboardController extends RequestServiceController implements Initable { + //Các thuộc tính FXML của form dashboard chung + @FXML + private BorderPane extraServiceScene; + @FXML + private VBox mainScene; + //Các thuộc tính chung + @FXML + private Label userLabel; + @FXML + private Button closeButton; + @FXML + private Button logoutButton; + @FXML + private Button backMainSceneButton; + @FXML + private Button myNotesButton; + @FXML + private Button myAccountButton; + @FXML + private Button homeButton; + //Các thuộc tính của myNotesScene + @FXML + private AnchorPane myNotesScene; + @FXML + private TextField searchNoteField; + @FXML + private VBox noteCardLayout; + @FXML + private Button createNoteButton; + @FXML + private Button deleteNoteButton; + //Các thuộc tính của myAccountScene + @FXML + private AnchorPane myAccountScene; + @FXML + private TextField usernameField; + @FXML + private PasswordField passwordField; + @FXML + private TextField emailAddressField; + @FXML + private TextField nameField; + @FXML + private TextField dayOfBirthField; + @FXML + private TextField monthOfBirthField; + @FXML + private TextField yearOfBirthField; + @FXML + private TextField schoolField; + @FXML + private RadioButton genderMale; + @FXML + private RadioButton genderFemale; + @FXML + private RadioButton genderOther; + @FXML + private Label errorEmailFieldLabel; + @FXML + private Label errorNameFieldLabel; + @FXML + private Label errorPasswordFieldLabel; + @FXML + private Label errorBirthdayFieldLabel; + @FXML + private Button changePasswordButton; + @FXML + private Button saveAccountButton; + + @FXML + private FlowPane recentlyVisitedLayout; + @FXML + private AnchorPane homeScene; + @FXML + private StackPane stackLayout; + + private User myUser; + private Note currentNote; + private List myNotes; + private List myReceivedNotes; + private List openedNotes; + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setUserService(new UserService(UserDAO.getInstance())); + noteAppService.setNoteService(new NoteService(NoteDAO.getInstance(), NoteFilterDAO.getInstance(), + NoteBlockDAO.getInstance(), TextBlockDAO.getInstance(), SurveyBlockDAO.getInstance())); + noteAppService.setShareNoteService(new ShareNoteService(ShareNoteDAO.getInstance(), + NoteDAO.getInstance(), NoteFilterDAO.getInstance(), + NoteBlockDAO.getInstance(), TextBlockDAO.getInstance(), SurveyBlockDAO.getInstance())); + initView(); + closeButton.setOnAction((ActionEvent event) -> { + super.close(); + }); + //Switch + myNotesButton.setOnAction((ActionEvent event) -> { + changeSceneInExtraScene(myNotesButton); + try { + myNotes = noteAppService.getNoteService().getAll(myUser.getUsername()); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + myNotes = new ArrayList<>(); + } + //Lấy tất cả các note được share tới myUser này + try { + myReceivedNotes = noteAppService.getShareNoteService().getAllReceived(myUser.getUsername()); + } catch (NoteAppServiceException ex) { + myReceivedNotes = new ArrayList<>(); + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + initMyNotesScene(myNotes, myReceivedNotes); + }); + myAccountButton.setOnAction((ActionEvent event) -> { + changeSceneInExtraScene(myAccountButton); + initMyAccountScene(myUser); + }); + homeButton.setOnAction((ActionEvent event) -> { + changeSceneInExtraScene(homeButton); + try { + myNotes = noteAppService.getNoteService().getAll(myUser.getUsername()); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + myNotes = new ArrayList<>(); + } + initHomeScene(myNotes); + }); + //My Note Scene + searchNoteField.setOnAction((ActionEvent event) -> { + searchNote(); + }); + createNoteButton.setOnAction((ActionEvent event) -> { + createNote(); + }); + deleteNoteButton.setOnAction((ActionEvent event) -> { + deleteNote(); + }); + //My Account Scene + changePasswordButton.setOnAction((ActionEvent event) -> { + changePassword(); + }); + saveAccountButton.setOnAction((ActionEvent event) -> { + saveAccount(); + }); + + //Other + backMainSceneButton.setOnAction((ActionEvent event) -> { + if (currentNote.isDefaultValue()) { + showAlert(Alert.AlertType.ERROR, "No note has chosen!"); + return; + } + if (!currentNote.isPubliced()) { + EditNoteController.open(myUser, currentNote, openedNotes, stage); + } else { + EditShareNoteController.open(myUser, (ShareNote) currentNote, openedNotes, stage); + } + }); + logoutButton.setOnAction((ActionEvent event) -> { + LoginController.open(stage); + }); + } + + protected void initView() { + userLabel.setText(myUser.getName()); + try { + myNotes = noteAppService.getNoteService().getAll(myUser.getUsername()); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + myNotes = new ArrayList<>(); + } + initHomeScene(myNotes); + changeSceneInExtraScene(homeButton); + } + + private void openNote(int noteId, Optional optional) { + if(optional.get() == ButtonType.OK) { + try { + currentNote = noteAppService.getNoteService().open(noteId); + if (!openedNotes.contains(currentNote)) { + openedNotes.add(currentNote); + } + if (currentNote.isPubliced()) { + currentNote = noteAppService.getShareNoteService().open(noteId, myUser.getUsername()); + EditShareNoteController.open(myUser, (ShareNote) currentNote, openedNotes, stage); + } else { + EditNoteController.open(myUser, currentNote, openedNotes, stage); + } + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + } + + /** + * Khởi tạo Scene My Notes, chứa danh sách các Note mà User sở hữu hoặc các + * Note được chia sẻ tới User này + * @param notes Danh sách các Note mà User sở hữu + * @param shareNotes Danh sách các Note được chia sẻ tới User này + */ + protected void initMyNotesScene(List notes, List shareNotes) { + //Làm sạch layout + noteCardLayout.getChildren().clear(); + if(notes.isEmpty() || shareNotes.isEmpty()) { + return; + } + //Load các Note Card + String filePath = Controller.DEFAULT_FXML_RESOURCE + "NoteCardView.fxml"; + for(int i=0; i < notes.size(); i++) { + //Load Note Card Layout + try { + //Thiết lập dữ liệu cho Note Card + NoteCardController controller = new NoteCardController(); + + HBox box = controller.loadFXML(filePath); + Note note = notes.get(i); + controller.setData(note); + //Xử lý khi nhấn vào note card + box.setOnMouseClicked((MouseEvent event) -> { + //Tạo thông báo và mở note nếu chọn OK + Optional optional = showAlert(Alert.AlertType.CONFIRMATION, + "Open " + controller.getHeader()); + openNote(controller.getId(), optional); + }); + //Thêm Note Card vào layout + noteCardLayout.getChildren().add(box); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can load note!"); + } + } + for(int i=0; i < shareNotes.size(); i++) { + //Load Note Card Layout + if (shareNotes.get(i).getAuthor().equals(myUser.getUsername())) { + continue; + } + try { + //Thiết lập dữ liệu cho Note Card + NoteCardController controller = new NoteCardController(); + + HBox box = controller.loadFXML(filePath); + controller.setData(shareNotes.get(i)); + //Xử lý khi nhấn vào note card + box.setOnMouseClicked((MouseEvent event) -> { + //Tạo thông báo và mở note nếu chọn OK + Optional optional = showAlert(Alert.AlertType.CONFIRMATION, + "Open " + controller.getHeader()); + openNote(controller.getId(), optional); + }); + //Thêm Note Card vào layout + noteCardLayout.getChildren().add(box); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can load note!"); + } + } + } + + /** + * Khởi tạo Scene Home + * @param recentlyNotes Các Note được truy cập gần nhất + */ + protected void initHomeScene(List recentlyNotes) { + recentlyVisitedLayout.getChildren().clear(); + if (recentlyNotes.isEmpty()) { + return; + } + if (recentlyNotes.size() > 3) { + recentlyNotes = recentlyNotes.subList(0, 3); + } + String filePath = Controller.DEFAULT_FXML_RESOURCE + "RecentlyNoteCardView.fxml"; + for (Note note: recentlyNotes) { + try { + RecentlyNoteCardController controller = new RecentlyNoteCardController(); + VBox box = controller.loadFXML(filePath); + controller.setNote(note); + box.setOnMouseClicked((event) -> { + Optional optional = showAlert(Alert.AlertType.CONFIRMATION, + "Open " + controller.getNote().getHeader()); + openNote(controller.getNote().getId(), optional); + }); + recentlyVisitedLayout.getChildren().add(box); + } catch (IOException ex) { + } + } + } + + /** + * Khởi tạo scene hiển thị các thông tin của User + * @param user User đang đăng nhập + */ + protected void initMyAccountScene(User user) { + //Thiết lập các thuộc tính + usernameField.setText(user.getUsername()); + usernameField.setEditable(false); + passwordField.setText(user.getPassword()); + emailAddressField.setText(user.getEmail().getAddress()); + nameField.setText(user.getName()); + schoolField.setText(user.getSchool()); + dayOfBirthField.setText(String.valueOf(user.getBirthday().toLocalDate().getDayOfMonth())); + monthOfBirthField.setText(String.valueOf(user.getBirthday().toLocalDate().getMonthValue())); + yearOfBirthField.setText(String.valueOf(user.getBirthday().toLocalDate().getYear())); + switch(user.getGender()) { + case User.Gender.MALE -> { + genderMale.setSelected(true); + } + case User.Gender.FEMALE -> { + genderFemale.setSelected(true); + } + case User.Gender.OTHER -> { + genderOther.setSelected(true); + } + } + //Ẩn các error + errorEmailFieldLabel.setVisible(false); + errorBirthdayFieldLabel.setVisible(false); + errorNameFieldLabel.setVisible(false); + errorPasswordFieldLabel.setVisible(false); + } + + public void setMyUser(User myUser) { + this.myUser = myUser; + } + + public void setCurrentNote(Note currentNote) { + this.currentNote = currentNote; + } + + public void setOpenedNotes(List openedNotes) { + this.openedNotes = openedNotes; + } + + private boolean checkMatchSearchText(Note note, String searchText) { + if(note.getHeader().contains(searchText)) { + return true; + } else { + for(NoteFilter noteFilter: note.getFilters()) { + if(noteFilter.getFilter().contains(searchText)) { + return true; + } + } + } + return false; + } + + /** + * Tìm kiếm một note có header hoặc filter chứa văn bản + * đang được nhập vào trong field + * @see searchNoteField + */ + protected void searchNote() { + //Lấy thông tin cần search + String searchText = searchNoteField.getText(); + //Tạo list mới để chứa các note hợp lệ + List notes = new ArrayList<>(); + List shareNotes = new ArrayList<>(); + //Thêm các note hợp lệ vào list + for(Note newNote: myNotes) { + if (checkMatchSearchText(newNote, searchText)) { + notes.add(newNote); + } + } + for (ShareNote newShareNote: myReceivedNotes) { + if (checkMatchSearchText(newShareNote, searchText)) { + shareNotes.add(newShareNote); + } + } + //Load lại My Notes Scene + initMyNotesScene(notes, shareNotes); + } + + protected void createNote() { + //Hiện dialog để nhập header cho Note mới + TextInputDialog dialog = new TextInputDialog(); + dialog.setTitle("Create new note"); + dialog.setHeaderText("Enter header for your new note"); + //Lấy kết quả + Optional confirm = dialog.showAndWait(); + //Xử lý kết quả khi nhấn OK + confirm.ifPresent(selectedHeader -> { + //Set dữ liệu cho note mới + Note newNote = new Note(); + newNote.setAuthor(myUser.getUsername()); + newNote.setHeader(selectedHeader); + newNote.getBlocks().add( + new TextBlock("EditHere", -1, + "B1", myUser.getUsername(), NoteBlock.BlockType.TEXT, 1)); + newNote.setLastModifiedDate(Date.valueOf(LocalDate.now())); + //Tạo Note mới + try { + //Tạo thành công + newNote = noteAppService.getNoteService().create(newNote); + showAlert(Alert.AlertType.INFORMATION, "Successfully create " + newNote.getHeader()); + //Thêm vào list và load lại + myNotes.add(newNote); + initMyNotesScene(myNotes, myReceivedNotes); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + }); + } + + protected void deleteNote() { + //Lấy list các header note + List myNotesHeader = new ArrayList<>(); + for(Note note: myNotes){ + myNotesHeader.add(note.getHeader()); + } + //Hiện dialog để chọn note cần xóa + ChoiceDialog dialog = new ChoiceDialog<>(myNotesHeader.get(0), myNotesHeader); + dialog.setTitle("Delete Note"); + dialog.setHeaderText("Choose note to delete"); + //Lấy kết quả + Optional confirm = dialog.showAndWait(); + //Xử lý kết quả khi nhấn OK + confirm.ifPresent(selectedHeader -> { + //Xóa Note được chọn + try { + //Xóa thành công + Note deletedNote = new Note(); + for(Note note: myNotes) { + if(note.getHeader().equals(selectedHeader)) { + deletedNote = note; + } + } + noteAppService.getNoteService().delete(deletedNote.getId()); + showAlert(Alert.AlertType.INFORMATION, "Successfully delete " + deletedNote.getHeader()); + //Xóa khỏi list và load lại + myNotes.remove(deletedNote); + //Load lại My Notes Scene + initMyNotesScene(myNotes, myReceivedNotes); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + }); + } + + private void getPasswordFromField() { + if("".equals(passwordField.getText())) { + errorPasswordFieldLabel.setVisible(true); + } + myUser.setPassword(passwordField.getText()); + } + + private void getEmailFromField() { + Email email = new Email(); + email.setAddress(emailAddressField.getText()); + if(!email.checkAddress()) { + errorEmailFieldLabel.setVisible(true); + } + myUser.setEmail(email); + } + + private void getBirthdayFromField() { + int dayOfBirth = -1; + int monthOfBirth = -1; + int yearOfBirth = -1; + if(dayOfBirthField.getText().matches("^[0-9]{1,2}$")) { + dayOfBirth = Integer.parseInt(dayOfBirthField.getText()); + } else if("".equals(dayOfBirthField.getText())) { + dayOfBirth = LocalDate.now().getDayOfMonth(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(monthOfBirthField.getText().matches("^[0-9]{1,2}$")) { + monthOfBirth = Integer.parseInt(monthOfBirthField.getText()); + } else if("".equals(monthOfBirthField.getText())) { + monthOfBirth = LocalDate.now().getMonthValue(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(yearOfBirthField.getText().matches("^[0-9]{4}$")) { + yearOfBirth = Integer.parseInt(yearOfBirthField.getText()); + } else if("".equals(yearOfBirthField.getText())) { + yearOfBirth = LocalDate.now().getYear(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(!errorBirthdayFieldLabel.isVisible()) { + myUser.setBirthday(Date.valueOf(LocalDate.of(yearOfBirth, monthOfBirth, dayOfBirth))); + } + } + + private void getNameFromField() { + //Láy thông tin name + if("".equals(nameField.getText())) { + errorNameFieldLabel.setVisible(true); + } + myUser.setName(nameField.getText()); + } + + private void getGenderFromBox() { + if(genderMale.isSelected()) { + myUser.setGender(User.Gender.MALE); + } else if (genderFemale.isSelected()) { + myUser.setGender(User.Gender.FEMALE); + } else { + myUser.setGender(User.Gender.OTHER); + } + } + + private boolean checkErrorAccountInfo() { + return errorNameFieldLabel.isVisible() || errorPasswordFieldLabel.isVisible() + || errorBirthdayFieldLabel.isVisible() || errorEmailFieldLabel.isVisible(); + } + + protected void saveAccount() { + errorEmailFieldLabel.setVisible(false); + errorBirthdayFieldLabel.setVisible(false); + errorNameFieldLabel.setVisible(false); + errorPasswordFieldLabel.setVisible(false); + //Lấy password + getPasswordFromField(); + //Lấy Email + getEmailFromField(); + //Lấy name + getNameFromField(); + //Lấy school + myUser.setSchool(schoolField.getText()); + //Lấy thông tin về birth + getBirthdayFromField(); + //Lấy gender + getGenderFromBox(); + //Kiểm tra xem có lỗi nào không + if(checkErrorAccountInfo()) { + return; + } + //Cập nhật User + try { + //Cập nhật thành công + noteAppService.getUserService().update(myUser); + showAlert(Alert.AlertType.INFORMATION, "Successfully update for " + myUser.getUsername()); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + protected void changePassword() { + //Hiện dialog để nhập mật khẩu cũ + TextInputDialog dialog = new TextInputDialog(); + dialog.setTitle("Change Password"); + dialog.setHeaderText("Enter your present password"); + //Lấy kết quả + Optional confirm = dialog.showAndWait(); + //Xử lý kết quả + confirm.ifPresent(password -> { + //Nếu nhập đúng thì cho phép nhập mật khẩu mới + if(password.equals(myUser.getPassword())) { + passwordField.setEditable(true); + } + }); + } + + /** + * Thay đổi Scene trên dashboard dựa vào việc nút nào đang được bấm + * @param button Nút được bấm + */ + private void changeSceneInExtraScene(Button button) { + String pressedStyle = "-fx-background-color: #1a91b8"; + String unPressedStyle = "-fx-background-color: transparent"; + //init lại + myNotesButton.setStyle(unPressedStyle); + myNotesScene.setVisible(false); + myAccountButton.setStyle(unPressedStyle); + myAccountScene.setVisible(false); + homeButton.setStyle(unPressedStyle); + homeScene.setVisible(false); + //Press button được chọn và chuyển scene tương ứng + if (button == myNotesButton) { + myNotesButton.setStyle(pressedStyle); + myNotesScene.setVisible(true); + } else if (button == myAccountButton) { + myAccountButton.setStyle(pressedStyle); + myAccountScene.setVisible(true); + } else if (button == homeButton) { + homeButton.setStyle(pressedStyle); + homeScene.setVisible(true); + } + } + + /** + * Mở một Dashboard cho User + * @param myUser User đã đăng nhập thành công + * @param stage Stage chứa Dashboard này + */ + public static void open(User myUser, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "DashboardView.fxml"; + + DashboardController controller = new DashboardController(); + + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setCurrentNote(new Note()); + controller.setOpenedNotes(new ArrayList<>()); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open dashboard"); + } + } + + /** + * Mở một Dashboard cho User khi đang Edit + * @param myUser User đang trong phiên đăng nhập + * @param currentNote Note được edit hiện tại + * @param openedNotes Các Note đang được mở + * @param stage Stage chứa Dashboard này + */ + public static void open(User myUser, Note currentNote, List openedNotes, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "DashboardView.fxml"; + + DashboardController controller = new DashboardController(); + + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setOpenedNotes(openedNotes); + controller.setCurrentNote(currentNote); + controller.loadFXMLAndSetScene(filePath); + + controller.init(); + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open dashboard"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/controller/EditNoteController.java b/src/main/java/com/noteapp/controller/EditNoteController.java new file mode 100644 index 0000000..05a05b9 --- /dev/null +++ b/src/main/java/com/noteapp/controller/EditNoteController.java @@ -0,0 +1,670 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.dao.NoteBlockDAO; +import com.noteapp.note.dao.NoteDAO; +import com.noteapp.note.dao.NoteFilterDAO; +import com.noteapp.note.dao.ShareNoteDAO; +import com.noteapp.note.dao.SurveyBlockDAO; +import com.noteapp.note.dao.TextBlockDAO; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.NoteBlock; +import com.noteapp.note.model.NoteFilter; +import com.noteapp.note.model.ShareNote; +import com.noteapp.note.model.SurveyBlock; +import com.noteapp.note.model.TextBlock; +import com.noteapp.note.service.NoteService; +import com.noteapp.user.model.User; +import com.noteapp.note.service.ShareNoteService; +import com.noteapp.note.service.io.PdfIOService; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.service.UserService; +import java.io.File; +import java.io.IOException; +import java.sql.Date; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.control.TextInputDialog; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; +import javafx.stage.Stage; + + +/** + * FXML Controller class cho trang Edit Note + * @author Nhóm 17 + */ +public class EditNoteController extends RequestServiceController implements Initable { + //Các thuộc tính chung + @FXML + protected Label noteHeaderLabel; + @FXML + protected Button homeMenuButton; + @FXML + protected Button editMenuButton; + @FXML + protected HBox editBox; + //Các thuộc tính của edit Box + @FXML + protected Button saveNoteButton; + @FXML + protected Button openNoteButton; + @FXML + protected Button addFilterButton; + @FXML + protected Button addTextBlockButton; + @FXML + protected Button addSurveyBlockButton; + @FXML + protected Button shareButton; + @FXML + protected Button importFileButton; + @FXML + protected Button exportFileButton; + //Các thuộc tính còn lại + @FXML + protected VBox blocksLayout; + @FXML + protected GridPane filterGridLayout; + @FXML + protected Button closeButton; + @FXML + protected HBox openedNotesLayout; + + protected User myUser; + protected Note myNote; + protected List textBlockControllers; + protected List surveyBlockControllers; + protected List openedNotes; + + public void setMyUser(User myUser) { + this.myUser = myUser; + } + + public void setMyNote(Note myNote) { + this.myNote = myNote; + } + + public void setOpenedNotes(List openedNotes) { + this.openedNotes = openedNotes; + } + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setUserService(new UserService(UserDAO.getInstance())); + noteAppService.setNoteService(new NoteService(NoteDAO.getInstance(), NoteFilterDAO.getInstance(), + NoteBlockDAO.getInstance(), TextBlockDAO.getInstance(), SurveyBlockDAO.getInstance())); + noteAppService.setShareNoteService(new ShareNoteService(ShareNoteDAO.getInstance(), + NoteDAO.getInstance(), NoteFilterDAO.getInstance(), + NoteBlockDAO.getInstance(), TextBlockDAO.getInstance(), SurveyBlockDAO.getInstance())); + noteAppService.setFileIOService(new PdfIOService()); + textBlockControllers = new ArrayList<>(); + surveyBlockControllers = new ArrayList<>(); + initView(); + closeButton.setOnAction((ActionEvent event) -> { + close(); + }); + homeMenuButton.setOnAction((ActionEvent event) -> { + DashboardController.open(myUser, myNote, openedNotes, stage); + }); + noteHeaderLabel.setOnMouseClicked((MouseEvent event) -> { + changeHeaderLabel(); + }); + saveNoteButton.setOnAction((ActionEvent event) -> { + saveMyNote(); + }); + addFilterButton.setOnAction((ActionEvent event) -> { + addFilter(); + }); + importFileButton.setOnAction((ActionEvent event) -> { + importFile(); + }); + exportFileButton.setOnAction((ActionEvent event) -> { + exportFile(); + }); + addTextBlockButton.setOnAction((ActionEvent event) -> { + TextBlock newBlock = new TextBlock(); + int maxSize = Integer.max(textBlockControllers.size(), surveyBlockControllers.size()); + newBlock.setOrder(maxSize + 1); + newBlock.setHeader("Block " + newBlock.getOrder() + " of " + myNote.getHeader()); + newBlock.setEditor(myUser.getUsername()); + newBlock.setContent("Edit here"); + addBlock(newBlock); + }); + addSurveyBlockButton.setOnAction((ActionEvent event) -> { + SurveyBlock newBlock = new SurveyBlock(); + int maxSize = Integer.max(textBlockControllers.size(), surveyBlockControllers.size()); + newBlock.setOrder(maxSize + 1); + newBlock.setHeader("SurveyBlock " + newBlock.getOrder() + " of " + myNote.getHeader()); + newBlock.setEditor(myUser.getUsername()); + addBlock(newBlock); + }); + shareButton.setOnAction((ActionEvent event) -> { + shareMyNote(); + }); + } + + protected void initView() { + noteHeaderLabel.setText(myNote.getHeader()); + initOpenedNotes(); + loadFilter(myNote.getFilters(), 8); + initBlock(); + } + + private void openNote(Note needOpenNote) { + if (needOpenNote.isPubliced()) { + try { + ShareNote needOpenShareNote = noteAppService.getShareNoteService().open(needOpenNote.getId(), myUser.getUsername()); + EditShareNoteController.open(myUser, needOpenShareNote, openedNotes, stage); + } catch (NoteAppServiceException e) { + } + } else { + EditNoteController.open(myUser, needOpenNote, openedNotes, stage); + } + + } + + private void addOpenedNotesBox(Note openedNote) throws IOException { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "OpenedNoteCardView.fxml"; + OpenedNoteCardController controller = new OpenedNoteCardController(); + HBox box = controller.loadFXML(filePath); + controller.setNote(openedNote); + controller.setHeader(openedNote.getHeader()); + controller.getRemoveNote().setOnMouseClicked((MouseEvent event) -> { + openedNotes.remove(controller.getNote()); + initOpenedNotes(); + }); + box.getStyleClass().clear(); + if (openedNote.getId() == myNote.getId()) { + box.getStyleClass().add("focused-opened-note-card"); + } else { + box.getStyleClass().add("free-opened-note-card"); + } + box.setOnMouseClicked((MouseEvent event) -> { + Note needOpenNote = controller.getNote(); + openNote(needOpenNote); + }); + openedNotesLayout.getChildren().add(box); + + } + + /** + * Khởi tạo các Note đang được mở, được truyền vào từ dashboard + * @see openNotesLayout + */ + protected void initOpenedNotes() { + openedNotesLayout.getChildren().clear(); + + for (Note openedNote: openedNotes) { + try { + addOpenedNotesBox(openedNote); + } catch (IOException ex) { + } + } + } + + /** + * Khởi tạo các block của Note này, các Block được truyền vào từ CSDL + * @see #addBlock(TextBlock) + * @see #addBlock(SurveyBlock) + */ + protected void initBlock() { + blocksLayout.getChildren().clear(); + List blocks = myNote.getBlocks(); + for(int i=0; i myNotes = noteAppService.getNoteService().getAll(myUser.getUsername()); + for(Note note: myNotes) { + if(note.getHeader().equals(newNoteHeader)) { + showAlert(Alert.AlertType.ERROR, "This header exist"); + return true; + } + } + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + return false; + } + + protected void changeHeaderLabel() { + //Mở dialog + TextInputDialog inputDialog = new TextInputDialog(); + inputDialog.setTitle("Change header for " + myNote.getHeader()); + inputDialog.setHeaderText("Input your new header"); + //Lấy kết quả và xử lý + Optional confirm = inputDialog.showAndWait(); + confirm.ifPresent(newNoteHeader -> { + if (checkExistHeader(newNoteHeader)) return; + noteHeaderLabel.setText(newNoteHeader); + }); + } + + /** + * Lưu Note hiện tại đang chỉnh sửa vào CSDL và thông báo lỗi nếu không lưu được. + * Phương thức này sẽ reset dữ liệu của các block và lấy lại dữ liệu trên + * trang edit hiện tại. + */ + protected void saveMyNote() { + myNote.setHeader(noteHeaderLabel.getText()); + myNote.setLastModifiedDate(Date.valueOf(LocalDate.now())); + myNote.getBlocks().clear(); + for(int i=0; i> dialog = new Dialog<>(); + dialog.setTitle("Share your note"); + dialog.setWidth(400); + + dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); + TextField receiverField = new TextField(); + receiverField.setPrefWidth(350); + receiverField.setPromptText("Input username of receiver!"); + + ComboBox shareTypeComboBox = new ComboBox<>(); + shareTypeComboBox.getItems().addAll("Read only", "Can edit"); + shareTypeComboBox.setPrefWidth(350); + + GridPane grid = new GridPane(); + grid.setHgap(10); grid.setVgap(10); + grid.add(receiverField, 0, 0); + grid.add(shareTypeComboBox, 0, 1); + + dialog.getDialogPane().setContent(grid); + + dialog.setResultConverter(dialogButton -> { + List results = new ArrayList<>(); + if (dialogButton == ButtonType.OK) { + results.add(receiverField.getText()); + results.add(shareTypeComboBox.getSelectionModel().getSelectedItem()); + } + return results; + }); + + dialog.showAndWait().ifPresent(result -> { + if (result.size() <= 1) return; + ShareNote.ShareType shareType; + if (result.get(1).equals("Can edit")) { + shareType = ShareNote.ShareType.CAN_EDIT; + } else { + shareType = ShareNote.ShareType.READ_ONLY; + } + String receiver = result.get(0); + boolean isExistReceiver = false; + try { + isExistReceiver = noteAppService.getUserService().isUser(receiver); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + if (!isExistReceiver) { + showAlert(Alert.AlertType.ERROR, "Receiver is not exist!"); + return; + } + boolean isLocked = false; + try { + isLocked = noteAppService.getUserService().checkLocked(receiver); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + if (isLocked) { + showAlert(Alert.AlertType.ERROR, "Your account is locked!"); + } + try { + noteAppService.getShareNoteService().share(myNote, receiver, shareType); + showAlert(Alert.AlertType.INFORMATION, "Successfully share!"); + ShareNote shareNote = noteAppService.getShareNoteService().open(myNote.getId(), myUser.getUsername()); + EditShareNoteController.open(myUser, shareNote, stage); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + }); + } + + protected void addBlock(TextBlock newTextBlock) { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "TextBlockView.fxml"; + try { + TextBlockController controller = new TextBlockController(); + + VBox box = controller.loadFXML(filePath); + controller.init(); + controller.setTextBlock(newTextBlock); + controller.setNoteId(myNote.getId()); + controller.setText(newTextBlock.getContent()); + controller.setHeader(newTextBlock.getHeader()); + + controller.getDeleteButton().setOnAction((ActionEvent event) -> { + int idxToDelete = controller.getTextBlock().getOrder()-1; + blocksLayout.getChildren().remove(idxToDelete); + myNote.getBlocks().remove(idxToDelete); + textBlockControllers.remove(idxToDelete); + }); + + controller.getUpButton().setOnAction((ActionEvent event) -> { + int order = controller.getTextBlock().getOrder(); + if (order <= 1) return; + swapOrder(order - 1, order); + + //Swap + Node temp = blocksLayout.getChildren().get(order - 1); + blocksLayout.getChildren().remove(order - 1); + blocksLayout.getChildren().add(order - 2, temp); + }); + + controller.getDownButton().setOnAction((ActionEvent event) -> { + int order = controller.getTextBlock().getOrder(); + if (order >= blocksLayout.getChildren().size()) return; + swapOrder(order, order + 1); + + //Swap + Node temp = blocksLayout.getChildren().get(order); + blocksLayout.getChildren().remove(order); + blocksLayout.getChildren().add(order - 1, temp); + }); + + controller.getBlockHeader().setOnMouseClicked((MouseEvent event) -> { + TextInputDialog dialog = new TextInputDialog(); + dialog.setHeaderText("Input your new header"); + + dialog.showAndWait().ifPresent(newHeader -> { + controller.setHeader(newHeader); + controller.getTextBlock().setHeader(newHeader); + }); + + }); + + blocksLayout.getChildren().add(box); + textBlockControllers.add(controller); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't load text block!"); + } + } + + protected void addBlock(SurveyBlock newSurveyBlock) { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "SurveyBlockView.fxml"; + try { + SurveyBlockController controller = new SurveyBlockController(); + + VBox box = controller.loadFXML(filePath); + controller.init(); + controller.setSurveyBlock(newSurveyBlock); + controller.setNoteId(myNote.getId()); + controller.setHeader(newSurveyBlock.getHeader()); + controller.loadItems(); + + controller.getDeleteButton().setOnAction((ActionEvent event) -> { + int idxToDelete = controller.getSurveyBlock().getOrder()-1; + blocksLayout.getChildren().remove(idxToDelete); + myNote.getBlocks().remove(idxToDelete); + surveyBlockControllers.remove(idxToDelete); + }); + + controller.getUpButton().setOnAction((ActionEvent event) -> { + int order = controller.getSurveyBlock().getOrder(); + if (order <= 1) return; + swapOrder(order - 1, order); + + //Swap + Node temp = blocksLayout.getChildren().get(order - 1); + blocksLayout.getChildren().remove(order - 1); + blocksLayout.getChildren().add(order - 2, temp); + }); + + controller.getDownButton().setOnAction((ActionEvent event) -> { + int order = controller.getSurveyBlock().getOrder(); + if (order >= blocksLayout.getChildren().size()) return; + swapOrder(order, order + 1); + + //Swap + Node temp = blocksLayout.getChildren().get(order); + blocksLayout.getChildren().remove(order); + blocksLayout.getChildren().add(order - 1, temp); + }); + + controller.getBlockHeader().setOnMouseClicked((MouseEvent event) -> { + TextInputDialog dialog = new TextInputDialog(); + dialog.setHeaderText("Input your new header"); + + dialog.showAndWait().ifPresent(newHeader -> { + controller.setHeader(newHeader); + controller.getSurveyBlock().setHeader(newHeader); + }); + }); + + blocksLayout.getChildren().add(box); + surveyBlockControllers.add(controller); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't load survey block!"); + } + } + + protected void addFilter() { + //Hiện Dialog để nhập filter mới + TextInputDialog inputDialog = new TextInputDialog(); + inputDialog.setTitle("Add filter for " + myNote.getHeader()); + inputDialog.setHeaderText("Enter your new filter"); + //Lấy kết quả + Optional confirm = inputDialog.showAndWait(); + //Xử lý kết quả khi nhấn OK + confirm.ifPresent(newFilterStr -> { + NoteFilter newFilter = new NoteFilter(newFilterStr); + //Thiết lập và add tất cả các filter cũ + if(myNote.getFilters().contains(newFilter)) { + //Nếu filter đã tồn tại thì thông báo lỗi + showAlert(Alert.AlertType.ERROR, "Exist Filter"); + } else { + //Thêm filter vào list + myNote.getFilters().add(newFilter); + //Load lại filter GUI + loadFilter(myNote.getFilters(), 8); + } + }); + } + + /** + * Load các filter của note này và hiển thị lên màn hình + * @param filters Các NoteFilter cần hiển thị + * @param maxColEachRow Số lượng filter lớn nhất ở mỗi hàng + */ + protected void loadFilter(List filters, int maxColEachRow) { + int column = 0; + int row = 0; + //Làm sạch filter layout + filterGridLayout.getChildren().clear(); + if(filters.isEmpty()) { + return; + } + //Thiết lập khoảng cách giữa các filter + filterGridLayout.setHgap(8); + filterGridLayout.setVgap(8); + //Thiết lập filter layout + String filePath = Controller.DEFAULT_FXML_RESOURCE + "NoteFiltersView.fxml"; + try { + for(int i = 0; i < filters.size(); i++) { + NoteFiltersController controller = new NoteFiltersController(); + HBox hbox = controller.loadFXML(filePath); + //Thiết lập dữ liệu cho filter + controller.setData(filters.get(i).getFilter()); + controller.getRemoveFilterView().setOnMouseClicked(event -> { + myNote.getFilters().remove(new NoteFilter(controller.getFilter())); + loadFilter(myNote.getFilters(), 8); + }); + //Chuyển hàng + if(column == maxColEachRow){ + column = 0; + row++; + } + //Thêm filter vừa tạo vào layout + filterGridLayout.add(hbox, column++, row); + } + } catch (IOException e) { + showAlert(Alert.AlertType.ERROR, "Can't load filter!"); + } + } + + /** + * Hàm trợ giúp việc thay đổi thứ tự giữa các block + * @param firstOrder order của block thứ nhất + * @param secondOrder order của block thứ hai + */ + protected void swapOrder(int firstOrder, int secondOrder) { + for (TextBlockController controller: textBlockControllers) { + if (controller.getTextBlock().getOrder() == firstOrder) { + controller.getTextBlock().setOrder(secondOrder); + } else if (controller.getTextBlock().getOrder() == secondOrder) { + controller.getTextBlock().setOrder(firstOrder); + } + } + + for (SurveyBlockController controller: surveyBlockControllers) { + if (controller.getSurveyBlock().getOrder() == firstOrder) { + controller.getSurveyBlock().setOrder(secondOrder); + } else if (controller.getSurveyBlock().getOrder() == secondOrder) { + controller.getSurveyBlock().setOrder(firstOrder); + } + } + } + + protected void importFile() { + //Tạo directory chooser + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Choose dir to export file"); + File file = fileChooser.showOpenDialog(stage); + if (file == null) { + return; + } + + try { + Note importedNote = noteAppService.getFileIOService().importNote(file.getPath()); + myNote.setBlocks(importedNote.getBlocks()); + initView(); + showAlert(Alert.AlertType.INFORMATION, "Successfully import."); + } catch (NoteAppServiceException | IOException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + protected void exportFile() { + //Tạo directory chooser + DirectoryChooser directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle("Choose dir to export file"); + File dir = directoryChooser.showDialog(stage); + if (dir == null) { + return; + } + //Export ra tên file tương ứng + String pdfFileName = myNote.getHeader() + "_" + myNote.getAuthor() + ".pdf"; + try { + noteAppService.getFileIOService().outputNote(dir + "\\" + pdfFileName, myNote); + showAlert(Alert.AlertType.INFORMATION, "Successfully export."); + } catch (NoteAppServiceException | IOException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Mở một trang edit note + * @param myUser User sở hữu Note + * @param myNote Note được mở + * @param stage Stage chứa trang edit này + */ + public static void open(User myUser, Note myNote, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "EditNoteView.fxml"; + + EditNoteController controller = new EditNoteController(); + + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setMyNote(myNote); + controller.setOpenedNotes(new ArrayList<>()); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open edit."); + } + } + + /** + * Mở một trang edit note với thông tin về các note đang được mở + * @param myUser User sở hữu các note này + * @param myNote Note đang được edit + * @param openedNotes Các Note đang được mở + * @param stage Stage chứa trang edit này + */ + public static void open(User myUser, Note myNote, List openedNotes, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "EditNoteView.fxml"; + + EditNoteController controller = new EditNoteController(); + + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setMyNote(myNote); + controller.setOpenedNotes(openedNotes); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open edit."); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/controller/EditShareNoteController.java b/src/main/java/com/noteapp/controller/EditShareNoteController.java new file mode 100644 index 0000000..8fc2736 --- /dev/null +++ b/src/main/java/com/noteapp/controller/EditShareNoteController.java @@ -0,0 +1,455 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppServiceException; +import static com.noteapp.controller.Controller.showAlert; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.NoteBlock; +import com.noteapp.note.model.ShareNote; +import com.noteapp.note.model.SurveyBlock; +import com.noteapp.note.model.TextBlock; +import com.noteapp.user.model.User; +import java.io.File; +import java.io.IOException; +import java.sql.Date; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Timer; +import java.util.TimerTask; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.scene.Node; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.VBox; +import javafx.stage.DirectoryChooser; +import javafx.stage.Stage; + +/** + * Controller cho trang edit một note được chia sẻ giữa nhiều người + * @author Nhóm 17 + */ +public class EditShareNoteController extends EditNoteController { + private Map> othersTextBlockById; + private Map> othersSurveyBlockById; + + private ShareNote myShareNote; + private Timer updateTimer; + private TimerTask updateTimerTask; + + private boolean needReload; + + public void setMyShareNote(ShareNote myShareNote) { + this.myShareNote = myShareNote; + } + + @Override + public void init() { + needReload = false; + super.init(); + } + + @Override + protected void initView() { + noteHeaderLabel.setText(myShareNote.getHeader()); + initOpenedNotes(); + loadFilter(myNote.getFilters(), 8); + this.initBlock(); + } + + @Override + protected void initBlock() { + blocksLayout.getChildren().clear(); + textBlockControllers.clear(); + surveyBlockControllers.clear(); + List blocks = myShareNote.getBlocks(); + Map> otherEditorBlocks = myShareNote.getOtherEditorBlocks(); + othersTextBlockById = new HashMap<>(); + othersSurveyBlockById = new HashMap<>(); + + getBlocksById(otherEditorBlocks); + + for(int i=0; i btnType = showAlert(Alert.AlertType.WARNING, "You need to reload."); + reload(); + } + myShareNote = noteAppService.getShareNoteService().open(myShareNote.getId(), myShareNote.getEditor()); + noteHeaderLabel.setText(myShareNote.getHeader()); + loadFilter(myShareNote.getFilters(), 8); + Map> otherEditorBlocks = myShareNote.getOtherEditorBlocks(); + getBlocksById(otherEditorBlocks); + updateTextBlock(); + updateSurveyBlock(); + } + + /** + * Cài đặt trang edit tự động cập nhật dữ liệu về các block được chỉnh sửa + * bởi các user khác. Trong trường hợp thứ tự của các block bị thay đổi, hoặc + * header của một block nào đó bị thay đổi, ứng dụng sẽ yêu cầu User reload lại + * trang edit này. + * @see #reload() + * @see #updateTextBlock() + * @see #updateSurveyBlock() + */ + public void setOnAutoUpdate() { + updateTimer = new Timer(); + updateTimerTask = new TimerTask() { + @Override + public void run() { + Platform.runLater(() -> { + try { + autoUpdate(); + + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.WARNING, "Can't update!"); + } + }); + } + }; + updateTimer.scheduleAtFixedRate(updateTimerTask, 2000, 4000); + } + + @Override + protected void addBlock(TextBlock newTextBlock) { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "TextBlockView.fxml"; + try { + int blockId = newTextBlock.getId(); + TextBlockController controller = new TextBlockController(); + + VBox box = controller.loadFXML(filePath); + controller.init(); + controller.setTextBlock(newTextBlock); + if (othersTextBlockById.containsKey(blockId)) { + controller.setOtherEditors(othersTextBlockById.get(blockId)); + } + controller.setNoteId(myNote.getId()); + controller.setText(newTextBlock.getContent()); + controller.setHeader(newTextBlock.getHeader()); + controller.initOtherEditComboBox(); + + controller.getDeleteButton().setOnAction((ActionEvent event) -> { + int idxToDelete = controller.getTextBlock().getOrder()-1; + blocksLayout.getChildren().remove(idxToDelete); + myNote.getBlocks().remove(idxToDelete); + textBlockControllers.remove(idxToDelete); + }); + controller.getSwitchToOtherButton().setOnAction((ActionEvent event) -> { + String otherEditor = controller.getOtherEditor(); + TextBlock otherTextBlock = new TextBlock(); + for (TextBlock block: othersTextBlockById.get(blockId)) { + if (block.getEditor().equals(otherEditor)) { + otherTextBlock = block; + break; + } + } + controller.setText(otherTextBlock.getContent()); + }); + controller.getUpButton().setOnAction((ActionEvent event) -> { + int order = controller.getTextBlock().getOrder(); + if (order <= 1) return; + swapOrder(order - 1, order); + + //Swap + Node temp = blocksLayout.getChildren().get(order - 1); + blocksLayout.getChildren().remove(order - 1); + blocksLayout.getChildren().add(order - 2, temp); + }); + + controller.getDownButton().setOnAction((ActionEvent event) -> { + int order = controller.getTextBlock().getOrder(); + if (order >= blocksLayout.getChildren().size()) return; + swapOrder(order, order + 1); + + //Swap + Node temp = blocksLayout.getChildren().get(order); + blocksLayout.getChildren().remove(order); + blocksLayout.getChildren().add(order - 1, temp); + }); + + controller.getBlockHeader().setOnMouseClicked((MouseEvent event) -> { + TextInputDialog dialog = new TextInputDialog(); + dialog.setHeaderText("Input your new header"); + + dialog.showAndWait().ifPresent(newHeader -> { + controller.setHeader(newHeader); + controller.getTextBlock().setHeader(newHeader); + }); + + }); + + blocksLayout.getChildren().add(box); + textBlockControllers.add(controller); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't load text block!"); + } + } + + @Override + protected void addBlock(SurveyBlock newSurveyBlock) { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "SurveyBlockView.fxml"; + try { + int blockId = newSurveyBlock.getId(); + SurveyBlockController controller = new SurveyBlockController(); + + VBox box = controller.loadFXML(filePath); + controller.init(); + controller.setSurveyBlock(newSurveyBlock); + if (othersSurveyBlockById.containsKey(blockId)) { + controller.setOtherEditors(othersSurveyBlockById.get(blockId)); + } + controller.setNoteId(myNote.getId()); + controller.setHeader(newSurveyBlock.getHeader()); + controller.loadItems(); + + controller.getDeleteButton().setOnAction((ActionEvent event) -> { + int idxToDelete = controller.getSurveyBlock().getOrder()-1; + blocksLayout.getChildren().remove(idxToDelete); + myNote.getBlocks().remove(idxToDelete); + surveyBlockControllers.remove(idxToDelete); + }); + + controller.getUpButton().setOnAction((ActionEvent event) -> { + int order = controller.getSurveyBlock().getOrder(); + if (order <= 1) return; + swapOrder(order - 1, order); + + //Swap + Node temp = blocksLayout.getChildren().get(order - 1); + blocksLayout.getChildren().remove(order - 1); + blocksLayout.getChildren().add(order - 2, temp); + }); + + controller.getDownButton().setOnAction((ActionEvent event) -> { + int order = controller.getSurveyBlock().getOrder(); + if (order >= blocksLayout.getChildren().size()) return; + swapOrder(order, order + 1); + + //Swap + Node temp = blocksLayout.getChildren().get(order); + blocksLayout.getChildren().remove(order); + blocksLayout.getChildren().add(order - 1, temp); + }); + + controller.getBlockHeader().setOnMouseClicked((MouseEvent event) -> { + TextInputDialog dialog = new TextInputDialog(); + dialog.setHeaderText("Input your new header"); + + dialog.showAndWait().ifPresent(newHeader -> { + controller.setHeader(newHeader); + controller.getSurveyBlock().setHeader(newHeader); + }); + }); + + blocksLayout.getChildren().add(box); + surveyBlockControllers.add(controller); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't load survey block!"); + } + } + + @Override + protected void saveMyNote() { + myShareNote.setHeader(noteHeaderLabel.getText()); + myShareNote.setLastModifiedDate(Date.valueOf(LocalDate.now())); + myShareNote.getBlocks().clear(); + for(int i=0; i> otherEditorBlocks) { + othersTextBlockById = new HashMap<>(); + othersSurveyBlockById = new HashMap<>(); + + for(Map.Entry> entry: otherEditorBlocks.entrySet()) { + int blockId = entry.getKey(); + List others = entry.getValue(); + + for(int i = 0; i < others.size(); i++) { + if(others.get(i).getBlockType() == NoteBlock.BlockType.TEXT) { + if (!othersTextBlockById.containsKey(blockId)) { + othersTextBlockById.put(blockId, new ArrayList<>()); + } + othersTextBlockById.get(blockId).add((TextBlock) others.get(i)); + } else { + if (!othersSurveyBlockById.containsKey(blockId)) { + othersSurveyBlockById.put(blockId, new ArrayList<>()); + } + othersSurveyBlockById.get(blockId).add((SurveyBlock) others.get(i)); + } + } + } + } + + protected void updateTextBlock() { + for (int i = 0; i < textBlockControllers.size(); i++) { + TextBlock thisBlock = textBlockControllers.get(i).getTextBlock(); + List otherEditors = othersTextBlockById.get(thisBlock.getId()); + for (TextBlock otherEditor: otherEditors) { + if (!otherEditor.getHeader().equals(thisBlock.getHeader())) { + needReload = true; + break; + } + if (otherEditor.getOrder() != thisBlock.getOrder()) { + needReload = true; + break; + } + } + + textBlockControllers.get(i).updateOtherEditors(otherEditors); + textBlockControllers.get(i).initOtherEditComboBox(); + } + } + + protected void updateSurveyBlock() { + for (int i = 0; i < surveyBlockControllers.size(); i++) { + SurveyBlock thisBlock = surveyBlockControllers.get(i).getSurveyBlock(); + List otherEditors = othersSurveyBlockById.get(thisBlock.getId()); + for (SurveyBlock otherEditor: otherEditors) { + if (!otherEditor.getHeader().equals(thisBlock.getHeader())) { + needReload = true; + break; + } + if (otherEditor.getOrder() != thisBlock.getOrder()) { + needReload = true; + break; + } + } + surveyBlockControllers.get(i).setOtherEditors(otherEditors); + surveyBlockControllers.get(i).loadItems(); + } + } + + protected NoteBlock getBlock(int order) { + for (TextBlockController textBlockController: textBlockControllers) { + if (textBlockController.getTextBlock().getOrder() == order) { + return textBlockController.getTextBlock(); + } + } + for (SurveyBlockController surveyBlockController: surveyBlockControllers) { + if (surveyBlockController.getSurveyBlock().getOrder() == order) { + return surveyBlockController.getSurveyBlock(); + } + } + return new NoteBlock(); + } + + @Override + protected void exportFile() { + //Tạo directory chooser + DirectoryChooser directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle("Choose dir to export file"); + File dir = directoryChooser.showDialog(stage); + if (dir == null) { + return; + } + //Export ra tên file tương ứng + String pdfFileName = myNote.getHeader() + "_" + myShareNote.getAuthor() + ".pdf"; + try { + noteAppService.getFileIOService().outputNote(dir + "\\" + pdfFileName, myShareNote); + showAlert(Alert.AlertType.INFORMATION, "Successfully export."); + } catch (NoteAppServiceException | IOException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Mở một trang edit cho một note được chia sẻ giữa nhiều người + * @param myUser User đang trong phiên đăng nhập + * @param myShareNote Một Note được mở và được chia sẻ tới User này + * @param stage Stage chứa trang edit này + */ + public static void open(User myUser, ShareNote myShareNote, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "EditNoteView.fxml"; + EditShareNoteController controller = new EditShareNoteController(); + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setMyNote(myShareNote); + controller.setMyShareNote(myShareNote); + controller.setOpenedNotes(new ArrayList<>()); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + controller.setOnAutoUpdate(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open view"); + } + } + + /** + * Mở một trang edit cho một note được chia sẻ giữa nhiều người + * @param myUser User đang trong phiên đăng nhập + * @param myShareNote Một Note được mở và được chia sẻ tới User này + * @param openedNotes Các Note đang được mở hiện tại + * @param stage Stage chứa trang edit này + */ + public static void open(User myUser, ShareNote myShareNote, List openedNotes, Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "EditNoteView.fxml"; + EditShareNoteController controller = new EditShareNoteController(); + + controller.setStage(stage); + controller.setMyUser(myUser); + controller.setMyNote(myShareNote); + controller.setMyShareNote(myShareNote); + controller.setOpenedNotes(openedNotes); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + controller.setOnAutoUpdate(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open edit."); + } + } +} diff --git a/src/main/java/com/noteapp/controller/Initable.java b/src/main/java/com/noteapp/controller/Initable.java new file mode 100644 index 0000000..4219a00 --- /dev/null +++ b/src/main/java/com/noteapp/controller/Initable.java @@ -0,0 +1,15 @@ +package com.noteapp.controller; + +/** + * Yêu cầu các class kế thừa nó phải khởi tạo qua một phương thức + * trước khi sử dụng + * @author admin + */ +public interface Initable { + /** + * Phương thức khởi tạo các giá trị, thuộc tính cần thiết + * và thiết lập các action event khi bấm vào các đối tượng + * hiển thị trên view + */ + public abstract void init(); +} diff --git a/src/main/java/com/noteapp/controller/LoginController.java b/src/main/java/com/noteapp/controller/LoginController.java new file mode 100644 index 0000000..816c133 --- /dev/null +++ b/src/main/java/com/noteapp/controller/LoginController.java @@ -0,0 +1,110 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.AdminDAO; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.model.User; +import com.noteapp.user.service.AdminService; +import com.noteapp.user.service.UserService; +import java.io.IOException; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.TextField; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; + +/** + * FXML Controller class cho trang Login + * @author Nhóm 17 + */ +public class LoginController extends RequestServiceController implements Initable { + //Các thuộc tính FXML + @FXML + private Button loginButton; + @FXML + private PasswordField passwordField; + @FXML + private TextField usernameField; + @FXML + private Label registerLabel; + @FXML + private Button closeButton; + @FXML + private Label forgotPasswordLabel; + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setUserService(new UserService(UserDAO.getInstance())); + noteAppService.setAdminService(new AdminService(UserDAO.getInstance(), AdminDAO.getInstance())); + loginButton.setOnAction((ActionEvent event) -> { + login(); + }); + closeButton.setOnAction((ActionEvent event) -> { + close(); + }); + registerLabel.setOnMouseClicked((MouseEvent event) -> { + RegisterController.open(stage); + }); + forgotPasswordLabel.setOnMouseClicked((MouseEvent event) -> { + ResetPasswordController.open(stage); + }); + } + + /** + * Kiểm tra username và password của User thông qua các field + * và tiến hành chuyển vào trang dashboard tương ứng nếu đăng nhập thành công + * @see usernameField + * @see passwordField + */ + protected void login() { + //Lấy username và password + String username = usernameField.getText(); + String password = passwordField.getText(); + + //Kiểm tra thông tin đăng nhập + try { + boolean isAdmin = noteAppService.getAdminService().isAdmin(username); + if (!isAdmin) { + User user = noteAppService.getUserService().checkUser(username, password); + showAlert(Alert.AlertType.INFORMATION, "Successfully Login"); + //Mở Dashboard của user này + DashboardController.open(user, stage); + } else { + noteAppService.getAdminService().checkAdmin(username, password); + showAlert(Alert.AlertType.INFORMATION, "Successfully Login"); + //Mở Dashboard của user này + AdminDashboardController.open(stage); + } + + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Mở một trang đăng nhập + * @param stage Stage chứa trang đăng nhập này + */ + public static void open(Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "LoginView.fxml"; + + LoginController controller = new LoginController(); + + controller.setStage(stage); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open login"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/controller/RegisterController.java b/src/main/java/com/noteapp/controller/RegisterController.java new file mode 100644 index 0000000..f6cb92c --- /dev/null +++ b/src/main/java/com/noteapp/controller/RegisterController.java @@ -0,0 +1,300 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.model.Email; +import com.noteapp.user.model.User; +import com.noteapp.user.service.UserService; +import com.noteapp.user.service.security.MailjetSevice; +import com.noteapp.user.service.security.SixNumCodeGenerator; +import com.noteapp.user.service.security.VerificationMailService; +import java.io.IOException; +import java.sql.Date; +import java.time.LocalDate; +import java.util.Optional; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextField; +import javafx.scene.control.TextInputDialog; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; + +/** + * FXML Controller class cho trang Register + * + * @author Nhóm 17 + */ +public class RegisterController extends RequestServiceController implements Initable { + //Các thuộc tính FXML + @FXML + private TextField nameField; + @FXML + private PasswordField passwordField; + @FXML + private Button registerButton; + @FXML + private TextField schoolField; + @FXML + private TextField usernameField; + @FXML + private TextField dayOfBirthField; + @FXML + private TextField monthOfBirthField; + @FXML + private TextField yearOfBirthField; + @FXML + private RadioButton genderMale; + @FXML + private RadioButton genderFemale; + @FXML + private RadioButton genderOther; + @FXML + private TextField emailAddressField; + @FXML + private TextField emailNameField; + @FXML + private Label errorNameFieldLabel; + @FXML + private Label errorUsernameFieldLabel; + @FXML + private Label errorPasswordFieldLabel; + @FXML + private Label errorBirthdayFieldLabel; + @FXML + private Label errorEmailFieldLabel; + @FXML + private Label backLoginLabel; + @FXML + private Button closeButton; + + private User newUser; + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setUserService(new UserService(UserDAO.getInstance())); + initView(); + registerButton.setOnAction((ActionEvent event) -> { + register(); + }); + closeButton.setOnAction((ActionEvent event) -> { + close(); + }); + backLoginLabel.setOnMouseClicked((MouseEvent event) -> { + LoginController.open(stage); + }); + } + + protected void initView() { + //Ẩn các error label + errorNameFieldLabel.setVisible(false); + errorUsernameFieldLabel.setVisible(false); + errorPasswordFieldLabel.setVisible(false); + errorEmailFieldLabel.setVisible(false); + errorBirthdayFieldLabel.setVisible(false); + + //Thiết lập lựa chọn mặc định cho gender + genderOther.setSelected(true); + + } + + private void getPasswordFromField() { + if("".equals(passwordField.getText())) { + errorPasswordFieldLabel.setVisible(true); + } + newUser.setPassword(passwordField.getText()); + } + + private void getEmailFromField() { + Email email = new Email(); + email.setAddress(emailAddressField.getText()); + if(!email.checkAddress()) { + errorEmailFieldLabel.setVisible(true); + } + newUser.setEmail(email); + } + + private void getBirthdayFromField() { + int dayOfBirth = -1; + int monthOfBirth = -1; + int yearOfBirth = -1; + if(dayOfBirthField.getText().matches("^[0-9]{1,2}$")) { + dayOfBirth = Integer.parseInt(dayOfBirthField.getText()); + } else if("".equals(dayOfBirthField.getText())) { + dayOfBirth = LocalDate.now().getDayOfMonth(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(monthOfBirthField.getText().matches("^[0-9]{1,2}$")) { + monthOfBirth = Integer.parseInt(monthOfBirthField.getText()); + } else if("".equals(monthOfBirthField.getText())) { + monthOfBirth = LocalDate.now().getMonthValue(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(yearOfBirthField.getText().matches("^[0-9]{4}$")) { + yearOfBirth = Integer.parseInt(yearOfBirthField.getText()); + } else if("".equals(yearOfBirthField.getText())) { + yearOfBirth = LocalDate.now().getYear(); + } else { + errorBirthdayFieldLabel.setVisible(true); + } + if(!errorBirthdayFieldLabel.isVisible()) { + newUser.setBirthday(Date.valueOf(LocalDate.of(yearOfBirth, monthOfBirth, dayOfBirth))); + } + } + private void getNameFromField() { + //Láy thông tin name + if("".equals(nameField.getText())) { + errorNameFieldLabel.setVisible(true); + } + newUser.setName(nameField.getText()); + } + + private void getUsernameFromField() { + if("".equals(usernameField.getText())) { + errorUsernameFieldLabel.setVisible(true); + } + newUser.setUsername(usernameField.getText()); + } + + private void getGenderFromBox() { + if(genderMale.isSelected()) { + newUser.setGender(User.Gender.MALE); + } else if (genderFemale.isSelected()) { + newUser.setGender(User.Gender.FEMALE); + } else { + newUser.setGender(User.Gender.OTHER); + } + } + + private boolean checkErrorAccountInfo() { + return errorNameFieldLabel.isVisible() || errorPasswordFieldLabel.isVisible() + || errorBirthdayFieldLabel.isVisible() || errorEmailFieldLabel.isVisible() + || errorUsernameFieldLabel.isVisible(); + } + /** + * Tiến hành lấy dữ liệu từ các field tương ứng để set dữ liệu cho {@link User}, + * thông qua đó thêm User này vào CSDL + */ + protected void register() { + initView(); + //Thiết lập các thuộc tính cho new user + newUser = new User(); + //Láy thông tin name + getNameFromField(); + //Lấy username + getUsernameFromField(); + //Lấy password + getPasswordFromField(); + //Lấy school + newUser.setSchool(schoolField.getText()); + //Lấy thông tin về birth + getBirthdayFromField(); + //Lấy gender + getGenderFromBox(); + //Lấy email + getEmailFromField(); + //Kiểm tra xem có lỗi nào không + if(checkErrorAccountInfo()) { + return; + } + if (!checkVerifyEmail()) { + return; + } + createUser(newUser); + } + + private boolean checkVerifyEmail() { + VerificationMailService.CodeStatus codeStatus = verifyEmail(); + switch (codeStatus) { + case EXPIRED -> { + showAlert(Alert.AlertType.ERROR, "This code is expired!"); + } + case FALSE -> { + showAlert(Alert.AlertType.ERROR, "This code is false!"); + } + case TRUE -> { + return true; + } + } + return true; + } + + private void createUser(User newUser) { + try { + //Tạo User mới thành công + noteAppService.getUserService().create(newUser); + showAlert(Alert.AlertType.INFORMATION, "Successfully create"); + Optional optional = showAlert(Alert.AlertType.CONFIRMATION, "Back to Login"); + if(optional.get() == ButtonType.OK) { + //Quay về trang đăng nhập + LoginController.open(stage); + } + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Xác thực một Email bằng cách gửi code về địa chỉ được nhập trong field + * @return Một {@link VerificationMailService.CodeStatus} miêu tả trạng thái + * của Code được nhập vào dialog + * @see emailAddressField + */ + private VerificationMailService.CodeStatus verifyEmail() { + try { + Email toEmail = new Email(); + toEmail.setAddress(emailAddressField.getText()); + toEmail.setName(emailNameField.getText()); + noteAppService.setVerificationMailService(new VerificationMailService(new MailjetSevice(), + new SixNumCodeGenerator())); + noteAppService.getVerificationMailService().sendCode(toEmail); + + TextInputDialog dialog = new TextInputDialog(); + dialog.setTitle("VERIFY CODE HAS SENT TO YOUR EMAIL"); + dialog.setHeaderText("Enter your verification code"); + //Lấy kết quả + Optional confirm = dialog.showAndWait(); + confirm.ifPresent(inputCode -> { + try { + noteAppService.getVerificationMailService().checkCode(inputCode); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + }); + return noteAppService.getVerificationMailService().getCodeStatus(); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + return VerificationMailService.CodeStatus.FALSE; + } + } + + /** + * Mở trang register + * @param stage Stage chứa trang register này + */ + public static void open(Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "RegisterView.fxml"; + + RegisterController controller = new RegisterController(); + + controller.setStage(stage); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open register"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/controller/RequestServiceController.java b/src/main/java/com/noteapp/controller/RequestServiceController.java new file mode 100644 index 0000000..378bed9 --- /dev/null +++ b/src/main/java/com/noteapp/controller/RequestServiceController.java @@ -0,0 +1,12 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; + +/** + * Một class đại diện cho các controller yêu cầu sử dụng dịch vụ của + * hệ thống NoteApp + * @author Nhóm 17 + */ +public abstract class RequestServiceController extends Controller { + protected NoteAppService noteAppService; +} diff --git a/src/main/java/com/noteapp/controller/ResetPasswordController.java b/src/main/java/com/noteapp/controller/ResetPasswordController.java new file mode 100644 index 0000000..eeac03c --- /dev/null +++ b/src/main/java/com/noteapp/controller/ResetPasswordController.java @@ -0,0 +1,157 @@ +package com.noteapp.controller; + +import com.noteapp.common.service.NoteAppService; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.UserDAO; +import com.noteapp.user.model.Email; +import com.noteapp.user.service.UserService; +import com.noteapp.user.service.security.MailjetSevice; +import com.noteapp.user.service.security.SixNumCodeGenerator; +import com.noteapp.user.service.security.VerificationMailService; +import java.io.IOException; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.TextField; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; + +/** + * Một Controller cho trang cấp lại mật khẩu mới + * @author Nhóm 17 + */ +public class ResetPasswordController extends RequestServiceController implements Initable { + @FXML + private Button closeButton; + @FXML + private Button confirmPasswordButton; + @FXML + private Label errorUsernameFieldLabel; + @FXML + private PasswordField passwordField; + @FXML + private Button sendCodeButton; + @FXML + private TextField usernameField; + @FXML + private TextField verificationCodeField; + @FXML + private Button verifyCodeButton; + @FXML + private Label backLoginLabel; + + @Override + public void init() { + noteAppService = new NoteAppService(); + noteAppService.setUserService(new UserService(UserDAO.getInstance())); + initScene(); + closeButton.setOnAction((ActionEvent event) -> { + close(); + }); + sendCodeButton.setOnAction((ActionEvent event) -> { + sendCode(); + }); + verifyCodeButton.setOnAction((ActionEvent event) -> { + checkVerifyCode(); + }); + confirmPasswordButton.setOnAction((ActionEvent event) -> { + resetPassword(); + }); + backLoginLabel.setOnMouseClicked((MouseEvent event) -> { + LoginController.open(stage); + }); + } + + protected void initScene() { + errorUsernameFieldLabel.setVisible(false); + verificationCodeField.setEditable(false); + passwordField.setEditable(false); + } + + /** + * Gửi một verify code tới email của User có username được nhập vào field, + * nếu user tồn tại và đã gửi email thì mở khóa field để nhập code + */ + protected void sendCode() { + String username = usernameField.getText(); + if("".equals(username)) { + errorUsernameFieldLabel.setVisible(true); + return; + } else { + errorUsernameFieldLabel.setVisible(false); + } + try { + Email vefiryEmail = noteAppService.getUserService().getVerificationEmail(username); + noteAppService.setVerificationMailService(new VerificationMailService(new MailjetSevice(), + new SixNumCodeGenerator())); + noteAppService.getVerificationMailService().sendCode(vefiryEmail); + verificationCodeField.setEditable(true); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + /** + * Kiểm tra code xác thực được nhập vào từ người dùng. + * Nếu code đúng thì mở khóa field để nhập password mới + */ + protected void checkVerifyCode() { + if(!verificationCodeField.isEditable()) { + return; + } + try { + String inputCode = verificationCodeField.getText(); + noteAppService.getVerificationMailService().checkCode(inputCode); + VerificationMailService.CodeStatus codeStatus = noteAppService.getVerificationMailService().getCodeStatus(); + switch (codeStatus) { + case EXPIRED -> { + showAlert(Alert.AlertType.ERROR, "This code is expired!"); + } + case FALSE -> { + showAlert(Alert.AlertType.ERROR, "This code is false!"); + } + case TRUE -> { + showAlert(Alert.AlertType.INFORMATION, "Please input your new password below"); + passwordField.setEditable(true); + } + } + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + protected void resetPassword() { + if(!passwordField.isEditable()) { + return; + } + String username = usernameField.getText(); + try { + noteAppService.getUserService().updatePassword(username, passwordField.getText()); + initScene(); + showAlert(Alert.AlertType.INFORMATION, "Successfully reset."); + LoginController.open(stage); + } catch (NoteAppServiceException ex) { + showAlert(Alert.AlertType.ERROR, ex.getMessage()); + } + } + + public static void open(Stage stage) { + try { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "ResetPasswordView.fxml"; + + ResetPasswordController controller = new ResetPasswordController(); + + controller.setStage(stage); + controller.loadFXMLAndSetScene(filePath); + controller.init(); + //Set scene cho stage và show + + controller.showFXML(); + } catch (IOException ex) { + showAlert(Alert.AlertType.ERROR, "Can't open reset Password"); + } + } +} diff --git a/src/main/java/com/noteapp/controller/SurveyBlockController.java b/src/main/java/com/noteapp/controller/SurveyBlockController.java new file mode 100644 index 0000000..fa9071c --- /dev/null +++ b/src/main/java/com/noteapp/controller/SurveyBlockController.java @@ -0,0 +1,213 @@ +package com.noteapp.controller; + +import com.noteapp.note.model.SurveyBlock; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextInputDialog; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * Một class Controller để hiển thị một SurveyBlock lên trang edit + * @author Nhóm 17 + * @see EditNoteController + */ +public class SurveyBlockController extends Controller implements Initable { + @FXML + private Label blockHeader; + @FXML + private Label changeNotify; + @FXML + private VBox itemsLayout; + @FXML + private Button addItemButton; + @FXML + private Button deleteButton; + @FXML + private Button upButton; + @FXML + private Button downButton; + + private int noteId; + private SurveyBlock surveyBlock; + private List otherEditors; + private List itemsController; + + @Override + public void init() { + noteId = -1; + surveyBlock = new SurveyBlock(); + otherEditors = new ArrayList<>(); + itemsController = new ArrayList<>(); + changeNotify.setVisible(false); + + addItemButton.setOnAction((ActionEvent event) -> { + addItem(); + }); + } + + private void loadItem(String choice, boolean isVoted) throws IOException { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "SurveyItemView.fxml"; + SurveyItemController controller = new SurveyItemController(); + HBox box = controller.loadFXML(filePath); + controller.init(); + controller.setChoice(choice); + + int numVoted = 0; + if (isVoted) { + numVoted += 1; + } + + for (SurveyBlock otherEditor: otherEditors) { + boolean otherVoted = otherEditor.getSurveyMap().get(choice); + if (otherVoted) { + numVoted += 1; + } + } + controller.getVotedRatioButton().setSelected(isVoted); + controller.setNum(numVoted); + controller.getVotedRatioButton().setOnAction((ActionEvent event) -> { + boolean radioVoted = controller.getVotedRatioButton().isSelected(); + controller.setVoted(radioVoted); + surveyBlock.getSurveyMap().put(choice, radioVoted); + }); + List others = new ArrayList<>(); + for (SurveyBlock otherBlock: otherEditors) { + if (otherBlock.getSurveyMap().get(choice)) { + others.add(otherBlock.getEditor()); + } + } + controller.setOther(others); + itemsController.add(controller); + itemsLayout.getChildren().add(box); + } + + /** + * Load các choice vào danh sách các choice + * @see SurveyItemController + * @see itemsLayout + */ + public void loadItems() { + itemsController.clear(); + itemsLayout.getChildren().clear(); + + if (surveyBlock.getSurveyMap().isEmpty()) { + return; + } + for (Map.Entry entry: surveyBlock.getSurveyMap().entrySet()) { + String choice = entry.getKey(); + boolean isVoted = entry.getValue(); + try { + loadItem(choice, isVoted); + } catch (IOException ex) { + System.err.println(ex.getMessage()); + } + } + } + + private void addNewItem(String newChoice) throws IOException { + String filePath = Controller.DEFAULT_FXML_RESOURCE + "SurveyItemView.fxml"; + SurveyItemController controller = new SurveyItemController(); + HBox box = controller.loadFXML(filePath); + + controller.init(); + controller.setChoice(newChoice); + controller.getDeleteChoiceButton().setOnAction((ActionEvent event) -> { + String deletedChoice = controller.getChoice(); + int deletedIdx = -1; + for (int i = 0; i < itemsController.size(); i++) { + if (deletedChoice.equals(itemsController.get(i).getChoice())) { + deletedIdx = i; + break; + } + } + itemsController.remove(deletedIdx); + itemsLayout.getChildren().remove(deletedIdx); + surveyBlock.getSurveyMap().remove(deletedChoice); + }); + controller.getVotedRatioButton().setOnAction((ActionEvent event) -> { + boolean radioVoted = controller.getVotedRatioButton().isSelected(); + controller.setVoted(radioVoted); + }); + itemsController.add(controller); + itemsLayout.getChildren().add(box); + } + + protected void addItem() { + TextInputDialog inputDialog = new TextInputDialog(); + inputDialog.setTitle("Add a choice to survey"); + inputDialog.setHeaderText("Input your new choice"); + //Lấy kết quả và xử lý + Optional confirm = inputDialog.showAndWait(); + confirm.ifPresent(newChoice -> { + //Lấy tất cả các Note của myUser + try { + addNewItem(newChoice); + } catch (IOException ex) { + System.err.println(ex.getMessage()); + } + }); + } + + + public String getHeader() { + return blockHeader.getText(); + } + + public void setHeader(String header) { + blockHeader.setText(header); + } + + public int getNoteId() { + return noteId; + } + + public void setNoteId(int noteId) { + this.noteId = noteId; + } + + public Label getBlockHeader() { + return blockHeader; + } + + public SurveyBlock getSurveyBlock() { + surveyBlock.getSurveyMap().clear(); + for (int i = 0; i < itemsController.size(); i++) { + String choice = itemsController.get(i).getChoice(); + boolean isVoted = itemsController.get(i).getVoted(); + surveyBlock.getSurveyMap().put(choice, isVoted); + } + return surveyBlock; + } + + public void setSurveyBlock(SurveyBlock surveyBlock) { + this.surveyBlock = surveyBlock; + } + + public List getOtherEditors() { + return otherEditors; + } + + public void setOtherEditors(List otherEditors) { + this.otherEditors = otherEditors; + } + + public Button getDeleteButton() { + return deleteButton; + } + + public Button getUpButton() { + return upButton; + } + + public Button getDownButton() { + return downButton; + } +} diff --git a/src/main/java/com/noteapp/controller/SurveyItemController.java b/src/main/java/com/noteapp/controller/SurveyItemController.java new file mode 100644 index 0000000..b7a5761 --- /dev/null +++ b/src/main/java/com/noteapp/controller/SurveyItemController.java @@ -0,0 +1,83 @@ +package com.noteapp.controller; + +import java.util.List; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; + +/** + * Một class Controller để hiển thị các lựa chọn trong một Survey Block + * @author Nhóm 17 + * @see SurveyBlockController + */ +public class SurveyItemController extends Controller implements Initable { + @FXML + private Label choice; + @FXML + private RadioButton voted; + @FXML + private Button deleteChoiceButton; + @FXML + private Label num; + @FXML + private Label other; + + @Override + public void init() { + voted.setSelected(false); + num.setText("0"); + other.setText("No one"); + } + + public void setChoice(String choice) { + this.choice.setText(choice); + } + + public String getChoice() { + return choice.getText(); + } + + public int getNum() { + return Integer.parseInt(num.getText()); + } + + public void setNum(int num) { + this.num.setText(String.valueOf(num)); + } + + public void setOther(List others) { + if (others.isEmpty()) { + other.setText("No one"); + return; + } + String otherStr = ""; + for (String otherVoted: others) { + otherStr += otherVoted + ", "; + } + other.setText(otherStr.substring(0, otherStr.length() - 2)); + } + + public boolean getVoted() { + return voted.isSelected(); + } + + public void setVoted(boolean isVoted) { + voted.setSelected(isVoted); + int nowNum = getNum(); + if (isVoted) { + nowNum++; + } else { + nowNum--; + } + setNum(nowNum); + } + + public Button getDeleteChoiceButton() { + return deleteChoiceButton; + } + + public RadioButton getVotedRatioButton() { + return voted; + } +} diff --git a/src/main/java/com/noteapp/controller/TextBlockController.java b/src/main/java/com/noteapp/controller/TextBlockController.java new file mode 100644 index 0000000..c6f2909 --- /dev/null +++ b/src/main/java/com/noteapp/controller/TextBlockController.java @@ -0,0 +1,200 @@ +package com.noteapp.controller; + +import com.noteapp.note.model.TextBlock; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.layout.Region; + +/** + * Một Controller để hiển thị một Text Block lên trang Edit + * @author Nhóm 17 + * @see EditNoteController + */ +public class TextBlockController extends Controller implements Initable { + @FXML + private TextArea editableText; + @FXML + private Button deleteButton; + @FXML + private ComboBox otherEditComboBox; + @FXML + private Label blockHeader; + @FXML + private Button returnToYoursButton; + @FXML + private Button switchToOtherButton; + @FXML + private Label changeNotify; + @FXML + private Button upButton; + @FXML + private Button downButton; + + private int noteId; + private TextBlock textBlock; + private List otherEditors; + + @Override + public void init() { + noteId = -1; + textBlock = new TextBlock(); + + returnToYoursButton.setOnAction((ActionEvent event) -> { + returnToYourContent(); + }); + otherEditComboBox.setPromptText("Other edit by"); + changeNotify.setText(""); + } + + public void initOtherEditComboBox() { + otherEditComboBox.getItems().clear(); + otherEditComboBox.setPromptText("Other edit by"); + if(otherEditors.isEmpty()) { + return; + } + for(TextBlock otherEditor: otherEditors) { + otherEditComboBox.getItems().add(otherEditor.getEditor()); + } + } + + public void setHeader(String header) { + blockHeader.setText(header); + } + + public void setNoteId(int noteId) { + this.noteId = noteId; + } + + public void setTextBlock(TextBlock textBlock) { + this.textBlock = textBlock; + } + + public void setOtherEditors(List otherEditors) { + this.otherEditors = otherEditors; + } + + /** + * Cập nhật trạng thái của các phiên bản chỉnh sửa bởi các editor + * khác với của block này + * @param otherEditors Một list các phiên bản khác của Block này + * được chỉnh sửa bởi các editor khác + */ + public void updateOtherEditors(List otherEditors) { + List hadModifiedEditor = new ArrayList<>(); + for (TextBlock oldBlock: this.otherEditors) { + for (TextBlock newBlock: otherEditors) { + boolean sameEditor = oldBlock.getEditor().equals(newBlock.getEditor()); + boolean sameContent = oldBlock.getContent().equals(newBlock.getContent()); + if (sameEditor && (!sameContent)) { + hadModifiedEditor.add(newBlock.getEditor()); + } + } + } + + setChangeNotify(hadModifiedEditor); + this.otherEditors = otherEditors; + } + + public Button getDeleteButton() { + return deleteButton; + } + + public Button getUpButton() { + return upButton; + } + + public Button getDownButton() { + return downButton; + } + + public ComboBox getOtherEditComboBox() { + return otherEditComboBox; + } + + public Button getReturnToYoursButton() { + return returnToYoursButton; + } + + public Button getSwitchToOtherButton() { + return switchToOtherButton; + } + + public int getNoteId() { + return noteId; + } + + public TextBlock getTextBlock() { + return textBlock; + } + + public List getOtherEditors() { + return otherEditors; + } + + public String getOtherEditor() { + return otherEditComboBox.getSelectionModel().getSelectedItem(); + } + + public String getText() { + return editableText.getText(); + } + + public void setText(String text) { + editableText.setText(text); + } + + public void returnToYourContent() { + editableText.setText(textBlock.getContent()); + } + + public Label getBlockHeader() { + return blockHeader; + } + + /** + * Thay đổi thông báo nếu có editor nào khác vừa chỉnh sửa block + * @param hadModifiedEditors Những editor vừa chỉnh sửa block này + */ + public void setChangeNotify(List hadModifiedEditors) { + if(hadModifiedEditors.isEmpty()) { + changeNotify.setText(""); + return; + } + String notify = ""; + for(String str: hadModifiedEditors) { + notify += str + ", "; + } + notify += "has modified their editor"; + changeNotify.setText(notify); + changeNotify.setPrefWidth(Region.USE_COMPUTED_SIZE); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 47 * hash + Objects.hashCode(this.textBlock); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TextBlockController other = (TextBlockController) obj; + return Objects.equals(this.textBlock, other.textBlock); + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/note/service/INoteService.java b/src/main/java/com/noteapp/note/service/INoteService.java new file mode 100644 index 0000000..b65cf0f --- /dev/null +++ b/src/main/java/com/noteapp/note/service/INoteService.java @@ -0,0 +1,58 @@ +package com.noteapp.note.service; + +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.model.Note; +import java.util.List; + +/** + * + * @author admin + */ +public interface INoteService { + /** + * Tạo một {@link Note} mới và lưu vào trong CSDL + * @param newNote Note mới cần tạo + * @return Note vừa được tạo thành công + * @throws NoteAppServiceException Xảy ra khi Note đã tồn tại, hoặc các + * thao tác với CSDL bị lỗi + */ + Note create(Note newNote) throws NoteAppServiceException; + + /** + * Xóa một Note đã tồn tại trong CSDL + * @param noteId id của Note cần xóa + * @return Note vừa được xóa thành công + * @throws NoteAppServiceException Xảy ra khi các thao tác tương ứng với CSDL + * bị lỗi + */ + Note delete(int noteId) throws NoteAppServiceException; + + /** + * Lấy tất cả các Note thuộc quyền sở hữu của User + * @param author username của User sở hữu các Note này + * @return Một List các Note thuộc quyền của User này nếu thành công + * @throws NoteAppServiceException Xảy ra khi các thao tác với CSDL liên quan + * bị lỗi + */ + List getAll(String author) throws NoteAppServiceException; + + /** + * Mở một Note, cụ thể là lấy tất cả các dữ liệu liên quan tới một Note từ + * các CSDL Note, NoteFilter, NoteBlock, TextBlock, SurveyBlock và trả về + * @param noteId id của Note cần mở + * @return Note được mở thành công + * @throws NoteAppServiceException Xảy ra khi các thao tác với các CSDL liên quan bị lỗi + */ + Note open(int noteId) throws NoteAppServiceException; + + /** + * Lưu một Note, bản chất là cập nhật các thông tin của một Note vào các + * CSDL tương ứng. Nếu Note chưa tồn tại thì tnos sẽ được tạo mới và đưa + * vào các CSDL tương ứng. + * @param note Note cần lưu + * @return Note sau khi được cập nhật hoặc tạo mới thành công + * @throws NoteAppServiceException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + */ + Note save(Note note) throws NoteAppServiceException; +} diff --git a/src/main/java/com/noteapp/note/service/IShareNoteService.java b/src/main/java/com/noteapp/note/service/IShareNoteService.java new file mode 100644 index 0000000..d8a27fc --- /dev/null +++ b/src/main/java/com/noteapp/note/service/IShareNoteService.java @@ -0,0 +1,43 @@ +package com.noteapp.note.service; + +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.ShareNote; +import java.util.List; + +/** + * + * @author admin + */ +public interface IShareNoteService { + /** + * Chia sẻ một Note tới một người chỉnh sửa khác theo một trong hai loại + * (chỉ đọc hoặc có thể chỉnh sửa) + * @param note Note cần được chia sẻ + * @param editor username của người nhận Note này + * @param shareType Loại chia sẻ (Chỉ đọc hoặc có thể Edit) + * @return Một ShareNote (một Note được chia sẻ giữa nhiều người) + * @throws NoteAppServiceException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + */ + ShareNote share(Note note, String editor, ShareNote.ShareType shareType) throws NoteAppServiceException; + + /** + * Mở một Note được chia sẻ (ShareNote) + * @param noteId id của Note cần mở + * @param editor username là người chỉnh sửa phiên bản Note này + * @return Một ShareNote được mở thành công + * @throws NoteAppServiceException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + */ + ShareNote open(int noteId, String editor) throws NoteAppServiceException; + + /** + * Lấy tất cả các ShareNote được chia sẻ tới người chỉnh sửa này + * @param editor username của User + * @return Một List các ShareNote là các Note được chia sẻ tới User này + * @throws NoteAppServiceException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + */ + List getAllReceived(String editor) throws NoteAppServiceException; +} diff --git a/src/main/java/com/noteapp/note/service/NoteService.java b/src/main/java/com/noteapp/note/service/NoteService.java index 416de50..0c26ee4 100644 --- a/src/main/java/com/noteapp/note/service/NoteService.java +++ b/src/main/java/com/noteapp/note/service/NoteService.java @@ -2,6 +2,13 @@ import com.noteapp.common.dao.DAOException; import com.noteapp.common.dao.NotExistDataException; +<<<<<<< Updated upstream +======= +import com.noteapp.common.service.CausedBySystemException; +import com.noteapp.common.service.CausedByUserException; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.dao.IConcreateBlockDAO; +>>>>>>> Stashed changes import com.noteapp.note.dao.INoteBlockDAO; import com.noteapp.note.dao.INoteDAO; import com.noteapp.note.dao.INoteFilterDAO; @@ -40,6 +47,7 @@ public NoteService() { } +<<<<<<< Updated upstream /** * Lấy các thể hiện tương ứng cho các DAO */ @@ -66,15 +74,26 @@ protected void getInstanceOfDAO() { */ public Note create(Note newNote) throws NoteServiceException { getInstanceOfDAO(); +======= + private void checkNullDAO() throws NoteAppServiceException { + if (noteDAO == null || noteFilterDAO == null) { + throw new CausedBySystemException("DAO is null!"); + } + } + + @Override + public Note create(Note newNote) throws NoteAppServiceException { + checkNullDAO(); +>>>>>>> Stashed changes int noteId = newNote.getId(); //Kiểm tra note đã tồn tại hay chưa try { noteDAO.get(noteId); - throw new NoteServiceException("Already exist note!"); + throw new CausedByUserException("Already exist note!"); } catch (NotExistDataException nedExByGet) { //Nếu chưa tồn tại thì tiếp tục } catch (DAOException exByGet) { - throw new NoteServiceException(exByGet.getMessage(), exByGet.getCause()); + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); } try { //Thêm các trường thông tin cơ bản vào CSDL Note @@ -91,10 +110,11 @@ public Note create(Note newNote) throws NoteServiceException { //Mở Note và trả về return this.open(newNote.getId()); } catch (DAOException exByCreate) { - throw new NoteServiceException(exByCreate.getMessage(), exByCreate.getCause()); + throw new CausedBySystemException(exByCreate.getMessage(), exByCreate.getCause()); } } +<<<<<<< Updated upstream /** * Xóa một Note đã tồn tại trong CSDL * @param noteId id của Note cần xóa @@ -107,6 +127,11 @@ public Note create(Note newNote) throws NoteServiceException { */ public Note delete(int noteId) throws NoteServiceException { getInstanceOfDAO(); +======= + @Override + public Note delete(int noteId) throws NoteAppServiceException { + checkNullDAO(); +>>>>>>> Stashed changes try { //Lấy Note bằng cách mở Note deletedNote = this.open(noteId); @@ -114,10 +139,11 @@ public Note delete(int noteId) throws NoteServiceException { noteDAO.delete(noteId); return deletedNote; } catch (DAOException exByGetAndDelete) { - throw new NoteServiceException(exByGetAndDelete.getMessage(), exByGetAndDelete.getCause()); + throw new CausedBySystemException(exByGetAndDelete.getMessage(), exByGetAndDelete.getCause()); } } +<<<<<<< Updated upstream /** * Lấy tất cả các Note thuộc quyền sở hữu của User * @param author username của User sở hữu các Note này @@ -130,6 +156,11 @@ public Note delete(int noteId) throws NoteServiceException { */ public List getAll(String author) throws NoteServiceException { getInstanceOfDAO(); +======= + @Override + public List getAll(String author) throws NoteAppServiceException { + checkNullDAO(); +>>>>>>> Stashed changes try { List notes = noteDAO.getAll(author); List returnNotes = new ArrayList<>(); @@ -138,10 +169,11 @@ public List getAll(String author) throws NoteServiceException { } return returnNotes; } catch (DAOException exByGetAll) { - throw new NoteServiceException(exByGetAll.getMessage(), exByGetAll.getCause()); + throw new CausedBySystemException(exByGetAll.getMessage(), exByGetAll.getCause()); } } +<<<<<<< Updated upstream /** * Mở một Note, cụ thể là lấy tất cả các dữ liệu liên quan tới một Note từ * các CSDL Note, NoteFilter, NoteBlock, TextBlock, SurveyBlock và trả về @@ -155,6 +187,11 @@ public List getAll(String author) throws NoteServiceException { */ public Note open(int noteId) throws NoteServiceException { getInstanceOfDAO(); +======= + @Override + public Note open(int noteId) throws NoteAppServiceException { + checkNullDAO(); +>>>>>>> Stashed changes try { //Lấy các thông tin cơ bản Note note = noteDAO.get(noteId); @@ -165,6 +202,7 @@ public Note open(int noteId) throws NoteServiceException { note.setBlocks(noteBlocks); return note; } catch (DAOException exByGet) { +<<<<<<< Updated upstream exByGet.printStackTrace(); throw new NoteServiceException(exByGet.getMessage(), exByGet.getCause()); } @@ -187,6 +225,15 @@ public Note open(int noteId) throws NoteServiceException { */ public Note save(Note note) throws NoteServiceException { getInstanceOfDAO(); +======= + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); + } + } + + @Override + public Note save(Note note) throws NoteAppServiceException { + checkNullDAO(); +>>>>>>> Stashed changes int noteId = note.getId(); //Kiểm tra note đã tồn tại chưa try { @@ -195,7 +242,7 @@ public Note save(Note note) throws NoteServiceException { //Nếu chưa tồn tại thì tạo note mới return this.create(note); } catch (DAOException exByGet) { - throw new NoteServiceException(exByGet.getMessage(), exByGet.getCause()); + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); } try { //Cập nhật các thông tin cơ bản vào CSDL Note @@ -210,8 +257,12 @@ public Note save(Note note) throws NoteServiceException { saveBlocks(note.getId(), note.getBlocks()); return note; } catch (DAOException exByUpdate) { +<<<<<<< Updated upstream exByUpdate.printStackTrace(); throw new NoteServiceException(exByUpdate.getMessage(), exByUpdate.getCause()); +======= + throw new CausedBySystemException(exByUpdate.getMessage(), exByUpdate.getCause()); +>>>>>>> Stashed changes } } diff --git a/src/main/java/com/noteapp/note/service/NoteServiceException.java b/src/main/java/com/noteapp/note/service/NoteServiceException.java deleted file mode 100644 index 12860b1..0000000 --- a/src/main/java/com/noteapp/note/service/NoteServiceException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.noteapp.note.service; - -/** - * Một ngoại lệ cho các dịch vụ liên quan tới Note - * @author Nhóm 17 - */ -public class NoteServiceException extends Exception { - - public NoteServiceException(String message) { - super(message); - } - - public NoteServiceException(String message, Throwable cause) { - super(message, cause); - } -} \ No newline at end of file diff --git a/src/main/java/com/noteapp/note/service/ShareNoteService.java b/src/main/java/com/noteapp/note/service/ShareNoteService.java new file mode 100644 index 0000000..d119d9e --- /dev/null +++ b/src/main/java/com/noteapp/note/service/ShareNoteService.java @@ -0,0 +1,147 @@ +package com.noteapp.note.service; + +import com.noteapp.common.dao.DAOException; +import com.noteapp.common.dao.NotExistDataException; +import com.noteapp.common.service.CausedBySystemException; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.dao.IConcreateBlockDAO; +import com.noteapp.note.dao.INoteBlockDAO; +import com.noteapp.note.dao.INoteDAO; +import com.noteapp.note.dao.INoteFilterDAO; +import com.noteapp.note.dao.IShareNoteDAO; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.NoteBlock; +import com.noteapp.note.model.ShareNote; +import com.noteapp.note.model.SurveyBlock; +import com.noteapp.note.model.TextBlock; +import java.util.ArrayList; +import java.util.List; + +/** + * Cung cấp các dịch vụ liên quan tới Note được chia sẻ (ShareNote) + * @author Nhóm 17 + * @see IUserDAO + * @see IShareNoteDAO + */ +public class ShareNoteService implements IShareNoteService { + protected IShareNoteDAO shareNoteDAO; + protected SupportedNoteBlockService blockService; + protected INoteService noteService; + + public ShareNoteService(IShareNoteDAO shareNoteDAO, INoteDAO noteDAO, INoteFilterDAO noteFilterDAO, INoteBlockDAO noteBlockDAO, IConcreateBlockDAO textBlockDAO, IConcreateBlockDAO surveyBlockDAO) { + this.shareNoteDAO = shareNoteDAO; + noteService = new NoteService(noteDAO, noteFilterDAO, noteBlockDAO, textBlockDAO, surveyBlockDAO); + blockService = new SupportedNoteBlockService(noteBlockDAO, textBlockDAO, surveyBlockDAO); + } + + public void setBlockService(SupportedNoteBlockService blockService) { + this.blockService = blockService; + } + + public void setNoteService(INoteService noteService) { + this.noteService = noteService; + } + + public void setShareNoteDAO(IShareNoteDAO shareNoteDAO) { + this.shareNoteDAO = shareNoteDAO; + } + + private void checkNullDAO() throws NoteAppServiceException { + if (shareNoteDAO == null) { + throw new CausedBySystemException("DAO is null!"); + } + } + + @Override + public ShareNote share(Note note, String editor, ShareNote.ShareType shareType) throws NoteAppServiceException { + checkNullDAO(); + //Set các thông tin của note cho shareNote + int noteId = note.getId(); + ShareNote shareNote = new ShareNote(); + shareNote.setNote(note); + //Kiểm tra xem Note đã được chia sẻ hay chưa + try { + //Nếu có thì chỉ cần update và open nó + shareNoteDAO.get(noteId, editor); + shareNoteDAO.update(shareNote); + return this.open(note.getId(), editor); + } catch (NotExistDataException ex1) { + //Nếu không thì cần tạo mới trong CSDL + } catch (DAOException ex2) { + throw new CausedBySystemException(ex2.getMessage(), ex2.getCause()); + } + //Kiểm tra note của User đã được chia sẻ cho người khác hay chưa + try { + //Nếu có thì chỉ cần update và open nó + shareNoteDAO.get(noteId, note.getAuthor()); + } catch (NotExistDataException ex1) { + shareNote.setShareType(ShareNote.ShareType.CAN_EDIT); + shareNote.setEditor(note.getAuthor()); + try { + shareNoteDAO.create(shareNote); + } catch (DAOException ex3) { + throw new CausedBySystemException(ex3.getMessage(), ex3.getCause()); + } + } catch (DAOException ex2) { + throw new CausedBySystemException(ex2.getMessage(), ex2.getCause()); + } + try { + //Tạo ShareNote mới + shareNote.setEditor(editor); + shareNote.setShareType(shareType); + //Sao lưu các Block của tác giả sang người chỉnh sửa khác + List authorBlocks = note.getBlocks(); + for(NoteBlock noteBlock: authorBlocks) { + NoteBlock thisEditorBlock = noteBlock; + blockService.createOtherVersion(thisEditorBlock, shareNote.getEditor()); + } + shareNoteDAO.create(shareNote); + note.setPubliced(true); + noteService.save(note); + return this.open(shareNote.getId(), shareNote.getEditor()); + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } + + @Override + public ShareNote open(int noteId, String editor) throws NoteAppServiceException { + checkNullDAO(); + //Trước hết mở Note + Note note = noteService.open(noteId); + //Mở phiên bản Note của editor + try { + ShareNote shareNote = shareNoteDAO.get(noteId, editor); + shareNote.setNote(note); + //Lấy và phân loại block nào của editor này và cái nào của editor khác + List blocks = blockService.getAll(noteId); + List thisEditorBlocks = new ArrayList<>(); + for(NoteBlock noteBlock: blocks) { + if(editor.equals(noteBlock.getEditor())) { + thisEditorBlocks.add(noteBlock); + } else { + shareNote.addOtherEditorBlock(noteBlock); + } + } + shareNote.setBlocks(thisEditorBlocks); + return shareNote; + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } + + @Override + public List getAllReceived(String editor) throws NoteAppServiceException { + checkNullDAO(); + try { + List shareNotes = shareNoteDAO.getAll(editor); + List receivedNotes = new ArrayList<>(); + for(ShareNote shareNote: shareNotes) { + receivedNotes.add(this.open(shareNote.getId(), editor)); + } + return receivedNotes; + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/note/service/SupportedNoteBlockService.java b/src/main/java/com/noteapp/note/service/SupportedNoteBlockService.java new file mode 100644 index 0000000..5eb1363 --- /dev/null +++ b/src/main/java/com/noteapp/note/service/SupportedNoteBlockService.java @@ -0,0 +1,279 @@ +package com.noteapp.note.service; + +import com.noteapp.common.dao.DAOException; +import com.noteapp.common.service.CausedBySystemException; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.note.dao.IConcreateBlockDAO; +import com.noteapp.note.dao.INoteBlockDAO; +import com.noteapp.note.model.NoteBlock; +import static com.noteapp.note.model.NoteBlock.BlockType.SURVEY; +import static com.noteapp.note.model.NoteBlock.BlockType.TEXT; +import com.noteapp.note.model.SurveyBlock; +import com.noteapp.note.model.TextBlock; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author admin + */ +public class SupportedNoteBlockService { + protected INoteBlockDAO noteBlockDAO; + protected IConcreateBlockDAO textBlockDAO; + protected IConcreateBlockDAO surveyBlockDAO; + + protected SupportedNoteBlockService(INoteBlockDAO noteBlockDAO, IConcreateBlockDAO textBlockDAO, IConcreateBlockDAO surveyBlockDAO) { + this.noteBlockDAO = noteBlockDAO; + this.textBlockDAO = textBlockDAO; + this.surveyBlockDAO = surveyBlockDAO; + } + + protected void setNoteBlockDAO(INoteBlockDAO noteBlockDAO) { + this.noteBlockDAO = noteBlockDAO; + } + + protected void setTextBlockDAO(IConcreateBlockDAO textBlockDAO) { + this.textBlockDAO = textBlockDAO; + } + + protected void setSurveyBlockDAO(IConcreateBlockDAO surveyBlockDAO) { + this.surveyBlockDAO = surveyBlockDAO; + } + + private void checkNullDAO() throws NoteAppServiceException { + if (noteBlockDAO == null || textBlockDAO == null || surveyBlockDAO == null) { + throw new CausedBySystemException("DAO is null!"); + } + } + + private List getTextBlocks(NoteBlock noteBlock) throws DAOException { + List returnBlocks = new ArrayList<>(); + List textBlocks = textBlockDAO.getAll(noteBlock.getId()); + for(TextBlock textBlock: textBlocks) { + textBlock.setNoteBlock(noteBlock); + returnBlocks.add(textBlock); + } + return returnBlocks; + } + + private TextBlock getTextBlock(NoteBlock noteBlock, String editor) throws DAOException { + List textBlocks = textBlockDAO.getAll(noteBlock.getId()); + for(TextBlock textBlock: textBlocks) { + if(editor.equals(textBlock.getEditor())) { + textBlock.setNoteBlock(noteBlock); + return textBlock; + } + } + throw new DAOException("Not found!"); + } + + private List getSurveyBlocks(NoteBlock noteBlock) throws DAOException { + List returnBlocks = new ArrayList<>(); + List surveyBlocks = surveyBlockDAO.getAll(noteBlock.getId()); + for(SurveyBlock surveyBlock: surveyBlocks) { + surveyBlock.setNoteBlock(noteBlock); + returnBlocks.add(surveyBlock); + } + return returnBlocks; + } + + private SurveyBlock getSurveyBlock(NoteBlock noteBlock, String editor) throws DAOException { + List surveyBlocks = surveyBlockDAO.getAll(noteBlock.getId()); + for(SurveyBlock surveyBlock: surveyBlocks) { + if(editor.equals(surveyBlock.getEditor())) { + surveyBlock.setNoteBlock(noteBlock); + return surveyBlock; + } + } + throw new DAOException("Not found!"); + } + + /** + * Lấy tất cả các block của một Note + * @param noteId id của Note chứa các block cần lấy + * @return Một List các block của note đó (bao gồm cả các phiên bản tương + * ứng của block) + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + * @see INoteBlockDAO#getAll(int) + * @see ITextBlockDAO#getAll(int) + * @see ISurveyBlockDAO#getAll(int) + * @see TextBlock + * @see SurveyBlock + */ + protected List getAll(int noteId) throws DAOException, NoteAppServiceException { + checkNullDAO(); + //Lấy các thông tin cơ bản của block trước + List noteBlocks = noteBlockDAO.getAll(noteId); + List returnBlocks = new ArrayList<>(); + //Dựa vào kiểu của block mà quyết định gọi DAO nào để lấy các phiên bản tương ứng + for(NoteBlock noteBlock: noteBlocks) { + switch (noteBlock.getBlockType()) { + case TEXT -> { + returnBlocks.addAll(getTextBlocks(noteBlock)); + } + case SURVEY -> { + returnBlocks.addAll(getSurveyBlocks(noteBlock)); + } + } + } + return returnBlocks; + } + + /** + * Lấy tất cả các block của một Note với một phiên bản chỉnh sửa của một User + * @param noteId id của Note chứa các block cần lấy + * @param editor username của chủ phiên bản chỉnh sửa này + * @return Một List các NoteBlock của phiên bản Note tương ứng + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + * @see INoteBlockDAO#getAll(int) + * @see ITextBlockDAO#getAll(int) + * @see ISurveyBlockDAO#getAll(int) + * @see #getAll(int) + * @see TextBlock + * @see SurveyBlock + */ + protected List getAll(int noteId, String editor) throws DAOException, NoteAppServiceException { + checkNullDAO(); + List noteBlocks = noteBlockDAO.getAll(noteId); + List returnBlocks = new ArrayList<>(); + for(NoteBlock noteBlock: noteBlocks) { + switch (noteBlock.getBlockType()) { + case TEXT -> { + returnBlocks.add(getTextBlock(noteBlock, editor)); + } + + case SURVEY -> { + returnBlocks.add(getSurveyBlock(noteBlock, editor)); + } + } + } + return returnBlocks; + } + + /** + * Tạo một block mới và lưu vào các CSDL tương ứng (NoteBlock, TextBlock, SurveyBlock) + * @param noteId id của Note chứa mà block chuẩn bị tạo thuộc về + * @param newBlock NoteBlock cần được tạo + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + * @see INoteBlockDAO#create(int, NoteBlock) + * @see ITextBlockDAO#create(TextBlock) + * @see ISurveyBlockDAO#create(SurveyBlock) + * @see TextBlock + * @see SurveyBlock + */ + protected void create(int noteId, NoteBlock newBlock) throws DAOException, NoteAppServiceException { + checkNullDAO(); + newBlock = noteBlockDAO.create(noteId, newBlock); + switch (newBlock.getBlockType()) { + case TEXT -> { + TextBlock newTextBlock = (TextBlock) newBlock; + textBlockDAO.create(newTextBlock); + } + case SURVEY -> { + SurveyBlock newSurveyBlock = (SurveyBlock) newBlock; + surveyBlockDAO.create(newSurveyBlock); + } + } + } + + protected void createOtherVersion(NoteBlock noteBlock, String otherEditor) throws DAOException, NoteAppServiceException { + checkNullDAO(); + noteBlock.setEditor(otherEditor); + switch (noteBlock.getBlockType()) { + case TEXT -> { + TextBlock newTextBlock = (TextBlock) noteBlock; + textBlockDAO.create(newTextBlock); + } + case SURVEY -> { + SurveyBlock newSurveyBlock = (SurveyBlock) noteBlock; + surveyBlockDAO.create(newSurveyBlock); + } + } + } + + /** + * Cập nhật một NoteBlock trong một Note + * @param noteId id của Note chứa NoteBlock cần cập nhật + * @param needUpdateBlock NoteBlock cần cập nhật + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + * @see INoteBlockDAO#update(int, NoteBlock) + * @see ITextBlockDAO#update(TextBlock) + * @see ISurveyBlockDAO#update(SurveyBlock) + * @see TextBlock + * @see SurveyBlock + */ + protected void update(int noteId, NoteBlock needUpdateBlock) throws DAOException, NoteAppServiceException { + checkNullDAO(); + noteBlockDAO.update(noteId, needUpdateBlock); + switch (needUpdateBlock.getBlockType()) { + case TEXT -> { + TextBlock needUpdateTextBlock = (TextBlock) needUpdateBlock; + textBlockDAO.update(needUpdateTextBlock); + } + case SURVEY -> { + SurveyBlock needUpdateSurveyBlock = (SurveyBlock) needUpdateBlock; + surveyBlockDAO.update(needUpdateSurveyBlock); + } + } + } + + /** + * Xóa một NoteBlock nào đó + * @param blockId id của block cần xóa + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + */ + protected void delete(int blockId) throws DAOException, NoteAppServiceException { + checkNullDAO(); + noteBlockDAO.delete(blockId); + } + + /** + * Lưu một số các blocks của một Note vào CSDL tương ứng + * @param noteId id của Note chứa các blocks cần lưu + * @param noteBlocks các block cần lưu + * @throws DAOException Xảy ra khi các thao tác với CSDL tương ứng + * bị lỗi + * @see #getAll(int, String) + * @see #create(int, NoteBlock) + * @see #update(int, NoteBlock) + * @see #delete(int) + * @see TextBlock + * @see SurveyBlock + */ + protected void save(int noteId, List noteBlocks) throws DAOException, NoteAppServiceException { + //Lấy các block của phiên bản note này + String editor = noteBlocks.get(0).getEditor(); + List blocksInDB = this.getAll(noteId, editor); + //Phân loại các note vào loại cần tạo mới, cần cập nhật, cần xóa + List newBlocks = new ArrayList<>(); + List needUpdateBlocks = new ArrayList<>(); + List deletedBlocks = new ArrayList<>(); + for(NoteBlock noteBlock: noteBlocks) { + if(blocksInDB.contains(noteBlock)) { + needUpdateBlocks.add(noteBlock); + } else { + newBlocks.add(noteBlock); + } + } + for(NoteBlock noteBlock: blocksInDB) { + if(!noteBlocks.contains(noteBlock)) { + deletedBlocks.add(noteBlock); + } + } + //Thực hiện dịch vụ tương ứng với từng loại + for(NoteBlock newBlock: newBlocks) { + this.create(noteId, newBlock); + } + for(NoteBlock needUpdateBlock: needUpdateBlocks) { + this.update(noteId, needUpdateBlock); + } + for(NoteBlock deletedBlock: deletedBlocks) { + this.delete(deletedBlock.getId()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/note/service/io/FileIOService.java b/src/main/java/com/noteapp/note/service/io/FileIOService.java new file mode 100644 index 0000000..a167b8f --- /dev/null +++ b/src/main/java/com/noteapp/note/service/io/FileIOService.java @@ -0,0 +1,36 @@ +package com.noteapp.note.service.io; + +import com.noteapp.note.model.Note; +import com.noteapp.note.model.ShareNote; +import java.io.IOException; + +/** + * + * @author admin + */ +public interface FileIOService { + + /** + * Nhập dữ liệu từ một file vào một Note + * @param inputFileDir Đường dẫn tới file chứa dữ liệu vào + * @return Một Note chứa dữ liệu được đoc + * @throws IOException Việc đọc dữ liệu bị lỗi + */ + Note importNote(String inputFileDir) throws IOException; + + /** + * Xuất dữ liệu từ một Note ra một file + * @param outputFileDir Đường dẫn tới file chứa dữ liệu ra + * @param outputNote Một Note chứa dữ liệu cần xuất + * @throws IOException Việc đọc dữ liệu bị lỗi + */ + void outputNote(String outputFileDir, Note outputNote) throws IOException; + + /** + * Xuất dữ liệu từ một Note ra một file + * @param outputFileDir Đường dẫn tới file chứa dữ liệu ra + * @param outputNote Một Note được chia sẻ chứa dữ liệu cần xuất + * @throws IOException Việc đọc dữ liệu bị lỗi + */ + void outputNote(String outputFileDir, ShareNote outputNote) throws IOException; +} diff --git a/src/main/java/com/noteapp/note/service/io/PdfExportService.java b/src/main/java/com/noteapp/note/service/io/PdfExportService.java new file mode 100644 index 0000000..c083781 --- /dev/null +++ b/src/main/java/com/noteapp/note/service/io/PdfExportService.java @@ -0,0 +1,139 @@ +package com.noteapp.note.service.io; + +import com.itextpdf.text.Chapter; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Font; +import com.itextpdf.text.FontFactory; +import com.itextpdf.text.PageSize; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.Phrase; +import com.itextpdf.text.Section; +import com.itextpdf.text.pdf.PdfPCell; +import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.List; + +/** + * + * @author admin + */ +public class PdfExportService { + private final Document document; + private Chapter allElements; + + /** + * Khởi tạo một Service giúp export ra định dạng file .pdf sử dụng api của itextpdf + * @param outputFileDir Đường dẫn tới file cần ghi + * @param header Đầu đề của file cần ghi + * @throws FileNotFoundException Khi không tìm thấy đường dẫn để ghi file + * @throws DocumentException Khi không thể ghi header vào file + * @see PageSize + */ + public PdfExportService(String outputFileDir, String header) throws FileNotFoundException, DocumentException { + document = new Document(PageSize.A4, 50, 30, 30, 30); + PdfWriter.getInstance(document, new FileOutputStream(outputFileDir)); + document.open(); + setHeaderOfFile(header); + } + + /** + * Khởi tạo một Service giúp export ra định dạng file .pdf sử dụng api của itextpdf + * @param pageSize Size của mỗi page, có thể là A0->A10, etc. + * @param marginLeft Độ rộng lề trái + * @param marginRight Độ rộng lề phải + * @param marginTop Độ rộng lề trên + * @param marginBottom Độ rộng lề dưới + * @param outputFileDir Đường dẫn tới file cần ghi + * @param header Đầu đề của file cần ghi + * @throws FileNotFoundException Khi không tìm thấy đường dẫn để ghi file + * @throws DocumentException Khi không thể ghi header vào file + * @see PageSize + */ + public PdfExportService(float marginLeft, float marginRight, float marginTop, float marginBottom, String outputFileDir, String header) throws FileNotFoundException, DocumentException { + document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom); + PdfWriter.getInstance(document, new FileOutputStream(outputFileDir)); + document.open(); + setHeaderOfFile(header); + } + + protected final void setHeaderOfFile(String fileHeader) { + Font headerFont = FontFactory.getFont(FontFactory.HELVETICA, 25, Font.BOLD); + Paragraph fileHeaderParagraph = new Paragraph(fileHeader, headerFont); + allElements = new Chapter(fileHeaderParagraph, 0); + allElements.setNumberDepth(0); + } + + /** + * Thêm một đoạn text dạng Paragraph và có header vào file document đã khởi tạo + * @param header header của đoạn text + * @param content nội dung của đoạn text + */ + public void writeText(String header, String content) { + //Thiết lập định dạng và nội dung cho header dưới dạng 1 section + Font headerFont = FontFactory.getFont(FontFactory.TIMES_ROMAN, 15, Font.BOLDITALIC); + Paragraph headerOfSection = new Paragraph(header, headerFont); + Section thisBlock = allElements.addSection(headerOfSection); + thisBlock.setNumberDepth(0); + //Thêm nội dung vào section + Paragraph newParagraph = new Paragraph(content); + thisBlock.add(newParagraph); + } + + /** + * Thêm một bảng vào document + * @param header tiêu đề của bảng + * @param columns danh sách tiêu đề của các cột + * @param datas một list 2 chiều lưu giữ data theo từng hàng + */ + public void writeTable(String header, List columns, List> datas) { + //Thiết lập định dạng và nội dung cho header dưới dạng 1 section + Font headerFont = FontFactory.getFont(FontFactory.TIMES_ROMAN, 15, Font.BOLDITALIC); + Paragraph headerOfSection = new Paragraph(header, headerFont); + Section thisBlock = allElements.addSection(headerOfSection); + thisBlock.setNumberDepth(0); + //Thêm một bảng + int numCols = columns.size(); + PdfPTable table = new PdfPTable(numCols); + table.setSpacingBefore(25); + table.setSpacingAfter(25); + //Thêm các cột + for (String column: columns) { + Font columnHeaderFont = FontFactory.getFont(FontFactory.TIMES_ROMAN, 13, Font.BOLD); + PdfPCell newCell = new PdfPCell(new Phrase(column, columnHeaderFont)); + table.addCell(newCell); + } + //Tìm số hàng cần thiết + int numRows = datas.size(); + //Duyệt từng hàng để thêm dữ liệu, nếu có một cột bị hết dữ liệu thì sẽ thêm chuỗi rỗng + for (int i = 0; i < numRows; i++) { + for (int j = 0; j < numCols; j++) { + try { + table.addCell(datas.get(i).get(j)); + } catch (IndexOutOfBoundsException e) { + table.addCell(""); + } + } + } + thisBlock.add(table); + } + + /** + * Kết thúc việc ghi dữ liệu ra file .pdf. Bạn phải gọi phương thức này + * để việc ghi dữ liệu được hoàn tất, nếu không, có thể dẫn tới trường + * hợp không được ghi thành công. + * @return {@code true} nếu quá trình ghi dữ liệu được hoàn thành, + * {@code false} nếu ngược lại + */ + public boolean endWrite() { + try { + document.add(allElements); + document.close(); + return true; + } catch (DocumentException e) { + return false; + } + } +} diff --git a/src/main/java/com/noteapp/note/service/io/PdfIOService.java b/src/main/java/com/noteapp/note/service/io/PdfIOService.java new file mode 100644 index 0000000..7e8c25e --- /dev/null +++ b/src/main/java/com/noteapp/note/service/io/PdfIOService.java @@ -0,0 +1,152 @@ +package com.noteapp.note.service.io; + +import com.itextpdf.text.DocumentException; +import com.noteapp.note.model.Note; +import com.noteapp.note.model.NoteBlock; +import com.noteapp.note.model.ShareNote; +import com.noteapp.note.model.SurveyBlock; +import com.noteapp.note.model.TextBlock; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + * @author admin + */ +public class PdfIOService implements FileIOService { + private PdfImportService importService; + private PdfExportService exportService; + + @Override + public Note importNote(String inputFileDir) throws IOException { + //Khởi tạo import service + importService = new PdfImportService(inputFileDir); + //Tạo note và đọc header, đọc mỗi page để lấy dữ liệu + Note note = new Note(); + note.setHeader(inputFileDir); + List blocks = importService.readTextEachPage(); + //Lấy mỗi block là dữ liệu ở một page và thêm vào Note + for (int i = 0; i < blocks.size(); i++) { + TextBlock newTextBlock = new TextBlock(); + newTextBlock.setOrder(i + 1); + newTextBlock.setHeader("page " + String.valueOf(i + 1)); + newTextBlock.setContent(blocks.get(i)); + note.getBlocks().add(newTextBlock); + } + return note; + } + + @Override + public void outputNote(String outputFileDir, Note outputNote) throws IOException { + //Khởi tạo export service + try { + exportService = new PdfExportService(outputFileDir, outputNote.getHeader()); + //Thực hiện duyệt các block và lưu trữ dạng dữ liệu tương ứng + for (NoteBlock block: outputNote.getBlocks()) { + if (block.getBlockType() == NoteBlock.BlockType.TEXT) { + exportService.writeText(block.getHeader(), ((TextBlock) block).getContent()); + } else { + List columns = new ArrayList<>(); + columns.add("choice"); + columns.add("your vote"); + List> datas = getTableDataFromSurvey(((SurveyBlock) block)); + exportService.writeTable(block.getHeader(), columns, datas); + } + } + exportService.endWrite(); + } catch (DocumentException ex) { + throw new IOException(ex.getCause()); + } + } + + @Override + public void outputNote(String outputFileDir, ShareNote outputNote) throws IOException { + //Khởi tạo export service + try { + exportService = new PdfExportService(outputFileDir, outputNote.getHeader()); + //Thực hiện duyệt các block và lưu trữ dạng dữ liệu tương ứng + for (NoteBlock block: outputNote.getBlocks()) { + if (block.getBlockType() == NoteBlock.BlockType.TEXT) { + exportService.writeText(block.getHeader(), ((TextBlock) block).getContent()); + } else { + List columns = new ArrayList<>(); + columns.add("choice"); + columns.add("your vote"); + columns.add("total vote"); + columns.add("other vote"); + List> datas = getTableDataFromSurvey((SurveyBlock) block, outputNote.getOtherEditorBlocks()); + exportService.writeTable(block.getHeader(), columns, datas); + } + } + exportService.endWrite(); + } catch (DocumentException ex) { + throw new IOException(ex.getCause()); + } + } + + protected List> getTableDataFromSurvey(SurveyBlock surveyBlock) { + List> datas = new ArrayList<>(); + for (Map.Entry entry: surveyBlock.getSurveyMap().entrySet()) { + List newRow = new ArrayList<>(); + newRow.add(entry.getKey()); + newRow.add(String.valueOf(entry.getValue())); + datas.add(newRow); + } + return datas; + } + + protected List> getTableDataFromSurvey(SurveyBlock surveyBlock, Map> otherEditors) { + List> datas = new ArrayList<>(); + for (Map.Entry entry: surveyBlock.getSurveyMap().entrySet()) { + //Lấy choice và your vote + List newRow = new ArrayList<>(); + String choice = entry.getKey(); + boolean isVoted = entry.getValue(); + int numVoted = 0; + newRow.add(choice); + + if (isVoted) { + newRow.add("yes"); + numVoted += 1; + } else { + newRow.add("no"); + } + //Lấy số lượng và vote của các editor khác + List otherSurveyBlocks = findOthersBlocks(surveyBlock, otherEditors); + List others = new ArrayList<>(); + for (SurveyBlock otherSurveyBlock: otherSurveyBlocks) { + if (otherSurveyBlock.getSurveyMap().get(choice)) { + numVoted += 1; + others.add(otherSurveyBlock.getEditor()); + } + } + + newRow.add(String.valueOf(numVoted)); + newRow.add(convertOthers(others)); + + datas.add(newRow); + } + return datas; + } + + protected String convertOthers(List others) { + String otherStr = ""; + for (String otherVoted: others) { + otherStr += otherVoted + ", "; + } + return otherStr; + } + + protected List findOthersBlocks(NoteBlock noteBlock, Map> otherEditors) { + List res = new ArrayList<>(); + if (noteBlock.getBlockType() == NoteBlock.BlockType.TEXT) { + return res; + } + for (NoteBlock block: otherEditors.get(noteBlock.getId())) { + res.add((SurveyBlock) block); + } + return res; + } +} diff --git a/src/main/java/com/noteapp/note/service/io/PdfImportService.java b/src/main/java/com/noteapp/note/service/io/PdfImportService.java new file mode 100644 index 0000000..c805453 --- /dev/null +++ b/src/main/java/com/noteapp/note/service/io/PdfImportService.java @@ -0,0 +1,62 @@ +package com.noteapp.note.service.io; + +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.parser.PdfTextExtractor; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author admin + */ +public class PdfImportService { + private final PdfReader pdfReader; + + /** + * Khởi tạo một service đọc file .pdf bằng api của itextpdf + * @param inputFileDir Đường dẫn tới file cần đọc + * @throws IOException Khi file không tồn tại hoặc việc đọc file bị lỗi + */ + public PdfImportService(String inputFileDir) throws IOException { + this.pdfReader = new PdfReader(inputFileDir); + } + + /** + * Đọc dữ liệu dạng văn bản từ file .pdf ở một trang xác định + * @param page số thứ tự của trang cần đọc + * @return Dữ liệu dạng văn bản được đọc trong trang này + * @throws IOException nếu việc đọc dữ liệu bị lỗi + */ + public String readTextAtPage(int page) throws IOException { + return PdfTextExtractor.getTextFromPage(pdfReader, page); + } + + /** + * Đọc dữ liệu dạng văn bản từ file .pdf + * @return Dữ liệu dạng văn bản được đọc + * @throws IOException nếu việc đọc dữ liệu bị lỗi + */ + public String readText() throws IOException { + int numOfPages = pdfReader.getNumberOfPages(); + String res = ""; + for (int i = 1; i <= numOfPages; i++) { + res += readTextAtPage(i); + } + return res; + } + + /** + * Đọc dữ liệu dạng văn bản từ file .pdf + * @return Trả về một List lưu giữ dữ liệu ở mỗi trang + * @throws IOException nếu việc đọc dữ liệu bị lỗi + */ + public List readTextEachPage() throws IOException { + int numOfPages = pdfReader.getNumberOfPages(); + List res = new ArrayList<>(); + for (int i = 1; i <= numOfPages; i++) { + res.add(readTextAtPage(i)); + } + return res; + } +} diff --git a/src/main/java/com/noteapp/user/service/AdminService.java b/src/main/java/com/noteapp/user/service/AdminService.java new file mode 100644 index 0000000..61b5afb --- /dev/null +++ b/src/main/java/com/noteapp/user/service/AdminService.java @@ -0,0 +1,99 @@ +package com.noteapp.user.service; + +import com.noteapp.common.dao.DAOException; +import com.noteapp.common.dao.NotExistDataException; +import com.noteapp.common.service.CausedBySystemException; +import com.noteapp.common.service.CausedByUserException; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.IAdminDAO; +import com.noteapp.user.dao.IUserDAO; +import com.noteapp.user.model.Admin; +import com.noteapp.user.model.User; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author admin + */ +public class AdminService implements IAdminService { + protected IUserDAO userDAO; + protected IAdminDAO adminDAO; + + public AdminService(IUserDAO userDAO, IAdminDAO adminDAO) { + this.userDAO = userDAO; + this.adminDAO = adminDAO; + } + + public void setUserDAO(IUserDAO userDAO) { + this.userDAO = userDAO; + } + + public void setAdminDAO(IAdminDAO adminDAO) { + this.adminDAO = adminDAO; + } + + private void checkNullDAO() throws NoteAppServiceException { + if (adminDAO == null || userDAO == null) { + throw new CausedBySystemException("DAO is null!"); + } + } + + @Override + public boolean isAdmin(String username) throws NoteAppServiceException { + checkNullDAO(); + try { + adminDAO.get(username); + return true; + } catch (NotExistDataException ex1) { + return false; + } catch (DAOException ex2) { + throw new CausedBySystemException(ex2.getMessage(), ex2.getCause()); + } + } + + @Override + public Admin checkAdmin(String username, String password) throws NoteAppServiceException { + checkNullDAO(); + try { + //Lấy tài khoản + Admin admin = adminDAO.get(username); + //Kiểm tra mật khẩu + if(password.equals(admin.getPassword())) { + return admin; + } else { + throw new CausedByUserException("Password is false!"); + } + } catch (DAOException exByGet) { + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); + } + } + + @Override + public Map getAllLockedStatus() throws NoteAppServiceException { + checkNullDAO(); + try { + List users = userDAO.getAll(); + Map lockedStatus = new HashMap<>(); + for (User user: users) { + lockedStatus.put(user.getUsername(), user.isLocked()); + } + return lockedStatus; + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } + + @Override + public void updateLockedStatus(String username, boolean lockedStatus) throws NoteAppServiceException { + checkNullDAO(); + try { + User user = userDAO.get(username); + user.setLocked(lockedStatus); + userDAO.update(user); + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/noteapp/user/service/IAdminService.java b/src/main/java/com/noteapp/user/service/IAdminService.java new file mode 100644 index 0000000..a016186 --- /dev/null +++ b/src/main/java/com/noteapp/user/service/IAdminService.java @@ -0,0 +1,47 @@ +package com.noteapp.user.service; + +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.model.Admin; +import java.util.Map; + +/** + * + * @author admin + */ +public interface IAdminService { + + /** + * Kiểm tra xem một tên đăng nhập có phải là admin hay không + * @param username username cần kiểm tra + * @return {@code true} nếu đây là một {@link Admin}, {@code false} nếu ngược lại + * @throws NoteAppServiceException Xảy ra khi các câu lệnh không thể + * thực hiện do kết nối tới CSDL + */ + public boolean isAdmin(String username) throws NoteAppServiceException; + + /** + * Kiểm tra tài khoản và mật khẩu để đăng nhập + * @param username username được nhập + * @param password password được nhập + * @return Các thông tin của Admin nếu tài khoản và mật khẩu đúng + * @throws NoteAppServiceException Xảy ra khi (1) Admin không tồn tại, + * (2) password sai, (3) Việc thực thi các câu lệnh lỗi + */ + Admin checkAdmin(String username, String password) throws NoteAppServiceException; + + /** + * Lất tất cả các thông tin bị khóa quyền hay không của các user + * @return Một Map chứa username và trạng thái khóa tương ứng của + * các {@link User} + * @throws NoteAppServiceException Xảy ra khi các câu lệnh bị lỗi + */ + public Map getAllLockedStatus() throws NoteAppServiceException; + + /** + * Cập nhật trạng thái khóa của một user + * @param username username của {@link User} cần cập nhật + * @param lockedStatus trạng thái khóa cần cập nhật của User + * @throws NoteAppServiceException Xảy ra khi các câu lệnh bị lỗi + */ + void updateLockedStatus(String username, boolean lockedStatus) throws NoteAppServiceException; +} diff --git a/src/main/java/com/noteapp/user/service/IUserService.java b/src/main/java/com/noteapp/user/service/IUserService.java new file mode 100644 index 0000000..e84c185 --- /dev/null +++ b/src/main/java/com/noteapp/user/service/IUserService.java @@ -0,0 +1,66 @@ +package com.noteapp.user.service; + +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.model.Email; +import com.noteapp.user.model.User; + +/** + * + * @author admin + */ +public interface IUserService { + + boolean isUser(String username) throws NoteAppServiceException; + + /** + * Tạo một {@link User} mới và lưu và CSDL, đồng thời trả lại User vừa tạo + * @param newUser User cần tạo + * @return User được tạo thành công. + * @throws NoteAppServiceException Xảy ra khi (1) User đã tồn tại, + * (2) Các câu lệnh không thể thực hiện do kết nối tới CSDL + */ + User create(User newUser) throws NoteAppServiceException; + + /** + * Kiểm tra tài khoản và mật khẩu để đăng nhập + * @param username username được nhập + * @param password password được nhập + * @return Các thông tin của User nếu tài khoản và mật khẩu đúng + * @throws NoteAppServiceException Xảy ra khi (1) User không tồn tại, + * (2) password sai, (3) Việc thực thi các câu lệnh lỗi + */ + User checkUser(String username, String password) throws NoteAppServiceException; + + /** + * Kiểm tra xem một user có bị khóa quyền không? + * @param username username của {@link User} cần kiểm tra + * @return {@code true} nếu User này bị khóa, {@code false} nếu ngược lại + * @throws NoteAppServiceException Xảy ra khi các câu lệnh bị lỗi + */ + boolean checkLocked(String username) throws NoteAppServiceException; + + /** + * Cập nhật mật khẩu của User + * @param username username của user + * @param newPassword password mới của user + * @throws NoteAppServiceException Xảy ra khi (1) User không tồn tại, + * (2) Các câu lệnh bị lỗi + */ + void updatePassword(String username, String newPassword) throws NoteAppServiceException; + + /** + * Cập nhật các thông tin của user + * @param user User cần cập nhật + * @return User sau khi cập nhật + * @throws NoteAppServiceException Xảy ra khi câu lệnh hoặc kết nối bị lỗi + */ + User update(User user) throws NoteAppServiceException; + + /** + * Lấy địa chỉ email xác thực của User + * @param username username của User cần lấy + * @return Một {@link Email} chứa địa chỉ email xác thực của User + * @throws NoteAppServiceException Xảy ra khi không thể lấy dữ liệu của User + */ + Email getVerificationEmail(String username) throws NoteAppServiceException; +} diff --git a/src/main/java/com/noteapp/user/service/UserService.java b/src/main/java/com/noteapp/user/service/UserService.java new file mode 100644 index 0000000..6543b1e --- /dev/null +++ b/src/main/java/com/noteapp/user/service/UserService.java @@ -0,0 +1,132 @@ +package com.noteapp.user.service; + +import com.noteapp.common.dao.DAOException; +import com.noteapp.common.dao.NotExistDataException; +import com.noteapp.common.service.CausedBySystemException; +import com.noteapp.common.service.CausedByUserException; +import com.noteapp.common.service.NoteAppServiceException; +import com.noteapp.user.dao.IUserDAO; +import com.noteapp.user.model.Email; +import com.noteapp.user.model.User; + +/** + * Cung cấp các service liên quan tới User + * @author Nhóm 17 + * @see IUserDAO + * @see User + */ +public class UserService implements IUserService { + protected IUserDAO userDAO; + + public UserService(IUserDAO userDAO) { + this.userDAO = userDAO; + } + + public void setUserDAO(IUserDAO userDAO) { + this.userDAO = userDAO; + } + + private void checkNullDAO() throws NoteAppServiceException { + if (userDAO == null) { + throw new CausedBySystemException("DAO is null!"); + } + } + + @Override + public boolean isUser(String username) throws NoteAppServiceException { + checkNullDAO(); + try { + userDAO.get(username); + return true; + } catch (NotExistDataException ex1) { + return false; + } catch (DAOException ex2) { + throw new CausedBySystemException(ex2.getMessage(), ex2.getCause()); + } + } + + @Override + public User create(User newUser) throws NoteAppServiceException { + checkNullDAO(); + String username = newUser.getUsername(); + //Kiểm tra đã tồn tại user hay chưa + try { + userDAO.get(username); + throw new CausedByUserException("This user is already exist!"); + } catch (NotExistDataException nedExForGet) { + //Nếu chưa thì tiếp tục + } catch (DAOException exByGet) { + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); + } + //Tạo User mới và trả về + try { + return userDAO.create(newUser); + } catch (DAOException exByCreate) { + throw new CausedBySystemException(exByCreate.getMessage()); + } + } + + @Override + public User checkUser(String username, String password) throws NoteAppServiceException { + checkNullDAO(); + try { + //Lấy tài khoản + User user = userDAO.get(username); + //Kiểm tra mật khẩu + if(password.equals(user.getPassword())) { + return user; + } else { + throw new CausedByUserException("Password is false!"); + } + } catch (DAOException exByGet) { + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); + } + } + + @Override + public boolean checkLocked(String username) throws NoteAppServiceException { + checkNullDAO(); + try { + //Lấy tài khoản + User user = userDAO.get(username); + //Kiểm tra mật khẩu + return user.isLocked(); + } catch (DAOException exByGet) { + throw new CausedBySystemException(exByGet.getMessage(), exByGet.getCause()); + } + } + + @Override + public void updatePassword(String username, String newPassword) throws NoteAppServiceException { + checkNullDAO(); + try { + User user = userDAO.get(username); + user.setPassword(newPassword); + userDAO.update(user); + } catch (DAOException ex) { + throw new CausedBySystemException(ex.getMessage(), ex.getCause()); + } + } + + @Override + public User update(User user) throws NoteAppServiceException { + checkNullDAO(); + try { + userDAO.update(user); + return user; + } catch (DAOException exByUpdate) { + throw new CausedBySystemException(exByUpdate.getMessage()); + } + } + + @Override + public Email getVerificationEmail(String username) throws NoteAppServiceException { + checkNullDAO(); + try { + User user = userDAO.get(username); + return user.getEmail(); + } catch (DAOException exByGet) { + throw new CausedBySystemException(exByGet.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index af66ab9..a1b08ee 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -6,6 +6,7 @@ requires com.mailjet.api; requires org.json; requires okhttp3; + requires itextpdf; opens com.noteapp to javafx.fxml; exports com.noteapp; diff --git a/src/main/resources/com/noteapp/view/EditNoteView.fxml b/src/main/resources/com/noteapp/view/EditNoteView.fxml new file mode 100644 index 0000000..dfe0b33 --- /dev/null +++ b/src/main/resources/com/noteapp/view/EditNoteView.fxml @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/noteapp/view/TextBlockView.fxml b/src/main/resources/com/noteapp/view/TextBlockView.fxml new file mode 100644 index 0000000..80400a1 --- /dev/null +++ b/src/main/resources/com/noteapp/view/TextBlockView.fxml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + +