Skip to content

Commit

Permalink
adding check logic and consiquent test
Browse files Browse the repository at this point in the history
  • Loading branch information
roman-iork committed Jun 26, 2024
1 parent 938e0f0 commit 39d07bb
Show file tree
Hide file tree
Showing 17 changed files with 348 additions and 54 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ dependencies {
implementation 'org.postgresql:postgresql:42.7.3'
implementation 'com.h2database:h2:2.2.224'
implementation 'gg.jte:jte:3.1.12'
implementation 'com.konghq:unirest-java-bom:4.4.0'
implementation 'com.konghq:unirest-java-core:4.4.0'
implementation 'com.konghq:unirest-modules-jackson:4.4.0'
//test
testImplementation platform('org.junit:junit-bom:5.10.2')
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
testImplementation('org.assertj:assertj-core:3.26.0')
testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0'
}

test {
Expand Down
49 changes: 13 additions & 36 deletions src/main/java/hexlet/code/App.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package hexlet.code;

import hexlet.code.utils.Utils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import gg.jte.ContentType;
import gg.jte.TemplateEngine;
import gg.jte.resolve.ResourceCodeResolver;
import hexlet.code.controller.RootController;
import hexlet.code.controller.UrlsController;
import hexlet.code.repository.BaseRepository;
Expand All @@ -18,47 +16,25 @@
import java.util.stream.Collectors;

public class App {

//entrance point -> create app and start it
public static void main(String[] args) throws SQLException {
var app = getApp();
app.start(7070);
}

private static String getDBUrl(boolean isTest) {
if (isTest) {
return "jdbc:h2:mem:project";
}
return System.getenv().getOrDefault("JDBC_DATABASE_URL", "jdbc:h2:mem:project");
// "jdbc:h2:mem:project;DB_CLOSE_DELAY=-1;"
}
private static String getSchemaTemplate(boolean isTest) {
if (isTest) {
return "schemaH2.sql";
}
var isH2 = System.getenv().get("JDBC_DATABASE_URL") == null;
return isH2 ? "schemaH2.sql" : "schema.sql";
}

private static TemplateEngine createTemplateEngine() {
ClassLoader classLoader = App.class.getClassLoader();
ResourceCodeResolver codeResolver = new ResourceCodeResolver("templates", classLoader);
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
return templateEngine;
}

//getApp with parameter -> to choose app for tests because of different DBs and table structures
public static Javalin getApp() throws SQLException {
return getApp(false);
}

public static Javalin getApp(boolean isTest) throws SQLException {
//configuring pool of connections
var hikariConfig = new HikariConfig();
var dbUrl = getDBUrl(isTest);
var dbUrl = Utils.getDBUrl(isTest);
hikariConfig.setJdbcUrl(dbUrl);

//creating source of connections
var dataSource = new HikariDataSource(hikariConfig);
BaseRepository.dataSource = dataSource;

var schema = App.class.getClassLoader().getResourceAsStream(getSchemaTemplate(isTest));
//creating table structure
var schema = App.class.getClassLoader().getResourceAsStream(Utils.getSchemaTemplate(isTest));
if (schema != null) {
var sql = new BufferedReader(new InputStreamReader(schema))
.lines().collect(Collectors.joining("\n"));
Expand All @@ -67,24 +43,25 @@ public static Javalin getApp(boolean isTest) throws SQLException {
try {
statement.execute(sql);
} catch (SQLException e) {
System.out.println("Looks like table already exists!");
System.out.println(e.getMessage());
}
}
} else {
throw new SQLException("DB structure was not provided!");
}

//creating javalin app and configuring logging and template engine
var app = Javalin.create(config -> {
config.bundledPlugins.enableDevLogging();
config.fileRenderer(new JavalinJte(createTemplateEngine()));
config.fileRenderer(new JavalinJte(Utils.createTemplateEngine()));
});
//root route
app.get(NamedRoutes.rootPath(), RootController::root);
//url related routes
app.get(NamedRoutes.urlsPath(), UrlsController::urls);
app.post(NamedRoutes.urlsPath(), UrlsController::add);
app.get(NamedRoutes.urlPath("{id}"), UrlsController::url);

app.post(NamedRoutes.checkPath("{id}"), UrlsController::check);
//ready app
return app;
}
}
51 changes: 45 additions & 6 deletions src/main/java/hexlet/code/controller/UrlsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
import hexlet.code.dto.UrlPage;
import hexlet.code.dto.UrlsPage;
import hexlet.code.model.Url;
import hexlet.code.model.UrlCheck;
import hexlet.code.repository.UrlCheckRepository;
import hexlet.code.repository.UrlsRepository;
import hexlet.code.utils.NamedRoutes;
import hexlet.code.utils.Utils;
import io.javalin.http.Context;
import kong.unirest.core.Unirest;
import kong.unirest.core.UnirestException;

import static io.javalin.rendering.template.TemplateUtil.model;

Expand All @@ -18,7 +23,9 @@
public class UrlsController {
public static void urls(Context ctx) throws SQLException {
var urlsList = UrlsRepository.getUrls();
var page = new UrlsPage(ctx.consumeSessionAttribute("flash"), ctx.consumeSessionAttribute("status"), urlsList);
var page = new UrlsPage(ctx.consumeSessionAttribute("flash"),
ctx.consumeSessionAttribute("flashStatus"),
urlsList);
ctx.render("urls.jte", model("page", page));
}

Expand All @@ -35,22 +42,26 @@ public static void add(Context ctx) throws SQLException {
Url url = new Url(urlString, createdAt);
UrlsRepository.save(url);
ctx.sessionAttribute("flash", "URL was successfully added \uD83D\uDCAA");
ctx.sessionAttribute("status", "alert-success");
ctx.sessionAttribute("flashStatus", "alert-success");
ctx.redirect(NamedRoutes.urlsPath());
} else {
var flash = "This URL already was added! \uD83D\uDE10";
var status = "alert-warning";
var flashStatus = "alert-warning";
var urls = UrlsRepository.getUrls();
var page = new UrlsPage(flash, status, urls);
var page = new UrlsPage(flash, flashStatus, urls);
ctx.render("urls.jte", model("page", page));
}
}

public static void url(Context ctx) throws SQLException {
var id = ctx.pathParamAsClass("id", Long.class).get();
try {
var url = UrlsRepository.find(id).orElseThrow(() -> new SQLException("No such URL! \uD83E\uDD26"));
var page = new UrlPage(url);
var url = UrlsRepository.find(id).orElseThrow(() -> new SQLException("No such URL in the list! \uD83E\uDD26"));
var urlChecks = UrlCheckRepository.getChecks(id);
var page = new UrlPage(url,
urlChecks,
ctx.consumeSessionAttribute("flash"),
ctx.consumeSessionAttribute("flashStatus"));
ctx.render("url.jte", model("page", page));
} catch (SQLException e) {
var urls = UrlsRepository.getUrls();
Expand All @@ -59,6 +70,34 @@ public static void url(Context ctx) throws SQLException {
}
}

public static void check(Context ctx) throws SQLException {
var urlId = ctx.pathParamAsClass("id", Long.class).get();
var urlName = UrlsRepository.find(urlId)
.orElseThrow(() -> new SQLException("No such URL id!"))
.getName();
try {
var response = Unirest.get(urlName).asString().getBody();
//create urlCheck instance and fill it with data
var urlCheck = new UrlCheck();
urlCheck.setStatusCode(Unirest.get(urlName).asJson().getStatus());
urlCheck.setTitle(Utils.getTitle(response));
urlCheck.setH1(Utils.getH1(response));
urlCheck.setDescription(Utils.getDescription(response));
urlCheck.setCreatedAt(Timestamp.valueOf(LocalDateTime.now()));
urlCheck.setUrlId(urlId);
//save urlCheck instance to DB adn redirect
UrlCheckRepository.save(urlCheck);
ctx.sessionAttribute("flash", "Check was successfully added! ✅");
ctx.sessionAttribute("flashStatus", "alert-success");
ctx.redirect(NamedRoutes.urlPath(urlId));
Unirest.shutDown(); //is it necessary???
} catch (UnirestException e) {
ctx.sessionAttribute("flash", "Oops! The address is incorrect! \uD83D\uDE45");
ctx.sessionAttribute("flashStatus", "alert-warning");
ctx.redirect(NamedRoutes.urlPath(urlId));
}
}

public static String toUrl(String canBeUrl) {
try {
var uri = new URI(canBeUrl);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/hexlet/code/dto/MainPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
@Setter
public class MainPage {
private String flash;
private String status;
private String flashStatus;
private String canBeUrl;
}
6 changes: 6 additions & 0 deletions src/main/java/hexlet/code/dto/UrlPage.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package hexlet.code.dto;
import hexlet.code.model.Url;
import hexlet.code.model.UrlCheck;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@AllArgsConstructor
@Getter
public class UrlPage {
private Url url;
private List<UrlCheck> urlChecks;
private String flash;
private String flashStatus;
}
3 changes: 2 additions & 1 deletion src/main/java/hexlet/code/dto/UrlsPage.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hexlet.code.dto;

import hexlet.code.model.Url;
import hexlet.code.model.UrlCheck;
import io.javalin.validation.ValidationError;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -15,6 +16,6 @@
@Setter
public class UrlsPage {
private String flash;
private String status;
private String flashStatus;
private List<Url> urls;
}
25 changes: 25 additions & 0 deletions src/main/java/hexlet/code/model/UrlCheck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hexlet.code.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.sql.Timestamp;
import java.time.LocalDateTime;

@NoArgsConstructor
@Getter
@Setter
public class UrlCheck {
private Long id;
private Integer statusCode;
private String title;
private String h1;
private String description;
private Timestamp createdAt;
private Long urlId;

public UrlCheck(Long urlId) {
this.urlId = urlId;
}
}
70 changes: 70 additions & 0 deletions src/main/java/hexlet/code/repository/UrlCheckRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package hexlet.code.repository;

import hexlet.code.model.UrlCheck;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

public class UrlCheckRepository extends BaseRepository {
//save
public static void save(UrlCheck urlCheck) throws SQLException {
if (urlCheck.getId() == null) {
var sql = "INSERT INTO url_checks (status_code, title, h1, description, created_at, url_id) VALUES (?, ?, ?, ?, ?, ?)";
try (var connection = dataSource.getConnection();
var preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
preparedStatement.setInt(1, urlCheck.getStatusCode());
preparedStatement.setString(2, urlCheck.getTitle());
preparedStatement.setString(3, urlCheck.getH1());
preparedStatement.setString(4, urlCheck.getDescription());
preparedStatement.setTimestamp(5, urlCheck.getCreatedAt());
preparedStatement.setLong(6, urlCheck.getUrlId());
preparedStatement.executeUpdate();
var generatedKeys = preparedStatement.getGeneratedKeys();
if (generatedKeys.next()) {
var id = generatedKeys.getLong("id");
urlCheck.setId(id);
} else {
throw new SQLException("DB didn't return any index");
}
}
} else {
throw new SQLException("Such urlCheck id already exists!");
}
}
//getChecks
public static List<UrlCheck> getChecks(Long urlId) throws SQLException {
var urlChecks = new LinkedList<UrlCheck>();
var sql = "SELECT * FROM url_checks WHERE url_id = ? ORDER BY created_at DESC";
try (var connection = dataSource.getConnection();
var preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setLong(1, urlId);
var resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
var urlCheck = new UrlCheck(urlId);
urlCheck.setId(resultSet.getLong("id"));
urlCheck.setStatusCode(resultSet.getInt("status_code"));
urlCheck.setTitle(resultSet.getString("title"));
urlCheck.setH1(resultSet.getString("h1"));
urlCheck.setDescription(resultSet.getString("description"));
urlCheck.setCreatedAt(resultSet.getTimestamp("created_at"));
urlChecks.add(urlCheck);
}
}
return urlChecks;
}
//findLast
public static Optional<UrlCheck> findLast(Long urlId) {
try {
var urlChecks = getChecks(urlId);
if (!urlChecks.isEmpty()) {
return Optional.of(urlChecks.getFirst());
}
return Optional.empty();
} catch (SQLException e) {
throw new RuntimeException("For some reason can't find last check of url");
}
}
}
1 change: 0 additions & 1 deletion src/main/java/hexlet/code/repository/UrlsRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public static boolean isUnique(String urlName) throws SQLException {
}

public static Optional<Url> find(Long id) throws SQLException {

var sql = "SELECT * FROM urls WHERE id = ?";
try (var connection = dataSource.getConnection();
var preparedStatement = connection.prepareStatement(sql)) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/hexlet/code/utils/NamedRoutes.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ public static String urlPath(String id) {
public static String urlPath(Long id) {
return "/urls/" + id;
}
public static String checkPath(Long id) {
return "/urls/" + id + "/check";
}
public static String checkPath(String id) {
return "/urls/" + id + "/check";
}
}
Loading

0 comments on commit 39d07bb

Please sign in to comment.