() {{
- put("січня", 1);
- put("лютого", 2);
- put("березня", 3);
- put("квітня", 4);
- put("травня", 5);
- put("червня", 6);
- put("липня", 7);
- put("серпня", 8);
- put("вересня", 9);
- put("жовтня", 10);
- put("листопада", 11);
- put("грудня", 12);
+ put("січня", 1);
+ put("лютого", 2);
+ put("березня", 3);
+ put("квітня", 4);
+ put("травня", 5);
+ put("червня", 6);
+ put("липня", 7);
+ put("серпня", 8);
+ put("вересня", 9);
+ put("жовтня", 10);
+ put("листопада", 11);
+ put("грудня", 12);
- put("января", 1);
- put("февраля", 2);
- put("марта", 3);
- put("апреля", 4);
- put("мая", 5);
- put("июня", 6);
- put("июля", 7);
- put("августа", 8);
- put("сентября", 9);
- put("октября", 10);
- put("ноября", 11);
- put("декабря", 12);
+ put("января", 1);
+ put("февраля", 2);
+ put("марта", 3);
+ put("апреля", 4);
+ put("мая", 5);
+ put("июня", 6);
+ put("июля", 7);
+ put("августа", 8);
+ put("сентября", 9);
+ put("октября", 10);
+ put("ноября", 11);
+ put("декабря", 12);
- put("янв", 1);
- put("фев", 2);
- put("мар", 3);
- put("апр", 4);
- put("май", 5);
- put("июн", 6);
- put("июл", 7);
- put("авг", 8);
- put("сен", 9);
- put("окт", 10);
- put("ноя", 11);
- put("дек", 12);
+ put("янв", 1);
+ put("фев", 2);
+ put("мар", 3);
+ put("апр", 4);
+ put("май", 5);
+ put("июн", 6);
+ put("июл", 7);
+ put("авг", 8);
+ put("сен", 9);
+ put("окт", 10);
+ put("ноя", 11);
+ put("дек", 12);
- put("january", 1);
- put("february", 2);
- put("march", 3);
- put("april", 4);
- put("may", 5);
- put("june", 6);
- put("july", 7);
- put("august", 8);
- put("september", 9);
- put("october", 10);
- put("november", 11);
- put("december", 12);
- }};
+ put("january", 1);
+ put("february", 2);
+ put("march", 3);
+ put("april", 4);
+ put("may", 5);
+ put("june", 6);
+ put("july", 7);
+ put("august", 8);
+ put("september", 9);
+ put("october", 10);
+ put("november", 11);
+ put("december", 12);
+ }};
- //if day or month starts with '0'
- public static void removeZero(String[] dateParts) {
- for (int i = 0; i < dateParts.length; i++) {
- if (dateParts[i].startsWith("0")) {
- dateParts[i] = dateParts[i].substring(1);
- }
- }
- }
+ //if day or month starts with '0'
+ public static void removeZero(String[] dateParts) {
+ for (int i = 0; i < dateParts.length; i++) {
+ if (dateParts[i].startsWith("0")) {
+ dateParts[i] = dateParts[i].substring(1);
+ }
+ }
+ }
}
diff --git a/src/main/java/com/olegshan/tools/PageBox.java b/src/main/java/com/olegshan/tools/PageBox.java
index 1088b5a..48813ea 100644
--- a/src/main/java/com/olegshan/tools/PageBox.java
+++ b/src/main/java/com/olegshan/tools/PageBox.java
@@ -2,59 +2,59 @@
public class PageBox {
- private static final int BUTTONS_TO_SHOW = 5;
+ private static final int BUTTONS_TO_SHOW = 5;
- private int totalPages;
- private int currentPage;
- private int firstPage;
- private int lastPage;
+ private int totalPages;
+ private int currentPage;
+ private int firstPage;
+ private int lastPage;
- public PageBox(int totalPages, int currentPage) {
+ public PageBox(int totalPages, int currentPage) {
- this.totalPages = totalPages;
- this.currentPage = currentPage;
- }
+ this.totalPages = totalPages;
+ this.currentPage = currentPage;
+ }
- public PageBox getPageBox() {
- int halfBoxSize = BUTTONS_TO_SHOW / 2;
+ public PageBox getPageBox() {
+ int halfBoxSize = BUTTONS_TO_SHOW / 2;
- if (totalPages <= BUTTONS_TO_SHOW) {
- setFirstPage(1);
- setLastPage(totalPages);
+ if (totalPages <= BUTTONS_TO_SHOW) {
+ setFirstPage(1);
+ setLastPage(totalPages);
- } else if (currentPage - halfBoxSize <= 0) {
- setFirstPage(1);
- setLastPage(BUTTONS_TO_SHOW);
+ } else if (currentPage - halfBoxSize <= 0) {
+ setFirstPage(1);
+ setLastPage(BUTTONS_TO_SHOW);
- } else if (currentPage + halfBoxSize == totalPages) {
- setFirstPage(currentPage - halfBoxSize);
- setLastPage(totalPages);
+ } else if (currentPage + halfBoxSize == totalPages) {
+ setFirstPage(currentPage - halfBoxSize);
+ setLastPage(totalPages);
- } else if (currentPage + halfBoxSize > totalPages) {
- setFirstPage(totalPages - BUTTONS_TO_SHOW + 1);
- setLastPage(totalPages);
+ } else if (currentPage + halfBoxSize > totalPages) {
+ setFirstPage(totalPages - BUTTONS_TO_SHOW + 1);
+ setLastPage(totalPages);
- } else {
- setFirstPage(currentPage - halfBoxSize);
- setLastPage(currentPage + halfBoxSize);
- }
+ } else {
+ setFirstPage(currentPage - halfBoxSize);
+ setLastPage(currentPage + halfBoxSize);
+ }
- return this;
- }
+ return this;
+ }
- public int getFirstPage() {
- return firstPage;
- }
+ public int getFirstPage() {
+ return firstPage;
+ }
- public void setFirstPage(int firstPage) {
- this.firstPage = firstPage;
- }
+ public void setFirstPage(int firstPage) {
+ this.firstPage = firstPage;
+ }
- public int getLastPage() {
- return lastPage;
- }
+ public int getLastPage() {
+ return lastPage;
+ }
- public void setLastPage(int lastPage) {
- this.lastPage = lastPage;
- }
+ public void setLastPage(int lastPage) {
+ this.lastPage = lastPage;
+ }
}
diff --git a/src/main/resources/templates/about.html b/src/main/resources/templates/about.html
index a8982ec..c6dc0ae 100644
--- a/src/main/resources/templates/about.html
+++ b/src/main/resources/templates/about.html
@@ -20,7 +20,9 @@
- jParser was created by Java developer Oleg Shankovskyi.
+ jParser was created by Java developer
+ Oleg Shankovskyi.
+
Source code is on Github.
diff --git a/src/test/java/com/olegshan/controllers/ErrorHandlerTest.java b/src/test/java/com/olegshan/controllers/ErrorHandlerTest.java
index 91724ef..106dd0b 100644
--- a/src/test/java/com/olegshan/controllers/ErrorHandlerTest.java
+++ b/src/test/java/com/olegshan/controllers/ErrorHandlerTest.java
@@ -15,25 +15,25 @@
@RunWith(MockitoJUnitRunner.class)
public class ErrorHandlerTest {
- @Mock
- private ParseController parseController;
- private MockMvc mockMvc;
-
- @Before
- public void setUp() throws Exception {
- mockMvc = MockMvcBuilders.standaloneSetup(parseController)
- .setControllerAdvice(new ErrorHandler())
- .build();
- }
-
- @Test
- public void unexpectedExceptionsAreCaught() throws Exception {
-
- when(parseController.about()).thenThrow(new RuntimeException("Unexpected exception"));
-
- mockMvc.perform(get("/about"))
- .andExpect(status().isOk())
- .andExpect(view().name("exception"))
- .andExpect(model().attribute("errorMessage", "Unexpected exception"));
- }
+ @Mock
+ private ParseController parseController;
+ private MockMvc mockMvc;
+
+ @Before
+ public void setUp() throws Exception {
+ mockMvc = MockMvcBuilders.standaloneSetup(parseController)
+ .setControllerAdvice(new ErrorHandler())
+ .build();
+ }
+
+ @Test
+ public void unexpectedExceptionsAreCaught() throws Exception {
+
+ when(parseController.about()).thenThrow(new RuntimeException("Unexpected exception"));
+
+ mockMvc.perform(get("/about"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("exception"))
+ .andExpect(model().attribute("errorMessage", "Unexpected exception"));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/olegshan/controllers/ParseControllerTest.java b/src/test/java/com/olegshan/controllers/ParseControllerTest.java
index 96163d6..d4c0cc3 100644
--- a/src/test/java/com/olegshan/controllers/ParseControllerTest.java
+++ b/src/test/java/com/olegshan/controllers/ParseControllerTest.java
@@ -13,29 +13,29 @@
public class ParseControllerTest extends AbstractTest {
- private MockMvc mockMvc;
- @Autowired
- private WebApplicationContext webApplicationContext;
-
- @Before
- public void setUp() throws Exception {
- mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
- }
-
- @Test
- public void showJobsReturnsCorrectModelAndView() throws Exception {
-
- mockMvc.perform(get("/"))
- .andExpect(status().isOk())
- .andExpect(view().name("index"))
- .andExpect(model().attributeExists("jobs"))
- .andExpect(model().attributeExists("pageBox"));
- }
-
- @Test
- public void aboutPageTest() throws Exception {
- mockMvc.perform(get("/about"))
- .andExpect(status().isOk())
- .andExpect(view().name("about"));
- }
+ private MockMvc mockMvc;
+ @Autowired
+ private WebApplicationContext webApplicationContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
+ }
+
+ @Test
+ public void showJobsReturnsCorrectModelAndView() throws Exception {
+
+ mockMvc.perform(get("/"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("index"))
+ .andExpect(model().attributeExists("jobs"))
+ .andExpect(model().attributeExists("pageBox"));
+ }
+
+ @Test
+ public void aboutPageTest() throws Exception {
+ mockMvc.perform(get("/about"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("about"));
+ }
}
\ No newline at end of file
From dda4cc0364a690e96f0aac82acf1ea2eba40c275 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 29 Oct 2017 14:59:49 +0200
Subject: [PATCH 20/62] Bug fixed
---
src/main/java/com/olegshan/service/impl/JobServiceImpl.java | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index 37bc913..b42472f 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -13,7 +13,6 @@
import org.springframework.stereotype.Service;
import java.time.LocalDate;
-import java.util.List;
@Service
public class JobServiceImpl implements JobService {
@@ -22,14 +21,11 @@ public class JobServiceImpl implements JobService {
private JTwitter twitter;
private Notifier notifier;
- private List jobsInDb;
-
@Autowired
public JobServiceImpl(JobRepository jobRepository, JTwitter twitter, Notifier notifier) {
this.jobRepository = jobRepository;
this.twitter = twitter;
this.notifier = notifier;
- jobsInDb = jobRepository.findAll();
}
public void save(Job job) {
@@ -43,7 +39,7 @@ public void save(Job job) {
}
private boolean jobExists(Job job) {
- return jobsInDb.contains(job);
+ return jobRepository.findOne(job.getUrl()) != null;
}
private void update(Job job) {
From e3dfb3f2fa2dc87651961ba2687888c39b694e03 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 29 Oct 2017 15:12:08 +0200
Subject: [PATCH 21/62] Rabota.ua url prefix fixed
---
src/main/java/com/olegshan/sites/RabotaUa.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/olegshan/sites/RabotaUa.java b/src/main/java/com/olegshan/sites/RabotaUa.java
index 084dba3..c4b69c2 100644
--- a/src/main/java/com/olegshan/sites/RabotaUa.java
+++ b/src/main/java/com/olegshan/sites/RabotaUa.java
@@ -9,7 +9,7 @@ public class RabotaUa implements JobSite {
private static final String SITE_NAME = "Rabota.ua";
private static final String SITE_URL = "https://rabota.ua/zapros/java/%D0%BA%D0%B8%D0%B5%D0%B2";
- private static final String URL_PREFIX = "http://rabota.ua";
+ private static final String URL_PREFIX = "https://rabota.ua";
private static final String SPLIT = "";
private static final Holder JOB_BOX = Holder.of("class", "f-vacancylist-vacancyblock");
private static final Holder TITLE_BOX = Holder.of("class", "fd-beefy-gunso");
From fc38715786a6050d18197a65ff6d0ae277aaa969 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Thu, 9 Nov 2017 00:26:46 +0200
Subject: [PATCH 22/62] Tweet length increased to 280
---
src/main/java/com/olegshan/social/JTwitter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/olegshan/social/JTwitter.java b/src/main/java/com/olegshan/social/JTwitter.java
index 80463ad..6810588 100644
--- a/src/main/java/com/olegshan/social/JTwitter.java
+++ b/src/main/java/com/olegshan/social/JTwitter.java
@@ -44,7 +44,7 @@ public void tweet(Job job) {
int twitterUrlLength = 23;
int tweetLength = jobTitle.length() + 1 + twitterUrlLength * 2 + moreJobs.length();
- if (tweetLength <= 140)
+ if (tweetLength <= 280)
tweet = jobTitle + " " + jobUrl + moreJobs + jParserUrl;
else tweet = jobTitle + " " + jobUrl;
From 1ce9f6bff13876b941ffbbff33e4d78bf865247c Mon Sep 17 00:00:00 2001
From: olegshan
Date: Fri, 22 Dec 2017 00:58:46 +0200
Subject: [PATCH 23/62] Tags for Work.ua and Jobs.ua actualized
---
src/main/java/com/olegshan/sites/JobsUa.java | 2 +-
src/main/java/com/olegshan/sites/WorkUa.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/olegshan/sites/JobsUa.java b/src/main/java/com/olegshan/sites/JobsUa.java
index 43be142..993960a 100644
--- a/src/main/java/com/olegshan/sites/JobsUa.java
+++ b/src/main/java/com/olegshan/sites/JobsUa.java
@@ -15,7 +15,7 @@ public class JobsUa implements JobSite {
private static final Holder TITLE_BOX = Holder.of("class", "b-vacancy__top__title js-item_title");
private static final Holder COMPANY_DATA = Holder.of("class", "b-vacancy__tech__item");
private static final Holder DESCRIPTION_DATA = Holder.of("class", "b-vacancy-full__block b-text");
- private static final Holder DATE_DATA = Holder.of("class", "b-vacancy-full__tech__item");
+ private static final Holder DATE_DATA = Holder.of("class", "b-vacancy-full__tech__item m-r-1");
@Override
public String name() {
diff --git a/src/main/java/com/olegshan/sites/WorkUa.java b/src/main/java/com/olegshan/sites/WorkUa.java
index d4cb9b4..b199957 100644
--- a/src/main/java/com/olegshan/sites/WorkUa.java
+++ b/src/main/java/com/olegshan/sites/WorkUa.java
@@ -11,7 +11,7 @@ public class WorkUa implements JobSite {
private static final String SITE_URL = "https://www.work.ua/jobs-kyiv-java/";
private static final String URL_PREFIX = "https://work.ua";
private static final String SPLIT = "\\.";
- private static final Holder JOB_BOX = Holder.of("class", "card card-hover card-visited job-link");
+ private static final Holder JOB_BOX = Holder.of("class", "card card-hover card-visited wordwrap job-link card-logotype");
private static final Holder TITLE_BOX = Holder.of("", "");
private static final Holder COMPANY_DATA = Holder.of("class", "dl-horizontal");
private static final Holder DESCRIPTION_DATA = Holder.of("class", "text-muted overflow");
From 7c65eed661250badec4bce956273c785e51bd866 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Fri, 22 Dec 2017 01:22:57 +0200
Subject: [PATCH 24/62] JobService refactored
---
.../olegshan/service/impl/JobServiceImpl.java | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index b42472f..0dd2f34 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -29,30 +29,29 @@ public JobServiceImpl(JobRepository jobRepository, JTwitter twitter, Notifier no
}
public void save(Job job) {
- if (jobExists(job)) {
+ if (jobRepository.exists(job.getUrl())) {
update(job);
} else {
- saveJob(job);
- twitter.tweet(job);
+ saveAndTweet(job);
log.info("New job '{}' on {} found", job.getTitle(), job.getSource());
}
}
- private boolean jobExists(Job job) {
- return jobRepository.findOne(job.getUrl()) != null;
- }
-
private void update(Job job) {
Job jobFromDb = jobRepository.findOne(job.getUrl());
LocalDate jobFromDbDate = jobFromDb.getDate().toLocalDate();
LocalDate jobDate = job.getDate().toLocalDate();
if (!jobFromDbDate.equals(jobDate)) {
- saveJob(job);
- twitter.tweet(job);
+ saveAndTweet(job);
log.info("Job '{}', {}, was updated", job.getTitle(), job.getUrl());
}
}
+ private void saveAndTweet(Job job) {
+ saveJob(job);
+ twitter.tweet(job);
+ }
+
public Page getJobs(PageRequest request) {
return jobRepository.findAll(request);
}
From 48c6e9fbfc17b15d7ab68f475b2d40b37fb14aa4 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sat, 23 Dec 2017 00:29:59 +0200
Subject: [PATCH 25/62] No emails for Twitter duplicate status exception
---
src/main/java/com/olegshan/social/JTwitter.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/olegshan/social/JTwitter.java b/src/main/java/com/olegshan/social/JTwitter.java
index 6810588..a147c92 100644
--- a/src/main/java/com/olegshan/social/JTwitter.java
+++ b/src/main/java/com/olegshan/social/JTwitter.java
@@ -51,10 +51,11 @@ public void tweet(Job job) {
try {
twitter.timelineOperations().updateStatus(tweet);
} catch (Exception e) {
- notifier.notifyAdmin(
- "Error while twitting following tweet:\n " + tweet +
- "\nException was:\n" + e.getMessage()
- );
+ if (!"Status is a duplicate".equals(e.getMessage()))
+ notifier.notifyAdmin(
+ "Error while twitting following tweet:\n " + tweet +
+ "\nException was:\n" + e.getMessage()
+ );
}
}
From b7196d6083b242e8a13742be1452edadb298421e Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 24 Dec 2017 16:53:00 +0200
Subject: [PATCH 26/62] Minor refactoring
---
.../parser/siteparsers/JobParser.java | 11 +-
.../parser/siteparsers/JobsUaJobParser.java | 28 +++-
.../parser/siteparsers/RabotaUaJobParser.java | 51 +++---
.../com/olegshan/service/JobServiceTest.java | 157 +++++++++---------
4 files changed, 126 insertions(+), 121 deletions(-)
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
index 10f84e9..41a2ae7 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
@@ -31,7 +31,6 @@ public Document getDoc(String siteUrl) throws ParserException {
try {
return Jsoup.connect(siteUrl).userAgent("Mozilla").timeout(0).get();
} catch (IOException e) {
- log.error("Connecting to {} failed", siteUrl);
throw new ParserException("Failed connecting to " + siteUrl + "\n" + e.getMessage());
}
}
@@ -84,13 +83,9 @@ protected LocalTime getTime() {
//in case we parse in January jobs of last December. Needed for jobs.ua and hh.ua
int getYear(int month) {
- int year;
- if (month > LocalDate.now(ZoneId.of("Europe/Athens")).getMonthValue()) {
- year = LocalDate.now().getYear() - 1;
- } else {
- year = LocalDate.now(ZoneId.of("Europe/Athens")).getYear();
- }
- return year;
+ if (month > LocalDate.now(ZoneId.of("Europe/Athens")).getMonthValue())
+ return LocalDate.now().getYear() - 1;
+ return LocalDate.now(ZoneId.of("Europe/Athens")).getYear();
}
Elements getElements(Element element, JobSite.Holder holder) {
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
index ccff71a..3cad8b8 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
@@ -23,27 +23,37 @@ public JobsUaJobParser(JobSite jobSite) {
public Elements getJobBlocks(Document doc) throws ParserException {
Elements jobBlocks = getElements(doc, jobSite.jobBox());
check(jobBlocks, "job blocks");
+ removeAd(jobBlocks);
+
+ return jobBlocks;
+ }
+
+ private void removeAd(Elements jobBlocks) {
// ad block on jobs.ua has the same tags as the job blocks, so it should be removed
for (int i = 0; i < jobBlocks.size(); i++) {
- if (getElements(jobBlocks.get(i), Holder.of("class", "b-city__title b-city__companies-title"), true)
- .text()
- .contains("VIP компании в Украине:")
- ) {
+
+ String jobBlock = getElements(
+ jobBlocks.get(i),
+ Holder.of("class", "b-city__title b-city__companies-title"),
+ true
+ )
+ .text();
+
+ if (jobBlock.contains("VIP компании в Украине:"))
jobBlocks.remove(i);
- }
}
- return jobBlocks;
}
@Override
public String getDescription(Element job, String url) throws ParserException {
Document descDoc = getDoc(url);
String description = getElements(descDoc, jobSite.description()).text();
- if (description.startsWith("Описание вакансии ")) {
+
+ if (description.startsWith("Описание вакансии "))
description = description.substring("Описание вакансии ".length());
- }
- return description.length() > 250 ? description.substring(0, 250) + ("...") : description;
+
+ return description.length() > 250 ? description.substring(0, 250) + "..." : description;
}
@Override
diff --git a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
index 7b7dbef..84b2f8b 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
@@ -15,6 +15,8 @@
import java.time.ZoneId;
import java.util.regex.Pattern;
+import static java.lang.Integer.parseInt;
+
public class RabotaUaJobParser extends JobParser {
public RabotaUaJobParser(JobSite jobSite) {
@@ -29,6 +31,7 @@ public String getUrl(Elements titleBlock) {
.attr("href");
}
+ @Override
public Elements getTitleBlock(Element job) throws ParserException {
Elements titleBlock = getElements(job, jobSite.titleBox(), true);
check(titleBlock, "title blocks");
@@ -43,30 +46,28 @@ public String getDescription(Element job, String url) throws ParserException {
@Override
public String getCompany(Element job, String url) throws ParserException {
String company = getElements(job, jobSite.company(), true).text();
- if (company.length() == 0) {
+ if (company.length() == 0)
company = "Anonymous employer";
- }
return company;
}
+ /**
+ * There are several problems here.
+ * First: there are different types of date tags, used on rabota.ua on different pages
+ * Second: sometimes date format is dd.mm.yyyy, sometimes — yyyy-mm-dd and sometimes — dd mmm yyyy.
+ * Third: sometimes there is no date at all.
+ */
@Override
public LocalDateTime getDate(Element job, String url) throws ParserException {
- /*
- * There are several problems here.
- * First: there are different types of date tags, used on rabota.ua on different pages
- * Second: sometimes date format is dd.mm.yyyy, sometimes — yyyy-mm-dd and sometimes — dd mmm yyyy.
- * Third: sometimes there is no date at all.
- */
-
Document dateDoc = getDoc(url);
String dateLine;
Elements dateElements = getElements(dateDoc, Holder.of("id", "d-date"));
- if (!dateElements.isEmpty()) {
+ if (!dateElements.isEmpty())
dateLine = getElements(dateElements.get(0), Holder.of("class", "d-ph-value")).text();
- } else {
+ else {
dateLine = getElements(dateDoc, Holder.of("itemprop", "datePosted")).text();
if (dateLine == null || dateLine.trim().length() == 0) {
try {
@@ -79,37 +80,39 @@ public LocalDateTime getDate(Element job, String url) throws ParserException {
}
}
}
+ return getDateByLine(dateLine, url);
+ }
+ private LocalDateTime getDateByLine(String dateLine, String url) throws ParserException {
String[] dateParts;
- int year;
- int month;
- int day;
+ int year, month, day;
if (Pattern.matches("\\d{2}\\.\\d{2}\\.\\d{4}", dateLine)) {
dateParts = dateLine.split("\\.");
MonthsTools.removeZero(dateParts);
- year = Integer.parseInt(dateParts[2]);
- month = Integer.parseInt(dateParts[1]);
- day = Integer.parseInt(dateParts[0]);
+ year = parseInt(dateParts[2]);
+ month = parseInt(dateParts[1]);
+ day = parseInt(dateParts[0]);
- } else if (Pattern.matches("\\d{4}\\.\\d{2}\\.\\d{2}", dateLine)) {
+ } else if (Pattern.matches("\\d{4}-\\d{2}-\\d{2}", dateLine)) {
dateParts = dateLine.split("-");
MonthsTools.removeZero(dateParts);
- year = Integer.parseInt(dateParts[0]);
- month = Integer.parseInt(dateParts[1]);
- day = Integer.parseInt(dateParts[2]);
+ year = parseInt(dateParts[0]);
+ month = parseInt(dateParts[1]);
+ day = parseInt(dateParts[2]);
} else if (Pattern.matches("\\d{2} [а-я]{3} \\d{4}", dateLine)) {
dateParts = dateLine.split(" ");
MonthsTools.removeZero(dateParts);
- day = Integer.parseInt(dateParts[0]);
+ day = parseInt(dateParts[0]);
month = MonthsTools.MONTHS.get(dateParts[1]);
- year = Integer.parseInt(dateParts[2]);
+ year = parseInt(dateParts[2]);
- } else throw new ParserException("Cannot parse date of following job: " + url + "\ndateLine is: " + dateLine);
+ } else
+ throw new ParserException("Cannot parse date of following job: " + url + "\ndateLine is: " + dateLine);
return LocalDate.of(year, month, day).atTime(getTime());
}
diff --git a/src/test/java/com/olegshan/service/JobServiceTest.java b/src/test/java/com/olegshan/service/JobServiceTest.java
index 8ee4f84..1694ff1 100644
--- a/src/test/java/com/olegshan/service/JobServiceTest.java
+++ b/src/test/java/com/olegshan/service/JobServiceTest.java
@@ -6,12 +6,9 @@
import com.olegshan.social.JTwitter;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -31,81 +28,81 @@
public class JobServiceTest extends AbstractTest {
- private static final String JOB_URL = "http://somesite.ua/company/vacancy";
- private static final int CURRENT_PAGE = 1;
- private static final int PAGE_SIZE = 5;
-
- @Mock
- private JTwitter mockTwitter;
-
- @InjectMocks
- @Autowired
- private JobService jobService;
- @Autowired
- private JobRepository jobRepository;
-
- @Before
- public void setUp() throws Exception {
- Job job;
- Random random = new Random();
- for (int i = 0; i < 10; i++) {
- //jobs are saved into database with random dates
- job = new Job("Title" + i, "Description" + i, "Company" + i, "Site" + i, JOB_URL + i,
- now(ZoneId.of("Europe/Athens")).minusDays(random.nextInt(20)));
- jobService.save(job);
- }
- }
-
- @Test
- public void jobsInSetUpMethodWereSaved() throws Exception {
- assertEquals("There should be 10 elements in the database", jobRepository.findAll().size(), 10);
- }
-
- @Test
- public void savingOfNewJobWithTheSameUrlAndDifferentDateUpdatesExistingJob() throws Exception {
- Job job = jobRepository.findOne(JOB_URL + 5);
- assertEquals("Title5", job.getTitle());
- LocalDateTime newDate = job.getDate().minusDays(1);
- job.setDate(newDate);
- job.setTitle("New title");
- jobService.save(job);
- verify(mockTwitter).tweet(job);
-
- job = jobRepository.findOne(JOB_URL + 5);
- assertEquals("New title", job.getTitle());
- assertEquals(newDate, job.getDate());
- assertEquals("There should be still 10 elements in the database after updating",
- jobRepository.findAll().size(), 10);
- }
-
- @Test
- public void savingOfJobWithTheSameUrlAndSameDateDoesNotUpdateExistingJob() throws Exception {
- Job job = jobRepository.findOne(JOB_URL + 7);
- assertEquals("Title7", job.getTitle());
- job.setTitle("New title");
- jobService.save(job);
- verify(mockTwitter, never()).tweet(job);
-
- job = jobRepository.findOne(JOB_URL + 7);
- assertEquals("Title7", job.getTitle());
- assertEquals("There should be still 10 elements in the database", jobRepository.findAll().size(), 10);
- }
-
- @Test
- public void jobsAreRetrievedFromDatabaseSortedByDateInDescendingOrder() throws Exception {
- Page jobs = jobService.getJobs(new PageRequest(CURRENT_PAGE, PAGE_SIZE, Sort.Direction.DESC, "date"));
- assertEquals(PAGE_SIZE + " elements should be retrieved", PAGE_SIZE, jobs.getContent().size());
- assertTrue("The jobs should be sorted from new to old", isSortedDescending(jobs));
- }
-
- private boolean isSortedDescending(Page page) {
- List list = page.getContent();
- return IntStream.range(0, PAGE_SIZE - 1).allMatch(i -> list.get(i).getDate()
- .compareTo(list.get(i + 1).getDate()) > 0);
- }
-
- @After
- public void tearDown() throws Exception {
- jobRepository.deleteAll();
- }
+ private static final String JOB_URL = "http://somesite.ua/company/vacancy";
+ private static final int CURRENT_PAGE = 1;
+ private static final int PAGE_SIZE = 5;
+
+ @Mock
+ private JTwitter mockTwitter;
+
+ @InjectMocks
+ @Autowired
+ private JobService jobService;
+ @Autowired
+ private JobRepository jobRepository;
+
+ @Before
+ public void setUp() throws Exception {
+ Job job;
+ Random random = new Random();
+ for (int i = 0; i < 10; i++) {
+ //jobs are saved into database with random dates
+ job = new Job("Title" + i, "Description" + i, "Company" + i, "Site" + i, JOB_URL + i,
+ now(ZoneId.of("Europe/Athens")).minusDays(random.nextInt(20)));
+ jobService.save(job);
+ }
+ }
+
+ @Test
+ public void jobsInSetUpMethodWereSaved() throws Exception {
+ assertEquals("There should be 10 elements in the database", jobRepository.findAll().size(), 10);
+ }
+
+ @Test
+ public void savingOfNewJobWithTheSameUrlAndDifferentDateUpdatesExistingJob() throws Exception {
+ Job job = jobRepository.findOne(JOB_URL + 5);
+ assertEquals("Title5", job.getTitle());
+ LocalDateTime newDate = job.getDate().minusDays(1);
+ job.setDate(newDate);
+ job.setTitle("New title");
+ jobService.save(job);
+ verify(mockTwitter).tweet(job);
+
+ job = jobRepository.findOne(JOB_URL + 5);
+ assertEquals("New title", job.getTitle());
+ assertEquals(newDate, job.getDate());
+ assertEquals("There should be still 10 elements in the database after updating",
+ jobRepository.findAll().size(), 10);
+ }
+
+ @Test
+ public void savingOfJobWithTheSameUrlAndSameDateDoesNotUpdateExistingJob() throws Exception {
+ Job job = jobRepository.findOne(JOB_URL + 7);
+ assertEquals("Title7", job.getTitle());
+ job.setTitle("New title");
+ jobService.save(job);
+ verify(mockTwitter, never()).tweet(job);
+
+ job = jobRepository.findOne(JOB_URL + 7);
+ assertEquals("Title7", job.getTitle());
+ assertEquals("There should be still 10 elements in the database", jobRepository.findAll().size(), 10);
+ }
+
+ @Test
+ public void jobsAreRetrievedFromDatabaseSortedByDateInDescendingOrder() throws Exception {
+ Page jobs = jobService.getJobs(new PageRequest(CURRENT_PAGE, PAGE_SIZE, Sort.Direction.DESC, "date"));
+ assertEquals(PAGE_SIZE + " elements should be retrieved", PAGE_SIZE, jobs.getContent().size());
+ assertTrue("The jobs should be sorted from new to old", isSortedDescending(jobs));
+ }
+
+ private boolean isSortedDescending(Page page) {
+ List list = page.getContent();
+ return IntStream.range(0, PAGE_SIZE - 1).allMatch(i -> list.get(i).getDate()
+ .compareTo(list.get(i + 1).getDate()) > 0);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ jobRepository.deleteAll();
+ }
}
\ No newline at end of file
From 47c4ebf77400f21e87382c8ff0bf7fb33cd06690 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 24 Dec 2017 19:36:14 +0200
Subject: [PATCH 27/62] Getting jobs by company implemented
---
.../com/olegshan/controllers/ParseController.java | 13 +++++++++++--
.../java/com/olegshan/repository/JobRepository.java | 4 ++++
src/main/java/com/olegshan/service/JobService.java | 6 ++++--
.../com/olegshan/service/impl/JobServiceImpl.java | 9 +++++++--
src/main/resources/templates/index.html | 2 +-
5 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index 93e22f3..a0ad834 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -6,6 +6,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -25,12 +26,20 @@ public ParseController(JobService jobService) {
}
@RequestMapping(value = "/", method = RequestMethod.GET)
- public ModelAndView showJobs(@RequestParam(value = "page", required = false) Integer page) {
+ public ModelAndView showJobs(
+ @RequestParam(value = "company", required = false) String company,
+ @RequestParam(value = "page", required = false) Integer page
+ ) {
ModelAndView modelAndView = new ModelAndView("index");
int currentPageNumber = (page == null || page < 1) ? 0 : page - 1;
- Page jobs = jobService.getJobs(new PageRequest(currentPageNumber, PAGE_SIZE, Sort.Direction.DESC, "date"));
+ Pageable request = new PageRequest(currentPageNumber, PAGE_SIZE, Sort.Direction.DESC, "date");
+ Page jobs;
+ if (company != null && !company.trim().isEmpty())
+ jobs = jobService.getJobsByCompany(company, request);
+ else
+ jobs = jobService.getJobs(request);
PageBox pageBox = new PageBox(jobs.getTotalPages(), jobs.getNumber());
modelAndView.addObject("jobs", jobs);
diff --git a/src/main/java/com/olegshan/repository/JobRepository.java b/src/main/java/com/olegshan/repository/JobRepository.java
index d5a971f..81d9541 100644
--- a/src/main/java/com/olegshan/repository/JobRepository.java
+++ b/src/main/java/com/olegshan/repository/JobRepository.java
@@ -1,7 +1,11 @@
package com.olegshan.repository;
import com.olegshan.entity.Job;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface JobRepository extends JpaRepository {
+
+ Page findAllByCompanyIgnoreCase(String company, Pageable request);
}
diff --git a/src/main/java/com/olegshan/service/JobService.java b/src/main/java/com/olegshan/service/JobService.java
index b38ada4..3af6065 100644
--- a/src/main/java/com/olegshan/service/JobService.java
+++ b/src/main/java/com/olegshan/service/JobService.java
@@ -2,11 +2,13 @@
import com.olegshan.entity.Job;
import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
public interface JobService {
void save(Job job);
- Page getJobs(PageRequest request);
+ Page getJobs(Pageable request);
+
+ Page getJobsByCompany(String company, Pageable request);
}
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index 0dd2f34..f29c980 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -9,7 +9,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
@@ -52,10 +52,15 @@ private void saveAndTweet(Job job) {
twitter.tweet(job);
}
- public Page getJobs(PageRequest request) {
+ public Page getJobs(Pageable request) {
return jobRepository.findAll(request);
}
+ @Override
+ public Page getJobsByCompany(String company, Pageable request) {
+ return jobRepository.findAllByCompanyIgnoreCase(company, request);
+ }
+
private void saveJob(Job job) {
try {
jobRepository.save(job);
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 3f5ea89..52898a4 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -12,7 +12,7 @@
From 8c68d4668a082feffd4b0cc0834ed622c4a4af81 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Mon, 25 Dec 2017 00:30:44 +0200
Subject: [PATCH 28/62] Bug while pagination with company parameter fixed
---
.../olegshan/controllers/ParseController.java | 4 ++++
src/main/resources/templates/index.html | 16 +++++++++-------
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index a0ad834..e3b7866 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -35,14 +35,18 @@ public ModelAndView showJobs(
int currentPageNumber = (page == null || page < 1) ? 0 : page - 1;
Pageable request = new PageRequest(currentPageNumber, PAGE_SIZE, Sort.Direction.DESC, "date");
+
Page jobs;
+
if (company != null && !company.trim().isEmpty())
jobs = jobService.getJobsByCompany(company, request);
else
jobs = jobService.getJobs(request);
+
PageBox pageBox = new PageBox(jobs.getTotalPages(), jobs.getNumber());
modelAndView.addObject("jobs", jobs);
+ modelAndView.addObject("company", company);
modelAndView.addObject("pageBox", pageBox.getPageBox());
return modelAndView;
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 52898a4..a61b09f 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -12,31 +12,33 @@
-
+
From 43d3296b3152f76018d48530372e394b34ef627b Mon Sep 17 00:00:00 2001
From: olegshan
Date: Thu, 28 Dec 2017 00:18:51 +0200
Subject: [PATCH 29/62] Removed nbsp; from some company names
---
src/main/java/com/olegshan/parser/siteparsers/JobParser.java | 2 +-
.../java/com/olegshan/parser/siteparsers/JobsUaJobParser.java | 2 +-
.../java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java | 2 +-
.../java/com/olegshan/parser/siteparsers/WorkUaJobParser.java | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
index 41a2ae7..e0663b9 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
@@ -60,7 +60,7 @@ public String getDescription(Element job, String url) throws ParserException {
}
public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company()).text();
+ String company = getElements(job, jobSite.company()).text().replaceAll("\u00a0", "");
check(company, "company", url);
return company;
}
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
index 3cad8b8..15aae35 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
@@ -81,7 +81,7 @@ protected LocalDateTime getDateByLine(String dateLine) {
@Override
public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company()).first().text();
+ String company = getElements(job, jobSite.company()).first().text().replaceAll("\u00a0", "");
check(company, "company", url);
return company;
}
diff --git a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
index 84b2f8b..c29d68e 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
@@ -45,7 +45,7 @@ public String getDescription(Element job, String url) throws ParserException {
@Override
public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company(), true).text();
+ String company = getElements(job, jobSite.company(), true).text().replaceAll("\u00a0", "");
if (company.length() == 0)
company = "Anonymous employer";
return company;
diff --git a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
index f2996cf..2be4e89 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
@@ -47,6 +47,6 @@ public String getCompany(Element job, String url) throws ParserException {
Document jobDoc = getDoc(url);
Elements companyBlock = getElements(jobDoc, jobSite.company());
check(companyBlock, "company block", url);
- return companyBlock.get(0).getElementsByTag("a").text();
+ return companyBlock.get(0).getElementsByTag("a").text().replaceAll("\u00a0", "");
}
}
From d23cf516348bc59c72d8d562b7146aa7dd110323 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sat, 6 Jan 2018 17:23:27 +0200
Subject: [PATCH 30/62] refactored; getting jobs by company removed
---
.../olegshan/controllers/ParseController.java | 2 +-
.../olegshan/parser/siteparsers/JobParser.java | 8 +++++++-
.../parser/siteparsers/JobsUaJobParser.java | 7 +++----
.../parser/siteparsers/RabotaUaJobParser.java | 6 +++---
.../parser/siteparsers/WorkUaJobParser.java | 2 +-
.../java/com/olegshan/sites/HeadHunterUa.java | 4 +++-
src/main/resources/templates/index.html | 16 +++++++---------
7 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index e3b7866..5229244 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -17,7 +17,7 @@
@Controller
public class ParseController {
- private static final int PAGE_SIZE = 40;
+ private static final int PAGE_SIZE = 4;
private JobService jobService;
@Autowired
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
index e0663b9..7cc62f1 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobParser.java
@@ -21,6 +21,8 @@
public class JobParser {
+ public static final String NBSP = "\u00a0";
+
JobSite jobSite;
public JobParser(JobSite jobSite) {
@@ -60,7 +62,7 @@ public String getDescription(Element job, String url) throws ParserException {
}
public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company()).text().replaceAll("\u00a0", "");
+ String company = removeNbsp(getElements(job, jobSite.company()).text());
check(company, "company", url);
return company;
}
@@ -98,6 +100,10 @@ Elements getElements(Element element, JobSite.Holder holder, boolean starting) {
return element.getElementsByAttributeValue(holder.key, holder.value);
}
+ String removeNbsp(String text) {
+ return text.replaceAll(NBSP, "");
+ }
+
void check(Object o, String data) throws ParserException {
check(o, data, null);
}
diff --git a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
index 15aae35..87f9fb6 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/JobsUaJobParser.java
@@ -58,7 +58,6 @@ public String getDescription(Element job, String url) throws ParserException {
@Override
public LocalDateTime getDate(Element job, String url) throws ParserException {
-
Document dateDoc = getDoc(url);
String dateLine = getElements(dateDoc, jobSite.date()).text();
@@ -68,20 +67,20 @@ public LocalDateTime getDate(Element job, String url) throws ParserException {
@Override
protected LocalDateTime getDateByLine(String dateLine) {
- dateLine = dateLine.replaceAll("\u00a0", "").trim();
+ dateLine = dateLine.substring(dateLine.indexOf(NBSP) + 1, dateLine.lastIndexOf(NBSP)).trim();
String[] dateParts = dateLine.split(jobSite.split());
MonthsTools.removeZero(dateParts);
int day = parseInt(dateParts[0]);
int month = MonthsTools.MONTHS.get(dateParts[1].toLowerCase());
- int year = getYear(month);
+ int year = dateParts.length > 2 ? Integer.parseInt(dateParts[2]) : getYear(month);
return LocalDate.of(year, month, day).atTime(getTime());
}
@Override
public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company()).first().text().replaceAll("\u00a0", "");
+ String company = removeNbsp(getElements(job, jobSite.company()).first().text());
check(company, "company", url);
return company;
}
diff --git a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
index c29d68e..c236fce 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/RabotaUaJobParser.java
@@ -39,13 +39,13 @@ public Elements getTitleBlock(Element job) throws ParserException {
}
@Override
- public String getDescription(Element job, String url) throws ParserException {
+ public String getDescription(Element job, String url) {
return getElements(job, jobSite.description(), true).text();
}
@Override
- public String getCompany(Element job, String url) throws ParserException {
- String company = getElements(job, jobSite.company(), true).text().replaceAll("\u00a0", "");
+ public String getCompany(Element job, String url) {
+ String company = removeNbsp(getElements(job, jobSite.company(), true).text());
if (company.length() == 0)
company = "Anonymous employer";
return company;
diff --git a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
index 2be4e89..6d53474 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
@@ -47,6 +47,6 @@ public String getCompany(Element job, String url) throws ParserException {
Document jobDoc = getDoc(url);
Elements companyBlock = getElements(jobDoc, jobSite.company());
check(companyBlock, "company block", url);
- return companyBlock.get(0).getElementsByTag("a").text().replaceAll("\u00a0", "");
+ return removeNbsp(companyBlock.get(0).getElementsByTag("a").text());
}
}
diff --git a/src/main/java/com/olegshan/sites/HeadHunterUa.java b/src/main/java/com/olegshan/sites/HeadHunterUa.java
index 8423fdd..6d6d271 100644
--- a/src/main/java/com/olegshan/sites/HeadHunterUa.java
+++ b/src/main/java/com/olegshan/sites/HeadHunterUa.java
@@ -4,13 +4,15 @@
import com.olegshan.parser.siteparsers.JobParser;
import org.springframework.stereotype.Component;
+import static com.olegshan.parser.siteparsers.JobParser.NBSP;
+
@Component
public class HeadHunterUa implements JobSite {
private static final String SITE_NAME = "HeadHunter.ua";
private static final String SITE_URL = "https://hh.ua/search/vacancy?text=java&area=115";
private static final String URL_PREFIX = "";
- private static final String SPLIT = "\u00a0";
+ private static final String SPLIT = NBSP;
private static final Holder JOB_BOX = Holder.of("class", "search-result-description");
private static final Holder TITLE_BOX = Holder.of("data-qa", "vacancy-serp__vacancy-title");
private static final Holder COMPANY_DATA = Holder.of("data-qa", "vacancy-serp__vacancy-employer");
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index a61b09f..3f5ea89 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -12,33 +12,31 @@
-
+
From daf73d17706cb10152f5eff504007b0ead0d51b4 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Wed, 17 Jan 2018 23:19:31 +0200
Subject: [PATCH 31/62] jobs count on page fixed
---
src/main/java/com/olegshan/controllers/ParseController.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index 5229244..e3b7866 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -17,7 +17,7 @@
@Controller
public class ParseController {
- private static final int PAGE_SIZE = 4;
+ private static final int PAGE_SIZE = 40;
private JobService jobService;
@Autowired
From 0b6b64153b64d40dd7fc942396f468791efa1fca Mon Sep 17 00:00:00 2001
From: olegshan
Date: Wed, 17 Jan 2018 23:51:09 +0200
Subject: [PATCH 32/62] error logger added
---
src/main/java/com/olegshan/parser/impl/ParserImpl.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/com/olegshan/parser/impl/ParserImpl.java b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
index 68dec20..ee80d51 100644
--- a/src/main/java/com/olegshan/parser/impl/ParserImpl.java
+++ b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
@@ -54,6 +54,7 @@ public void parse(JobSite jobSite) {
}
log.info("Parsing of {} completed\n", jobSite.name());
} catch (Exception e) {
+ log.error("Error while parsing", e);
notifier.notifyAdmin("Error while parsing " + url + "\nError message is: " + e.getMessage());
}
}
From 881083e05ddfd5098e54c7c8053188be2c41bee0 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Wed, 17 Jan 2018 23:51:58 +0200
Subject: [PATCH 33/62] work.ua date parsing fixed
---
.../com/olegshan/parser/siteparsers/WorkUaJobParser.java | 7 ++++---
src/main/java/com/olegshan/sites/WorkUa.java | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
index 6d53474..a09e76c 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
@@ -2,6 +2,7 @@
import com.olegshan.exception.ParserException;
import com.olegshan.sites.JobSite;
+import com.olegshan.tools.MonthsTools;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
@@ -31,12 +32,12 @@ public Elements getTitleBlock(Element job) {
@Override
public LocalDateTime getDate(Element job, String url) throws ParserException {
- String dateLine = getTitleBlock(job).attr("title");
- String[] dateParts = dateLine.substring(dateLine.length() - 8).split(jobSite.split());
+ String title = getTitleBlock(job).attr("title");
+ String[] dateParts = title.substring(title.indexOf("вакансия от ") + "вакансия от ".length()).split(jobSite.split());
check(dateParts, "date parts", url);
int year = parseInt(dateParts[2]) + 2000;
- int month = parseInt(dateParts[1]);
+ int month = MonthsTools.MONTHS.get(dateParts[1]);
int day = parseInt(dateParts[0]);
return LocalDate.of(year, month, day).atTime(getTime());
diff --git a/src/main/java/com/olegshan/sites/WorkUa.java b/src/main/java/com/olegshan/sites/WorkUa.java
index b199957..22f18ea 100644
--- a/src/main/java/com/olegshan/sites/WorkUa.java
+++ b/src/main/java/com/olegshan/sites/WorkUa.java
@@ -10,7 +10,7 @@ public class WorkUa implements JobSite {
private static final String SITE_NAME = "Work.ua";
private static final String SITE_URL = "https://www.work.ua/jobs-kyiv-java/";
private static final String URL_PREFIX = "https://work.ua";
- private static final String SPLIT = "\\.";
+ private static final String SPLIT = " ";
private static final Holder JOB_BOX = Holder.of("class", "card card-hover card-visited wordwrap job-link card-logotype");
private static final Holder TITLE_BOX = Holder.of("", "");
private static final Holder COMPANY_DATA = Holder.of("class", "dl-horizontal");
From 193a4e29a4d7055695340f5f2dd3ce66ccd4d587 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Wed, 17 Jan 2018 23:57:08 +0200
Subject: [PATCH 34/62] getting jobs by company removed
---
.../com/olegshan/controllers/ParseController.java | 11 +----------
.../java/com/olegshan/repository/JobRepository.java | 4 ----
src/main/java/com/olegshan/service/JobService.java | 2 --
.../com/olegshan/service/impl/JobServiceImpl.java | 5 -----
4 files changed, 1 insertion(+), 21 deletions(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index e3b7866..6f5d713 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -27,7 +27,6 @@ public ParseController(JobService jobService) {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showJobs(
- @RequestParam(value = "company", required = false) String company,
@RequestParam(value = "page", required = false) Integer page
) {
@@ -35,18 +34,10 @@ public ModelAndView showJobs(
int currentPageNumber = (page == null || page < 1) ? 0 : page - 1;
Pageable request = new PageRequest(currentPageNumber, PAGE_SIZE, Sort.Direction.DESC, "date");
-
- Page jobs;
-
- if (company != null && !company.trim().isEmpty())
- jobs = jobService.getJobsByCompany(company, request);
- else
- jobs = jobService.getJobs(request);
-
+ Page jobs = jobService.getJobs(request);
PageBox pageBox = new PageBox(jobs.getTotalPages(), jobs.getNumber());
modelAndView.addObject("jobs", jobs);
- modelAndView.addObject("company", company);
modelAndView.addObject("pageBox", pageBox.getPageBox());
return modelAndView;
diff --git a/src/main/java/com/olegshan/repository/JobRepository.java b/src/main/java/com/olegshan/repository/JobRepository.java
index 81d9541..d5a971f 100644
--- a/src/main/java/com/olegshan/repository/JobRepository.java
+++ b/src/main/java/com/olegshan/repository/JobRepository.java
@@ -1,11 +1,7 @@
package com.olegshan.repository;
import com.olegshan.entity.Job;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface JobRepository extends JpaRepository {
-
- Page findAllByCompanyIgnoreCase(String company, Pageable request);
}
diff --git a/src/main/java/com/olegshan/service/JobService.java b/src/main/java/com/olegshan/service/JobService.java
index 3af6065..574a8f2 100644
--- a/src/main/java/com/olegshan/service/JobService.java
+++ b/src/main/java/com/olegshan/service/JobService.java
@@ -9,6 +9,4 @@ public interface JobService {
void save(Job job);
Page getJobs(Pageable request);
-
- Page getJobsByCompany(String company, Pageable request);
}
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index f29c980..e96e1dc 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -56,11 +56,6 @@ public Page getJobs(Pageable request) {
return jobRepository.findAll(request);
}
- @Override
- public Page getJobsByCompany(String company, Pageable request) {
- return jobRepository.findAllByCompanyIgnoreCase(company, request);
- }
-
private void saveJob(Job job) {
try {
jobRepository.save(job);
From cde5869199bfe7ada5ebba1db2aa5e4651973545 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 28 Jan 2018 14:35:21 +0200
Subject: [PATCH 35/62] minor fix
---
src/main/java/com/olegshan/controllers/ParseController.java | 4 +---
src/main/java/com/olegshan/social/JTwitter.java | 2 +-
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index 6f5d713..28b7452 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -26,9 +26,7 @@ public ParseController(JobService jobService) {
}
@RequestMapping(value = "/", method = RequestMethod.GET)
- public ModelAndView showJobs(
- @RequestParam(value = "page", required = false) Integer page
- ) {
+ public ModelAndView showJobs(@RequestParam(value = "page", required = false) Integer page) {
ModelAndView modelAndView = new ModelAndView("index");
int currentPageNumber = (page == null || page < 1) ? 0 : page - 1;
diff --git a/src/main/java/com/olegshan/social/JTwitter.java b/src/main/java/com/olegshan/social/JTwitter.java
index a147c92..1e3153a 100644
--- a/src/main/java/com/olegshan/social/JTwitter.java
+++ b/src/main/java/com/olegshan/social/JTwitter.java
@@ -51,7 +51,7 @@ public void tweet(Job job) {
try {
twitter.timelineOperations().updateStatus(tweet);
} catch (Exception e) {
- if (!"Status is a duplicate".equals(e.getMessage()))
+ if (!"Status is a duplicate.".equals(e.getMessage()))
notifier.notifyAdmin(
"Error while twitting following tweet:\n " + tweet +
"\nException was:\n" + e.getMessage()
From e2e1abba2ffa98ed08e53841f782e43b34707605 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 28 Jan 2018 14:50:05 +0200
Subject: [PATCH 36/62] work.ua date fixed
---
.../java/com/olegshan/parser/siteparsers/WorkUaJobParser.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
index a09e76c..a3096e4 100644
--- a/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
+++ b/src/main/java/com/olegshan/parser/siteparsers/WorkUaJobParser.java
@@ -36,7 +36,7 @@ public LocalDateTime getDate(Element job, String url) throws ParserException {
String[] dateParts = title.substring(title.indexOf("вакансия от ") + "вакансия от ".length()).split(jobSite.split());
check(dateParts, "date parts", url);
- int year = parseInt(dateParts[2]) + 2000;
+ int year = parseInt(dateParts[2]);
int month = MonthsTools.MONTHS.get(dateParts[1]);
int day = parseInt(dateParts[0]);
From 2fbfebbd461b3baeef221a24b0293323012040c2 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Wed, 31 Jan 2018 22:29:32 +0200
Subject: [PATCH 37/62] hh parsing fixed
---
src/main/java/com/olegshan/sites/HeadHunterUa.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/olegshan/sites/HeadHunterUa.java b/src/main/java/com/olegshan/sites/HeadHunterUa.java
index 6d6d271..0de0e72 100644
--- a/src/main/java/com/olegshan/sites/HeadHunterUa.java
+++ b/src/main/java/com/olegshan/sites/HeadHunterUa.java
@@ -13,7 +13,7 @@ public class HeadHunterUa implements JobSite {
private static final String SITE_URL = "https://hh.ua/search/vacancy?text=java&area=115";
private static final String URL_PREFIX = "";
private static final String SPLIT = NBSP;
- private static final Holder JOB_BOX = Holder.of("class", "search-result-description");
+ private static final Holder JOB_BOX = Holder.of("class", "vacancy-serp-item ");
private static final Holder TITLE_BOX = Holder.of("data-qa", "vacancy-serp__vacancy-title");
private static final Holder COMPANY_DATA = Holder.of("data-qa", "vacancy-serp__vacancy-employer");
private static final Holder DESCRIPTION_DATA = Holder.of("data-qa", "vacancy-serp__vacancy_snippet_requirement");
From 08c176ae12b49e5b417e1ff4a6f900772c78e14a Mon Sep 17 00:00:00 2001
From: olegshan
Date: Tue, 6 Feb 2018 00:30:12 +0200
Subject: [PATCH 38/62] minor refactoring
---
.../java/com/olegshan/social/JTwitter.java | 37 +++++++------------
1 file changed, 14 insertions(+), 23 deletions(-)
diff --git a/src/main/java/com/olegshan/social/JTwitter.java b/src/main/java/com/olegshan/social/JTwitter.java
index 1e3153a..b90c1f8 100644
--- a/src/main/java/com/olegshan/social/JTwitter.java
+++ b/src/main/java/com/olegshan/social/JTwitter.java
@@ -21,33 +21,13 @@ public class JTwitter {
public JTwitter(Environment environment, Notifier notifier) {
this.environment = environment;
this.notifier = notifier;
-
- if (!dev()) {
- String consumerKey = System.getProperty("CKjP");
- String consumerSecret = System.getProperty("CSjP");
- String accessToken = System.getProperty("ATjP");
- String accessTokenSecret = System.getProperty("ATSjP");
-
- twitter = new TwitterTemplate(consumerKey, consumerSecret, accessToken, accessTokenSecret);
- }
+ initTwitter();
}
public void tweet(Job job) {
-
if (twitter == null) return;
- String tweet;
- String jobTitle = job.getTitle();
- String jobUrl = job.getUrl();
- String moreJobs = " More jobs here: ";
- String jParserUrl = "http://jparser.info";
- int twitterUrlLength = 23;
- int tweetLength = jobTitle.length() + 1 + twitterUrlLength * 2 + moreJobs.length();
-
- if (tweetLength <= 280)
- tweet = jobTitle + " " + jobUrl + moreJobs + jParserUrl;
- else tweet = jobTitle + " " + jobUrl;
-
+ String tweet = String.format("%s %s More jobs here: http://jparser.info", job.getTitle(), job.getUrl());
try {
twitter.timelineOperations().updateStatus(tweet);
} catch (Exception e) {
@@ -59,7 +39,18 @@ public void tweet(Job job) {
}
}
- private boolean dev() {
+ private void initTwitter() {
+ if (isDevEnv()) return;
+
+ String consumerKey = System.getProperty("CKjP");
+ String consumerSecret = System.getProperty("CSjP");
+ String accessToken = System.getProperty("ATjP");
+ String accessTokenSecret = System.getProperty("ATSjP");
+
+ twitter = new TwitterTemplate(consumerKey, consumerSecret, accessToken, accessTokenSecret);
+ }
+
+ private boolean isDevEnv() {
return Arrays.stream(environment.getActiveProfiles())
.anyMatch(env -> env.equalsIgnoreCase("dev"));
}
From d319b040b323306a082910154321fb207006f79d Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 18 Mar 2018 17:06:15 +0200
Subject: [PATCH 39/62] test corrected
---
src/test/java/com/olegshan/service/JobServiceTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/com/olegshan/service/JobServiceTest.java b/src/test/java/com/olegshan/service/JobServiceTest.java
index 1694ff1..f47bb2a 100644
--- a/src/test/java/com/olegshan/service/JobServiceTest.java
+++ b/src/test/java/com/olegshan/service/JobServiceTest.java
@@ -98,7 +98,7 @@ public void jobsAreRetrievedFromDatabaseSortedByDateInDescendingOrder() throws E
private boolean isSortedDescending(Page page) {
List list = page.getContent();
return IntStream.range(0, PAGE_SIZE - 1).allMatch(i -> list.get(i).getDate()
- .compareTo(list.get(i + 1).getDate()) > 0);
+ .compareTo(list.get(i + 1).getDate()) >= 0);
}
@After
From b3c062f3409a62c8a5ffead82cdf49d13394e976 Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sun, 18 Mar 2018 17:19:18 +0200
Subject: [PATCH 40/62] sorting issue fixed
---
src/main/java/com/olegshan/parser/impl/ParserImpl.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/olegshan/parser/impl/ParserImpl.java b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
index ee80d51..eb49660 100644
--- a/src/main/java/com/olegshan/parser/impl/ParserImpl.java
+++ b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
@@ -16,6 +16,8 @@
import java.time.LocalDateTime;
+import static java.time.temporal.ChronoUnit.MINUTES;
+
@Component
public class ParserImpl implements Parser {
@@ -41,8 +43,7 @@ public void parse(JobSite jobSite) {
Elements titleBlock = jobParser.getTitleBlock(job);
url = jobParser.getUrl(titleBlock);
- LocalDateTime date = jobParser.getDate(job, url);
-
+ LocalDateTime date = jobParser.getDate(job, url).truncatedTo(MINUTES);
if (isJobTooOld(date)) continue;
String title = jobParser.getTitle(titleBlock);
From 01924d667fab2293b3b73c2cc8223637c46cc40a Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sat, 24 Mar 2018 14:37:58 +0200
Subject: [PATCH 41/62] statistics implementing in progress
---
.../olegshan/controllers/ParseController.java | 19 ++++++-
.../java/com/olegshan/parser/Performer.java | 33 +++++++----
.../com/olegshan/parser/impl/ParserImpl.java | 9 ++-
.../repository/StatisticsRepository.java | 7 +++
.../java/com/olegshan/service/JobService.java | 1 +
.../olegshan/service/impl/JobServiceImpl.java | 57 ++++++++++++++++---
.../com/olegshan/statistics/Statistics.java | 31 ++++++++++
src/main/resources/static/style.css | 2 +-
src/main/resources/templates/index.html | 3 +-
src/main/resources/templates/statistics.html | 17 ++++++
10 files changed, 154 insertions(+), 25 deletions(-)
create mode 100644 src/main/java/com/olegshan/repository/StatisticsRepository.java
create mode 100644 src/main/java/com/olegshan/statistics/Statistics.java
create mode 100644 src/main/resources/templates/statistics.html
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index 28b7452..61c2e4f 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -1,7 +1,9 @@
package com.olegshan.controllers;
import com.olegshan.entity.Job;
+import com.olegshan.repository.StatisticsRepository;
import com.olegshan.service.JobService;
+import com.olegshan.statistics.Statistics;
import com.olegshan.tools.PageBox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -14,15 +16,19 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
+import java.util.List;
+
@Controller
public class ParseController {
private static final int PAGE_SIZE = 40;
- private JobService jobService;
+ private JobService jobService;
+ private StatisticsRepository statisticsRepository;
@Autowired
- public ParseController(JobService jobService) {
+ public ParseController(JobService jobService, StatisticsRepository statisticsRepository) {
this.jobService = jobService;
+ this.statisticsRepository = statisticsRepository;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
@@ -41,6 +47,15 @@ public ModelAndView showJobs(@RequestParam(value = "page", required = false) Int
return modelAndView;
}
+ @RequestMapping(value = "/statistics", method = RequestMethod.GET)
+ public ModelAndView showStatistics() {
+
+ ModelAndView modelAndView = new ModelAndView("statistics");
+ List stats = statisticsRepository.findAll();
+ modelAndView.addObject("statistics", stats);
+ return modelAndView;
+ }
+
@RequestMapping("/about")
public String about() {
return "about";
diff --git a/src/main/java/com/olegshan/parser/Performer.java b/src/main/java/com/olegshan/parser/Performer.java
index 6131055..45be2de 100644
--- a/src/main/java/com/olegshan/parser/Performer.java
+++ b/src/main/java/com/olegshan/parser/Performer.java
@@ -1,6 +1,8 @@
package com.olegshan.parser;
import com.olegshan.sites.JobSite;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -10,18 +12,25 @@
@Component
public class Performer {
- private List sites;
- private Parser parser;
+ private List sites;
+ private Parser parser;
- @Autowired
- public Performer(List sites, Parser parser) {
- this.sites = sites;
- this.parser = parser;
- }
+ @Autowired
+ public Performer(List sites, Parser parser) {
+ this.sites = sites;
+ this.parser = parser;
+ }
- @Scheduled(cron = "0 1 7-23 * * *", zone = "Europe/Athens")
- public void perform() {
- for (JobSite jobSite : sites)
- parser.parse(jobSite);
- }
+ @Scheduled(cron = "0 1 7-23 * * *", zone = "Europe/Athens")
+ public void perform() {
+ log.error("\n\n!!!!!!!!!!!!!!!!!!!!!!!!!! count of sites: {}\n\n", sites.size());
+ for (JobSite jobSite : sites) {
+ log.error("\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
+ log.error("\nWill parse {}\n\n", jobSite.name());
+
+ parser.parse(jobSite);
+ }
+ }
+
+ private static final Logger log = LoggerFactory.getLogger(Performer.class);
}
diff --git a/src/main/java/com/olegshan/parser/impl/ParserImpl.java b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
index eb49660..e61b18e 100644
--- a/src/main/java/com/olegshan/parser/impl/ParserImpl.java
+++ b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
@@ -24,6 +24,8 @@ public class ParserImpl implements Parser {
private JobService jobService;
private Notifier notifier;
+ public static boolean isSiteParsingEnded;
+
@Autowired
public ParserImpl(JobService jobService, Notifier notifier) {
this.jobService = jobService;
@@ -34,6 +36,7 @@ public void parse(JobSite jobSite) {
JobParser jobParser = jobSite.getParser();
String url = "";
+ isSiteParsingEnded = false;
try {
Document doc = jobParser.getDoc(jobSite.url());
@@ -51,9 +54,13 @@ public void parse(JobSite jobSite) {
String company = jobParser.getCompany(job, url);
Job parsedJob = new Job(title, description, company, jobSite.name(), url, date);
+ log.error("\n\n**** PARSER: Job to save: {}, {}\n\n", parsedJob.getTitle(), parsedJob.getSource());
jobService.save(parsedJob);
}
- log.info("Parsing of {} completed\n", jobSite.name());
+
+ jobService.saveStatistics(jobSite.name());
+ log.error("\n\n**** PARSER: Save statistics of {}\n\n", jobSite.name());
+ log.info("\n\n+++++++++ Parsing of {} completed ++++++++\n\n\n", jobSite.name());
} catch (Exception e) {
log.error("Error while parsing", e);
notifier.notifyAdmin("Error while parsing " + url + "\nError message is: " + e.getMessage());
diff --git a/src/main/java/com/olegshan/repository/StatisticsRepository.java b/src/main/java/com/olegshan/repository/StatisticsRepository.java
new file mode 100644
index 0000000..64f4720
--- /dev/null
+++ b/src/main/java/com/olegshan/repository/StatisticsRepository.java
@@ -0,0 +1,7 @@
+package com.olegshan.repository;
+
+import com.olegshan.statistics.Statistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface StatisticsRepository extends JpaRepository {
+}
diff --git a/src/main/java/com/olegshan/service/JobService.java b/src/main/java/com/olegshan/service/JobService.java
index 574a8f2..c834e04 100644
--- a/src/main/java/com/olegshan/service/JobService.java
+++ b/src/main/java/com/olegshan/service/JobService.java
@@ -7,6 +7,7 @@
public interface JobService {
void save(Job job);
+ void saveStatistics(String siteName);
Page getJobs(Pageable request);
}
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index e96e1dc..7db7db6 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -3,8 +3,10 @@
import com.olegshan.entity.Job;
import com.olegshan.notifier.Notifier;
import com.olegshan.repository.JobRepository;
+import com.olegshan.repository.StatisticsRepository;
import com.olegshan.service.JobService;
import com.olegshan.social.JTwitter;
+import com.olegshan.statistics.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,26 +15,40 @@
import org.springframework.stereotype.Service;
import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static java.time.temporal.ChronoUnit.MINUTES;
@Service
public class JobServiceImpl implements JobService {
- private JobRepository jobRepository;
- private JTwitter twitter;
- private Notifier notifier;
+ private JobRepository jobRepository;
+ private StatisticsRepository statisticsRepository;
+ private JTwitter twitter;
+ private Notifier notifier;
+
+ private Statistics statistics;
@Autowired
- public JobServiceImpl(JobRepository jobRepository, JTwitter twitter, Notifier notifier) {
+ public JobServiceImpl(
+ JobRepository jobRepository,
+ StatisticsRepository statisticsRepository,
+ JTwitter twitter,
+ Notifier notifier
+ ) {
this.jobRepository = jobRepository;
+ this.statisticsRepository = statisticsRepository;
this.twitter = twitter;
this.notifier = notifier;
+ statistics = new Statistics();
}
public void save(Job job) {
if (jobRepository.exists(job.getUrl())) {
+ log.error("\n\n------- SERVICE: Job exists, will try to update {}, {}\n\n", job.getTitle(), job.getSource());
update(job);
} else {
- saveAndTweet(job);
+ saveAndTweet(job, true);
log.info("New job '{}' on {} found", job.getTitle(), job.getSource());
}
}
@@ -42,16 +58,41 @@ private void update(Job job) {
LocalDate jobFromDbDate = jobFromDb.getDate().toLocalDate();
LocalDate jobDate = job.getDate().toLocalDate();
if (!jobFromDbDate.equals(jobDate)) {
- saveAndTweet(job);
+ saveAndTweet(job, false);
log.info("Job '{}', {}, was updated", job.getTitle(), job.getUrl());
- }
+ } else
+ log.error("\n\n////////////// SERVICE: will not update job {}, {}", job.getTitle(), job.getSource());
}
- private void saveAndTweet(Job job) {
+ private void saveAndTweet(Job job, boolean isNew) {
saveJob(job);
+ updateStatistics(job.getTitle(), isNew);
twitter.tweet(job);
}
+ private void updateStatistics(String jobTitle, boolean isNew) {
+ if (isNew) {
+ log.error("\n\n**** SERVICE: incrementNewJobsCount by job {}\n\n", jobTitle);
+ statistics.incrementNewJobsCount();
+ } else {
+ log.error("\n\n**** SERVICE: incrementUpdatedJobsCount {}\n\n", jobTitle);
+ statistics.incrementUpdatedJobsCount();
+ }
+ }
+
+ @Override
+ public void saveStatistics(String siteName) {
+ statistics.setRun(LocalDateTime.now().truncatedTo(MINUTES));
+ statistics.setId(siteName);
+ statistics.setSiteName(siteName);
+ if (!statisticsRepository.exists(statistics.getId())) {
+ log.error("\n\n^^^^^^^^^^^^^^^^^ SERVICE: saveStatistics of {} with {} new jobs and {} updated jobs\n\n",
+ siteName, statistics.getNewJobsFoundByRun(), statistics.getUpdatedJobsByRun());
+ statisticsRepository.save(statistics);
+ }
+ statistics = new Statistics();
+ }
+
public Page getJobs(Pageable request) {
return jobRepository.findAll(request);
}
diff --git a/src/main/java/com/olegshan/statistics/Statistics.java b/src/main/java/com/olegshan/statistics/Statistics.java
new file mode 100644
index 0000000..3745bfb
--- /dev/null
+++ b/src/main/java/com/olegshan/statistics/Statistics.java
@@ -0,0 +1,31 @@
+package com.olegshan.statistics;
+
+import lombok.Data;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.time.LocalDateTime;
+
+@Entity
+@Data
+public class Statistics {
+
+ @Id
+ private String id;
+ private String siteName;
+ private LocalDateTime run;
+ private int newJobsFoundByRun;
+ private int updatedJobsByRun;
+
+ public void setId(String siteName) {
+ id = siteName + run.toString();
+ }
+
+ public void incrementNewJobsCount() {
+ newJobsFoundByRun = newJobsFoundByRun + 1;
+ }
+
+ public void incrementUpdatedJobsCount() {
+ updatedJobsByRun = updatedJobsByRun + 1;
+ }
+}
diff --git a/src/main/resources/static/style.css b/src/main/resources/static/style.css
index 1ada486..c99f96f 100644
--- a/src/main/resources/static/style.css
+++ b/src/main/resources/static/style.css
@@ -34,7 +34,7 @@
vertical-align: super;
}
-.under {
+.under, .statistics {
font-size: 12px;
}
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 3f5ea89..bc49983 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -43,7 +43,8 @@
diff --git a/src/main/resources/templates/statistics.html b/src/main/resources/templates/statistics.html
new file mode 100644
index 0000000..b9cbf67
--- /dev/null
+++ b/src/main/resources/templates/statistics.html
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
From 4b0a5f952a6f6ba439dbdff531cf85846da4b4cf Mon Sep 17 00:00:00 2001
From: olegshan
Date: Sat, 24 Mar 2018 14:39:46 +0200
Subject: [PATCH 42/62] current year to footer added
---
src/main/resources/templates/index.html | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 3f5ea89..bc49983 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -43,7 +43,8 @@
From 659a66b610a7ffef27c9fa061975d28e9c348cbc Mon Sep 17 00:00:00 2001
From: olegshan
Date: Tue, 24 Apr 2018 23:19:01 +0300
Subject: [PATCH 43/62] in progress
---
pom.xml | 12 ++++
.../olegshan/controllers/ParseController.java | 14 +++-
.../java/com/olegshan/entity/Statistics.java | 33 +++++++++
.../java/com/olegshan/parser/Performer.java | 10 ++-
.../com/olegshan/parser/impl/ParserImpl.java | 3 -
.../repository/StatisticsRepository.java | 2 +-
.../java/com/olegshan/service/JobService.java | 1 +
.../olegshan/service/StatisticsService.java | 11 +++
.../olegshan/service/impl/JobServiceImpl.java | 43 ++++--------
.../service/impl/StatisticsServiceImpl.java | 70 +++++++++++++++++++
src/main/resources/templates/statistics.html | 11 ++-
11 files changed, 167 insertions(+), 43 deletions(-)
create mode 100644 src/main/java/com/olegshan/entity/Statistics.java
create mode 100644 src/main/java/com/olegshan/service/StatisticsService.java
create mode 100644 src/main/java/com/olegshan/service/impl/StatisticsServiceImpl.java
diff --git a/pom.xml b/pom.xml
index 26a3347..f74cda0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,18 @@
1.9.2
+
+ io.prometheus
+ simpleclient
+ 0.3.0
+
+
+
+ io.prometheus
+ simpleclient_common
+ 0.3.0
+
+
diff --git a/src/main/java/com/olegshan/controllers/ParseController.java b/src/main/java/com/olegshan/controllers/ParseController.java
index 61c2e4f..a92533d 100644
--- a/src/main/java/com/olegshan/controllers/ParseController.java
+++ b/src/main/java/com/olegshan/controllers/ParseController.java
@@ -1,10 +1,12 @@
package com.olegshan.controllers;
import com.olegshan.entity.Job;
+import com.olegshan.entity.Statistics;
import com.olegshan.repository.StatisticsRepository;
import com.olegshan.service.JobService;
-import com.olegshan.statistics.Statistics;
import com.olegshan.tools.PageBox;
+import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.exporter.common.TextFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -16,6 +18,9 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collections;
import java.util.List;
@Controller
@@ -52,6 +57,7 @@ public ModelAndView showStatistics() {
ModelAndView modelAndView = new ModelAndView("statistics");
List stats = statisticsRepository.findAll();
+ Collections.reverse(stats);
modelAndView.addObject("statistics", stats);
return modelAndView;
}
@@ -60,4 +66,10 @@ public ModelAndView showStatistics() {
public String about() {
return "about";
}
+
+ @RequestMapping(path = "/metrics")
+ public void metrics(Writer responseWriter) throws IOException {
+ TextFormat.write004(responseWriter, CollectorRegistry.defaultRegistry.metricFamilySamples());
+ responseWriter.close();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/olegshan/entity/Statistics.java b/src/main/java/com/olegshan/entity/Statistics.java
new file mode 100644
index 0000000..3d6b593
--- /dev/null
+++ b/src/main/java/com/olegshan/entity/Statistics.java
@@ -0,0 +1,33 @@
+package com.olegshan.entity;
+
+import lombok.Data;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.time.LocalDateTime;
+
+import static java.time.temporal.ChronoUnit.HOURS;
+
+@Entity
+@Data
+public class Statistics {
+
+ @Id
+ private String id;
+ private String siteName;
+ private LocalDateTime run;
+ private int newJobsFoundByRun;
+ private int updatedJobsByRun;
+
+ public void setId(String siteName) {
+ id = siteName + "_" + run.truncatedTo(HOURS);
+ }
+
+ public void incrementNewJobsCount() {
+ newJobsFoundByRun++;
+ }
+
+ public void incrementUpdatedJobsCount() {
+ updatedJobsByRun++;
+ }
+}
diff --git a/src/main/java/com/olegshan/parser/Performer.java b/src/main/java/com/olegshan/parser/Performer.java
index 45be2de..0736667 100644
--- a/src/main/java/com/olegshan/parser/Performer.java
+++ b/src/main/java/com/olegshan/parser/Performer.java
@@ -14,6 +14,7 @@ public class Performer {
private List sites;
private Parser parser;
+ private boolean isParsingRunning;
@Autowired
public Performer(List sites, Parser parser) {
@@ -23,13 +24,18 @@ public Performer(List sites, Parser parser) {
@Scheduled(cron = "0 1 7-23 * * *", zone = "Europe/Athens")
public void perform() {
+ if (isParsingRunning) {
+ log.error("~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parsing is already running!");
+ return;
+ }
+ isParsingRunning = true;
log.error("\n\n!!!!!!!!!!!!!!!!!!!!!!!!!! count of sites: {}\n\n", sites.size());
for (JobSite jobSite : sites) {
- log.error("\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
- log.error("\nWill parse {}\n\n", jobSite.name());
+ log.error("\n\n\n\n\n\n\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$ {}\n\n\n\n\n\n\n\n", jobSite.name().toUpperCase());
parser.parse(jobSite);
}
+ isParsingRunning = false;
}
private static final Logger log = LoggerFactory.getLogger(Performer.class);
diff --git a/src/main/java/com/olegshan/parser/impl/ParserImpl.java b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
index e61b18e..cb2d818 100644
--- a/src/main/java/com/olegshan/parser/impl/ParserImpl.java
+++ b/src/main/java/com/olegshan/parser/impl/ParserImpl.java
@@ -24,8 +24,6 @@ public class ParserImpl implements Parser {
private JobService jobService;
private Notifier notifier;
- public static boolean isSiteParsingEnded;
-
@Autowired
public ParserImpl(JobService jobService, Notifier notifier) {
this.jobService = jobService;
@@ -36,7 +34,6 @@ public void parse(JobSite jobSite) {
JobParser jobParser = jobSite.getParser();
String url = "";
- isSiteParsingEnded = false;
try {
Document doc = jobParser.getDoc(jobSite.url());
diff --git a/src/main/java/com/olegshan/repository/StatisticsRepository.java b/src/main/java/com/olegshan/repository/StatisticsRepository.java
index 64f4720..d40519f 100644
--- a/src/main/java/com/olegshan/repository/StatisticsRepository.java
+++ b/src/main/java/com/olegshan/repository/StatisticsRepository.java
@@ -1,6 +1,6 @@
package com.olegshan.repository;
-import com.olegshan.statistics.Statistics;
+import com.olegshan.entity.Statistics;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StatisticsRepository extends JpaRepository {
diff --git a/src/main/java/com/olegshan/service/JobService.java b/src/main/java/com/olegshan/service/JobService.java
index c834e04..1676a73 100644
--- a/src/main/java/com/olegshan/service/JobService.java
+++ b/src/main/java/com/olegshan/service/JobService.java
@@ -7,6 +7,7 @@
public interface JobService {
void save(Job job);
+
void saveStatistics(String siteName);
Page getJobs(Pageable request);
diff --git a/src/main/java/com/olegshan/service/StatisticsService.java b/src/main/java/com/olegshan/service/StatisticsService.java
new file mode 100644
index 0000000..b84f833
--- /dev/null
+++ b/src/main/java/com/olegshan/service/StatisticsService.java
@@ -0,0 +1,11 @@
+package com.olegshan.service;
+
+import com.olegshan.entity.Job;
+import com.olegshan.entity.Statistics;
+
+public interface StatisticsService {
+
+ void saveStatistics(Statistics statistics, String siteName);
+
+ void updateStatistics(Statistics statistics, Job job, boolean isNew);
+}
diff --git a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
index 7db7db6..5089199 100644
--- a/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
+++ b/src/main/java/com/olegshan/service/impl/JobServiceImpl.java
@@ -1,12 +1,12 @@
package com.olegshan.service.impl;
import com.olegshan.entity.Job;
+import com.olegshan.entity.Statistics;
import com.olegshan.notifier.Notifier;
import com.olegshan.repository.JobRepository;
-import com.olegshan.repository.StatisticsRepository;
import com.olegshan.service.JobService;
+import com.olegshan.service.StatisticsService;
import com.olegshan.social.JTwitter;
-import com.olegshan.statistics.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -15,29 +15,26 @@
import org.springframework.stereotype.Service;
import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-import static java.time.temporal.ChronoUnit.MINUTES;
@Service
public class JobServiceImpl implements JobService {
- private JobRepository jobRepository;
- private StatisticsRepository statisticsRepository;
- private JTwitter twitter;
- private Notifier notifier;
+ private JobRepository jobRepository;
+ private StatisticsService statisticsService;
+ private JTwitter twitter;
+ private Notifier notifier;
private Statistics statistics;
@Autowired
public JobServiceImpl(
JobRepository jobRepository,
- StatisticsRepository statisticsRepository,
+ StatisticsService statisticsService,
JTwitter twitter,
Notifier notifier
) {
this.jobRepository = jobRepository;
- this.statisticsRepository = statisticsRepository;
+ this.statisticsService = statisticsService;
this.twitter = twitter;
this.notifier = notifier;
statistics = new Statistics();
@@ -45,7 +42,6 @@ public JobServiceImpl(
public void save(Job job) {
if (jobRepository.exists(job.getUrl())) {
- log.error("\n\n------- SERVICE: Job exists, will try to update {}, {}\n\n", job.getTitle(), job.getSource());
update(job);
} else {
saveAndTweet(job, true);
@@ -61,35 +57,22 @@ private void update(Job job) {
saveAndTweet(job, false);
log.info("Job '{}', {}, was updated", job.getTitle(), job.getUrl());
} else
- log.error("\n\n////////////// SERVICE: will not update job {}, {}", job.getTitle(), job.getSource());
+ log.error("\n\n////////////// SERVICE: will not update job {}, {}\n\n", job.getTitle(), job.getSource());
}
private void saveAndTweet(Job job, boolean isNew) {
saveJob(job);
- updateStatistics(job.getTitle(), isNew);
+ updateStatistics(job, isNew);
twitter.tweet(job);
}
- private void updateStatistics(String jobTitle, boolean isNew) {
- if (isNew) {
- log.error("\n\n**** SERVICE: incrementNewJobsCount by job {}\n\n", jobTitle);
- statistics.incrementNewJobsCount();
- } else {
- log.error("\n\n**** SERVICE: incrementUpdatedJobsCount {}\n\n", jobTitle);
- statistics.incrementUpdatedJobsCount();
- }
+ private void updateStatistics(Job job, boolean isNew) {
+ statisticsService.updateStatistics(statistics, job, isNew);
}
@Override
public void saveStatistics(String siteName) {
- statistics.setRun(LocalDateTime.now().truncatedTo(MINUTES));
- statistics.setId(siteName);
- statistics.setSiteName(siteName);
- if (!statisticsRepository.exists(statistics.getId())) {
- log.error("\n\n^^^^^^^^^^^^^^^^^ SERVICE: saveStatistics of {} with {} new jobs and {} updated jobs\n\n",
- siteName, statistics.getNewJobsFoundByRun(), statistics.getUpdatedJobsByRun());
- statisticsRepository.save(statistics);
- }
+ statisticsService.saveStatistics(statistics, siteName);
statistics = new Statistics();
}
diff --git a/src/main/java/com/olegshan/service/impl/StatisticsServiceImpl.java b/src/main/java/com/olegshan/service/impl/StatisticsServiceImpl.java
new file mode 100644
index 0000000..3e6fbed
--- /dev/null
+++ b/src/main/java/com/olegshan/service/impl/StatisticsServiceImpl.java
@@ -0,0 +1,70 @@
+package com.olegshan.service.impl;
+
+import com.olegshan.entity.Job;
+import com.olegshan.entity.Statistics;
+import com.olegshan.repository.StatisticsRepository;
+import com.olegshan.service.StatisticsService;
+import io.prometheus.client.Counter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+@Service
+public class StatisticsServiceImpl implements StatisticsService {
+
+ private StatisticsRepository statisticsRepository;
+
+ private final Counter newJobsCounter = Counter.build()
+ .name("new_jobs_counter")
+ .help("New jobs counter.")
+ .labelNames("site_name")
+ .register();
+
+ private final Counter updatedJobsCounter = Counter.build()
+ .name("updated_jobs_counter")
+ .help("Updated jobs counter.")
+ .labelNames("site_name")
+ .register();
+
+ @Autowired
+ public StatisticsServiceImpl(StatisticsRepository statisticsRepository) {
+ this.statisticsRepository = statisticsRepository;
+ }
+
+ @Override
+ public void updateStatistics(Statistics statistics, Job job, boolean isNew) {
+ if (isNew) {
+ log.error("\n\n**** SERVICE: incrementNewJobsCount by job {}\n\n", job.getTitle());
+ statistics.incrementNewJobsCount();
+ newJobsCounter
+ .labels(job.getSource())
+ .inc();
+ } else {
+ log.error("\n\n**** SERVICE: incrementUpdatedJobsCount {}\n\n", job.getTitle());
+ statistics.incrementUpdatedJobsCount();
+ updatedJobsCounter
+ .labels(job.getSource())
+ .inc();
+ }
+ }
+
+ @Override
+ public void saveStatistics(Statistics statistics, String siteName) {
+ statistics.setRun(LocalDateTime.now().truncatedTo(SECONDS));
+ statistics.setId(siteName);
+ statistics.setSiteName(siteName);
+ if (!statisticsRepository.exists(statistics.getId())) {
+ log.error("\n\n^^^^^^^^^^^^^^^^^ SERVICE: saveStatistics of {} with {} new jobs and {} updated jobs\n\n",
+ siteName, statistics.getNewJobsFoundByRun(), statistics.getUpdatedJobsByRun());
+ statisticsRepository.save(statistics);
+ } else
+ log.error("\n\n######################## SERVICE: statistics with id {} exists\n\n", statistics.getId());
+ }
+
+ private static final Logger log = LoggerFactory.getLogger(StatisticsServiceImpl.class);
+}
diff --git a/src/main/resources/templates/statistics.html b/src/main/resources/templates/statistics.html
index b9cbf67..8d08cac 100644
--- a/src/main/resources/templates/statistics.html
+++ b/src/main/resources/templates/statistics.html
@@ -2,16 +2,15 @@