Skip to content

Commit 9a695c3

Browse files
added controllers and repository for url and url checks management
1 parent 226719e commit 9a695c3

File tree

5 files changed

+238
-20
lines changed

5 files changed

+238
-20
lines changed

.idea/workspace.xml

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package hexlet.code.controller;
2+
3+
import hexlet.code.model.UrlCheck;
4+
import hexlet.code.repository.UrlCheckRepository;
5+
import hexlet.code.repository.UrlRepository;
6+
import hexlet.code.util.NamedRoutes;
7+
import io.javalin.http.Context;
8+
import io.javalin.http.NotFoundResponse;
9+
import kong.unirest.Unirest;
10+
import org.jsoup.Jsoup;
11+
import org.jsoup.nodes.Document;
12+
13+
import java.sql.SQLException;
14+
import java.sql.Timestamp;
15+
16+
public class UrlChecksController {
17+
public static void check(Context ctx) throws SQLException {
18+
var urlId = ctx.pathParamAsClass("id", Long.class).get();
19+
20+
var url = UrlRepository.findById(urlId)
21+
.orElseThrow(() -> new NotFoundResponse("URL not found"));
22+
var name = url.getName();
23+
24+
25+
try {
26+
var response = Unirest.get(name).asString();
27+
Document responseBody = Jsoup.parse(response.getBody());
28+
29+
int statusCode = response.getStatus();
30+
31+
String h1 = responseBody.selectFirst("h1") != null
32+
? responseBody.selectFirst("h1").text() : "";
33+
34+
String title = responseBody.title();
35+
36+
String description = !responseBody.select("meta[name=description]").isEmpty()
37+
? responseBody.select("meta[name=description]").get(0).attr("content") : "";
38+
39+
var createdAt = new Timestamp(System.currentTimeMillis());
40+
41+
var urlCheck = new UrlCheck(statusCode, h1, title, description, createdAt);
42+
urlCheck.setUrlId(urlId);
43+
UrlCheckRepository.save(urlCheck);
44+
45+
ctx.redirect(NamedRoutes.urlPath(urlId));
46+
} catch (RuntimeException e) {
47+
ctx.sessionAttribute("message", "Проверка не прошла");
48+
ctx.redirect(NamedRoutes.urlPath(urlId));
49+
}
50+
}
51+
}
52+
53+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package hexlet.code.controller;
2+
3+
import hexlet.code.dto.BasePage;
4+
import hexlet.code.dto.urls.UrlPage;
5+
import hexlet.code.dto.urls.UrlsPage;
6+
import hexlet.code.model.Url;
7+
import hexlet.code.model.UrlCheck;
8+
import hexlet.code.repository.UrlCheckRepository;
9+
import hexlet.code.repository.UrlRepository;
10+
import hexlet.code.util.NamedRoutes;
11+
import io.javalin.http.Context;
12+
import io.javalin.http.NotFoundResponse;
13+
14+
import java.net.MalformedURLException;
15+
import java.net.URI;
16+
import java.net.URISyntaxException;
17+
import java.sql.SQLException;
18+
import java.sql.Timestamp;
19+
import java.util.Collections;
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
23+
public class UrlsController {
24+
25+
public static void build(Context ctx) {
26+
String message = ctx.consumeSessionAttribute("message");
27+
var page = new BasePage(message);
28+
ctx.render("urls/build.jte", Collections.singletonMap("page", page));
29+
30+
}
31+
32+
public static void create(Context ctx) throws SQLException {
33+
try {
34+
var url = new Url();
35+
var name = normalizeUrl(ctx.formParamAsClass("url", String.class).get());
36+
37+
if (UrlRepository.existsByName(name)) {
38+
ctx.sessionAttribute("message", "URL already exists");
39+
} else {
40+
url.setName(name);
41+
url.setCreatedAt(new Timestamp(System.currentTimeMillis()));
42+
UrlRepository.save(url);
43+
ctx.sessionAttribute("message", "URL successfully created");
44+
}
45+
ctx.redirect(NamedRoutes.urlsPath());
46+
} catch (IllegalArgumentException | URISyntaxException | MalformedURLException e) {
47+
ctx.sessionAttribute("message", "Некорректный URL");
48+
ctx.redirect(NamedRoutes.rootPath());
49+
}
50+
}
51+
52+
public static void index(Context ctx) throws SQLException {
53+
var urls = UrlRepository.getEntities();
54+
final int itemsPerPage = 10;
55+
var pageCount = getPage(urls.size(), itemsPerPage);
56+
int pageNumber = ctx.queryParamAsClass("page", Integer.class).getOrDefault(pageCount);
57+
var page = new UrlsPage();
58+
59+
if (!urls.isEmpty() && pageNumber > pageCount) {
60+
throw new NotFoundResponse("Page not found");
61+
} else if (!urls.isEmpty()) {
62+
urls = UrlRepository.getEntitiesPerPage(itemsPerPage, pageNumber);
63+
64+
Map<Url, UrlCheck> urlsWithLatestChecks = new HashMap<>();
65+
for (Url item : urls) {
66+
var latestCheck = UrlCheckRepository.findLatestCheck(item.getId())
67+
.orElse(null);
68+
urlsWithLatestChecks.put(item, latestCheck);
69+
}
70+
page.setChecks(urlsWithLatestChecks);
71+
page.setPageNumber(pageNumber);
72+
}
73+
page.setUrls(urls);
74+
75+
String message = ctx.consumeSessionAttribute("message");
76+
page.setMessage(message);
77+
ctx.render("urls/index.jte", Collections.singletonMap("page", page));
78+
}
79+
80+
public static void show(Context ctx) throws SQLException {
81+
var id = ctx.pathParamAsClass("id", Long.class).get();
82+
var url = UrlRepository.findById(id)
83+
.orElseThrow(() -> new NotFoundResponse("URL not found"));
84+
var checks = UrlCheckRepository.find(id);
85+
86+
var page = new UrlPage(url, checks);
87+
String message = ctx.consumeSessionAttribute("message");
88+
page.setMessage(message);
89+
90+
ctx.render("urls/show.jte", Collections.singletonMap("page", page));
91+
92+
}
93+
private static String normalizeUrl(String path) throws URISyntaxException, MalformedURLException {
94+
var newPath = new URI(path).toURL();
95+
return String.format("%s://%s", newPath.getProtocol(), newPath.getAuthority());
96+
}
97+
98+
private static int getPage(int a, int b) {
99+
return (a % b == 0) ? (a / b) : (a / b + 1);
100+
}
101+
102+
}
103+

app/src/main/java/hexlet/code/dto/urls/UrlsPage.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,14 @@
77
import lombok.NoArgsConstructor;
88
import lombok.Setter;
99

10-
import java.util.HashMap;
1110
import java.util.List;
1211
import java.util.Map;
1312

1413
@NoArgsConstructor
1514
@Getter
1615
@Setter
1716
public class UrlsPage extends BasePage {
18-
1917
private List<Url> urls;
20-
private Map<Long, List<UrlCheck>> urlChecks;
18+
private Map<Url, UrlCheck> checks;
2119
private int pageNumber;
22-
23-
public Map<Url, UrlCheck> getChecks() {
24-
Map<Url, UrlCheck> latestChecks = new HashMap<>();
25-
if (urls != null && urlChecks != null) {
26-
for (Url url : urls) {
27-
List<UrlCheck> checks = urlChecks.get(url.getId());
28-
if (checks != null && !checks.isEmpty()) {
29-
// Предполагаем, что список checks отсортирован по дате убыванию: самая свежая — первая
30-
latestChecks.put(url, checks.get(0));
31-
}
32-
}
33-
}
34-
return latestChecks;
35-
}
3620
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package hexlet.code.repository;
2+
3+
import hexlet.code.model.UrlCheck;
4+
5+
import java.sql.SQLException;
6+
import java.sql.Statement;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.Optional;
10+
11+
public class UrlCheckRepository extends BaseRepository {
12+
13+
public static void save(UrlCheck urlCheck) throws SQLException {
14+
var sql = "INSERT INTO url_checks (url_id, status_code, h1, title, description, created_at) "
15+
+ "VALUES (?, ?, ?, ?, ?, ?)";
16+
try (var conn = dataSource.getConnection();
17+
var preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
18+
19+
preparedStatement.setLong(1, urlCheck.getUrlId());
20+
preparedStatement.setInt(2, urlCheck.getStatusCode());
21+
preparedStatement.setString(3, urlCheck.getH1());
22+
preparedStatement.setString(4, urlCheck.getTitle());
23+
preparedStatement.setString(5, urlCheck.getDescription());
24+
preparedStatement.setTimestamp(6, urlCheck.getCreatedAt());
25+
preparedStatement.executeUpdate();
26+
27+
var generatedKeys = preparedStatement.getGeneratedKeys();
28+
if (generatedKeys.next()) {
29+
urlCheck.setId(generatedKeys.getLong(1));
30+
} else {
31+
throw new SQLException("Не сформирован ID");
32+
}
33+
}
34+
}
35+
36+
public static List<UrlCheck> find(Long urlId) throws SQLException {
37+
var sql = "SELECT * FROM url_checks WHERE url_id = ?";
38+
try (var conn = dataSource.getConnection();
39+
var stmt = conn.prepareStatement(sql)) {
40+
41+
stmt.setLong(1, urlId);
42+
var resultSet = stmt.executeQuery();
43+
44+
var results = new ArrayList<UrlCheck>();
45+
var currentListId = 1L;
46+
47+
while (resultSet.next()) {
48+
var statusCode = resultSet.getInt("status_code");
49+
var h1 = resultSet.getString("h1");
50+
var title = resultSet.getString("title");
51+
var description = resultSet.getString("description");
52+
var createdAt = resultSet.getTimestamp("created_at");
53+
var urlCheck = new UrlCheck(statusCode, h1, title, description, createdAt);
54+
urlCheck.setId(currentListId);
55+
56+
currentListId++;
57+
results.add(urlCheck);
58+
}
59+
return results;
60+
}
61+
}
62+
63+
public static Optional<UrlCheck> findLatestCheck(Long urlId) throws SQLException {
64+
var sql = "SELECT status_code, created_at FROM url_checks WHERE url_id = ? ORDER BY id DESC LIMIT 1";
65+
try (var conn = dataSource.getConnection();
66+
var stmt = conn.prepareStatement(sql)) {
67+
68+
stmt.setLong(1, urlId);
69+
var resultSet = stmt.executeQuery();
70+
71+
if (resultSet.next()) {
72+
var statusCode = resultSet.getInt("status_code");
73+
var createdAt = resultSet.getTimestamp("created_at");
74+
var check = new UrlCheck(statusCode, createdAt);
75+
return Optional.of(check);
76+
}
77+
return Optional.empty();
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)