Skip to content

Commit

Permalink
Alustava arkkitehtuuri dokumentaatio, lisättiin käyttäjän luontisivu,…
Browse files Browse the repository at this point in the history
… lisää testejä, jacocon pientä konfiguroimista
  • Loading branch information
JoonasC committed May 4, 2021
1 parent 6b8f215 commit a47b067
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Contactmanager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ javafx {
version = '16'
modules = ['javafx.controls']
}

jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: ['views/*', 'dialogs/*', 'utils/*'])
}))
}
}
28 changes: 28 additions & 0 deletions Contactmanager/src/main/java/controllers/CreateUserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package controllers;

import models.CreateUserModel;
import utils.PathUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CreateUserController extends Controller<CreateUserModel> {
public void createUser(String username) throws IOException {
if (!Paths.get(PathUtils.getDataDir().toString(), username).toFile().exists() && !username.isEmpty()) {
Files.createDirectory(Paths.get(PathUtils.getDataDir().toString(), username));
model.setUserCreated(true);
model.setErrorMessage("");
} else {
model.setUserCreated(false);
model.setErrorMessage("Username is taken");
}

model.renderView();
}

public void exit() {
model.setUserCreated(false);
model.setErrorMessage("");
}
}
4 changes: 4 additions & 0 deletions Contactmanager/src/main/java/controllers/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ public void logout() {
model.setErrorMessage("");
model.renderView();
}

public void exit() {
model.setErrorMessage("");
}
}
9 changes: 9 additions & 0 deletions Contactmanager/src/main/java/controllers/MainController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import models.MainModel;
import utils.PathUtils;

import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.Set;
Expand All @@ -30,6 +32,13 @@ private void saveContacts() throws IOException {
}

public void loadContacts() throws IOException {
if (!Paths.get(PathUtils.getDataDir().toString(), model.getLoggedInUsername(), "contacts.json").toFile().exists()) {
Files.createFile(Paths.get(PathUtils.getDataDir().toString(), model.getLoggedInUsername(), "contacts.json"));
FileWriter fileWriter = new FileWriter(Paths.get(PathUtils.getDataDir().toString(), model.getLoggedInUsername(), "contacts.json").toString());
fileWriter.write("[]");
fileWriter.close();
}

Set<Contact> loadedContacts = objectMapper
.readValue(
Paths.get(
Expand Down
24 changes: 24 additions & 0 deletions Contactmanager/src/main/java/models/CreateUserModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package models;

import views.CreateUserView;

public class CreateUserModel extends Model<CreateUserView> {
private boolean userCreated = false;
private String errorMessage = "";

public boolean isUserCreated() {
return userCreated;
}

public void setUserCreated(boolean userCreated) {
this.userCreated = userCreated;
}

public String getErrorMessage() {
return errorMessage;
}

public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
4 changes: 4 additions & 0 deletions Contactmanager/src/main/java/routing/Router.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package routing;

import controllers.Controller;
import controllers.CreateUserController;
import controllers.LoginController;
import controllers.MainController;
import javafx.stage.Stage;
import models.CreateUserModel;
import models.LoginModel;
import models.MainModel;
import models.Model;
import views.CreateUserView;
import views.LoginView;
import views.MainView;
import views.View;
Expand All @@ -29,6 +32,7 @@ public Router(Stage mainStage) throws InvocationTargetException, NoSuchMethodExc
this.mainStage = mainStage;

instantiateViewsControllersAndModels(LoginView.class, LoginController.class, LoginModel.class);
instantiateViewsControllersAndModels(CreateUserView.class, CreateUserController.class, CreateUserModel.class);
instantiateViewsControllersAndModels(MainView.class, MainController.class, MainModel.class);

navigateTo(LoginView.class, Map.of());
Expand Down
106 changes: 106 additions & 0 deletions Contactmanager/src/main/java/views/CreateUserView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package views;

import controllers.CreateUserController;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import models.CreateUserModel;
import routing.Router;

import java.io.IOException;
import java.util.Map;

public class CreateUserView extends View<CreateUserController, CreateUserModel> {
private final Label errorLabel;
private final TextField usernameTextField;
private final Scene scene;

public CreateUserView(Router router) {
super(router);

errorLabel = new Label();
errorLabel.setVisible(false);
errorLabel.setTextFill(Color.RED);
Label usernameLabel = new Label("Username");
usernameTextField = new TextField();
Button createUserButton = new Button("Create user");
Button cancelButton = new Button("Cancel");
HBox createUserButtonContainer = new HBox(
createUserButton
);
createUserButtonContainer.setAlignment(Pos.CENTER);
HBox cancelButtonContainer = new HBox(
cancelButton
);
cancelButtonContainer.setAlignment(Pos.CENTER);
VBox mainContainer = new VBox(
errorLabel,
usernameLabel,
usernameTextField,
createUserButtonContainer,
cancelButtonContainer
);
mainContainer.setSpacing(2);
mainContainer.setPadding(new Insets(10));
scene = new Scene(
mainContainer
);

createUserButton.setOnMouseClicked(event -> {
try {
controller.createUser(usernameTextField.getText());
} catch (IOException exc) {
exc.printStackTrace();
}
});
cancelButton.setOnMouseClicked(event -> {
controller.exit();
usernameTextField.clear();
render();
router.navigateTo(LoginView.class, Map.of());
});
}

@Override
public String getWindowTitleSuffix() {
return "Create user";
}

@Override
public int getWindowWidth() {
return 400;
}

@Override
public int getWindowHeight() {
return 200;
}

@Override
public Scene getScene() {
return scene;
}

@Override
public void onNavigateTo(Map<String, Object> arguments) {
}

@Override
public void render() {
errorLabel.setText(model.getErrorMessage());
errorLabel.setVisible(!model.getErrorMessage().isEmpty());

if (model.isUserCreated()) {
controller.exit();
usernameTextField.clear();

router.navigateTo(LoginView.class, Map.of());
}
}
}
7 changes: 7 additions & 0 deletions Contactmanager/src/main/java/views/LoginView.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public LoginView(Router router) {
);

loginButton.setOnMouseClicked(event -> controller.login(usernameTextField.getText()));
createUserButton.setOnMouseClicked(event -> {
controller.exit();
usernameTextField.clear();
render();
router.navigateTo(CreateUserView.class, Map.of());
});
}

@Override
Expand Down Expand Up @@ -95,6 +101,7 @@ public void render() {
errorLabel.setVisible(!model.getErrorMessage().isEmpty());

if (model.isLoggedIn()) {
controller.exit();
usernameTextField.clear();

router.navigateTo(MainView.class, Map.of("loggedInUsername", model.getLoggedInUsername()));
Expand Down
59 changes: 59 additions & 0 deletions Contactmanager/src/test/java/CreateUserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import controllers.CreateUserController;
import models.CreateUserModel;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import utils.PathUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class CreateUserTest {
private CreateUserController controller;
private CreateUserModel model;

@BeforeClass
public static void environmentSetUp() throws IOException {
PathUtils.ensureDataDirExists();
}

@Before
public void setUp() {
controller = new CreateUserController();
model = new CreateUserModel();
controller.setModel(model);

controller.mock();
model.mock();
}

@After
public void tearDown() throws IOException {
Files.delete(Paths.get(PathUtils.getDataDir().toString(), "test"));
}

@Test
public void creatingAUserWithAUsernameThatIsAlreadyTakenShouldWorkAsExpected() throws IOException {
Path testUserPath = Paths.get(PathUtils.getDataDir().toString(), "test");

Files.createDirectory(testUserPath);

controller.createUser("test");
assertEquals(model.getErrorMessage(), "Username is taken");
}

@Test
public void creatingAUserWithAUsernameThatIsNotAlreadyTakenShouldWorkAsExpected() throws IOException {
controller.createUser("test");

assertEquals(model.getErrorMessage(), "");
assertTrue(model.isUserCreated());
assertTrue(Paths.get(PathUtils.getDataDir().toString(), "test").toFile().exists());
}
}
55 changes: 54 additions & 1 deletion dokumentaatio/Arkkitehtuurikuvaus.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,61 @@ Ohjelman pakkausrakenne on seuraavanlainen:



## Käyttöliittymä

Käyttöliittymä sisältää kolme erillistä sivua:

- Sisäänkirjautumissivu
- Uuuden käytttäjän luomissivu
- Yhteystietojen managointisivu



Kuten aiemmin kuvattu, jokainen sivu muodostuu kolmesta osasta: mallista, näkymästä ja ohjaajasta:

- Malli sisältää sivun tilan, esim. sisäänkirjautumissivun suhteen malli sisältää tiedon siitä:
- Onko virheviestiä joka pitäisi näyttää käyttäjälle.
- Onko käyttäjä kirjautunut sisään.
- Mikä on sisäänkirjautuneen käyttäjän nimi.
- Näkymä toteuttaa sivun visuaaliset elementit JavaFX:llä, se sisältää oman scene olionsa, tiedon siitä kuinka suuri ikkunan täytyy olla kun sivu näytetään, tiedon siitä mikä ikkunan otsikon täytyy olla kun sivu näytetään sekä renderöintilogiikan (hakee mallista tilan ja renderöi sivun sen mukaisesti) ja logiikan joka kutsuu ohjaajaa kun käyttäjä käyttää sivua (esim. painaa nappia).
- Ohjaaja sisältää sivun logiikan ja päivittää mallia käyttäjän toimien mukaisesti, esim. sisäänkirjautumissivun suhteen ohjaaja:
- Toteuttaa sisäänkirjautumislogiikan (katsoo onko käyttäjä olemassa, ja päivittää mallia sen mukaisesti).
- Toteuttaa uloskirjautumislogiikan (resetoi mallin takaisin alkutilaan).



Toinen käyttöliittymälle tärkeä osa on reititin, jonka tehtävänä on vaihtaa sivua.

Kun reitin vaihtaa sivua, se:

- Katsoo onko sivu suojattu (vaatii sisäänkirjautumista), ja jos on, tarkistaa onko käyttäjä sisäänkirjautunut. Jos käyttäjä ei ole sisäänkirjautunut, reititin ei tee mitään.
- Löytää sivun näkymän instanssin.
- Ottaa sivun näkymästä scene olion, tiedot ikkunan koosta sekä otsikosta ja configuroi stagen niiden mukaisesti.

Lisäksi reititin voi myös kuljettaa tietoa sivujen välillä, esim. kun käyttäjä kirjautuu sisään ja reititin vaihtaa sivua sisäänkirjautumissivusta yhteystietojen managointisivuun, se vie sisäänkirjautumissivusta tiedon siitä mikä käyttäjä on kirjautunut sisään yhteystietojen managointisivuun.



Lisäksi, käyttöliittymä sisältää myös MVC mallille ulkoisia ponnahdusikkunoita, kuten hälytysikkunoita ja yhteystiedon luomis/muokkaus ikkunan. Nämä ovat kertakäyttöisiä, eivätkä siten tarvitse pysyvää tilaa.



## Datamalli

Ohjelma esittää yhteystietoja `Contact` olioina, nämä oliot sisältävät yhteystiedon nimen, puhelinnumeron ja sähköpostiosoitteen.



## Tietojen pysyväistallennus

Tietojen tallennuksesta ja lataamisesta huolehtivat sivujen ohjaajat. Yhteystiedot tallennetaan käyttäjälle luodun kansion sisälle JSON tiedostoon.



## Päätoiminnallisuudet

### Sisäänkirjautuminen

![](https://raw.githubusercontent.com/JoonasC/ot-harjoitustyo/master/dokumentaatio/kuvat/Sis%C3%A4%C3%A4nkirjautumis-sekvenssikaavio.png)
![](https://raw.githubusercontent.com/JoonasC/ot-harjoitustyo/master/dokumentaatio/kuvat/Sis%C3%A4%C3%A4nkirjautumis-sekvenssikaavio.png)

**Huom:** Ylläolevassa sekvenssikaaviossa on pieni virhe, `Router` ei pyydä `MainModelilta` kontakteja, `MainView` pyytää.

0 comments on commit a47b067

Please sign in to comment.