From f079c387bc156fe1edd5891834833b8505b87042 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Thu, 18 Aug 2016 19:16:58 +0200 Subject: [PATCH 01/21] Done DTO classes --- .../com/academy/model/{ => dao}/Account.java | 2 +- .../com/academy/model/{ => dao}/Activity.java | 2 +- .../com/academy/model/{ => dao}/Points.java | 2 +- .../com/academy/model/{ => dao}/Subpage.java | 2 +- .../com/academy/model/{ => dao}/Website.java | 2 +- .../com/academy/model/dto/AccountDTO.java | 71 +++++++++++++++++++ .../com/academy/model/dto/ActivityDTO.java | 37 ++++++++++ .../java/com/academy/model/dto/PointsDTO.java | 35 +++++++++ .../com/academy/model/dto/SubpageDTO.java | 53 ++++++++++++++ .../com/academy/model/dto/WebsiteDTO.java | 35 +++++++++ .../com/academy/service/AccountService.java | 7 ++ .../service/mappers/AccountMapper.java | 7 ++ .../web/controller/AccountController.java | 6 +- .../academy/web/controller/Controller.java | 17 +++++ .../templates/{ => public}/index.html | 2 +- 15 files changed, 269 insertions(+), 11 deletions(-) rename ClickMapActivity-model/src/main/java/com/academy/model/{ => dao}/Account.java (98%) rename ClickMapActivity-model/src/main/java/com/academy/model/{ => dao}/Activity.java (96%) rename ClickMapActivity-model/src/main/java/com/academy/model/{ => dao}/Points.java (95%) rename ClickMapActivity-model/src/main/java/com/academy/model/{ => dao}/Subpage.java (97%) rename ClickMapActivity-model/src/main/java/com/academy/model/{ => dao}/Website.java (96%) create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/AccountDTO.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java rename ClickMapActivity-web/src/main/resources/templates/{ => public}/index.html (79%) diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/Account.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java similarity index 98% rename from ClickMapActivity-model/src/main/java/com/academy/model/Account.java rename to ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java index 2e88e70..471da0b 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/Account.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java @@ -1,4 +1,4 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/Activity.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java similarity index 96% rename from ClickMapActivity-model/src/main/java/com/academy/model/Activity.java rename to ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java index 76b5a07..3b759c1 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/Activity.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java @@ -1,4 +1,4 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.*; import java.util.Date; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/Points.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Points.java similarity index 95% rename from ClickMapActivity-model/src/main/java/com/academy/model/Points.java rename to ClickMapActivity-model/src/main/java/com/academy/model/dao/Points.java index 4cd5014..e204dee 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/Points.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Points.java @@ -1,4 +1,4 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.*; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/Subpage.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java similarity index 97% rename from ClickMapActivity-model/src/main/java/com/academy/model/Subpage.java rename to ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java index 53d1042..72c1950 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/Subpage.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java @@ -1,4 +1,4 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.*; import java.util.List; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/Website.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java similarity index 96% rename from ClickMapActivity-model/src/main/java/com/academy/model/Website.java rename to ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java index 7f865d1..d16ab15 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/Website.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java @@ -1,4 +1,4 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.*; import java.util.List; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/AccountDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/AccountDTO.java new file mode 100644 index 0000000..cecc31c --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/AccountDTO.java @@ -0,0 +1,71 @@ +package com.academy.model.dto; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class AccountDTO { + + private Long id; + private String userName; + private String password; + private String firstName; + private String surName; + private String phoneNumber; + private String email; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getSurName() { + return surName; + } + + public void setSurName(String surName) { + this.surName = surName; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java new file mode 100644 index 0000000..06e3c90 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java @@ -0,0 +1,37 @@ +package com.academy.model.dto; + +import java.util.Date; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class ActivityDTO { + + private Long id; + private Date date; + private Long subpageId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Long getSubpageId() { + return subpageId; + } + + public void setSubpageId(Long subpageId) { + this.subpageId = subpageId; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java new file mode 100644 index 0000000..86d4ddc --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java @@ -0,0 +1,35 @@ +package com.academy.model.dto; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class PointsDTO { + + private Long id; + private String pairValue; + private Long activityId; + + public Long getActivityId() { + return activityId; + } + + public void setActivityId(Long activityId) { + this.activityId = activityId; + } + + public String getPairValue() { + return pairValue; + } + + public void setPairValue(String pairValue) { + this.pairValue = pairValue; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java new file mode 100644 index 0000000..ce39692 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java @@ -0,0 +1,53 @@ +package com.academy.model.dto; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class SubpageDTO { + + private Long id; + private String name; + private Integer resX; + private Integer resY; + private Long websiteId; + + public Long getWebsiteId() { + return websiteId; + } + + public void setWebsiteId(Long websiteId) { + this.websiteId = websiteId; + } + + public Integer getResY() { + return resY; + } + + public void setResY(Integer resY) { + this.resY = resY; + } + + public Integer getResX() { + return resX; + } + + public void setResX(Integer resX) { + this.resX = resX; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java new file mode 100644 index 0000000..c673d68 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java @@ -0,0 +1,35 @@ +package com.academy.model.dto; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class WebsiteDTO { + + private Long id; + private String url; + private Long accountId; + + public Long getAccountId() { + return accountId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java new file mode 100644 index 0000000..68d9a29 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java @@ -0,0 +1,7 @@ +package com.academy.service; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class AccountService { +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java new file mode 100644 index 0000000..d9d6ecc --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java @@ -0,0 +1,7 @@ +package com.academy.service.mappers; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class AccountMapper { +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java index 511db00..23edacd 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java @@ -6,11 +6,7 @@ /** * Created by Daniel Palonek on 2016-08-04. */ -@RestController +@RestController("/") public class AccountController { - @RequestMapping("/index") - public String index() { - return "Test Spring Boot"; - } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java new file mode 100644 index 0000000..6be16ce --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java @@ -0,0 +1,17 @@ +package com.academy.web.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@RestController +public class Controller { + + @RequestMapping("/") + public ModelAndView index(){ + return new ModelAndView("public/index"); + } +} diff --git a/ClickMapActivity-web/src/main/resources/templates/index.html b/ClickMapActivity-web/src/main/resources/templates/public/index.html similarity index 79% rename from ClickMapActivity-web/src/main/resources/templates/index.html rename to ClickMapActivity-web/src/main/resources/templates/public/index.html index 6da5204..7a9185b 100644 --- a/ClickMapActivity-web/src/main/resources/templates/index.html +++ b/ClickMapActivity-web/src/main/resources/templates/public/index.html @@ -1,7 +1,7 @@ - + Main page From 0ac299efdfb015d108e967ad70cb95b27652fc1d Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Fri, 19 Aug 2016 16:20:24 +0200 Subject: [PATCH 02/21] Done mappers and repo --- .../java/com/academy/model/dao/Account.java | 10 ++-- ClickMapActivity-repo/build.gradle | 3 ++ .../java/com/academy/repo/AccountRepo.java | 7 ++- .../java/com/academy/repo/ActivityRepo.java | 10 ++++ .../java/com/academy/repo/PointsRepo.java | 10 ++++ .../java/com/academy/repo/SubpageRepo.java | 10 ++++ .../java/com/academy/repo/WebsiteRepo.java | 10 ++++ ClickMapActivity-service/build.gradle | 6 ++- .../service/mappers/AccountMapper.java | 34 +++++++++++++- .../service/mappers/ActivityMapper.java | 44 ++++++++++++++++++ .../com/academy/service/mappers/Mapper.java | 22 +++++++++ .../academy/service/mappers/PointsMapper.java | 43 +++++++++++++++++ .../service/mappers/SubpageMapper.java | 46 +++++++++++++++++++ .../service/mappers/WebsiteMapper.java | 42 +++++++++++++++++ 14 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/ActivityRepo.java create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/SubpageRepo.java create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/ActivityMapper.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java index 471da0b..73348b1 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java @@ -15,7 +15,7 @@ public class Account { @Id @GeneratedValue private Long id; - private String username; + private String userName; private String password; private String firstName; private String surName; @@ -33,12 +33,12 @@ public void setId(Long id) { this.id = id; } - public String getUsername() { - return username; + public String getUserName() { + return userName; } - public void setUsername(String username) { - this.username = username; + public void setUserName(String userName) { + this.userName = userName; } public String getPassword() { diff --git a/ClickMapActivity-repo/build.gradle b/ClickMapActivity-repo/build.gradle index 6f128ce..c335f2f 100644 --- a/ClickMapActivity-repo/build.gradle +++ b/ClickMapActivity-repo/build.gradle @@ -2,6 +2,7 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' apply plugin: 'java' +apply plugin: 'spring-boot' sourceCompatibility = 1.8 @@ -10,5 +11,7 @@ repositories { } dependencies { + compile("org.springframework.boot:spring-boot-starter-data-jpa") + compile project(':ClickMapActivity-model') testCompile group: 'junit', name: 'junit', version: '4.11' } diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java index 4265795..6933248 100644 --- a/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java @@ -1,7 +1,10 @@ package com.academy.repo; +import com.academy.model.dao.Account; +import org.springframework.data.repository.CrudRepository; + /** - * Created by Daniel Palonek on 2016-08-15. + * Created by Daniel Palonek on 2016-08-19. */ -public class AccountRepo { +public interface AccountRepo extends CrudRepository { } diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/ActivityRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/ActivityRepo.java new file mode 100644 index 0000000..795e410 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/ActivityRepo.java @@ -0,0 +1,10 @@ +package com.academy.repo; + +import com.academy.model.dao.Activity; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface ActivityRepo extends CrudRepository { +} diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java new file mode 100644 index 0000000..2c7b7c1 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java @@ -0,0 +1,10 @@ +package com.academy.repo; + +import com.academy.model.dao.Points; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface PointsRepo extends CrudRepository { +} diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/SubpageRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/SubpageRepo.java new file mode 100644 index 0000000..0abf8b4 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/SubpageRepo.java @@ -0,0 +1,10 @@ +package com.academy.repo; + +import com.academy.model.dao.Subpage; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface SubpageRepo extends CrudRepository { +} diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java new file mode 100644 index 0000000..3b6c89b --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java @@ -0,0 +1,10 @@ +package com.academy.repo; + +import com.academy.model.dao.Website; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface WebsiteRepo extends CrudRepository { +} diff --git a/ClickMapActivity-service/build.gradle b/ClickMapActivity-service/build.gradle index 7ce2fb6..207e599 100644 --- a/ClickMapActivity-service/build.gradle +++ b/ClickMapActivity-service/build.gradle @@ -2,13 +2,17 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' apply plugin: 'java' +apply plugin: 'spring-boot' -sourceCompatibility = 1.5 +sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + compile project(':ClickMapActivity-model') + compile project(':ClickMapActivity-repo') testCompile group: 'junit', name: 'junit', version: '4.11' } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java index d9d6ecc..b896932 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java @@ -1,7 +1,39 @@ package com.academy.service.mappers; +import com.academy.model.dao.Account; +import com.academy.model.dto.AccountDTO; +import org.springframework.stereotype.Component; + /** * Created by Daniel Palonek on 2016-08-18. */ -public class AccountMapper { +@Component +public class AccountMapper implements Mapper { + + @Override + public Account convertToDAO(AccountDTO dto) { + final Account dao = new Account(); + dao.setPassword(dto.getPassword()); + dao.setUserName(dto.getUserName()); + dao.setEmail(dto.getEmail()); + dao.setId(dto.getId()); + dao.setPhoneNumber(dto.getPhoneNumber()); + dao.setSurName(dto.getSurName()); + dao.setFirstName(dto.getFirstName()); + return dao; + } + + @Override + public AccountDTO convertToDTO(Account dao) { + final AccountDTO dto = new AccountDTO(); + dto.setFirstName(dao.getFirstName()); + dto.setSurName(dao.getSurName()); + dto.setPhoneNumber(dao.getPhoneNumber()); + dto.setId(dao.getId()); + dto.setEmail(dao.getEmail()); + dto.setPassword(dao.getPassword()); + dto.setUserName(dao.getUserName()); + return dto; + } + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/ActivityMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/ActivityMapper.java new file mode 100644 index 0000000..6878d27 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/ActivityMapper.java @@ -0,0 +1,44 @@ +package com.academy.service.mappers; + +import com.academy.model.dao.Activity; +import com.academy.model.dao.Subpage; +import com.academy.model.dto.ActivityDTO; +import com.academy.repo.SubpageRepo; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class ActivityMapper implements Mapper { + + @Autowired + SubpageRepo subpageRepo; + + @Override + public Activity convertToDAO(ActivityDTO dto) { + final Activity dao = new Activity(); + dao.setId(dto.getId()); + dao.setDate(dto.getDate() == null ? new Date() : dto.getDate()); + if(dto.getSubpageId() != null) { + Subpage subpage = subpageRepo.findOne(dto.getSubpageId()); + if(subpage != null) { + dao.setSubpage(subpage); + } + } + return dao; + } + + @Override + public ActivityDTO convertToDTO(Activity dao) { + final ActivityDTO dto = new ActivityDTO(); + dto.setId(dao.getId()); + dto.setDate(dao.getDate()); + if(dao.getSubpage() != null) { + dto.setSubpageId(dao.getSubpage().getId()); + } + return dto; + } + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java new file mode 100644 index 0000000..6b1b691 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java @@ -0,0 +1,22 @@ +package com.academy.service.mappers; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public interface Mapper { + + DAO convertToDAO(DTO dto); + + DTO convertToDTO(DAO dao); + + default Iterable convertToDAO(Iterable dto) { + return Stream.of(dto).map(this::convertToDAO).collect(Collectors.toList()); + } + + default Iterable convertToDTO(Iterable dao) { + return Stream.of(dao).map(this::convertToDTO).collect(Collectors.toList()); + } +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java new file mode 100644 index 0000000..4d43e68 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java @@ -0,0 +1,43 @@ +package com.academy.service.mappers; + +import com.academy.model.dao.Activity; +import com.academy.model.dao.Points; +import com.academy.model.dto.PointsDTO; +import com.academy.repo.AccountRepo; +import com.academy.repo.ActivityRepo; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class PointsMapper implements Mapper { + + @Autowired + ActivityRepo activityRepo; + + @Override + public Points convertToDAO(PointsDTO dto) { + final Points dao = new Points(); + dao.setId(dto.getId()); + dao.setPairValue(dto.getPairValue()); + if(dto.getActivityId() != null) { + Activity activity = activityRepo.findOne(dto.getActivityId()); + if(activity != null) { + dao.setActivity(activity); + } + } + return dao; + } + + @Override + public PointsDTO convertToDTO(Points dao) { + final PointsDTO dto = new PointsDTO(); + dto.setId(dao.getId()); + dto.setPairValue(dao.getPairValue()); + if(dao.getActivity() != null) { + dto.setActivityId(dao.getActivity().getId()); + } + return dto; + } + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java new file mode 100644 index 0000000..135ca6d --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java @@ -0,0 +1,46 @@ +package com.academy.service.mappers; + +import com.academy.model.dao.Subpage; +import com.academy.model.dao.Website; +import com.academy.model.dto.SubpageDTO; +import com.academy.repo.WebsiteRepo; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class SubpageMapper implements Mapper { + + @Autowired + WebsiteRepo websiteRepo; + + @Override + public Subpage convertToDAO(SubpageDTO dto) { + final Subpage dao = new Subpage(); + dao.setId(dto.getId()); + dao.setName(dto.getName()); + dao.setResX(dto.getResX()); + dao.setResY(dto.getResY()); + if(dto.getWebsiteId() != null) { + Website website = websiteRepo.findOne(dto.getWebsiteId()); + if(website != null) { + dao.setWebsite(website); + } + } + return dao; + } + + @Override + public SubpageDTO convertToDTO(Subpage dao) { + final SubpageDTO dto = new SubpageDTO(); + dto.setId(dao.getId()); + dto.setResX(dao.getResX()); + dto.setResY(dao.getResY()); + dto.setName(dao.getName()); + if(dao.getWebsite() != null) { + dto.setWebsiteId(dao.getWebsite().getId()); + } + return dto; + } + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java new file mode 100644 index 0000000..21aeb0f --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java @@ -0,0 +1,42 @@ +package com.academy.service.mappers; + +import com.academy.model.dao.Account; +import com.academy.model.dao.Website; +import com.academy.model.dto.WebsiteDTO; +import com.academy.repo.AccountRepo; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class WebsiteMapper implements Mapper { + + @Autowired + AccountRepo accountRepo; + + @Override + public Website convertToDAO(WebsiteDTO dto) { + final Website dao = new Website(); + dao.setId(dto.getId()); + dao.setUrl(dto.getUrl()); + if(dto.getAccountId() != null) { + Account account = accountRepo.findOne(dto.getAccountId()); + if (account != null) { + dao.setAccount(account); + } + } + return dao; + } + + @Override + public WebsiteDTO convertToDTO(Website dao) { + final WebsiteDTO dto = new WebsiteDTO(); + dto.setId(dao.getId()); + dto.setUrl(dao.getUrl()); + if(dao.getAccount() != null) { + dto.setAccountId(dao.getAccount().getId()); + } + return dto; + } + +} From 92ef1fc6476f72effdd26fcdfebffdcb55fbfc45 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Fri, 19 Aug 2016 22:46:49 +0200 Subject: [PATCH 03/21] Skeleton of services --- .../com/academy/service/AbstractService.java | 50 +++++++++++++++++++ .../com/academy/service/AccountService.java | 7 ++- .../com/academy/service/ActivityService.java | 13 +++++ .../com/academy/service/PointsService.java | 12 +++++ .../com/academy/service/SubpageService.java | 13 +++++ .../com/academy/service/WebsiteService.java | 12 +++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/AbstractService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/AbstractService.java b/ClickMapActivity-service/src/main/java/com/academy/service/AbstractService.java new file mode 100644 index 0000000..b226465 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AbstractService.java @@ -0,0 +1,50 @@ +package com.academy.service; + +import com.academy.service.mappers.Mapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +abstract public class AbstractService, M extends Mapper> { + + @Autowired + R repo; + + @Autowired + M mapper; + + public DTO findOne(Long id) { + DAO dao = repo.findOne(id); + if(dao != null) { + return mapper.convertToDTO(dao); + } + return null; + } + + public Iterable findAll() { + return mapper.convertToDTO(repo.findAll()); + } + + public void save(DTO dto) { + repo.save(mapper.convertToDAO(dto)); + } + + public void save(Iterable dtos) { + repo.save(mapper.convertToDAO(dtos)); + } + + public void delete(DTO dto) { + repo.delete(mapper.convertToDAO(dto)); + } + + public void delete(Iterable dtos) { + repo.delete(mapper.convertToDAO(dtos)); + } + + public M getMapper() { + return mapper; + } + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java index 68d9a29..99b20d6 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java @@ -1,7 +1,12 @@ package com.academy.service; +import com.academy.model.dao.Account; +import com.academy.model.dto.AccountDTO; +import com.academy.repo.AccountRepo; +import com.academy.service.mappers.AccountMapper; + /** * Created by Daniel Palonek on 2016-08-18. */ -public class AccountService { +public class AccountService extends AbstractService { } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java new file mode 100644 index 0000000..b2295f5 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java @@ -0,0 +1,13 @@ +package com.academy.service; + +import com.academy.model.dao.Activity; +import com.academy.model.dto.ActivityDTO; +import com.academy.repo.ActivityRepo; +import com.academy.service.mappers.ActivityMapper; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public class ActivityService extends AbstractService { + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java new file mode 100644 index 0000000..59d0cbd --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java @@ -0,0 +1,12 @@ +package com.academy.service; + +import com.academy.model.dao.Points; +import com.academy.model.dto.PointsDTO; +import com.academy.repo.PointsRepo; +import com.academy.service.mappers.PointsMapper; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public class PointsService extends AbstractService { +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java new file mode 100644 index 0000000..54655d8 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -0,0 +1,13 @@ +package com.academy.service; + +import com.academy.model.dao.Subpage; +import com.academy.model.dto.SubpageDTO; +import com.academy.repo.SubpageRepo; +import com.academy.service.AbstractService; +import com.academy.service.mappers.SubpageMapper; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public class SubpageService extends AbstractService { +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java new file mode 100644 index 0000000..dd60eed --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java @@ -0,0 +1,12 @@ +package com.academy.service; + +import com.academy.model.dao.Website; +import com.academy.model.dto.WebsiteDTO; +import com.academy.repo.WebsiteRepo; +import com.academy.service.mappers.WebsiteMapper; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public class WebsiteService extends AbstractService { +} From 3cb5f56c5748562958d9ed4678d3def46cca1e55 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Sat, 3 Sep 2016 12:10:20 +0200 Subject: [PATCH 04/21] Basic main page --- ClickMapActivity-web/build.gradle | 10 +- .../com/academy/web/config/WebConfig.java | 2 +- .../src/main/resources/app.properties | 3 +- .../resources/templates/public/index.html | 306 +++++++++++++++++- 4 files changed, 312 insertions(+), 9 deletions(-) diff --git a/ClickMapActivity-web/build.gradle b/ClickMapActivity-web/build.gradle index b268ac7..0ba650d 100644 --- a/ClickMapActivity-web/build.gradle +++ b/ClickMapActivity-web/build.gradle @@ -15,12 +15,12 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web"){ exclude module: "spring-boot-starter-tomcat" } - compile("org.springframework.boot:spring-boot-starter-data-jpa") - compile("org.springframework.security:spring-security-config") - compile("org.springframework.boot:spring-boot-starter-websocket") + compile ("org.springframework.boot:spring-boot-starter-data-jpa") + compile ("org.springframework.security:spring-security-config") + compile ("org.springframework.boot:spring-boot-starter-websocket") compile ("org.apache.tomcat.embed:tomcat-embed-websocket") - compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '1.4.0.RELEASE' - compile("mysql:mysql-connector-java") + compile ("org.springframework.boot:spring-boot-starter-thymeleaf") + compile ("mysql:mysql-connector-java") compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') testCompile group: 'junit', name: 'junit', version: '4.11' diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java index a9e998f..4f14c85 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java @@ -14,7 +14,7 @@ public class WebConfig extends WebMvcConfigurerAdapter { public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/"); registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/"); - registry.addResourceHandler("/image/**").addResourceLocations("classpath:/image/"); + registry.addResourceHandler("/img/**").addResourceLocations("classpath:/img/"); registry.addResourceHandler("/**").addResourceLocations("classpath:/templates/"); registry.addResourceHandler("/angular/**").addResourceLocations("classpath:/js/angular/"); registry.addResourceHandler("/bootstrap/**").addResourceLocations("classpath:/js/bootstrap/"); diff --git a/ClickMapActivity-web/src/main/resources/app.properties b/ClickMapActivity-web/src/main/resources/app.properties index 8be8415..89193c2 100644 --- a/ClickMapActivity-web/src/main/resources/app.properties +++ b/ClickMapActivity-web/src/main/resources/app.properties @@ -5,7 +5,8 @@ db.username=root db.password=labdb loggin.level.org.springframework.web = DEBUG - +#Template cache +spring.thymeleaf.cache=false #Hibernate Configuration hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect diff --git a/ClickMapActivity-web/src/main/resources/templates/public/index.html b/ClickMapActivity-web/src/main/resources/templates/public/index.html index 7a9185b..88d7880 100644 --- a/ClickMapActivity-web/src/main/resources/templates/public/index.html +++ b/ClickMapActivity-web/src/main/resources/templates/public/index.html @@ -2,9 +2,311 @@ - Main page + + Click Map Activity - improve your site now! + + + + + + + + + + + + + + + + -Hello! + +

+

+

+
+ MainPhoto +
+

Let's improve your site.

+
+
+

ClickMapActivity allows you to control user's activity on your website. + Every single click will be saved and then show on sighty map for you.

+
+
+ +
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
v +
Witaj
+
Witaj
+
Witaj
+
Witaj
v +
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+v +v
Witaj

Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
+
Witaj
v + + \ No newline at end of file From 75c77f117875754dccc2ec5bc9523f06bc626d3e Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 13 Sep 2016 18:03:40 +0200 Subject: [PATCH 05/21] Added registration, login, logout, working communication between fron and back end based on angular --- ClickMapActivity-model/build.gradle | 11 - .../java/com/academy/model/ValueWrapper.java | 13 + .../main/java/com/academy/model/dao/User.java | 71 ++++++ .../java/com/academy/model/dao/UserRole.java | 53 ++++ .../java/com/academy/model/dto/UserDTO.java | 43 ++++ ClickMapActivity-repo/build.gradle | 10 - .../java/com/academy/repo/AccountRepo.java | 2 + .../main/java/com/academy/repo/UserRepo.java | 11 + .../java/com/academy/repo/UserRoleRepo.java | 10 + ClickMapActivity-service/build.gradle | 12 +- .../com/academy/service/AccountService.java | 36 +++ .../service/CustUserDetailsService.java | 36 +++ .../java/com/academy/service/UserService.java | 37 +++ .../com/academy/service/mappers/Mapper.java | 5 +- .../academy/service/mappers/UserMapper.java | 28 +++ ClickMapActivity-web/build.gradle | 18 +- .../LoginAuthenticationSuccessHandler.java | 49 ++++ .../com/academy/web/config/RedirectUrls.java | 13 + .../com/academy/web/config/WebConfig.java | 2 +- .../academy/web/config/WebSecurityConfig.java | 7 + .../web/config/cache/CacheConstants.java | 9 + .../config/cache/HazelcastConfiguration.java | 17 ++ .../LogoutAuthenticationSuccessHandler.java | 28 +++ .../web/controller/AbstractController.java | 52 ++++ .../web/controller/AccountController.java | 36 ++- .../academy/web/controller/Controller.java | 5 + .../resources/js/public/accountControllers.js | 12 + .../resources/js/public/accountServices.js | 16 ++ .../resources/js/public/indexControllers.js | 23 ++ .../main/resources/js/public/indexServices.js | 25 ++ .../main/resources/js/public/routeProvider.js | 33 +++ .../resources/js/user/userRouteProvider.js | 33 +++ .../resources/templates/public/index.html | 229 ++++++------------ .../main/resources/templates/public/main.html | 68 ++++++ .../resources/templates/public/register.html | 60 +++++ .../resources/templates/user/userIndex.html | 221 +++++++++++++++++ build.gradle | 19 +- 37 files changed, 1142 insertions(+), 211 deletions(-) create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/ValueWrapper.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dao/User.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dao/UserRole.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/dto/UserDTO.java create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/UserRepo.java create mode 100644 ClickMapActivity-repo/src/main/java/com/academy/repo/UserRoleRepo.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/UserService.java create mode 100644 ClickMapActivity-service/src/main/java/com/academy/service/mappers/UserMapper.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/RedirectUrls.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java create mode 100644 ClickMapActivity-web/src/main/resources/js/public/accountControllers.js create mode 100644 ClickMapActivity-web/src/main/resources/js/public/accountServices.js create mode 100644 ClickMapActivity-web/src/main/resources/js/public/indexControllers.js create mode 100644 ClickMapActivity-web/src/main/resources/js/public/indexServices.js create mode 100644 ClickMapActivity-web/src/main/resources/js/public/routeProvider.js create mode 100644 ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js create mode 100644 ClickMapActivity-web/src/main/resources/templates/public/main.html create mode 100644 ClickMapActivity-web/src/main/resources/templates/public/register.html create mode 100644 ClickMapActivity-web/src/main/resources/templates/user/userIndex.html diff --git a/ClickMapActivity-model/build.gradle b/ClickMapActivity-model/build.gradle index 520ffde..73d6d16 100644 --- a/ClickMapActivity-model/build.gradle +++ b/ClickMapActivity-model/build.gradle @@ -1,17 +1,6 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' -apply plugin: 'spring-boot' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - dependencies { - compile("org.springframework.boot:spring-boot-starter-web") compile group: 'org.hibernate', name: 'hibernate-entitymanager', version: '5.2.1.Final' - testCompile group: 'junit', name: 'junit', version: '4.11' } diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/ValueWrapper.java b/ClickMapActivity-model/src/main/java/com/academy/model/ValueWrapper.java new file mode 100644 index 0000000..d47ff9f --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/ValueWrapper.java @@ -0,0 +1,13 @@ +package com.academy.model; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +public class ValueWrapper { + + public T value; + + public ValueWrapper(T value) { + this.value = value; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/User.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/User.java new file mode 100644 index 0000000..4d8e6ba --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/User.java @@ -0,0 +1,71 @@ +package com.academy.model.dao; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +@Entity +@Table(name = "users") +public class User { + + private Long id; + private String username; + private String password; + private boolean enabled; + private Set userRole = new HashSet<>(); + + public User() { + } + + public User(String username, String password, boolean enabled) { + this.username = username; + this.password = password; + this.enabled = enabled; + } + + public User(String username, String password, boolean enabled, Set userRole) { + this(username,password,enabled); + this.userRole = userRole; + } + + @Id + @Column(name = "username", unique = true, nullable = false, length = 45) + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Column(name = "password", nullable = false, length = 65) + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Column(name = "enabled", nullable = false) + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") + public Set getUserRole() { + return userRole; + } + + public void setUserRole(Set userRole) { + this.userRole = userRole; + } + +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/UserRole.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/UserRole.java new file mode 100644 index 0000000..dd4a524 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/UserRole.java @@ -0,0 +1,53 @@ +package com.academy.model.dao; + +import javax.persistence.*; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +@Entity +@Table(name = "user_roles", uniqueConstraints = @UniqueConstraint(columnNames = {"role", "username"})) +public class UserRole { + + private Integer userRoleId; + private User user; + private String role; + + public UserRole() { + } + + public UserRole(User user, String role) { + this.user = user; + this.role = role; + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_role_id", unique = true, nullable = false) + public Integer getUserRoleId() { + return userRoleId; + } + + public void setUserRoleId(Integer userRoleId) { + this.userRoleId = userRoleId; + } + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "username", nullable = false) + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + @Column(name = "role", nullable = false, length = 45) + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/UserDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/UserDTO.java new file mode 100644 index 0000000..ffd7611 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/UserDTO.java @@ -0,0 +1,43 @@ +package com.academy.model.dto; + +/** + * Created by Daniel Palonek on 2016-09-09. + */ +public class UserDTO { + private Long id; + private String username; + private String password; + private String email; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/ClickMapActivity-repo/build.gradle b/ClickMapActivity-repo/build.gradle index c335f2f..d5c390c 100644 --- a/ClickMapActivity-repo/build.gradle +++ b/ClickMapActivity-repo/build.gradle @@ -1,17 +1,7 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' -apply plugin: 'spring-boot' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - dependencies { compile("org.springframework.boot:spring-boot-starter-data-jpa") compile project(':ClickMapActivity-model') - testCompile group: 'junit', name: 'junit', version: '4.11' } diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java index 6933248..5eaf6bf 100644 --- a/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/AccountRepo.java @@ -7,4 +7,6 @@ * Created by Daniel Palonek on 2016-08-19. */ public interface AccountRepo extends CrudRepository { + + Account findAccountByUserName(String username); } diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRepo.java new file mode 100644 index 0000000..7cebaad --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRepo.java @@ -0,0 +1,11 @@ +package com.academy.repo; + +import com.academy.model.dao.User; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +public interface UserRepo extends CrudRepository { + User findByUsername(String name); +} diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRoleRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRoleRepo.java new file mode 100644 index 0000000..d01f75c --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/UserRoleRepo.java @@ -0,0 +1,10 @@ +package com.academy.repo; + +import com.academy.model.dao.UserRole; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +public interface UserRoleRepo extends CrudRepository { +} diff --git a/ClickMapActivity-service/build.gradle b/ClickMapActivity-service/build.gradle index 207e599..0339221 100644 --- a/ClickMapActivity-service/build.gradle +++ b/ClickMapActivity-service/build.gradle @@ -1,18 +1,10 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' -apply plugin: 'spring-boot' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - dependencies { compile("org.springframework.boot:spring-boot-starter-web") + compile("org.springframework.boot:spring-boot-starter-security") compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') - testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'com.hazelcast:hazelcast:3.7.1' } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java index 99b20d6..9dbf83d 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java @@ -4,9 +4,45 @@ import com.academy.model.dto.AccountDTO; import com.academy.repo.AccountRepo; import com.academy.service.mappers.AccountMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; /** * Created by Daniel Palonek on 2016-08-18. */ +@Service public class AccountService extends AbstractService { + + @Autowired + UserService userService; + + public boolean checkIfAccountWithGivenUsernameExists(String username) { + return !(repo.findAccountByUserName(username) == null); + } + + public boolean saveAccount(MultiValueMap data) { + + if(findAccountIdByUsername(data.getFirst("username")) != -1L) { + return false; + } + + AccountDTO accountDTO = new AccountDTO(); + accountDTO.setUserName(data.getFirst("username")); + accountDTO.setPassword(data.getFirst("password")); + accountDTO.setFirstName(data.getFirst("firstName")); + accountDTO.setSurName(data.getFirst("surname")); + accountDTO.setPhoneNumber(data.getFirst("phone")); + accountDTO.setEmail(data.getFirst("email")); + + repo.save(mapper.convertToDAO(accountDTO)); + userService.save(data.getFirst("username"), data.getFirst("password")); + return true; + } + + public Long findAccountIdByUsername(String username) { + Account account = repo.findAccountByUserName(username); + return account == null ? -1L : account.getId(); + } + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java new file mode 100644 index 0000000..d84e1a1 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java @@ -0,0 +1,36 @@ +package com.academy.service; + +import com.academy.model.dao.User; +import com.academy.repo.UserRepo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +@Service("userDetailsService") +public class CustUserDetailsService implements UserDetailsService { + + @Autowired + private UserRepo userRepo; + + @Transactional(readOnly = true) + public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { + User user = userRepo.findByUsername(username); + if (user == null) { + throw new UsernameNotFoundException("Username not found"); + } + List authorities = user.getUserRole().stream().map(u -> new SimpleGrantedAuthority(u.getRole())).collect(Collectors.toList()); + return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities); + } +} \ No newline at end of file diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/UserService.java b/ClickMapActivity-service/src/main/java/com/academy/service/UserService.java new file mode 100644 index 0000000..2938e4f --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/UserService.java @@ -0,0 +1,37 @@ +package com.academy.service; + +import com.academy.model.dao.User; +import com.academy.model.dao.UserRole; +import com.academy.model.dto.UserDTO; +import com.academy.repo.UserRepo; +import com.academy.repo.UserRoleRepo; +import com.academy.service.mappers.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +@Service +public class UserService extends AbstractService { + + @Autowired + UserRoleRepo userRoleRepo; + + public void save(String username, String password) { + User user = new User(); + user.setUsername(username); + user.setPassword(password); + user.setEnabled(true); + + UserRole userRole = new UserRole(); + userRole.setRole("ROLE_USER"); + + user.getUserRole().add(userRole); + userRole.setUser(user); + + repo.save(user); + userRoleRepo.save(userRole); + } + +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java index 6b1b691..9a133ed 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java @@ -1,5 +1,6 @@ package com.academy.service.mappers; +import java.util.ArrayList; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -13,10 +14,10 @@ public interface Mapper { DTO convertToDTO(DAO dao); default Iterable convertToDAO(Iterable dto) { - return Stream.of(dto).map(this::convertToDAO).collect(Collectors.toList()); + return Stream.of(dto).map(m -> (DAO)convertToDAO(m)).collect(Collectors.toList()); } default Iterable convertToDTO(Iterable dao) { - return Stream.of(dao).map(this::convertToDTO).collect(Collectors.toList()); + return Stream.of(dao).map(m -> (DTO)convertToDTO(m)).collect(Collectors.toList()); } } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/UserMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/UserMapper.java new file mode 100644 index 0000000..d7b74cb --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/UserMapper.java @@ -0,0 +1,28 @@ +package com.academy.service.mappers; + +import com.academy.model.dao.User; +import com.academy.model.dto.UserDTO; +import org.springframework.stereotype.Component; + +/** + * Created by Daniel Palonek on 2016-09-09. + */ +@Component +public class UserMapper implements Mapper { + + @Override + public User convertToDAO(UserDTO dto) { + User user = new User(); + user.setUsername(dto.getUsername()); + user.setPassword(dto.getPassword()); + return user; + } + + @Override + public UserDTO convertToDTO(User dao) { + UserDTO userDTO = new UserDTO(); + userDTO.setUsername(dao.getUsername()); + userDTO.setPassword(dao.getPassword()); + return userDTO; + } +} diff --git a/ClickMapActivity-web/build.gradle b/ClickMapActivity-web/build.gradle index 0ba650d..49c4c44 100644 --- a/ClickMapActivity-web/build.gradle +++ b/ClickMapActivity-web/build.gradle @@ -1,27 +1,15 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' -apply plugin: 'spring-boot' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - - dependencies { - compile("org.springframework.boot:spring-boot-starter-web"){ - exclude module: "spring-boot-starter-tomcat" - } compile ("org.springframework.boot:spring-boot-starter-data-jpa") - compile ("org.springframework.security:spring-security-config") + compile("org.springframework.boot:spring-boot-starter-security") compile ("org.springframework.boot:spring-boot-starter-websocket") compile ("org.apache.tomcat.embed:tomcat-embed-websocket") compile ("org.springframework.boot:spring-boot-starter-thymeleaf") compile ("mysql:mysql-connector-java") compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') - testCompile group: 'junit', name: 'junit', version: '4.11' + compile project(':ClickMapActivity-service') + compile 'com.hazelcast:hazelcast:3.7.1' } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java new file mode 100644 index 0000000..ba65c21 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java @@ -0,0 +1,49 @@ +package com.academy.web.config; + +import com.academy.web.config.cache.CacheConstants; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.DefaultRedirectStrategy; +import org.springframework.security.web.RedirectStrategy; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +@Component +public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler { + + @Autowired + HazelcastInstance hzInstance; + + private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); + + + @Override + public void onAuthenticationSuccess(javax.servlet.http.HttpServletRequest req, HttpServletResponse rsp, Authentication auth) throws IOException, ServletException { +// String url = req.getParameter("url"); +// if(url == null) { +// redirectStrategy.sendRedirect(req,rsp,"/"); +// return; +// } + StringBuilder stringBuilder = new StringBuilder(); + for(GrantedAuthority grantedAuthority: auth.getAuthorities()) { + if("ROLE_USER".equals(grantedAuthority.getAuthority()) || "ROLE_ADMIN".equals(grantedAuthority.getAuthority())) { + stringBuilder.append("user/#"); + hzInstance.getUserContext().put(CacheConstants.LOGGED_USERNAME,auth.getName()); + break; + } + } +// stringBuilder.append(url); + redirectStrategy.sendRedirect(req,rsp,stringBuilder.toString()); + } + + +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/RedirectUrls.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/RedirectUrls.java new file mode 100644 index 0000000..c5bb8d1 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/RedirectUrls.java @@ -0,0 +1,13 @@ +package com.academy.web.config; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +public class RedirectUrls { + + public static final String HOME = "http://localhost:8080/#/"; + public static final String ERROR = "error/"; + public static final String ERROR_LOGIN = HOME + ERROR + "login"; + public static final String ERROR_USER_EXIST = HOME + ERROR + "userExisted"; + +} \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java index 4f14c85..e62308a 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebConfig.java @@ -14,7 +14,7 @@ public class WebConfig extends WebMvcConfigurerAdapter { public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/"); registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/"); - registry.addResourceHandler("/img/**").addResourceLocations("classpath:/img/"); + registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/"); registry.addResourceHandler("/**").addResourceLocations("classpath:/templates/"); registry.addResourceHandler("/angular/**").addResourceLocations("classpath:/js/angular/"); registry.addResourceHandler("/bootstrap/**").addResourceLocations("classpath:/js/bootstrap/"); diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java new file mode 100644 index 0000000..79e374b --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java @@ -0,0 +1,7 @@ +package com.academy.web.config; + +/** + * Created by Daniel Palonek on 2016-09-03. + */ +public class WebSecurityConfig { +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java new file mode 100644 index 0000000..d0b535a --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java @@ -0,0 +1,9 @@ +package com.academy.web.config.cache; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +public class CacheConstants { + + public static final String LOGGED_USERNAME = "loggedUsername"; +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java new file mode 100644 index 0000000..55f43eb --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java @@ -0,0 +1,17 @@ +package com.academy.web.config.cache; + +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +@Configuration +public class HazelcastConfiguration { + @Bean + public HazelcastInstance config() { + return Hazelcast.newHazelcastInstance(); + } +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java new file mode 100644 index 0000000..57053b7 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java @@ -0,0 +1,28 @@ +package com.academy.web.config.cache; + +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by Daniel Palonek on 2016-09-10. + */ +@Component +public class LogoutAuthenticationSuccessHandler implements LogoutSuccessHandler { + + @Autowired + HazelcastInstance hazelcastInstance; + + @Override + public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse rsp, Authentication auth) + throws IOException, ServletException { + hazelcastInstance.getUserContext().remove(CacheConstants.LOGGED_USERNAME); + } +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java new file mode 100644 index 0000000..6c8655c --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java @@ -0,0 +1,52 @@ +package com.academy.web.controller; + +import com.academy.service.AbstractService; +import com.academy.service.mappers.Mapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.CrudRepository; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; + +/** + * Created by Daniel Palonek on 2016-09-08. + */ +abstract public class AbstractController, ? extends Mapper>> { + + @Autowired + S service; + + @RequestMapping("/{id}") + public DTO findOne(@PathVariable int id, HttpServletRequest request) { + return service.findOne(new Long(id)); + } + + @RequestMapping("/all") + public Iterable findAll() { + return service.findAll(); + } + + @RequestMapping(value = "/save", method = RequestMethod.POST) + public void save(@RequestBody DTO modelToSave) { + service.save(modelToSave); + } + + @RequestMapping(value = "/save/all", method = RequestMethod.POST) + public void save(@RequestBody Iterable modelsToSave) { + service.save(modelsToSave); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public void delete(@RequestBody DTO modelToDelete, @PathVariable int id) { + service.delete(modelToDelete); + } + + @RequestMapping(value = "/delete/all", method = RequestMethod.POST) + public void delete(@RequestBody Iterable modelsToDelete) { + service.delete(modelsToDelete); + } + +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java index 23edacd..90e6943 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java @@ -1,12 +1,40 @@ package com.academy.web.controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import com.academy.model.ValueWrapper; +import com.academy.model.dao.Account; +import com.academy.model.dto.AccountDTO; +import com.academy.service.AccountService; +import com.academy.web.config.RedirectUrls; +import com.academy.web.config.cache.CacheConstants; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; /** * Created by Daniel Palonek on 2016-08-04. */ -@RestController("/") -public class AccountController { +@RestController +@RequestMapping("/account") +public class AccountController extends AbstractController{ + @Autowired + HazelcastInstance hazelcastInstance; + + @RequestMapping(value = "/logged/name") + public ValueWrapper getLoggedUsername() { + return new ValueWrapper(hazelcastInstance.getUserContext().getOrDefault(CacheConstants.LOGGED_USERNAME,null)); + } + + @RequestMapping(value = "/register", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded") + public ModelAndView register(@RequestBody final MultiValueMap data) { + return new ModelAndView(service.saveAccount(data) ? "redirect:" : RedirectUrls.ERROR_USER_EXIST); + } + + @RequestMapping(value = "/exist/{username}", method = RequestMethod.GET) + public ValueWrapper checkIfUserAlreadyExist(@PathVariable("username") String username) { + Boolean ret = service.checkIfAccountWithGivenUsernameExists(username); + return new ValueWrapper<>(ret); + } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java index 6be16ce..4d1d6a4 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java @@ -14,4 +14,9 @@ public class Controller { public ModelAndView index(){ return new ModelAndView("public/index"); } + + @RequestMapping("/user/") + public ModelAndView getUserIndex() { + return new ModelAndView("user/userIndex"); + } } diff --git a/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js new file mode 100644 index 0000000..c613837 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js @@ -0,0 +1,12 @@ +/** + * Created by Daniel Palonek on 2016-09-05. + */ +var accountControllers = angular.module( + 'AccountControllers', []); + +accountControllers.controller('AccountController', ['$scope', '$routeParams', '$location', 'AccountService', function ($scope, $routeParams, $location, AccountService) { + $scope.checkIfExist = function(username) { + var rsp = AccountService.checkIfAccountExist({username: username}); + return rsp.value; + } +}]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/accountServices.js b/ClickMapActivity-web/src/main/resources/js/public/accountServices.js new file mode 100644 index 0000000..4187816 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/public/accountServices.js @@ -0,0 +1,16 @@ +/** + * Created by Daniel Palonek on 2016-09-08. + */ +var AccountServices = angular.module('AccountServices',['ngResource']); + +AccountServices.factory('AccountService', [ + '$resource', function ($resource) { + return $resource('', [], { + + checkIfAccountExist: { + method: 'GET', + url: '/account/exist/:username', + params: {username: "@username"} + } + }); + }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js b/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js new file mode 100644 index 0000000..5520e05 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js @@ -0,0 +1,23 @@ +/** + * Created by Daniel Palonek on 2016-09-09. + */ +var indexControllers = angular.module('IndexControllers', []); + +indexControllers.controller('IndexController', ['$scope', '$location', 'IndexService', function ($scope, $location, IndexService) { + $scope.username = ''; + IndexService.getLoggedUsername(function (username) { + if(username.value !== null) { + $scope.username = username.value; + } + }); + + $scope.logout = function() { + IndexService.logout( function() { + IndexService.getLoggedUsername(function (username) { + if(username.value === null) { + window.location = "/#" + $location.path(); + } + }); + }); + } +}]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/indexServices.js b/ClickMapActivity-web/src/main/resources/js/public/indexServices.js new file mode 100644 index 0000000..8ca735c --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/public/indexServices.js @@ -0,0 +1,25 @@ +/** + * Created by Daniel Palonek on 2016-09-05. + */ +var IndexServices = angular.module("IndexServices", ['ngResource']); + +IndexServices.factory('IndexService', [ + '$resource', function ($resource) { + return $resource('', {}, { + + login: { + method: 'GET', + url: '/login' + }, + + logout: { + method: 'GET', + url: '/logout' + }, + + getLoggedUsername: { + method: 'GET', + url: '/account/logged/name' + } + }); + }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js b/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js new file mode 100644 index 0000000..160a834 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js @@ -0,0 +1,33 @@ +/** + * Created by Daniel Palonek on 2016-09-05. + */ +var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'ui.grid.pagination', 'IndexServices', 'IndexControllers', 'AccountServices', 'AccountControllers']); + +mainApp.config(['$routeProvider', function ($routeProvider) { + $routeProvider. + + when('/register', { + templateUrl: '/public/register.html', + controller: 'AccountController' + }). + + when('/main', { + templateUrl: '/public/main.html', + controller: 'IndexController' + }). + + otherwise({ + templateUrl: '/public/main.html', + controller: 'IndexController' + }); +}]); + +mainApp.run(['$rootScope', '$location', 'IndexService', function ($rootScope, $location, IndexService) { + $rootScope.$on('$routeChangeStart', function (event) { + IndexService.getLoggedUsername(function (username) { + if(username.value !== null) { + window.location = "/user/" + $location.path(); + } + }); + }); +}]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js new file mode 100644 index 0000000..b3d87a3 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js @@ -0,0 +1,33 @@ +/** + * Created by Daniel Palonek on 2016-09-10. + */ +var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'IndexControllers', 'IndexServices', + 'AccountControllers', 'AccountServices', 'ui.grid', 'ui.grid.pagination']); + +mainApp.config(['$routeProvider', function ($routeProvider) { + $routeProvider. + when('/register', { + templateUrl: '/public/register.html' + }). + when('/main', { + templateUrl: '/public/main.html', + controller: 'IndexController' + }). + when('/myWebsites', { + templateUrl: '/user/myWebsites.html' + }). + otherwise({ + templateUrl: '/public/main.html', + controller: 'IndexController' + }); +}]); + +mainApp.run(['$rootScope', '$location', 'IndexService', function ($rootScope, $location, IndexService) { + $rootScope.$on('$routeChangeStart', function (event) { + IndexService.getLoggedUsername(function (username) { + if (username.value === null) { + window.location = "/#" + $location.path(); + } + }) ; + }); +}]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/public/index.html b/ClickMapActivity-web/src/main/resources/templates/public/index.html index 88d7880..6f68995 100644 --- a/ClickMapActivity-web/src/main/resources/templates/public/index.html +++ b/ClickMapActivity-web/src/main/resources/templates/public/index.html @@ -1,34 +1,44 @@ - + Click Map Activity - improve your site now! - - + + + + + + + + + + - - - - - - - + + + + + + + + + - - - -

-

-

-
- MainPhoto -
-

Let's improve your site.

-
-
-

ClickMapActivity allows you to control user's activity on your website. - Every single click will be saved and then show on sighty map for you.

+
-
- -
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
v -
Witaj
-
Witaj
-
Witaj
-
Witaj
v -
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-v -v
Witaj

Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
-
Witaj
v - - +

+

+

+
\ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/public/main.html b/ClickMapActivity-web/src/main/resources/templates/public/main.html new file mode 100644 index 0000000..1986014 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/templates/public/main.html @@ -0,0 +1,68 @@ + +
+ MainPhoto +
+

Let's improve your site.

+
+
+

ClickMapActivity allows you to control user's activity on your website. + Every single click will be saved and then show on sighty map for you.

+
+
+
\ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/public/register.html b/ClickMapActivity-web/src/main/resources/templates/public/register.html new file mode 100644 index 0000000..52e3916 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/templates/public/register.html @@ -0,0 +1,60 @@ + + +

+

+

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
\ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html new file mode 100644 index 0000000..83e832a --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html @@ -0,0 +1,221 @@ + + + + + + Click Map Activity - improve your site now! + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+

+

+
+ + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 3623794..f01ddeb 100644 --- a/build.gradle +++ b/build.gradle @@ -31,10 +31,27 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-jetty") compile("org.springframework.boot:spring-boot-starter-actuator") - testCompile group: 'junit', name: 'junit', version: '4.11' } +subprojects { + apply plugin: 'java' + apply plugin: 'spring-boot' + + sourceCompatibility = 1.8 + + repositories { + mavenCentral() + } + + dependencies { + compile("org.springframework.boot:spring-boot-starter-web") { + exclude module: "spring-boot-starter-tomcat" + } + testCompile group: 'junit', name: 'junit', version: '4.11' + } +} + task wrapper(type: Wrapper) { gradleVersion = '2.14.1' } From 7acae8c9d091b5ecf3b90c5fe2393dd6e106e089 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Thu, 6 Oct 2016 11:13:38 +0200 Subject: [PATCH 06/21] Added website panel, distributed cache, plenty of improvements --- .../academy/cache/AbstractCacheSupplier.java | 19 +++ .../academy/model/RegisterRequestBody.java | 61 +++++++++ .../com/academy/model/dto/WebsiteDTO.java | 4 +- .../java/com/academy/repo/WebsiteRepo.java | 3 + ClickMapActivity-service/build.gradle | 1 + .../com/academy/service/AccountService.java | 27 ++-- .../com/academy/service/WebsiteService.java | 36 +++++ .../com/academy/service/mappers/Mapper.java | 6 +- .../service/mappers/WebsiteMapper.java | 2 + ClickMapActivity-web/build.gradle | 1 + .../LoginAuthenticationSuccessHandler.java | 12 +- .../LogoutAuthenticationSuccessHandler.java | 9 +- .../academy/web/config/WebSecurityConfig.java | 57 +++++++- .../web/config/cache/CacheConstants.java | 9 -- .../config/cache/HazelcastConfiguration.java | 17 --- .../web/controller/AbstractController.java | 4 +- .../web/controller/AccountController.java | 22 ++- .../web/controller/WebsitesController.java | 36 +++++ .../resources/js/public/accountControllers.js | 92 ++++++++++++- .../resources/js/public/accountServices.js | 7 +- .../resources/js/public/indexControllers.js | 4 +- .../main/resources/js/public/routeProvider.js | 2 +- .../resources/js/user/userRouteProvider.js | 7 +- .../resources/js/user/websitesControllers.js | 27 ++++ .../resources/js/user/websitesServices.js | 28 ++++ .../resources/templates/public/index.html | 5 + .../resources/templates/public/register.html | 104 +++++++++++---- .../resources/templates/user/userIndex.html | 16 ++- .../resources/templates/user/websites.html | 125 ++++++++++++++++++ build.gradle | 1 + settings.gradle | 3 + 31 files changed, 645 insertions(+), 102 deletions(-) create mode 100644 ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/RegisterRequestBody.java rename ClickMapActivity-web/src/main/java/com/academy/web/config/{cache => }/LogoutAuthenticationSuccessHandler.java (78%) delete mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java delete mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java create mode 100644 ClickMapActivity-web/src/main/resources/js/user/websitesControllers.js create mode 100644 ClickMapActivity-web/src/main/resources/js/user/websitesServices.js create mode 100644 ClickMapActivity-web/src/main/resources/templates/user/websites.html diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java new file mode 100644 index 0000000..317d400 --- /dev/null +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java @@ -0,0 +1,19 @@ +package com.academy.cache; + +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.ConcurrentMap; + +/** + * Created by Daniel Palonek on 2016-09-17. + */ +public class AbstractCacheSupplier { + + @Autowired + private HazelcastInstance hazelcastInstance; + + protected ConcurrentMap getUserContext() { + return hazelcastInstance.getUserContext(); + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/RegisterRequestBody.java b/ClickMapActivity-model/src/main/java/com/academy/model/RegisterRequestBody.java new file mode 100644 index 0000000..5043632 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/RegisterRequestBody.java @@ -0,0 +1,61 @@ +package com.academy.model; + +/** + * Created by Daniel Palonek on 2016-09-15. + */ +public class RegisterRequestBody { + private String username; + private String password; + private String firstName; + private String surname; + private String phone; + private String email; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java index c673d68..21c7dae 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java @@ -1,9 +1,11 @@ package com.academy.model.dto; +import java.io.Serializable; + /** * Created by Daniel Palonek on 2016-08-18. */ -public class WebsiteDTO { +public class WebsiteDTO implements Serializable { private Long id; private String url; diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java index 3b6c89b..a39ca3b 100644 --- a/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java @@ -7,4 +7,7 @@ * Created by Daniel Palonek on 2016-08-19. */ public interface WebsiteRepo extends CrudRepository { + Iterable findByAccountId(Long accountId); + void deleteById(Long websiteId); + } diff --git a/ClickMapActivity-service/build.gradle b/ClickMapActivity-service/build.gradle index 0339221..b170976 100644 --- a/ClickMapActivity-service/build.gradle +++ b/ClickMapActivity-service/build.gradle @@ -6,5 +6,6 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-security") compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') + compile project(':ClickMapActivity-cache') compile 'com.hazelcast:hazelcast:3.7.1' } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java index 9dbf83d..6a5d6ab 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java @@ -1,5 +1,7 @@ package com.academy.service; +import com.academy.cache.UserCache; +import com.academy.model.RegisterRequestBody; import com.academy.model.dao.Account; import com.academy.model.dto.AccountDTO; import com.academy.repo.AccountRepo; @@ -17,26 +19,29 @@ public class AccountService extends AbstractService data) { + public boolean saveAccount(RegisterRequestBody data) { - if(findAccountIdByUsername(data.getFirst("username")) != -1L) { + if(findAccountIdByUsername(data.getUsername()) != -1L) { return false; } AccountDTO accountDTO = new AccountDTO(); - accountDTO.setUserName(data.getFirst("username")); - accountDTO.setPassword(data.getFirst("password")); - accountDTO.setFirstName(data.getFirst("firstName")); - accountDTO.setSurName(data.getFirst("surname")); - accountDTO.setPhoneNumber(data.getFirst("phone")); - accountDTO.setEmail(data.getFirst("email")); + accountDTO.setUserName(data.getUsername()); + accountDTO.setPassword(data.getPassword()); + accountDTO.setFirstName(data.getFirstName()); + accountDTO.setSurName(data.getSurname()); + accountDTO.setPhoneNumber(data.getPhone()); + accountDTO.setEmail(data.getEmail()); repo.save(mapper.convertToDAO(accountDTO)); - userService.save(data.getFirst("username"), data.getFirst("password")); + userService.save(data.getUsername(), data.getPassword()); return true; } @@ -45,4 +50,8 @@ public Long findAccountIdByUsername(String username) { return account == null ? -1L : account.getId(); } + public Long getLoggedUserAccountId() { + return findAccountIdByUsername(cache.getLoggedUsername()); + } + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java index dd60eed..144a19f 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java @@ -1,12 +1,48 @@ package com.academy.service; +import com.academy.cache.UserCache; import com.academy.model.dao.Website; import com.academy.model.dto.WebsiteDTO; import com.academy.repo.WebsiteRepo; import com.academy.service.mappers.WebsiteMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; /** * Created by Daniel Palonek on 2016-08-19. */ +@Service public class WebsiteService extends AbstractService { + + @Autowired + AccountService accountService; + + @Autowired + UserCache cache; + + public Iterable getUserWebsites() { + String username = cache.getLoggedUsername(); + Long accountId = accountService.findAccountIdByUsername(username); + Iterable websites = repo.findByAccountId(accountId); + return mapper.convertToDTO(websites); + } + + public boolean saveWebsite(String websiteUrl) { + WebsiteDTO website = new WebsiteDTO(); + website.setAccountId(accountService.getLoggedUserAccountId()); + website.setUrl(websiteUrl); + save(website); + cache.replace(getUserWebsites()); + return true; + } + + public boolean delete(Long websiteId) { + repo.delete(websiteId); + cache.replace(getUserWebsites()); + return true; + } + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java index 9a133ed..e7a1e75 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java @@ -1,6 +1,8 @@ package com.academy.service.mappers; import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -18,6 +20,8 @@ default Iterable convertToDAO(Iterable dto) { } default Iterable convertToDTO(Iterable dao) { - return Stream.of(dao).map(m -> (DTO)convertToDTO(m)).collect(Collectors.toList()); + Collection dtos = new ArrayList<>(); + dao.forEach(d -> dtos.add(convertToDTO(d))); + return dtos; } } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java index 21aeb0f..5e0e58a 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java @@ -5,10 +5,12 @@ import com.academy.model.dto.WebsiteDTO; import com.academy.repo.AccountRepo; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * Created by Daniel Palonek on 2016-08-18. */ +@Component public class WebsiteMapper implements Mapper { @Autowired diff --git a/ClickMapActivity-web/build.gradle b/ClickMapActivity-web/build.gradle index 49c4c44..88ad445 100644 --- a/ClickMapActivity-web/build.gradle +++ b/ClickMapActivity-web/build.gradle @@ -11,5 +11,6 @@ dependencies { compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') compile project(':ClickMapActivity-service') + compile project(':ClickMapActivity-cache') compile 'com.hazelcast:hazelcast:3.7.1' } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java index ba65c21..28c7b34 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java @@ -1,7 +1,7 @@ package com.academy.web.config; -import com.academy.web.config.cache.CacheConstants; -import com.hazelcast.core.HazelcastInstance; +import com.academy.cache.UserCache; +import com.academy.service.WebsiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -21,7 +21,10 @@ public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired - HazelcastInstance hzInstance; + UserCache cache; + + @Autowired + WebsiteService websiteService; private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @@ -37,7 +40,8 @@ public void onAuthenticationSuccess(javax.servlet.http.HttpServletRequest req, H for(GrantedAuthority grantedAuthority: auth.getAuthorities()) { if("ROLE_USER".equals(grantedAuthority.getAuthority()) || "ROLE_ADMIN".equals(grantedAuthority.getAuthority())) { stringBuilder.append("user/#"); - hzInstance.getUserContext().put(CacheConstants.LOGGED_USERNAME,auth.getName()); + cache.setLoggedUsername(auth.getName()); + cache.setUserWebsites(websiteService.getUserWebsites()); break; } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java similarity index 78% rename from ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java rename to ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java index 57053b7..6182809 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/LogoutAuthenticationSuccessHandler.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java @@ -1,6 +1,6 @@ -package com.academy.web.config.cache; +package com.academy.web.config; -import com.hazelcast.core.HazelcastInstance; +import com.academy.cache.UserCache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; @@ -18,11 +18,12 @@ public class LogoutAuthenticationSuccessHandler implements LogoutSuccessHandler { @Autowired - HazelcastInstance hazelcastInstance; + UserCache cache; @Override public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse rsp, Authentication auth) throws IOException, ServletException { - hazelcastInstance.getUserContext().remove(CacheConstants.LOGGED_USERNAME); + cache.removeLoggedUsername(); + cache.removeUserWebsites(); } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java index 79e374b..7df7b28 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java @@ -1,7 +1,62 @@ package com.academy.web.config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + /** * Created by Daniel Palonek on 2016-09-03. */ -public class WebSecurityConfig { +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + @Qualifier("userDetailsService") + UserDetailsService userDetailsService; + + @Autowired + LoginAuthenticationSuccessHandler loginSuccessHandler; + + @Autowired + LogoutAuthenticationSuccessHandler logoutSuccessHandler; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/user/**") + .access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") + .and() + .formLogin() + .loginPage("/login") + .successHandler(loginSuccessHandler) + .failureUrl(RedirectUrls.ERROR_LOGIN) + .and() + .logout() + .logoutSuccessHandler(logoutSuccessHandler) + .logoutSuccessUrl("/") + .and().csrf().disable(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() { + @Override + public String encode(CharSequence rawPassword) { + return rawPassword.toString(); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return encodedPassword.contentEquals(rawPassword); + } + }); + } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java deleted file mode 100644 index d0b535a..0000000 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/CacheConstants.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.academy.web.config.cache; - -/** - * Created by Daniel Palonek on 2016-09-05. - */ -public class CacheConstants { - - public static final String LOGGED_USERNAME = "loggedUsername"; -} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java deleted file mode 100644 index 55f43eb..0000000 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/cache/HazelcastConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.academy.web.config.cache; - -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by Daniel Palonek on 2016-09-05. - */ -@Configuration -public class HazelcastConfiguration { - @Bean - public HazelcastInstance config() { - return Hazelcast.newHazelcastInstance(); - } -} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java index 6c8655c..b214060 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java @@ -40,8 +40,8 @@ public void save(@RequestBody Iterable modelsToSave) { } @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) - public void delete(@RequestBody DTO modelToDelete, @PathVariable int id) { - service.delete(modelToDelete); + public void delete(@RequestBody DTO model, @PathVariable int id) { + service.delete(model); } @RequestMapping(value = "/delete/all", method = RequestMethod.POST) diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java index 90e6943..5727d3b 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AccountController.java @@ -1,16 +1,15 @@ package com.academy.web.controller; +import com.academy.cache.UserCache; +import com.academy.model.RegisterRequestBody; import com.academy.model.ValueWrapper; import com.academy.model.dao.Account; import com.academy.model.dto.AccountDTO; import com.academy.service.AccountService; -import com.academy.web.config.RedirectUrls; -import com.academy.web.config.cache.CacheConstants; -import com.hazelcast.core.HazelcastInstance; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; + +import java.text.ParseException; /** * Created by Daniel Palonek on 2016-08-04. @@ -20,21 +19,20 @@ public class AccountController extends AbstractController{ @Autowired - HazelcastInstance hazelcastInstance; + UserCache cache; @RequestMapping(value = "/logged/name") public ValueWrapper getLoggedUsername() { - return new ValueWrapper(hazelcastInstance.getUserContext().getOrDefault(CacheConstants.LOGGED_USERNAME,null)); + return new ValueWrapper(cache.getLoggedUsername()); } - @RequestMapping(value = "/register", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded") - public ModelAndView register(@RequestBody final MultiValueMap data) { - return new ModelAndView(service.saveAccount(data) ? "redirect:" : RedirectUrls.ERROR_USER_EXIST); + @RequestMapping(value = "/register", method = RequestMethod.POST) + public ValueWrapper register(@RequestBody RegisterRequestBody data) throws ParseException { + return new ValueWrapper<>(service.saveAccount(data)); } @RequestMapping(value = "/exist/{username}", method = RequestMethod.GET) public ValueWrapper checkIfUserAlreadyExist(@PathVariable("username") String username) { - Boolean ret = service.checkIfAccountWithGivenUsernameExists(username); - return new ValueWrapper<>(ret); + return new ValueWrapper<>(service.checkIfAccountWithGivenUsernameExists(username)); } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java new file mode 100644 index 0000000..f79aa95 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java @@ -0,0 +1,36 @@ +package com.academy.web.controller; + +import com.academy.cache.UserCache; +import com.academy.model.ValueWrapper; +import com.academy.model.dao.Website; +import com.academy.model.dto.WebsiteDTO; +import com.academy.service.WebsiteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * Created by Daniel Palonek on 2016-09-16. + */ +@RestController +@RequestMapping("/websites") +public class WebsitesController extends AbstractController { + + @Autowired + private UserCache cache; + + @RequestMapping(value = "/getUserWebsites", method = RequestMethod.GET) + public Iterable getUserWebsites() { + return (Iterable)cache.getUserWebsites(); + } + + @RequestMapping(value = "/add/{websiteUrl:.+}", method = RequestMethod.POST) + public ValueWrapper addWebsite(@PathVariable final String websiteUrl) { + return new ValueWrapper<>(service.saveWebsite(websiteUrl)); + } + + @RequestMapping(value ="delete/{id}", method=RequestMethod.DELETE) + public ValueWrapper deleteWebsite(@PathVariable final Long id) { + return new ValueWrapper<>(service.delete(id)); + } + +} diff --git a/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js index c613837..027e44e 100644 --- a/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js @@ -4,9 +4,93 @@ var accountControllers = angular.module( 'AccountControllers', []); -accountControllers.controller('AccountController', ['$scope', '$routeParams', '$location', 'AccountService', function ($scope, $routeParams, $location, AccountService) { - $scope.checkIfExist = function(username) { - var rsp = AccountService.checkIfAccountExist({username: username}); - return rsp.value; +accountControllers.controller('AccountController', ['$scope', '$routeParams', '$location', 'AccountService', 'toaster', function ($scope, $routeParams, $location, AccountService, toaster) { + $scope.username = ""; + $scope.password = ""; + $scope.firstNam = ""; + $scope.surname = ""; + $scope.phone = ""; + $scope.email = ""; + $scope.isUserNameExisted = false; + $scope.isUserNameTooong = false; + $scope.isUsernameInvalidFormat = false; + $scope.isPasswordTooLong = false; + $scope.isFirstNameTooLong = false; + $scope.isFirstNameInvalidFormat = false; + $scope.isSurnameTooLong = false; + $scope.isSurnameInvalidFormat = false; + $scope.isPhoneInvalidFormat = {}; + $scope.firstEmpty = true; + $scope.secondEmpty = true; + $scope.thirdEmpty = true; + $scope.fourthEmpty = true; + + $scope.checkUsernameValidate = function() { + AccountService.checkIfAccountExist({username: $scope.username}, function (rsp) { + $scope.isUserNameExisted = rsp.value; + }); + $scope.isUserNameTooLong = $scope.username.length > 10; + $scope.isUsernameInvalidFormat = !(/^[a-zA-Z0-9_]+$/.test($scope.username)); + $scope.firstEmpty = $scope.username.length == 1; + }; + + $scope.checkPasswordValidate = function() { + $scope.isPasswordTooLong = $scope.password.length > 20; + $scope.secondEmpty = $scope.password.length == 1; + }; + + $scope.checkFirstNameValidate = function() { + $scope.isFirstNameTooLong = $scope.firstName.length > 15; + $scope.isFirstNameInvalidFormat = !(/^[a-zA-Z_]+$/.test($scope.firstName)); + $scope.thirdEmpty = $scope.firstName.length == 1; + }; + + $scope.checkSurnameValidate = function() { + $scope.isSurnameTooLong = $scope.surname.length > 20; + $scope.isSurnameInvalidFormat = !(/^[a-zA-Z_]+$/.test($scope.surname)); + $scope.fourthEmpty = $scope.surname.length == 1; + }; + + $scope.checkPhoneValidate = function() { + $scope.isPhoneInvalidFormat = !(/^(\d{3})-(\d{3})-(\d{3}\d?)$/.test($scope.phone)); + }; + + $scope.checkEmailValidate = function() { + + }; + + $scope.register = function() { + var reqBody = { + username: $scope.username, + password: $scope.password, + firstName: $scope.firstName, + surname: $scope.surname, + phone: $scope.phone, + email: $scope.email + }; + + AccountService.register(reqBody, function (rsp) { + if (rsp.value) { + toaster.pop({ + type: 'success', + title: 'Account registered successfully', + body: 'You can now log in' + }); + $scope.username = ""; + $scope.password = ""; + $scope.firstName = ""; + $scope.surname = ""; + $scope.phone = ""; + $scope.email = ""; + + } else { + toaster.pop({ + type: 'warning', + title: 'Account not registered', + body: 'Error occured please repeat registration' + }); + } + }); + } }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/accountServices.js b/ClickMapActivity-web/src/main/resources/js/public/accountServices.js index 4187816..2c3213f 100644 --- a/ClickMapActivity-web/src/main/resources/js/public/accountServices.js +++ b/ClickMapActivity-web/src/main/resources/js/public/accountServices.js @@ -1,7 +1,7 @@ /** * Created by Daniel Palonek on 2016-09-08. */ -var AccountServices = angular.module('AccountServices',['ngResource']); +var AccountServices = angular.module('AccountServices',['ngResource', 'toaster']); AccountServices.factory('AccountService', [ '$resource', function ($resource) { @@ -11,6 +11,11 @@ AccountServices.factory('AccountService', [ method: 'GET', url: '/account/exist/:username', params: {username: "@username"} + }, + + register: { + method: 'POST', + url: '/account/register' } }); }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js b/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js index 5520e05..e76e33b 100644 --- a/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/public/indexControllers.js @@ -8,7 +8,7 @@ indexControllers.controller('IndexController', ['$scope', '$location', 'IndexSer IndexService.getLoggedUsername(function (username) { if(username.value !== null) { $scope.username = username.value; - } + } }); $scope.logout = function() { @@ -19,5 +19,5 @@ indexControllers.controller('IndexController', ['$scope', '$location', 'IndexSer } }); }); - } + }; }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js b/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js index 160a834..dfce6b0 100644 --- a/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js +++ b/ClickMapActivity-web/src/main/resources/js/public/routeProvider.js @@ -1,7 +1,7 @@ /** * Created by Daniel Palonek on 2016-09-05. */ -var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'ui.grid.pagination', 'IndexServices', 'IndexControllers', 'AccountServices', 'AccountControllers']); +var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'ui.grid.pagination','angular-loading-bar', 'IndexServices', 'IndexControllers', 'AccountServices', 'AccountControllers']); mainApp.config(['$routeProvider', function ($routeProvider) { $routeProvider. diff --git a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js index b3d87a3..5d43b4e 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js +++ b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js @@ -2,7 +2,7 @@ * Created by Daniel Palonek on 2016-09-10. */ var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'IndexControllers', 'IndexServices', - 'AccountControllers', 'AccountServices', 'ui.grid', 'ui.grid.pagination']); + 'AccountControllers', 'WebsitesControllers', 'WebsitesServices', 'AccountServices', 'ui.grid', 'ui.grid.pagination']); mainApp.config(['$routeProvider', function ($routeProvider) { $routeProvider. @@ -13,8 +13,9 @@ mainApp.config(['$routeProvider', function ($routeProvider) { templateUrl: '/public/main.html', controller: 'IndexController' }). - when('/myWebsites', { - templateUrl: '/user/myWebsites.html' + when('/websites', { + templateUrl: '/user/websites.html', + controller: 'WebsitesController' }). otherwise({ templateUrl: '/public/main.html', diff --git a/ClickMapActivity-web/src/main/resources/js/user/websitesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/websitesControllers.js new file mode 100644 index 0000000..2d5d09c --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/user/websitesControllers.js @@ -0,0 +1,27 @@ +/** + * Created by Daniel Palonek on 2016-09-16. + */ +var WebsitesControllers = angular.module('WebsitesControllers', []); + +WebsitesControllers.controller('WebsitesController', ['$scope', '$routeParams', '$route', 'WebsitesService', + function ($scope, $routeParams, $route, WebsitesService) { + $scope.userWebsites = {}; + $scope.websiteUrl; + $scope.deleteConfirm; + + WebsitesService.getUserWebsites(function (websites) { + $scope.userWebsites = websites; + }); + + $scope.addWebsite = function () { + WebsitesService.saveWebsite({websiteUrl: $scope.websiteUrl}, function () { + $route.reload(); + }); + }; + + $scope.deleteWebsite = function (website) { + WebsitesService.deleteWebsite({id: website.id}, function() { + $route.reload(); + }); + } +}]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/user/websitesServices.js b/ClickMapActivity-web/src/main/resources/js/user/websitesServices.js new file mode 100644 index 0000000..7ff008c --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/user/websitesServices.js @@ -0,0 +1,28 @@ +/** + * Created by Daniel Palonek on 2016-09-16. + */ +var WebsitesServices = angular.module('WebsitesServices', ['ngResource']); + +WebsitesServices.factory('WebsitesService', [ + '$resource', function ($resource) { + return $resource('', [], { + + getUserWebsites: { + method: 'GET', + url: "/websites/getUserWebsites", + isArray: true + }, + + saveWebsite: { + params: {websiteUrl: "@websiteUrl"}, + method: 'POST', + url: '/websites/add/:websiteUrl' + }, + + deleteWebsite: { + method: 'DELETE', + params: {id: "@id"}, + url: '/websites/delete/:id' + } + }); + }]); \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/public/index.html b/ClickMapActivity-web/src/main/resources/templates/public/index.html index 6f68995..9a0df87 100644 --- a/ClickMapActivity-web/src/main/resources/templates/public/index.html +++ b/ClickMapActivity-web/src/main/resources/templates/public/index.html @@ -15,6 +15,10 @@ + + + + @@ -134,6 +138,7 @@ } #loginBar { + left: -16%; height: 260%; line-height: 75%; padding: 27px; diff --git a/ClickMapActivity-web/src/main/resources/templates/public/register.html b/ClickMapActivity-web/src/main/resources/templates/public/register.html index 52e3916..57676bb 100644 --- a/ClickMapActivity-web/src/main/resources/templates/public/register.html +++ b/ClickMapActivity-web/src/main/resources/templates/public/register.html @@ -9,7 +9,7 @@ margin: 0 auto; border-radius: 10px; border: solid 2px #7a43b6; - padding-left: 6%; + padding-left: 1%; padding-top: 2%; padding-bottom: 2%; } @@ -24,37 +24,89 @@ #btnRegister:active, #btnRegister:hover, #btnRegister:focus { border-color: white; } + + #username-fail, #password-fail, #firstName-fail, #surname-fail { + color: red; + } + + #username-ok, #password-ok, #firstName-ok, #surname-ok, #phone-ok { + color: green; + } +





-
-
- - -
+ +
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- + + +
+ Username already exists. Please type different. + Username is too long. It should has maximum 10 characters. + Wrong characters in username. +
+
+ +
+
+ + +
+ Password is too long. It should has maximum 20 characters. +
+
+ +
+
+
+ + +
+ First name is too long. It should has maximum 15 characters. + Wrong characters in first name. +
+
+ +
+ +
+
+ + +
+ First name is too long. It should has maximum 15 characters. + Wrong characters in first name. +
+
+ +
+
+
+ + +
+ +
+
+
+ + +
+
+ +

+ * required +
\ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html index 83e832a..6ef67b1 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html @@ -9,12 +9,17 @@ + + + + + @@ -28,6 +33,8 @@ + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index f01ddeb..1601c71 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,7 @@ subprojects { apply plugin: 'spring-boot' sourceCompatibility = 1.8 + targetCompatibility = 1.8 repositories { mavenCentral() diff --git a/settings.gradle b/settings.gradle index ba433fc..396ff20 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,7 @@ include 'ClickMapActivity-model' include 'ClickMapActivity-service' include 'ClickMapActivity-repo' include 'ClickMapActivity-web' +include 'ClickMapActivity-cache' +include 'ClickMapActivity-cache' +include 'ClickMapActivity-cache' From 79056237e383ce0344726ce4f23db1c0f972c011 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Mon, 10 Oct 2016 18:03:32 +0200 Subject: [PATCH 07/21] Subpage bookmark started, improvenents --- .../academy/cache/AbstractCacheSupplier.java | 7 +- .../src/main/resources/hazelcast.xml | 159 +++++++++ .../com/academy/service/SubpageService.java | 2 + .../com/academy/service/WebsiteService.java | 4 +- .../service/mappers/SubpageMapper.java | 2 + .../LogoutAuthenticationSuccessHandler.java | 2 +- .../web/controller/SubpagesController.java | 16 + .../web/controller/WebsitesController.java | 19 +- .../jquery.bsPhotoGallery.css | 87 +++++ .../jquery.bsPhotoGallery.js | 307 ++++++++++++++++++ .../resources/js/user/subpagesControllers.js | 24 ++ .../resources/js/user/subpagesServices.js | 11 + .../resources/js/user/userRouteProvider.js | 7 +- .../resources/js/user/websitesControllers.js | 15 +- .../resources/js/user/websitesServices.js | 38 ++- .../resources/templates/user/css/subpages.css | 229 +++++++++++++ .../resources/templates/user/subpages.html | 89 +++++ .../resources/templates/user/userIndex.html | 4 + .../resources/templates/user/websites.html | 6 +- 19 files changed, 1013 insertions(+), 15 deletions(-) create mode 100644 ClickMapActivity-cache/src/main/resources/hazelcast.xml create mode 100644 ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java create mode 100644 ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.css create mode 100644 ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.js create mode 100644 ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js create mode 100644 ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js create mode 100644 ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css create mode 100644 ClickMapActivity-web/src/main/resources/templates/user/subpages.html diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java index 317d400..0e566c0 100644 --- a/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java @@ -1,6 +1,7 @@ package com.academy.cache; import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.core.IMap; import org.springframework.beans.factory.annotation.Autowired; import java.util.concurrent.ConcurrentMap; @@ -8,7 +9,7 @@ /** * Created by Daniel Palonek on 2016-09-17. */ -public class AbstractCacheSupplier { +public abstract class AbstractCacheSupplier { @Autowired private HazelcastInstance hazelcastInstance; @@ -16,4 +17,8 @@ public class AbstractCacheSupplier { protected ConcurrentMap getUserContext() { return hazelcastInstance.getUserContext(); } + + protected IMap getMap(String mapName) { + return hazelcastInstance.getMap(mapName); + } } diff --git a/ClickMapActivity-cache/src/main/resources/hazelcast.xml b/ClickMapActivity-cache/src/main/resources/hazelcast.xml new file mode 100644 index 0000000..bfb7d10 --- /dev/null +++ b/ClickMapActivity-cache/src/main/resources/hazelcast.xml @@ -0,0 +1,159 @@ + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.2.2.3 + 54327 + + + 127.0.0.1 + + 127.0.0.1 + + + + my-access-key + my-secret-key + + us-west-1 + + ec2.amazonaws.com + + hazelcast-sg + type + hz-nodes + + + + + + 10.10.1.* + + + + + + PBEWithMD5AndDES + + thesalt + + thepass + + 19 + + + + + 16 + + 0 + + + + 0 + + 1 + + + 0 + + -1 + + + BINARY + 1 + 0 + 0 + 0 + LRU + 0 + com.hazelcast.map.merge.PutIfAbsentMapMergePolicy + INDEX-ONLY + + + + 1 + SET + + + + 1 + + + + 1 + + + + 0 + + 0 + 0 + 1000 + true + CANCEL_RUNNING_OPERATION + + + + 0 + 1 + 0 + + + + 10 + BLOCK + true + + + + 10000 + 1 + 0 + 30 + BINARY + + + + 0 + + + + + + + \ No newline at end of file diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 54655d8..2606e6e 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -5,9 +5,11 @@ import com.academy.repo.SubpageRepo; import com.academy.service.AbstractService; import com.academy.service.mappers.SubpageMapper; +import org.springframework.stereotype.Service; /** * Created by Daniel Palonek on 2016-08-19. */ +@Service public class SubpageService extends AbstractService { } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java index 144a19f..f6fbecc 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java @@ -35,13 +35,13 @@ public boolean saveWebsite(String websiteUrl) { website.setAccountId(accountService.getLoggedUserAccountId()); website.setUrl(websiteUrl); save(website); - cache.replace(getUserWebsites()); + cache.setUserWebsites(getUserWebsites()); return true; } public boolean delete(Long websiteId) { repo.delete(websiteId); - cache.replace(getUserWebsites()); + cache.setUserWebsites(getUserWebsites()); return true; } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java index 135ca6d..4cd6d31 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java @@ -5,10 +5,12 @@ import com.academy.model.dto.SubpageDTO; import com.academy.repo.WebsiteRepo; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * Created by Daniel Palonek on 2016-08-18. */ +@Component public class SubpageMapper implements Mapper { @Autowired diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java index 6182809..389b23e 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java @@ -23,7 +23,7 @@ public class LogoutAuthenticationSuccessHandler implements LogoutSuccessHandler @Override public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse rsp, Authentication auth) throws IOException, ServletException { - cache.removeLoggedUsername(); cache.removeUserWebsites(); + cache.removeLoggedUsername(); } } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java new file mode 100644 index 0000000..87be8e8 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -0,0 +1,16 @@ +package com.academy.web.controller; + +import com.academy.model.dao.Subpage; +import com.academy.model.dto.SubpageDTO; +import com.academy.service.SubpageService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Created by Daniel Palonek on 2016-10-06. + */ +@RestController +@RequestMapping("/subpages") +public class SubpagesController extends AbstractController { + +} diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java index f79aa95..1a7ea02 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java @@ -7,6 +7,13 @@ import com.academy.service.WebsiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Created by Daniel Palonek on 2016-09-16. @@ -28,9 +35,19 @@ public ValueWrapper addWebsite(@PathVariable final String websiteUrl) { return new ValueWrapper<>(service.saveWebsite(websiteUrl)); } - @RequestMapping(value ="delete/{id}", method=RequestMethod.DELETE) + @RequestMapping(value ="/delete/{id}", method=RequestMethod.DELETE) public ValueWrapper deleteWebsite(@PathVariable final Long id) { return new ValueWrapper<>(service.delete(id)); } + @RequestMapping(value = "/saveRequestedWebsite", method = RequestMethod.PUT) + public void saveRequestedWebsite(@RequestBody final WebsiteDTO website) { + cache.setRequestedWebsite(website); + } + + @RequestMapping(value = "/getRequestedWebsite", method = RequestMethod.GET) + public WebsiteDTO getRequestedWebsite() { + return (WebsiteDTO)cache.getRequestedWebsite(); + } + } diff --git a/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.css b/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.css new file mode 100644 index 0000000..caf2936 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.css @@ -0,0 +1,87 @@ +#bsPhotoGalleryModal .modal-content { + border-radius:0; +} +#bsPhotoGalleryModal .modal-dialog img { + text-align:center; + margin:0 auto; + width:100%; +} +#bsPhotoGalleryModal .modal-body { + padding:0px !important; +} +#bsPhotoGalleryModal .bsp-close { + position: absolute; + right: -14px; + top: -11px; + font-size: 30px; + color:#fff; + text-shadow: 1px 1px 18px #000; +} + +#bsPhotoGalleryModal .bsp-close:hover { + cursor: pointer; + opacity:.6; + text-shadow: none; + +} +.bspHasModal { + cursor: pointer; +} +.bspHasModal .text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.imgWrapper { + overflow: hidden; + max-height: 99px; +} + +a.bsp-controls, +a.bsp-controls:visited, +a.bsp-controls:active { + position: absolute; + top: 44%; + font-size: 26px; + color: #fff; + text-shadow: 1px 1px 18px #000; +} +a.bsp-controls.next { + right:-10px; +} +a.bsp-controls.previous { + left:-10px; +} +a.bsp-controls:hover { + opacity:.6; + text-shadow: none; +} +.bsp-text-container { + clear:both; + display:block; + padding-bottom: 5px; +} +#bsPhotoGalleryModal h6{ + margin-bottom: 0; + font-weight: bold; + color: #000; + font-size: 14px; + padding-left: 12px; + padding-right: 12px; + margin-bottom: 5px; +} +#bsPhotoGalleryModal .pText { + font-size: 11px; + margin-bottom: 0px; + padding: 0 12px 5px; +} + + +@media screen and (max-width: 380px){ + .col-xxs-12 { + width:100%; + } + .col-xxs-12 img { + width:100%; + } +} \ No newline at end of file diff --git a/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.js b/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.js new file mode 100644 index 0000000..471728d --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/bower_components/bootstrap-photo-gallery/jquery.bsPhotoGallery.js @@ -0,0 +1,307 @@ +(function($) { + "use strict"; + $.fn.bsPhotoGallery = function(options) { + + var settings = $.extend({}, $.fn.bsPhotoGallery.defaults, options); + var id = generateId(); + var classesString = settings.classes; + var classesArray = classesString.split(" "); + var clicked = {}; + + function getCurrentUl(){ + return 'ul[data-bsp-ul-id="'+clicked.ulId+'"][data-bsp-ul-index="'+clicked.ulIndex+'"]'; + } + function generateId() { + //http://fiznool.com/blog/2014/11/16/short-id-generation-in-javascript/ + var ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + var ID_LENGTH = 4; + var out = ''; + for (var i = 0; i < ID_LENGTH; i++) { + out += ALPHABET.charAt(Math.floor(Math.random() * ALPHABET.length)); + } + return 'bsp-'+out; + } + function createModalWrap(){ + + if($('#bsPhotoGalleryModal').length !== 0){ + return false; + } + + var modal = ''; + modal += ' From 04c115217e5c29dd52be5fe5e0042b42905d2dd1 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Mon, 7 Nov 2016 23:55:28 +0100 Subject: [PATCH 12/21] Done logging activity, show click map on subpage image, basic stats --- .../java/com/academy/cache/UserCache.java | 14 ++++++ ClickMapActivity-model/build.gradle | 2 +- .../java/com/academy/model/dao/Activity.java | 5 ++- .../java/com/academy/model/dao/Subpage.java | 4 +- .../java/com/academy/model/dao/Website.java | 2 +- .../com/academy/model/dto/ActivityDTO.java | 7 ++- .../java/com/academy/model/dto/PointsDTO.java | 4 +- .../com/academy/model/dto/SubpageDTO.java | 18 ++++++++ .../java/com/academy/repo/PointsRepo.java | 3 ++ .../com/academy/service/ActivityService.java | 39 +++++++++++++---- .../com/academy/service/PointsService.java | 4 ++ .../com/academy/service/SubpageService.java | 24 ++++++++--- .../service/mappers/SubpageMapper.java | 4 ++ .../academy/service/tools/ImageConverter.java | 40 +++++++++++++++++- .../com/academy/web/config/CacheLoader.java | 37 ++++++++++++---- .../web/controller/ActivitiesController.java | 5 ++- .../src/main/resources/images/Thumbs.db | Bin 131584 -> 131584 bytes .../resources/js/user/subpagesControllers.js | 19 ++++++++- .../resources/js/user/subpagesServices.js | 9 +++- .../resources/js/user/userRouteProvider.js | 6 ++- .../resources/templates/user/css/subpages.css | 5 +++ .../main/resources/templates/user/image.html | 2 + .../resources/templates/user/subpages.html | 24 ++++++----- 23 files changed, 230 insertions(+), 47 deletions(-) create mode 100644 ClickMapActivity-web/src/main/resources/templates/user/image.html diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java index 1a81927..6d63fbf 100644 --- a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java @@ -2,6 +2,8 @@ import org.springframework.stereotype.Component; +import java.time.LocalDateTime; + /** * Created by Daniel Palonek on 2016-09-16. */ @@ -64,4 +66,16 @@ public void deleteSubpageActivities(Long subpageId) { getMap(CacheConstants.ACTIVITIES).removeAsync(subpageId); } + public void setActivityPoints(Long activityId, Iterable points) { + getMap(CacheConstants.POINTS).set(activityId, points); + } + + public Iterable getActivityPoints(Long activityId) { + return (Iterable)getMap(CacheConstants.POINTS).get(activityId); + } + + public void deleteActivityPoints(Long activityId) { + getMap(CacheConstants.POINTS).removeAsync(activityId); + } + } diff --git a/ClickMapActivity-model/build.gradle b/ClickMapActivity-model/build.gradle index 73d6d16..e8ee3d7 100644 --- a/ClickMapActivity-model/build.gradle +++ b/ClickMapActivity-model/build.gradle @@ -2,5 +2,5 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' dependencies { - compile group: 'org.hibernate', name: 'hibernate-entitymanager', version: '5.2.1.Final' + compile group: 'org.hibernate', name: 'hibernate-java8', version: '5.2.1.Final' } diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java index c869e4e..41d9ef1 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java @@ -15,11 +15,12 @@ public class Activity { @GeneratedValue private Long id; - @OneToMany(mappedBy = "activity") + @OneToMany(mappedBy = "activity", cascade = {CascadeType.ALL}) private Set points; + private LocalDateTime date; - @ManyToOne + @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) private Subpage subpage; public Long getId() { diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java index 72c1950..3f53ad5 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Subpage.java @@ -16,10 +16,10 @@ public class Subpage { private Integer resX; private Integer resY; - @ManyToOne + @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) private Website website; - @OneToMany(mappedBy = "subpage") + @OneToMany(mappedBy = "subpage", cascade = {CascadeType.ALL}) private List activityPoints; public Long getId() { diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java index d16ab15..b9d06a0 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java @@ -17,7 +17,7 @@ public class Website { @ManyToOne private Account account; - @OneToMany(mappedBy = "website") + @OneToMany(mappedBy = "website", cascade = {CascadeType.ALL}) private List subpages; public Long getId() { diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java index 823b6ba..f165e88 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java @@ -1,11 +1,12 @@ package com.academy.model.dto; +import java.io.Serializable; import java.time.LocalDateTime; /** * Created by Daniel Palonek on 2016-08-18. */ -public class ActivityDTO { +public class ActivityDTO implements Serializable { private Long id; private LocalDateTime date; @@ -34,4 +35,8 @@ public Long getSubpageId() { public void setSubpageId(Long subpageId) { this.subpageId = subpageId; } + + public int compare(LocalDateTime other) { + return this.getDate().compareTo(other); + } } diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java index 86d4ddc..4c00adb 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java @@ -1,9 +1,11 @@ package com.academy.model.dto; +import java.io.Serializable; + /** * Created by Daniel Palonek on 2016-08-18. */ -public class PointsDTO { +public class PointsDTO implements Serializable { private Long id; private String pairValue; diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java b/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java index b8b6eed..a558698 100644 --- a/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java @@ -11,6 +11,8 @@ public class SubpageDTO implements Serializable { private String name; private Integer resX; private Integer resY; + private Long lastUpdateEpoch; + private Long displays; private Long websiteId; public Long getWebsiteId() { @@ -52,4 +54,20 @@ public Long getId() { public void setId(Long id) { this.id = id; } + + public Long getLastUpdateEpoch() { + return lastUpdateEpoch; + } + + public void setLastUpdateEpoch(Long lastUpdateEpoch) { + this.lastUpdateEpoch = lastUpdateEpoch; + } + + public Long getDisplays() { + return displays; + } + + public void setDisplays(Long displays) { + this.displays = displays; + } } diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java index 2c7b7c1..c4cd7e0 100644 --- a/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java @@ -7,4 +7,7 @@ * Created by Daniel Palonek on 2016-08-19. */ public interface PointsRepo extends CrudRepository { + + Iterable findByActivityId(Long activityId); + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java index bc78328..2d1695d 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java @@ -11,6 +11,7 @@ import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.Date; @@ -19,7 +20,7 @@ * Created by Daniel Palonek on 2016-08-19. */ @Service -public class ActivityService extends AbstractService { +public class ActivityService extends AbstractService { private final static Logger LOGGER = LogManager.getLogger(ActivityService.class); @@ -35,27 +36,49 @@ public class ActivityService extends AbstractService pointsService.addPointsCouple(activityId,(String)p ) ); + points.forEach(p -> pointsService.addPointsCouple(activityId, (String) p)); } + private Iterable adjustResolution(Integer subpageResX, Integer subpageResY, String pointsRes, Iterable points) { + String[] separatedRes = pointsRes.split("x"); + try { + Integer pointsResX = Integer.parseInt(separatedRes[0]); + Integer pointsResY = Integer.parseInt(separatedRes[1]); + if (separatedRes.length == 2 && Integer.parseInt(separatedRes[0]) > 0 && Integer.parseInt(separatedRes[1]) > 0) { + if(subpageResX < pointsResX) { +// pointsResX - subpageResX + } + } else { + throw new IllegalStateException(); + } + } catch (Exception e) { + LOGGER.warn("Error while adjusting points resolution, subpage resolution: " + + subpageResX.toString() + "x" + subpageResY.toString() + ", points resolution: " + pointsRes); + throw e; + } + return null; + } + + public Activity addActivity(LocalDateTime date, Long subpageId) { ActivityDTO activityDTO = new ActivityDTO(); activityDTO.setDate(date); diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java index 598b0c4..3d066b3 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java @@ -23,4 +23,8 @@ public void addPointsCouple(Long activityId, String pointsCouple) { repo.save(mapper.convertToDAO(pointsDTO)); } + public Iterable getByActivityId(Long activityId) { + return mapper.convertToDTO(repo.findByActivityId(activityId)); + } + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 610e8aa..7af6ee9 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -2,6 +2,8 @@ import com.academy.cache.UserCache; import com.academy.model.dao.Subpage; +import com.academy.model.dto.ActivityDTO; +import com.academy.model.dto.PointsDTO; import com.academy.model.dto.SubpageDTO; import com.academy.model.dto.WebsiteDTO; import com.academy.repo.SubpageRepo; @@ -18,9 +20,15 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.imageio.ImageIO; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.stream.StreamSupport; /** @@ -43,11 +51,10 @@ public boolean saveSubpage(String name, MultipartFile file, RedirectAttributes r if(!f.exists()) f.mkdirs(); f = new File("ClickMapActivity-web/src/main/resources/images/" + websiteDTO.getId() + "/" + name); - BufferedOutputStream s = new BufferedOutputStream(new FileOutputStream(f)); - FileCopyUtils.copy(file.getInputStream(),s); - s.close(); final SubpageDTO subpageDTO = new SubpageDTO(); - BufferedImage img = ImageIO.read(f); + BufferedImage img = ImageIO.read(file.getInputStream()); + img = ImageConverter.grayScale(img); + ImageIO.write(img, "png", f); subpageDTO.setName(name); subpageDTO.setResX(img.getWidth()); subpageDTO.setResY(img.getHeight()); @@ -80,7 +87,14 @@ public void getImage(String name, HttpServletResponse response) { File f = new File("ClickMapActivity-web/src/main/resources/images/" + website.getId() + "/" + name); BufferedImage img = ImageIO.read(f); ByteArrayOutputStream outStr = new ByteArrayOutputStream(); - img = ImageConverter.grayScale(img); + final SubpageDTO subpage = mapper.convertToDTO(repo.findByNameAndWebsiteId(name,website.getId())); + Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); + List points = new ArrayList<>(); + if(activities != null) { + activities.stream().forEach(a -> points.addAll((Collection) cache.getActivityPoints(a.getId()))); + } + int [][] clickMatrix = ImageConverter.makeClickMatrix(points,img.getWidth(),img.getHeight()); + img = ImageConverter.fillPointsMap(img,clickMatrix); ImageIO.write(img,"png",outStr); InputStream inputStream = new ByteArrayInputStream(outStr.toByteArray()); IOUtils.copy(inputStream, response.getOutputStream()); diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java index 4cd6d31..89610a0 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.LocalDateTime; + /** * Created by Daniel Palonek on 2016-08-18. */ @@ -39,6 +41,8 @@ public SubpageDTO convertToDTO(Subpage dao) { dto.setResX(dao.getResX()); dto.setResY(dao.getResY()); dto.setName(dao.getName()); + dto.setDisplays(0L); + dto.setLastUpdateEpoch(0L); if(dao.getWebsite() != null) { dto.setWebsiteId(dao.getWebsite().getId()); } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java index 1984469..7a58ba1 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java @@ -1,7 +1,10 @@ package com.academy.service.tools; +import com.academy.model.dto.PointsDTO; + import java.awt.*; import java.awt.image.BufferedImage; +import java.util.List; /** * Created by Daniel Palonek on 2016-10-21. @@ -33,12 +36,31 @@ public static BufferedImage grayScale(BufferedImage original) { // Write pixels into image avg_gray.setRGB(i, j, newPixel); - } } - return avg_gray; + } + public static BufferedImage fillPointsMap(BufferedImage img, int[][] points) { + final Color pointColor = new Color(255,0,0,80); + Graphics2D graphics = img.createGraphics(); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); + graphics.setPaint(pointColor); + for(int i=0; i 0) { + drawPoint(graphics, i, j, points[i][j]); + } + } + } + graphics.dispose(); + return img; + } + + private static void drawPoint(Graphics2D graphics, int x, int y, int loop) { + for(int i = 0; i { + String indexes [] = ((PointsDTO)p).getPairValue().split(";"); + clickMatrix[Integer.parseInt(indexes[0])][Integer.parseInt(indexes[1])] += 1; + }); +// for(int i=0 ; i<300; i++) { +// for(int j = 0; j<400;j++) { +// clickMatrix[i][j] = true; +// } +// } + return clickMatrix; + } + } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java index 7663ae5..9fc226c 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java @@ -1,14 +1,18 @@ package com.academy.web.config; import com.academy.cache.UserCache; -import com.academy.model.dto.SubpageDTO; -import com.academy.model.dto.WebsiteDTO; +import com.academy.model.dto.*; import com.academy.service.ActivityService; +import com.academy.service.PointsService; import com.academy.service.SubpageService; import com.academy.service.WebsiteService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collection; + /** * Created by Daniel Palonek on 2016-10-20. */ @@ -27,24 +31,41 @@ public class CacheLoader { @Autowired ActivityService activityService; + @Autowired + PointsService pointsService; + public void load(final String username) { cache.setLoggedUsername(username); Iterable websites = websiteService.getUserWebsites(); cache.setUserWebsites(websites); websites.forEach( w -> { final Iterable subpages = subpageService.getSubgapesForWebsiteId(w.getId()); + subpages.forEach(s-> { + Collection activities = (Collection)activityService.getBySubpageId(s.getId()); + cache.setSubpageActivities(s.getId(), activities); + activities.stream() + .sorted((a1,a2) -> a1.getDate().compareTo(a2.getDate())) + .forEach(a-> { + Iterable points = pointsService.getByActivityId(a.getId()); + s.setDisplays(new Long(((Collection)points).size()) + s.getDisplays()); + cache.setActivityPoints(a.getId(), points); + }); + if(activities.size() > 0) { + s.setLastUpdateEpoch(new ArrayList<>(activities).get(activities.size() - 1).getDate().toInstant(ZoneOffset.UTC).getEpochSecond()); + } + }); cache.setWebsiteSubpages(w.getId(), subpages); - subpages.forEach(s-> - cache.setSubpageActivities(s.getId(), activityService.getBySubpageId(s.getId())) - ); }); } public void clean() { cache.getUserWebsites().forEach(w -> { - cache.getWebsiteSubpages(((WebsiteDTO) w).getId()).forEach(s-> - cache.deleteSubpageActivities(((SubpageDTO)s).getId()) - ); + cache.getWebsiteSubpages(((WebsiteDTO) w).getId()).forEach(s-> { + cache.getSubpageActivities(((SubpageDTO)s).getId()).forEach(a-> + cache.deleteActivityPoints(((ActivityDTO)a).getId()) + ); + cache.deleteSubpageActivities(((SubpageDTO) s).getId()); + }); cache.deleteWebsiteSubpages(((WebsiteDTO) w).getId()); }); cache.removeUserWebsites(); diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java index b048c1b..7c2feb1 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java @@ -14,11 +14,12 @@ public class ActivitiesController { @Autowired private ActivityService activityService; - @RequestMapping(value = "/log/{wName}/{sName}", method = RequestMethod.POST) + @RequestMapping(value = "/log/{wName}/{sName}/{res}", method = RequestMethod.POST) public void logActivity(@PathVariable("wName") String websiteName, @PathVariable("sName") String subpageName, + @PathVariable("res") String resolution, Iterable points) { - activityService.logActivity(websiteName, subpageName, points); + activityService.logActivity(websiteName, subpageName, resolution, points); } } diff --git a/ClickMapActivity-web/src/main/resources/images/Thumbs.db b/ClickMapActivity-web/src/main/resources/images/Thumbs.db index ff030a112b1c0f2820fd4b7e4897960d8dee37ee..86fc20bd14a25788f915dbf233cc5925abf827cb 100644 GIT binary patch delta 181 zcmZo@;b>^#*pS1*mJmB*(|YsCMJ$&lA31F>xr8-@gO!1S;Xe>ezR04o`3tKA6AOs9 zS%BjYI}1>XVY7gM@h)CQMj(?7N$KR0Qz0B2NCKO`oC^#*pS1*wqV)Z(oCJnMJ$(iSQ!`?IDq&+5KO+vqB6OJHH3o+NnrCARtY8+ zpa8>W0ggZHEFguO1q6(D@iH(11=*04PA)kW!U2*80gz#vznltjpU$y{QDA$b5aWEt q$p$Q(+e8>$Or#OOcSnbmOn7b8XqMz9sz1xy$}oCN^1$v{T{ diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index 862fa76..0326501 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -10,7 +10,8 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$route', '$time $scope.isSubpageExists = false; $scope.websiteUrl = window.location.href.split("/subpages/")[1]; $scope.isFileLoaded = false; - $ + $scope.imgName = {}; + $scope.displays = {}; SubpagesService.getByWebsiteId(function (subpages) { $scope.subpages = subpages; @@ -34,6 +35,22 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$route', '$time }) }; + $scope.loadImageName = function() { + $scope.imgName = window.location.href.split("/subpages/image/")[1]; + }; + + $scope.redirectToImage = function(name) { + $location.path('/subpages/image/' + name); + }; + + $scope.showDate = function (epoch) { + if(epoch === 0) { + return "Inactive"; + } + var date = new Date(epoch * 1000); + return date.toLocaleString(); + }; + // $scope.shouldShow = $(document).mouseup(function (e) { // var container = $('#subpage-panel'); // if(!container.is(e.target)) { diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index 064579b..ec1a339 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -16,7 +16,8 @@ SubpagesServices.factory('SubpagesService', [ getSubpageImage: { url: '/subpages/images/:name', params: {name: "@name"}, - method: 'GET' + method: 'GET', + responseType: 'arraybuffer' }, deleteSubpage: { @@ -25,6 +26,12 @@ SubpagesServices.factory('SubpagesService', [ method: 'DELETE' }, + getDisplays: { + url: '/subpages/displays/:id', + params: {id: '@id'}, + method: 'GET' + }, + checkIfExists: { url: '/subpages/checkIfExists/:name', params: {name: '@name'}, diff --git a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js index c39f632..6bda826 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js +++ b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js @@ -21,7 +21,11 @@ mainApp.config(['$routeProvider', function ($routeProvider) { when('/subpages/:websiteUrl', { templateUrl: '/user/subpages.html', controller: 'SubpagesController' - }). + }). + when('/subpages/image/:imgName', { + templateUrl: '/user/image.html', + controller: 'SubpagesController' + }). otherwise({ templateUrl: '/public/main.html', controller: 'IndexController' diff --git a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css index 5eff1d6..6601e45 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css +++ b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css @@ -232,6 +232,11 @@ font-size: 1.4em; } +#refresh-icon { + padding-right: 2%; +} + + .loader { border: 16px solid #f3f3f3; border-radius: 50%; diff --git a/ClickMapActivity-web/src/main/resources/templates/user/image.html b/ClickMapActivity-web/src/main/resources/templates/user/image.html new file mode 100644 index 0000000..8f5f3e8 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/templates/user/image.html @@ -0,0 +1,2 @@ +
+
{{imgName}}
diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index a8b988a..bb091a1 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -39,26 +39,28 @@

Your subpages for {{websiteUrl}}

From 8a94a7259297528a20e4fa73c78f3ce79ef375e6 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 15 Nov 2016 22:27:21 +0100 Subject: [PATCH 13/21] Added improvements in real-time showing click map na subpage --- .../java/com/academy/cache/UserCache.java | 21 ++++++- .../java/com/academy/model/PointsWrapper.java | 19 ++++++ .../com/academy/service/ActivityService.java | 61 +++++++++++++------ .../com/academy/service/PointsService.java | 4 +- .../academy/service/tools/ImageConverter.java | 5 -- .../web/controller/ActivitiesController.java | 9 ++- .../resources/js/public/accountControllers.js | 17 ++++++ .../resources/js/user/userRouteProvider.js | 3 +- 8 files changed, 110 insertions(+), 29 deletions(-) create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/PointsWrapper.java diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java index 6d63fbf..ab29c62 100644 --- a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java @@ -1,8 +1,15 @@ package com.academy.cache; +import org.hibernate.mapping.Array; import org.springframework.stereotype.Component; +import sun.text.CollatorUtilities; import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static java.util.stream.StreamSupport.stream; /** * Created by Daniel Palonek on 2016-09-16. @@ -58,6 +65,18 @@ public void setSubpageActivities(Long subpageId, Iterable activities) { getMap(CacheConstants.ACTIVITIES).set(subpageId,activities); } + public synchronized void addSubpageActivity(Long subpageId, Object activity) { + Iterable values = (Iterable)getMap(CacheConstants.ACTIVITIES).get(subpageId); + if(values != null) { + List l = (List)StreamSupport.stream(values.spliterator(),false).collect(Collectors.toList()); + l.add(activity); + getMap(CacheConstants.ACTIVITIES).set(subpageId, l); + } else { + List c = Arrays.asList(activity); + getMap(CacheConstants.ACTIVITIES).set(subpageId, c); + } + } + public Iterable getSubpageActivities(Long subpageId) { return (Iterable)getMap(CacheConstants.ACTIVITIES).get(subpageId); } @@ -78,4 +97,4 @@ public void deleteActivityPoints(Long activityId) { getMap(CacheConstants.POINTS).removeAsync(activityId); } -} +} \ No newline at end of file diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/PointsWrapper.java b/ClickMapActivity-model/src/main/java/com/academy/model/PointsWrapper.java new file mode 100644 index 0000000..e7e7f62 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/PointsWrapper.java @@ -0,0 +1,19 @@ +package com.academy.model; + +import java.util.List; + +/** + * Created by Daniel Palonek on 2016-11-08. + */ +public class PointsWrapper { + + private List points; + + public List getPoints() { + return points; + } + + public void setPoints(List points) { + this.points = points; + } +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java index 2d1695d..9a1f00d 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java @@ -3,18 +3,26 @@ import com.academy.cache.UserCache; import com.academy.model.dao.Activity; import com.academy.model.dto.ActivityDTO; +import com.academy.model.dto.PointsDTO; import com.academy.model.dto.SubpageDTO; import com.academy.model.dto.WebsiteDTO; import com.academy.repo.ActivityRepo; import com.academy.service.mappers.ActivityMapper; +import com.academy.service.mappers.PointsMapper; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; +import org.hibernate.mapping.Array; +import org.hibernate.mapping.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; -import java.util.Date; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * Created by Daniel Palonek on 2016-08-19. @@ -36,9 +44,13 @@ public class ActivityService extends AbstractService points) throws IllegalStateException { LocalDateTime receivedTime = LocalDateTime.now(); final WebsiteDTO websiteDTO = websiteService.getByName(websiteName); + List pointsList = StreamSupport.stream(points.spliterator(),false).collect(Collectors.toList()); if (websiteDTO == null) { LOGGER.warn("Request from unauthorized site [" + websiteName + "]"); return; @@ -48,46 +60,61 @@ public void logActivity(String websiteName, String subpageName, String resolutio LOGGER.warn("Request from authorized site [" + websiteName + "], but from unauthorized subpage [" + subpageName + "]"); return; } - points = adjustResolution(subpageDTO.getResX(), subpageDTO.getResY(), resolution, points); - Activity activity = addActivity(receivedTime, subpageDTO.getId()); + points = adjustResolution(subpageDTO.getResX(), subpageDTO.getResY(), resolution, pointsList); + Activity activity = insertActivity(receivedTime, subpageDTO.getId()); if (activity == null) { LOGGER.warn("Could not insert activity for request from site [" + websiteName + "] and subpage [" + subpageName + "]"); return; } final Long activityId = activity.getId(); - points.forEach(p -> pointsService.addPointsCouple(activityId, (String) p)); + List convertedPoints = new ArrayList<>(); + points.forEach(p -> + convertedPoints.add(pointsMapper.convertToDTO(pointsService.addPointsCouple(activityId, p))) + ); + if(cache.getLoggedUsername() != null) { + cache.setActivityPoints(activityId, convertedPoints); + } } - private Iterable adjustResolution(Integer subpageResX, Integer subpageResY, String pointsRes, Iterable points) { + private Iterable adjustResolution(Integer subX, Integer subY, String pointsRes, List points) { String[] separatedRes = pointsRes.split("x"); + List convertedPoints = new ArrayList<>(); try { - Integer pointsResX = Integer.parseInt(separatedRes[0]); - Integer pointsResY = Integer.parseInt(separatedRes[1]); + Integer pointsX = Integer.parseInt(separatedRes[0]); + Integer pointsY = Integer.parseInt(separatedRes[1]); if (separatedRes.length == 2 && Integer.parseInt(separatedRes[0]) > 0 && Integer.parseInt(separatedRes[1]) > 0) { - if(subpageResX < pointsResX) { -// pointsResX - subpageResX - } + final double propX = (double)subX / (double)pointsX; + final double propY = (double)subY / (double)pointsY; + points.forEach(p-> { + final String [] tmp = p.split(";"); + convertedPoints.add((int)(Integer.parseInt(tmp[0]) * propX) + ";" + (int)(Integer.parseInt(tmp[1]) * propY)); + }); } else { throw new IllegalStateException(); } } catch (Exception e) { LOGGER.warn("Error while adjusting points resolution, subpage resolution: " + - subpageResX.toString() + "x" + subpageResY.toString() + ", points resolution: " + pointsRes); + subX.toString() + "x" + subY.toString() + ", points resolution: " + pointsRes); throw e; } - return null; + return convertedPoints; } - public Activity addActivity(LocalDateTime date, Long subpageId) { + public Activity insertActivity(LocalDateTime date, Long subpageId) { ActivityDTO activityDTO = new ActivityDTO(); activityDTO.setDate(date); activityDTO.setSubpageId(subpageId); - return repo.save(mapper.convertToDAO(activityDTO)); + Activity a = repo.save(mapper.convertToDAO(activityDTO)); + if(cache.getLoggedUsername() != null) { + activityDTO.setId(a.getId()); + cache.addSubpageActivity(subpageId, activityDTO); + } + return a; } public Iterable getBySubpageId(Long subpageId) { return mapper.convertToDTO(repo.findBySubpageId(subpageId)); } -} +} \ No newline at end of file diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java index 3d066b3..fd19f49 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java @@ -16,11 +16,11 @@ public class PointsService extends AbstractService getByActivityId(Long activityId) { diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java index 7a58ba1..66e72c7 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java @@ -82,11 +82,6 @@ public static int colorToRGB(int alpha, int red, int green, int blue) { String indexes [] = ((PointsDTO)p).getPairValue().split(";"); clickMatrix[Integer.parseInt(indexes[0])][Integer.parseInt(indexes[1])] += 1; }); -// for(int i=0 ; i<300; i++) { -// for(int j = 0; j<400;j++) { -// clickMatrix[i][j] = true; -// } -// } return clickMatrix; } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java index 7c2feb1..ef7f784 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java @@ -1,9 +1,12 @@ package com.academy.web.controller; +import com.academy.model.PointsWrapper; import com.academy.service.ActivityService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.Iterator; + /** * Created by Daniel Palonek on 2016-10-25. */ @@ -14,12 +17,12 @@ public class ActivitiesController { @Autowired private ActivityService activityService; - @RequestMapping(value = "/log/{wName}/{sName}/{res}", method = RequestMethod.POST) + @RequestMapping(value = "/log/{wName}/{sName}/{res}", method = RequestMethod.POST, consumes = "application/json") public void logActivity(@PathVariable("wName") String websiteName, @PathVariable("sName") String subpageName, @PathVariable("res") String resolution, - Iterable points) { - activityService.logActivity(websiteName, subpageName, resolution, points); + @RequestBody PointsWrapper points) { + activityService.logActivity(websiteName, subpageName, resolution, points.getPoints()); } } diff --git a/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js index 027e44e..8cd1e97 100644 --- a/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/public/accountControllers.js @@ -25,6 +25,23 @@ accountControllers.controller('AccountController', ['$scope', '$routeParams', '$ $scope.thirdEmpty = true; $scope.fourthEmpty = true; + document.body.addEventListener("click", logActivity, false); + + function logActivity(e) { + var x = e.clientX; + var y = e.clientY; + var w = $(document).width(); + var h = $(document).height(); + var xhr = new XMLHttpRequest(); + xhr.open("POST", "http://localhost:8080/activities/log/www.clickmapactivity.com/Register/" + w + "x" + h, false); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.send(JSON.stringify({ + points: [ + x + ";" + y + ] + })); + } + $scope.checkUsernameValidate = function() { AccountService.checkIfAccountExist({username: $scope.username}, function (rsp) { $scope.isUserNameExisted = rsp.value; diff --git a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js index 6bda826..85d8557 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js +++ b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js @@ -8,7 +8,8 @@ var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'IndexControlle mainApp.config(['$routeProvider', function ($routeProvider) { $routeProvider. when('/register', { - templateUrl: '/public/register.html' + templateUrl: '/public/register.html', + controller: 'AccountController' }). when('/main', { templateUrl: '/public/main.html', From c832c18ac7c37561eaf49c772edb9f51e780d992 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Mon, 21 Nov 2016 20:33:44 +0100 Subject: [PATCH 14/21] Almost done selecting date range of click map --- .../java/com/academy/cache/UserCache.java | 18 +++-- .../com/academy/service/ActivityService.java | 9 ++- .../com/academy/service/SubpageService.java | 30 ++++--- .../com/academy/web/config/CacheLoader.java | 10 ++- .../web/controller/SubpagesController.java | 6 +- .../src/main/resources/js/bower.json | 5 +- .../resources/js/user/subpagesControllers.js | 78 +++++++++++++++--- .../resources/js/user/subpagesServices.js | 6 +- .../main/resources/templates/user/image.html | 79 ++++++++++++++++++- .../resources/templates/user/subpages.html | 2 +- .../resources/templates/user/userIndex.html | 31 ++++++-- 11 files changed, 225 insertions(+), 49 deletions(-) diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java index ab29c62..ceb4fd9 100644 --- a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java @@ -1,10 +1,7 @@ package com.academy.cache; -import org.hibernate.mapping.Array; import org.springframework.stereotype.Component; -import sun.text.CollatorUtilities; -import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -49,12 +46,19 @@ public Object getRequestedWebsite() { return getUserContext().getOrDefault(CacheConstants.REQUESTED_WEBSITE,null); } - public void setWebsiteSubpages(Long websiteId, Iterable subpages) { - getMap(CacheConstants.WEBSITE_SUBPAGES).set(websiteId,subpages); + public void setWebsiteSubpages(Long websiteId, Map subpages) { + getMap(CacheConstants.WEBSITE_SUBPAGES).set(websiteId, subpages); } - public Iterable getWebsiteSubpages(Long websiteId) { - return (Iterable)getMap(CacheConstants.WEBSITE_SUBPAGES).get(websiteId); + public void updateWebsiteSubpage(Long websiteId, Long subpageId, Object subpage) { + Map subpages = (Map)getMap(CacheConstants.WEBSITE_SUBPAGES).get(websiteId); + subpages.put(subpageId, subpage); + getMap(CacheConstants.WEBSITE_SUBPAGES).set(websiteId, subpages); + } + + public Iterable getWebsiteSubpages(Long key) { + Map subpages = (Map)getMap(CacheConstants.WEBSITE_SUBPAGES).get(key); + return subpages.entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toList()); } public void deleteWebsiteSubpages(Long websiteId) { diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java index 9a1f00d..d5db3e5 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java @@ -11,15 +11,13 @@ import com.academy.service.mappers.PointsMapper; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.hibernate.mapping.Array; -import org.hibernate.mapping.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -62,6 +60,9 @@ public void logActivity(String websiteName, String subpageName, String resolutio } points = adjustResolution(subpageDTO.getResX(), subpageDTO.getResY(), resolution, pointsList); Activity activity = insertActivity(receivedTime, subpageDTO.getId()); + subpageDTO.setLastUpdateEpoch(activity.getDate().toInstant(ZoneOffset.UTC).getEpochSecond()); + subpageDTO.setDisplays(new Long(((Collection)cache.getSubpageActivities(subpageDTO.getId())).size())); + cache.updateWebsiteSubpage(websiteDTO.getId(), subpageDTO.getId(), subpageDTO); if (activity == null) { LOGGER.warn("Could not insert activity for request from site [" + websiteName + "] and subpage [" + subpageName + "]"); return; diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 7af6ee9..6924a5c 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -15,20 +15,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.imageio.ImageIO; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.*; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.StreamSupport; /** @@ -51,7 +51,7 @@ public boolean saveSubpage(String name, MultipartFile file, RedirectAttributes r if(!f.exists()) f.mkdirs(); f = new File("ClickMapActivity-web/src/main/resources/images/" + websiteDTO.getId() + "/" + name); - final SubpageDTO subpageDTO = new SubpageDTO(); + SubpageDTO subpageDTO = new SubpageDTO(); BufferedImage img = ImageIO.read(file.getInputStream()); img = ImageConverter.grayScale(img); ImageIO.write(img, "png", f); @@ -59,8 +59,8 @@ public boolean saveSubpage(String name, MultipartFile file, RedirectAttributes r subpageDTO.setResX(img.getWidth()); subpageDTO.setResY(img.getHeight()); subpageDTO.setWebsiteId(((WebsiteDTO) cache.getRequestedWebsite()).getId()); - repo.save(mapper.convertToDAO(subpageDTO)); - cache.setWebsiteSubpages(websiteDTO.getId(),mapper.convertToDTO(repo.getByWebsiteId(websiteDTO.getId()))); + subpageDTO = mapper.convertToDTO(repo.save(mapper.convertToDAO(subpageDTO))); + cache.updateWebsiteSubpage(websiteDTO.getId(), subpageDTO.getId(), subpageDTO); redAttr.addAttribute("websiteUrl", websiteDTO.getUrl()); return true; }catch(IOException e) { @@ -81,9 +81,14 @@ public SubpageDTO getByNameAndWebsiteId(String name, Long websiteId) { return mapper.convertToDTO(repo.findByNameAndWebsiteId(name,websiteId)); } - public void getImage(String name, HttpServletResponse response) { + public void getImage(String name, String dateFromChain, String dateToChain, HttpServletResponse response) { final WebsiteDTO website = (WebsiteDTO) cache.getRequestedWebsite(); + if(website == null) { + return; + } try { + final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.replace(" ", "T")); + final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.replace(" ", "T")); File f = new File("ClickMapActivity-web/src/main/resources/images/" + website.getId() + "/" + name); BufferedImage img = ImageIO.read(f); ByteArrayOutputStream outStr = new ByteArrayOutputStream(); @@ -91,7 +96,9 @@ public void getImage(String name, HttpServletResponse response) { Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); List points = new ArrayList<>(); if(activities != null) { - activities.stream().forEach(a -> points.addAll((Collection) cache.getActivityPoints(a.getId()))); + activities.stream() + .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .forEach(a -> points.addAll((Collection) cache.getActivityPoints(a.getId()))); } int [][] clickMatrix = ImageConverter.makeClickMatrix(points,img.getWidth(),img.getHeight()); img = ImageConverter.fillPointsMap(img,clickMatrix); @@ -100,7 +107,7 @@ public void getImage(String name, HttpServletResponse response) { IOUtils.copy(inputStream, response.getOutputStream()); response.flushBuffer(); inputStream.close(); - } catch (IOException e) { + } catch (Exception e) { LOGGER.warn(e.getMessage()); } } @@ -113,7 +120,10 @@ public boolean delete(final String name) { return false; } repo.deleteByNameAndWebsiteId(name,websiteId); - cache.setWebsiteSubpages(websiteId,getSubgapesForWebsiteId(websiteId)); + cache.setWebsiteSubpages(websiteId, + StreamSupport.stream(getSubgapesForWebsiteId(websiteId).spliterator(), true) + .collect(Collectors.toMap(SubpageDTO::getId, Function.identity())) + ); return true; } catch(Exception e) { LOGGER.warn(e.getMessage()); diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java index 9fc226c..dc26d44 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java @@ -1,7 +1,10 @@ package com.academy.web.config; import com.academy.cache.UserCache; -import com.academy.model.dto.*; +import com.academy.model.dto.ActivityDTO; +import com.academy.model.dto.PointsDTO; +import com.academy.model.dto.SubpageDTO; +import com.academy.model.dto.WebsiteDTO; import com.academy.service.ActivityService; import com.academy.service.PointsService; import com.academy.service.SubpageService; @@ -12,6 +15,9 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collection; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * Created by Daniel Palonek on 2016-10-20. @@ -54,7 +60,7 @@ public void load(final String username) { s.setLastUpdateEpoch(new ArrayList<>(activities).get(activities.size() - 1).getDate().toInstant(ZoneOffset.UTC).getEpochSecond()); } }); - cache.setWebsiteSubpages(w.getId(), subpages); + cache.setWebsiteSubpages(w.getId(), StreamSupport.stream(subpages.spliterator(), false).collect(Collectors.toMap(SubpageDTO::getId, Function.identity()))); }); } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index afd5961..3dbf59a 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -52,10 +52,12 @@ public Iterable getByWebsiteId() { return cache.getWebsiteSubpages(website.getId()); } - @RequestMapping(value = "/images/{name:.+}", method = RequestMethod.GET) + @RequestMapping(value = "/images/{name:.+}/{dateFrom}/{dateTo}", method = RequestMethod.GET) public void getSubpageImage(@PathVariable("name") String name, + @PathVariable("dateFrom") String dateFrom, + @PathVariable("dateTo") String dateTo, HttpServletResponse response) { - service.getImage(name,response); + service.getImage(name, dateFrom, dateTo, response); } @RequestMapping(value = "/delete/{name}", method = RequestMethod.DELETE) diff --git a/ClickMapActivity-web/src/main/resources/js/bower.json b/ClickMapActivity-web/src/main/resources/js/bower.json index c5634f3..28c0873 100644 --- a/ClickMapActivity-web/src/main/resources/js/bower.json +++ b/ClickMapActivity-web/src/main/resources/js/bower.json @@ -26,7 +26,10 @@ "angular-modal-service": "latest", "angular-file-model": "latest", "bootstrap": "latest", - "jquery-circle-progress": "latest" + "moment": "latest", + "jquery": "latest", + "jquery-circle-progress": "latest", + "eonasdan-bootstrap-datetimepicker": "^4.17.43" }, "resolutions": { "angular": "1.5.5" diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index 0326501..d842c08 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -3,8 +3,8 @@ */ var SubpagesControllers = angular.module('SubpagesControllers', []); -SubpagesControllers.controller('SubpagesController', ['$scope', '$route', '$timeout', '$location', '$routeParams', 'SubpagesService', 'WebsitesService', 'WebsitesServiceRepo', - function ($scope, $route, $timeout, $location, $routeParams, SubpagesService, WebsitesService, WebsitesServiceRepo) { +SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route', '$timeout', '$location', '$routeParams', 'SubpagesService', 'WebsitesService', 'WebsitesServiceRepo', + function ($scope, $http, $route, $timeout, $location, $routeParams, SubpagesService, WebsitesService, WebsitesServiceRepo) { $scope.shouldShow = true; $scope.subpages = {}; $scope.isSubpageExists = false; @@ -12,6 +12,14 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$route', '$time $scope.isFileLoaded = false; $scope.imgName = {}; $scope.displays = {}; + $scope.dateTo = moment().format("YYYY-MM-DD HH:mm:ss"); + $scope.dateFrom = moment().subtract(1, 'hours').format("YYYY-MM-DD HH:mm:ss"); + + // var d1 = new Date(); + // var d2 = new Date(); + // d2.setHours(d1.getHours() - 1); + // $scope.dateFrom = d1.toLocaleString(); + // $scope.dateFrom = d2.toLocaleString(); SubpagesService.getByWebsiteId(function (subpages) { $scope.subpages = subpages; @@ -35,27 +43,71 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$route', '$time }) }; - $scope.loadImageName = function() { + $scope.loadImageName = function () { $scope.imgName = window.location.href.split("/subpages/image/")[1]; }; - $scope.redirectToImage = function(name) { + $scope.redirectToImage = function (name) { $location.path('/subpages/image/' + name); }; $scope.showDate = function (epoch) { - if(epoch === 0) { + if (epoch === 0) { return "Inactive"; } var date = new Date(epoch * 1000); return date.toLocaleString(); }; - // $scope.shouldShow = $(document).mouseup(function (e) { - // var container = $('#subpage-panel'); - // if(!container.is(e.target)) { - // return true; - // } - // }); - - }]); \ No newline at end of file + $scope.getDateTo = function () { + var d = new Date(); + d.setHours(d.getHours() + 1); + return d.toISOString(); + }; + + $scope.getDateFrom = function (hours) { + var d = new Date(); + d.setHours(d.getHours() + 1 - hours); + return d.toISOString(); + }; + + $scope.getSubpageImage = function (name) { + $http({ + method: 'GET', + url: '/subpages/images/name/dateFrom/dateTo', + params: {name: name, + dateFrom: $scope.dateFrom, + dateTo: $scope.dateTo}, + responseType: 'arraybuffer' + }) + .then(function (response) { + console.log(response); + var str = _arrayBufferToBase64(response.data); + console.log(str); + // str is base64 encoded. + }, function (response) { + console.error('error in getting static img.'); + }); + }; + + + function _arrayBufferToBase64(buffer) { + var binary = ''; + var bytes = new Uint8Array(buffer); + var len = bytes.byteLength; + for (var i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return window.btoa(binary); + } + + }]); + + + + + + + + + diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index ec1a339..d8aa08d 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -14,8 +14,10 @@ SubpagesServices.factory('SubpagesService', [ }, getSubpageImage: { - url: '/subpages/images/:name', - params: {name: "@name"}, + url: '/subpages/images/:name/:dateFrom/:dateTo', + params: {name: "@name", + dateFrom: "@dateFrom", + dateTo: "@dateTo"}, method: 'GET', responseType: 'arraybuffer' }, diff --git a/ClickMapActivity-web/src/main/resources/templates/user/image.html b/ClickMapActivity-web/src/main/resources/templates/user/image.html index 8f5f3e8..903ef0c 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/image.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/image.html @@ -1,2 +1,79 @@ + +
-
{{imgName}}
+
+
+
+
+
+
From:
+
+ + + + +
+
+
+
+
+
To:
+
+ + + + +
+
+
+
+ +
+
+ +
+
+ + + diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index bb091a1..130d2d4 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -49,7 +49,7 @@

- {{s.name}} + {{s.name}}
diff --git a/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html index 5a8466a..b158b4e 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/userIndex.html @@ -6,22 +6,41 @@ Click Map Activity - improve your site now! + + + + - - - - - - + + , + + + + + + + + + + + + + + + + + + + From a796d38078f5b7c7e484e1d8782e387555946829 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 22 Nov 2016 00:14:29 +0100 Subject: [PATCH 15/21] Select date range is now done --- .../java/com/academy/repo/PointsRepo.java | 4 +++ .../com/academy/service/PointsService.java | 6 +++++ .../com/academy/web/config/CacheLoader.java | 3 +-- .../web/controller/SubpagesController.java | 8 +++--- .../resources/js/user/subpagesControllers.js | 25 +++++++++++++------ .../main/resources/templates/user/image.html | 16 ++++++------ .../resources/templates/user/subpages.html | 5 +--- 7 files changed, 43 insertions(+), 24 deletions(-) diff --git a/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java index c4cd7e0..3e509b4 100644 --- a/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java @@ -3,6 +3,8 @@ import com.academy.model.dao.Points; import org.springframework.data.repository.CrudRepository; +import java.util.Set; + /** * Created by Daniel Palonek on 2016-08-19. */ @@ -10,4 +12,6 @@ public interface PointsRepo extends CrudRepository { Iterable findByActivityId(Long activityId); + Iterable findByActivityIdIn(Set activityIdSet); + } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java index fd19f49..7c04454 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java @@ -8,6 +8,8 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Service; +import java.util.Set; + /** * Created by Daniel Palonek on 2016-08-19. */ @@ -27,4 +29,8 @@ public Iterable getByActivityId(Long activityId) { return mapper.convertToDTO(repo.findByActivityId(activityId)); } + public Iterable getByActivityIds(Set activityIds) { + return mapper.convertToDTO(repo.findByActivityIdIn(activityIds)); + } + } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java index dc26d44..bd6436e 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java @@ -13,8 +13,7 @@ import org.springframework.stereotype.Component; import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Collection; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index 3dbf59a..195b682 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -52,10 +52,10 @@ public Iterable getByWebsiteId() { return cache.getWebsiteSubpages(website.getId()); } - @RequestMapping(value = "/images/{name:.+}/{dateFrom}/{dateTo}", method = RequestMethod.GET) - public void getSubpageImage(@PathVariable("name") String name, - @PathVariable("dateFrom") String dateFrom, - @PathVariable("dateTo") String dateTo, + @RequestMapping(value = "/images/get", method = RequestMethod.GET) + public void getSubpageImage(@RequestParam("name") String name, + @RequestParam("dateFrom") String dateFrom, + @RequestParam("dateTo") String dateTo, HttpServletResponse response) { service.getImage(name, dateFrom, dateTo, response); } diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index d842c08..48a66c8 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -15,6 +15,8 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route $scope.dateTo = moment().format("YYYY-MM-DD HH:mm:ss"); $scope.dateFrom = moment().subtract(1, 'hours').format("YYYY-MM-DD HH:mm:ss"); + $scope.img = {}; + // var d1 = new Date(); // var d2 = new Date(); // d2.setHours(d1.getHours() - 1); @@ -71,20 +73,29 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route return d.toISOString(); }; + $('#datetimepicker6').on('dp.change', function(e) { + $scope.dateFrom = e.date.format(("YYYY-MM-DD HH:mm:ss")) ; + }); + + $('#datetimepicker7').on('dp.change', function(e) { + $scope.dateTo = e.date.format(("YYYY-MM-DD HH:mm:ss")) ; + }); + $scope.getSubpageImage = function (name) { + $scope.isFileLoaded = false; $http({ method: 'GET', - url: '/subpages/images/name/dateFrom/dateTo', - params: {name: name, + url: '/subpages/images/get', + params: { + name: name, dateFrom: $scope.dateFrom, - dateTo: $scope.dateTo}, + dateTo: $scope.dateTo + }, responseType: 'arraybuffer' }) .then(function (response) { - console.log(response); - var str = _arrayBufferToBase64(response.data); - console.log(str); - // str is base64 encoded. + $scope.img = _arrayBufferToBase64(response.data); + $scope.isFileLoaded = true; }, function (response) { console.error('error in getting static img.'); }); diff --git a/ClickMapActivity-web/src/main/resources/templates/user/image.html b/ClickMapActivity-web/src/main/resources/templates/user/image.html index 903ef0c..ddfc46b 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/image.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/image.html @@ -23,7 +23,7 @@ -
+
From 290336ff8b6a68b9ccdab27b29aea0e55cc1287d Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Sun, 11 Dec 2016 17:09:47 +0100 Subject: [PATCH 16/21] Statistic chart prepared, remained only provide data --- .../java/com/academy/cache/UserCache.java | 3 + .../src/main/resources/hazelcast.xml | 16 ++-- .../com/academy/service/SubpageService.java | 9 ++- .../academy/service/tools/ImageConverter.java | 16 ++-- .../com/academy/web/config/CacheLoader.java | 4 +- .../src/main/resources/app.properties | 2 +- .../resources/js/user/subpagesControllers.js | 74 +++++++++++++++++++ .../resources/js/user/subpagesServices.js | 15 ++-- .../resources/js/user/userRouteProvider.js | 2 +- .../resources/templates/user/css/subpages.css | 2 +- .../main/resources/templates/user/image.html | 12 +++ .../resources/templates/user/subpages.html | 5 ++ .../resources/templates/user/userIndex.html | 4 + .../resources/templates/user/websites.html | 2 +- 14 files changed, 133 insertions(+), 33 deletions(-) diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java index ceb4fd9..6300301 100644 --- a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java @@ -52,6 +52,9 @@ public void setWebsiteSubpages(Long websiteId, Map subpages) { public void updateWebsiteSubpage(Long websiteId, Long subpageId, Object subpage) { Map subpages = (Map)getMap(CacheConstants.WEBSITE_SUBPAGES).get(websiteId); + if(subpages == null) { + subpages = new HashMap<>(); + } subpages.put(subpageId, subpage); getMap(CacheConstants.WEBSITE_SUBPAGES).set(websiteId, subpages); } diff --git a/ClickMapActivity-cache/src/main/resources/hazelcast.xml b/ClickMapActivity-cache/src/main/resources/hazelcast.xml index 97c7fad..5e52783 100644 --- a/ClickMapActivity-cache/src/main/resources/hazelcast.xml +++ b/ClickMapActivity-cache/src/main/resources/hazelcast.xml @@ -97,8 +97,8 @@ BINARY 1 0 - 0 - 0 + 24000 + 24000 LRU 0 com.hazelcast.map.merge.PutIfAbsentMapMergePolicy @@ -108,8 +108,8 @@ BINARY 1 0 - 0 - 0 + 24000 + 24000 LRU 0 com.hazelcast.map.merge.PutIfAbsentMapMergePolicy @@ -119,8 +119,8 @@ BINARY 1 0 - 0 - 0 + 24000 + 24000 LRU 0 com.hazelcast.map.merge.PutIfAbsentMapMergePolicy @@ -130,8 +130,8 @@ BINARY 1 0 - 0 - 0 + 24000 + 24000 LRU 0 com.hazelcast.map.merge.PutIfAbsentMapMergePolicy diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 6924a5c..3a6a0c6 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -6,6 +6,7 @@ import com.academy.model.dto.PointsDTO; import com.academy.model.dto.SubpageDTO; import com.academy.model.dto.WebsiteDTO; +import com.academy.repo.PointsRepo; import com.academy.repo.SubpageRepo; import com.academy.service.mappers.SubpageMapper; import com.academy.service.tools.ImageConverter; @@ -43,6 +44,9 @@ public class SubpageService extends AbstractService a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) - .forEach(a -> points.addAll((Collection) cache.getActivityPoints(a.getId()))); + .forEach(a -> points.addAll((Collection)cache.getActivityPoints(a.getId()))); } int [][] clickMatrix = ImageConverter.makeClickMatrix(points,img.getWidth(),img.getHeight()); img = ImageConverter.fillPointsMap(img,clickMatrix); @@ -107,6 +112,8 @@ public void getImage(String name, String dateFromChain, String dateToChain, Http IOUtils.copy(inputStream, response.getOutputStream()); response.flushBuffer(); inputStream.close(); + final long end = System.currentTimeMillis(); + LOGGER.info("Fetched image in: " + (end - start) + "milis"); } catch (Exception e) { LOGGER.warn(e.getMessage()); } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java index 66e72c7..a984d13 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java @@ -1,6 +1,8 @@ package com.academy.service.tools; import com.academy.model.dto.PointsDTO; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; import java.awt.*; import java.awt.image.BufferedImage; @@ -12,25 +14,17 @@ public class ImageConverter { public static BufferedImage grayScale(BufferedImage original) { - - int alpha, red, green, blue; - int newPixel; - + int alpha, red, green, blue, newPixel; BufferedImage avg_gray = new BufferedImage(original.getWidth(), original.getHeight(), original.getType()); - int[] avgLUT = new int[766]; - for(int i=0; i websites = websiteService.getUserWebsites(); @@ -48,7 +50,7 @@ public void load(final String username) { subpages.forEach(s-> { Collection activities = (Collection)activityService.getBySubpageId(s.getId()); cache.setSubpageActivities(s.getId(), activities); - activities.stream() + activities.parallelStream() .sorted((a1,a2) -> a1.getDate().compareTo(a2.getDate())) .forEach(a-> { Iterable points = pointsService.getByActivityId(a.getId()); diff --git a/ClickMapActivity-web/src/main/resources/app.properties b/ClickMapActivity-web/src/main/resources/app.properties index 89193c2..f25c722 100644 --- a/ClickMapActivity-web/src/main/resources/app.properties +++ b/ClickMapActivity-web/src/main/resources/app.properties @@ -12,7 +12,7 @@ spring.thymeleaf.cache=false hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect hibernate.hbm2ddl.auto=update hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy -hibernate.show_sql=true +hibernate.show_sql=false hibernate.format_sql=true multipart.maxFileSize: 128MB diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index 48a66c8..fac42ec 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -14,9 +14,75 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route $scope.displays = {}; $scope.dateTo = moment().format("YYYY-MM-DD HH:mm:ss"); $scope.dateFrom = moment().subtract(1, 'hours').format("YYYY-MM-DD HH:mm:ss"); + $scope.granulation = {}; + $scope.data = {}; $scope.img = {}; + $scope.options = { + chart: { + type: 'multiBarChart', + height: 400, + margin : { + top: 20, + right: 20, + bottom: 45, + left: 45 + }, + clipEdge: true, + //staggerLabels: true, + duration: 500, + stacked: true, + xAxis: { + axisLabel: 'Date (day)', + showMaxMin: false, + tickFormat: function(d){ + return d3.format(',f')(d); + } + }, + yAxis: { + axisLabel: 'Clicks', + axisLabelDistance: -20, + tickFormat: function(d){ + return d3.format(',.1f')(d); + } + }, + color: ['#7a43b6'] + } + }; + + function generateData() { + return stream_layers(1,100+Math.random()*50,.1).map(function(data, i) { + return { + key: 'Stream', + values: data + }; + }); + } + + function stream_layers(n, m, o) { + if (arguments.length < 3) o = 0; + function bump(a) { + var x = 1 / (.1 + Math.random()), + y = 2 * Math.random() - .5, + z = 10 / (.1 + Math.random()); + for (var i = 0; i < m; i++) { + var w = (i / m - y) * z; + a[i] += x * Math.exp(-w * w); + } + } + return d3.range(n).map(function() { + var a = [], i; + for (i = 0; i < m; i++) a[i] = o + o * Math.random(); + for (i = 0; i < 5; i++) bump(a); + return a.map(stream_index); + }); + } + + function stream_index(d, i) { + return {x: i, y: Math.max(0, d)}; + } + // var d1 = new Date(); // var d2 = new Date(); // d2.setHours(d1.getHours() - 1); @@ -101,6 +167,14 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route }); }; + $scope.getChartData = function() { + SubpagesService.getChartData({dateFrom: $scope.dateFrom, + dateTo: $scope.dateTo, + gran: $scope.granulation}, function (rsp) { + $scope.data = rsp; + }) + }; + function _arrayBufferToBase64(buffer) { var binary = ''; diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index d8aa08d..3071c53 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -13,15 +13,14 @@ SubpagesServices.factory('SubpagesService', [ isArray: true }, - getSubpageImage: { - url: '/subpages/images/:name/:dateFrom/:dateTo', - params: {name: "@name", - dateFrom: "@dateFrom", - dateTo: "@dateTo"}, - method: 'GET', - responseType: 'arraybuffer' + getChartData: { + url: '/subpages/chart/:dateFrom/:dateTo/:gran', + params: {dateFrom: "@dateFrom", + dateTo: "@dateTo", + gran: "@gran"}, + method: 'GET' }, - + deleteSubpage: { url: '/subpages/delete/:name', params: {name: '@name'}, diff --git a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js index 85d8557..b26b2a2 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js +++ b/ClickMapActivity-web/src/main/resources/js/user/userRouteProvider.js @@ -3,7 +3,7 @@ */ var mainApp = angular.module("mainApp", ['ngRoute', 'ngAnimate', 'IndexControllers', 'IndexServices', 'AccountControllers', 'WebsitesControllers', 'WebsitesServices', 'SubpagesControllers', 'SubpagesServices','AccountServices', - 'ui.grid', 'ui.grid.pagination']); + 'ui.grid', 'ui.grid.pagination', 'nvd3']); mainApp.config(['$routeProvider', function ($routeProvider) { $routeProvider. diff --git a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css index 6601e45..7aff838 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css +++ b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css @@ -214,7 +214,7 @@ margin-top: 10%; } -#subpage-name { +#subpage-name, #subpage-url { margin: 8% 0% 0% 23%; } diff --git a/ClickMapActivity-web/src/main/resources/templates/user/image.html b/ClickMapActivity-web/src/main/resources/templates/user/image.html index ddfc46b..ce74bd9 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/image.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/image.html @@ -49,6 +49,17 @@
+
+
+
Granulation:
+
+ +
+
+
+
diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index 2d84a9c..f06b854 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -83,6 +83,11 @@

Browse +
+ + +
+ + + + diff --git a/ClickMapActivity-web/src/main/resources/templates/user/websites.html b/ClickMapActivity-web/src/main/resources/templates/user/websites.html index 757303b..0d08e81 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/websites.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/websites.html @@ -82,7 +82,7 @@

Your websites

- +

From 2cbc9375bfd59f56242b5ef4b386ce5fcd56fb35 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 13 Dec 2016 21:57:02 +0100 Subject: [PATCH 17/21] Done hourly and daily statistic chart --- .../java/com/academy/model/ChartData.java | 32 ++++++++ .../com/academy/model/ChartResponseData.java | 33 ++++++++ .../com/academy/service/SubpageService.java | 78 ++++++++++++++++++- .../web/controller/SubpagesController.java | 11 +++ .../resources/js/user/subpagesControllers.js | 38 +++++---- .../resources/js/user/subpagesServices.js | 8 +- .../main/resources/templates/user/image.html | 21 ++--- 7 files changed, 187 insertions(+), 34 deletions(-) create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/ChartData.java create mode 100644 ClickMapActivity-model/src/main/java/com/academy/model/ChartResponseData.java diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/ChartData.java b/ClickMapActivity-model/src/main/java/com/academy/model/ChartData.java new file mode 100644 index 0000000..926383e --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/ChartData.java @@ -0,0 +1,32 @@ +package com.academy.model; + +/** + * Created by Daniel Palonek on 2016-12-12. + */ +public class ChartData { + + private String x; + private long y; + + public ChartData(String x, long y) { + this.x = x; + this.y = y; + } + + public String getX() { + return x; + } + + public void setX(String x) { + this.x = x; + } + + public long getY() { + return y; + } + + public void setY(long y) { + this.y = y; + } + +} diff --git a/ClickMapActivity-model/src/main/java/com/academy/model/ChartResponseData.java b/ClickMapActivity-model/src/main/java/com/academy/model/ChartResponseData.java new file mode 100644 index 0000000..9f99839 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/ChartResponseData.java @@ -0,0 +1,33 @@ +package com.academy.model; + +import java.util.List; + +/** + * Created by Daniel Palonek on 2016-12-12. + */ +public class ChartResponseData { + + private String key; + private List values; + + public ChartResponseData(String key, List values) { + this.key = key; + this.values = values; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + } +} diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 3a6a0c6..1f2d2b3 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -1,12 +1,13 @@ package com.academy.service; import com.academy.cache.UserCache; +import com.academy.model.ChartData; +import com.academy.model.ChartResponseData; import com.academy.model.dao.Subpage; import com.academy.model.dto.ActivityDTO; import com.academy.model.dto.PointsDTO; import com.academy.model.dto.SubpageDTO; import com.academy.model.dto.WebsiteDTO; -import com.academy.repo.PointsRepo; import com.academy.repo.SubpageRepo; import com.academy.service.mappers.SubpageMapper; import com.academy.service.tools.ImageConverter; @@ -25,11 +26,12 @@ import java.io.*; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.stream.StreamSupport; /** @@ -119,6 +121,74 @@ public void getImage(String name, String dateFromChain, String dateToChain, Http } } + public Iterable getChartData(String dateFromChain, String dateToChain, String granulation, String name) { + final WebsiteDTO website = (WebsiteDTO) cache.getRequestedWebsite(); + if(website == null) { + return Collections.EMPTY_LIST; + } + final SubpageDTO subpage = mapper.convertToDTO(repo.findByNameAndWebsiteId(name, website.getId())); + if (subpage == null) { + return Collections.EMPTY_LIST; + } + if("day".equals(granulation)) { + return getChartResponseDaily(dateFromChain, dateToChain, subpage); + } else if("hour".equals(granulation)) { + return getChartResponseHourly(dateFromChain, dateToChain, subpage); + } + return Collections.EMPTY_LIST; + } + + private Iterable getChartResponseHourly(String dateFromChain, String dateToChain, SubpageDTO subpage) { + Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); + final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.substring(0,dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.substring(0,dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + Map periodOccurances = activities.stream() + .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .map(a -> LocalDateTime.parse(a.getDate().toString().replace("T", " ").substring(0, a.getDate().toString().length() - (a.getDate().toString().length() > 16 ? 6 : 3)), DateTimeFormatter.ofPattern("yyyy-MM-dd kk"))) + .collect(Collectors.groupingBy(a -> a, Collectors.counting())); + long hoursCount = ChronoUnit.HOURS.between(dateFrom, dateTo); + List values = new LinkedList<>(); + for(long i = 0; i < hoursCount + 1; i++) { + String incrementedDate = dateFrom.plusHours(i).toString(); + LocalDateTime parsedDate = magicDateParse(incrementedDate); + values.add(new ChartData(parsedDate.toString(), 0)); + } + for(long i = 0; i < values.size(); i++) { + String incrementedDate = dateFrom.plusHours(i).toString(); + LocalDateTime parsedDate = magicDateParse(incrementedDate); + if (periodOccurances.get(parsedDate) != null) { + values.get(Math.toIntExact(i)).setY(periodOccurances.get(parsedDate)); + } + } + return Collections.singletonList((new ChartResponseData("Clicks", values))); + } + + private LocalDateTime magicDateParse(String dateToParse) { + return LocalDateTime.parse(dateToParse.replace("T", " ").substring(0, dateToParse.length() - (dateToParse.length() > 16 ? 6 : 3)), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + } + + private Iterable getChartResponseDaily(String dateFromChain, String dateToChain, SubpageDTO subpage) { + Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); + final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.replace(" ", "T")); + final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.replace(" ", "T")); + Map periodOccurances = activities.stream() + .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .collect(Collectors.groupingBy(a -> a.getDate().toLocalDate(), Collectors.counting())); + long daysCount = ChronoUnit.DAYS.between(dateFrom, dateTo); + List values = new LinkedList<>(); + for(long i = 0; i < daysCount + 1; i++) { + values.add(new ChartData(dateFrom.plusDays(i).toLocalDate().toString(), 0)); + } + values.add(new ChartData(dateTo.toLocalDate().toString(), 0)); + for(long i = 0; i < values.size(); i++) { + final LocalDate date = dateFrom.plusDays(i).toLocalDate(); + if (periodOccurances.get(date) != null) { + values.get(Math.toIntExact(i)).setY(periodOccurances.get(date)); + } + } + return Collections.singletonList((new ChartResponseData("Clicks", values))); + } + public boolean delete(final String name) { final Long websiteId = ((WebsiteDTO)cache.getRequestedWebsite()).getId(); try{ diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index 195b682..12013ef 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -1,6 +1,7 @@ package com.academy.web.controller; import com.academy.cache.UserCache; +import com.academy.model.ChartResponseData; import com.academy.model.ValueWrapper; import com.academy.model.dao.Subpage; import com.academy.model.dto.SubpageDTO; @@ -14,6 +15,7 @@ import org.apache.log4j.Logger; import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.apache.tomcat.util.http.parser.MediaType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -24,6 +26,7 @@ import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.*; +import java.util.Map; /** * Created by Daniel Palonek on 2016-10-06. @@ -60,6 +63,14 @@ public void getSubpageImage(@RequestParam("name") String name, service.getImage(name, dateFrom, dateTo, response); } + @RequestMapping(value = "/chart", method = RequestMethod.GET) + public Iterable getChartData(@RequestParam("dateFrom") String dateFrom, + @RequestParam("dateTo") String dateTo, + @RequestParam("gran") String granulation, + @RequestParam("name") String name) { + return service.getChartData(dateFrom, dateTo, granulation, name); + } + @RequestMapping(value = "/delete/{name}", method = RequestMethod.DELETE) public ValueWrapper deleteSubpage(@PathVariable("name") String name) { return new ValueWrapper<>(service.delete(name)); diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index fac42ec..ce3547c 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -13,8 +13,9 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route $scope.imgName = {}; $scope.displays = {}; $scope.dateTo = moment().format("YYYY-MM-DD HH:mm:ss"); - $scope.dateFrom = moment().subtract(1, 'hours').format("YYYY-MM-DD HH:mm:ss"); + $scope.dateFrom = moment().subtract(7, 'days').format("YYYY-MM-DD HH:mm:ss"); $scope.granulation = {}; + $scope.granulationTypes = ["day","hour"]; $scope.data = {}; $scope.img = {}; @@ -35,16 +36,13 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route stacked: true, xAxis: { axisLabel: 'Date (day)', - showMaxMin: false, - tickFormat: function(d){ - return d3.format(',f')(d); - } + showMaxMin: false }, yAxis: { axisLabel: 'Clicks', axisLabelDistance: -20, tickFormat: function(d){ - return d3.format(',.1f')(d); + return d3.format('')(d); } }, color: ['#7a43b6'] @@ -53,6 +51,7 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route function generateData() { return stream_layers(1,100+Math.random()*50,.1).map(function(data, i) { + console.info(data); return { key: 'Stream', values: data @@ -83,12 +82,6 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route return {x: i, y: Math.max(0, d)}; } - // var d1 = new Date(); - // var d2 = new Date(); - // d2.setHours(d1.getHours() - 1); - // $scope.dateFrom = d1.toLocaleString(); - // $scope.dateFrom = d2.toLocaleString(); - SubpagesService.getByWebsiteId(function (subpages) { $scope.subpages = subpages; }); @@ -167,12 +160,23 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route }); }; - $scope.getChartData = function() { - SubpagesService.getChartData({dateFrom: $scope.dateFrom, - dateTo: $scope.dateTo, - gran: $scope.granulation}, function (rsp) { - $scope.data = rsp; + $scope.getChartData = function (name) { + $http({ + method: 'GET', + url: '/subpages/chart', + params: { + dateFrom: $scope.dateFrom, + dateTo: $scope.dateTo, + gran: $scope.granulation, + name: name + }, + isArray: true }) + .then(function (response) { + $scope.data = response.data; + }, function (response) { + console.error('error fetchin response with chart data.'); + }); }; diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index 3071c53..12f46c6 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -14,11 +14,13 @@ SubpagesServices.factory('SubpagesService', [ }, getChartData: { - url: '/subpages/chart/:dateFrom/:dateTo/:gran', + url: '/subpages/chart', params: {dateFrom: "@dateFrom", dateTo: "@dateTo", - gran: "@gran"}, - method: 'GET' + gran: "@gran", + name: "@name"}, + method: 'GET', + isArray: true }, deleteSubpage: { diff --git a/ClickMapActivity-web/src/main/resources/templates/user/image.html b/ClickMapActivity-web/src/main/resources/templates/user/image.html index ce74bd9..0284ef2 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/image.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/image.html @@ -1,6 +1,6 @@ -
-
+
@@ -53,15 +52,16 @@
Granulation:
-
-
-
@@ -87,7 +87,8 @@
- + +

From 89c055098d7b708198a81d671fea8caf423601bb Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 20 Dec 2016 00:12:43 +0100 Subject: [PATCH 18/21] Preparing subpage capture with external API --- ClickMapActivity-cache/build.gradle | 10 ++++++++++ ClickMapActivity-repo/build.gradle | 2 +- ClickMapActivity-service/build.gradle | 1 - .../com/academy/service/SubpageService.java | 13 +++++++++++-- ClickMapActivity-web/build.gradle | 3 --- .../web/controller/ActivitiesController.java | 2 -- .../web/controller/SubpagesController.java | 17 +++++++---------- .../resources/js/user/subpagesControllers.js | 10 +++++++--- .../main/resources/js/user/subpagesServices.js | 6 ++++++ .../resources/templates/user/css/subpages.css | 2 +- .../main/resources/templates/user/subpages.html | 5 ++++- build.gradle | 7 ++----- 12 files changed, 49 insertions(+), 29 deletions(-) diff --git a/ClickMapActivity-cache/build.gradle b/ClickMapActivity-cache/build.gradle index 14f2434..7ef086b 100644 --- a/ClickMapActivity-cache/build.gradle +++ b/ClickMapActivity-cache/build.gradle @@ -1,6 +1,16 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' +apply plugin: 'java' +apply plugin: 'spring-boot' + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +repositories { + mavenCentral() +} + dependencies { compile 'com.hazelcast:hazelcast:3.7.1' compile ("org.springframework.boot:spring-boot-starter-data-jpa") diff --git a/ClickMapActivity-repo/build.gradle b/ClickMapActivity-repo/build.gradle index e1082f3..92900bf 100644 --- a/ClickMapActivity-repo/build.gradle +++ b/ClickMapActivity-repo/build.gradle @@ -2,6 +2,6 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' dependencies { - compile project(':ClickMapActivity-model') compile("org.springframework.boot:spring-boot-starter-data-jpa") + compile project (':ClickMapActivity-model') } diff --git a/ClickMapActivity-service/build.gradle b/ClickMapActivity-service/build.gradle index 54ed24e..09a535c 100644 --- a/ClickMapActivity-service/build.gradle +++ b/ClickMapActivity-service/build.gradle @@ -5,7 +5,6 @@ dependencies { compile 'org.springframework.boot:spring-boot-starter-web', 'org.springframework.boot:spring-boot-starter-security', 'com.hazelcast:hazelcast:3.7.1' - compile project(':ClickMapActivity-model') compile project(':ClickMapActivity-repo') compile project(':ClickMapActivity-cache') } diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 1f2d2b3..f9021c7 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -23,7 +23,10 @@ import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -31,7 +34,6 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.stream.StreamSupport; /** @@ -79,6 +81,10 @@ public boolean saveSubpage(String name, MultipartFile file, RedirectAttributes r return false; } + public boolean captureSubpage(String subpageUrl) { + return true; + } + public Iterable getSubgapesForWebsiteId(final Long websiteId) { return mapper.convertToDTO(repo.getByWebsiteId(websiteId)); } @@ -157,7 +163,10 @@ private Iterable getChartResponseHourly(String dateFromChain, String incrementedDate = dateFrom.plusHours(i).toString(); LocalDateTime parsedDate = magicDateParse(incrementedDate); if (periodOccurances.get(parsedDate) != null) { + values.get(Math.toIntExact(i)).setX(incrementedDate.substring(incrementedDate.length() - 5, incrementedDate.length())); values.get(Math.toIntExact(i)).setY(periodOccurances.get(parsedDate)); + } else { + values.get(Math.toIntExact(i)).setX(incrementedDate.substring(incrementedDate.length() - 5, incrementedDate.length())); } } return Collections.singletonList((new ChartResponseData("Clicks", values))); diff --git a/ClickMapActivity-web/build.gradle b/ClickMapActivity-web/build.gradle index 249bf30..fcff7a3 100644 --- a/ClickMapActivity-web/build.gradle +++ b/ClickMapActivity-web/build.gradle @@ -9,8 +9,5 @@ dependencies { 'org.springframework.boot:spring-boot-starter-thymeleaf', 'mysql:mysql-connector-java', 'com.hazelcast:hazelcast:3.7.1' - compile project(':ClickMapActivity-model') - compile project(':ClickMapActivity-repo') compile project(':ClickMapActivity-service') - compile project(':ClickMapActivity-cache') } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java index ef7f784..bacad86 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java @@ -5,8 +5,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import java.util.Iterator; - /** * Created by Daniel Palonek on 2016-10-25. */ diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index 12013ef..5007aef 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -7,26 +7,16 @@ import com.academy.model.dto.SubpageDTO; import com.academy.model.dto.WebsiteDTO; import com.academy.service.SubpageService; -import com.academy.service.tools.ImageConverter; import com.academy.web.config.RedirectUrls; -import com.hazelcast.nio.IOUtil; -import com.sun.org.apache.xpath.internal.operations.Bool; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; -import org.apache.tomcat.util.http.fileupload.IOUtils; -import org.apache.tomcat.util.http.parser.MediaType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; -import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; -import java.awt.image.BufferedImage; -import java.io.*; -import java.util.Map; /** * Created by Daniel Palonek on 2016-10-06. @@ -55,6 +45,13 @@ public Iterable getByWebsiteId() { return cache.getWebsiteSubpages(website.getId()); } + @RequestMapping(value = "/capture/{subpageUrl:.+}", method = RequestMethod.POST) + public ModelAndView captureSubpage(@PathVariable String subpageUrl) { + return new ModelAndView(service.captureSubpage(subpageUrl) ? + "redirect:/user/#/subpages/{websiteUrl}" + : RedirectUrls.ERROR_COULD_NOT_UPLOAD_SUBPAGE); + } + @RequestMapping(value = "/images/get", method = RequestMethod.GET) public void getSubpageImage(@RequestParam("name") String name, @RequestParam("dateFrom") String dateFrom, diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index ce3547c..984ef30 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -8,6 +8,7 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route $scope.shouldShow = true; $scope.subpages = {}; $scope.isSubpageExists = false; + $scope.isCaptureMode = false; $scope.websiteUrl = window.location.href.split("/subpages/")[1]; $scope.isFileLoaded = false; $scope.imgName = {}; @@ -35,7 +36,7 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route duration: 500, stacked: true, xAxis: { - axisLabel: 'Date (day)', + axisLabel: 'Date (hour)', showMaxMin: false }, yAxis: { @@ -178,8 +179,11 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route console.error('error fetchin response with chart data.'); }); }; - - + + $scope.captureSubpage = function (url) { + SubpagesService.captureSubpage({subpageUrl: url}) + }; + function _arrayBufferToBase64(buffer) { var binary = ''; var bytes = new Uint8Array(buffer); diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index 12f46c6..558e5d0 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -13,6 +13,12 @@ SubpagesServices.factory('SubpagesService', [ isArray: true }, + captureSubpage: { + url: '/subpages/capture/:subpageUrl', + method: 'POST', + params: {subpageUrl: "@subpageUrl"} + }, + getChartData: { url: '/subpages/chart', params: {dateFrom: "@dateFrom", diff --git a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css index 7aff838..07890fe 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css +++ b/ClickMapActivity-web/src/main/resources/templates/user/css/subpages.css @@ -222,7 +222,7 @@ margin: 10% 0% 0% 35%; } -#addBtn { +#addBtn, #captBtn { background-color: #7a43b6; color:white; margin: 5% 0% 10% 25%; diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index f06b854..01a64a8 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -94,7 +94,10 @@

ng-model="subpageName" name="subpageName" ng-change="checkIfExists()" required> Subpage with that name already exists. Please type different.
- + diff --git a/build.gradle b/build.gradle index 1601c71..c210d1b 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } +apply plugin: 'war' apply plugin: 'java' apply plugin: 'spring-boot' apply plugin: 'idea' @@ -29,7 +30,7 @@ springBoot { dependencies { compile("org.springframework.boot:spring-boot-starter-web") - compile("org.springframework.boot:spring-boot-starter-jetty") + compile("org.springframework.boot:spring-boot-starter-tomcat") compile("org.springframework.boot:spring-boot-starter-actuator") testCompile group: 'junit', name: 'junit', version: '4.11' } @@ -52,7 +53,3 @@ subprojects { testCompile group: 'junit', name: 'junit', version: '4.11' } } - -task wrapper(type: Wrapper) { - gradleVersion = '2.14.1' -} From 05d10127941110d3e9b73f7b29975d1934dbd026 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Tue, 20 Dec 2016 21:17:16 +0100 Subject: [PATCH 19/21] Preparing multipart get request from back end --- .../com/academy/service/SubpageService.java | 108 +++++++++++------- .../web/controller/SubpagesController.java | 5 +- .../resources/js/user/subpagesControllers.js | 1 + .../resources/templates/user/subpages.html | 2 +- 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index f9021c7..3643df3 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -15,8 +15,11 @@ import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; import org.apache.tomcat.util.http.fileupload.IOUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @@ -27,6 +30,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -41,7 +46,7 @@ */ @Service @Transactional -public class SubpageService extends AbstractService { +public class SubpageService extends AbstractService { private static final Logger LOGGER = org.apache.log4j.LogManager.getLogger(SubpageService.class); @@ -52,11 +57,11 @@ public class SubpageService extends AbstractService entity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange( + "http://api.screenshotmachine.com/?key=573ab4&size=F&format=PNG&url=" + subpageUrl, + HttpMethod.GET, entity, byte[].class, "1"); + + if (response.getStatusCode() == HttpStatus.OK) { + try { + Files.write(Paths.get("ClickMapActivity-web/src/main/resources/images/test.png"), response.getBody()); + return true; + } catch (IOException e) { + LOGGER.warn(e.getMessage()); + redAttrs.addFlashAttribute("message", "Could not upload subpage. Please try again."); + return false; + } + } + return false; } public Iterable getSubgapesForWebsiteId(final Long websiteId) { @@ -90,13 +118,13 @@ public Iterable getSubgapesForWebsiteId(final Long websiteId) { } public SubpageDTO getByNameAndWebsiteId(String name, Long websiteId) { - return mapper.convertToDTO(repo.findByNameAndWebsiteId(name,websiteId)); + return mapper.convertToDTO(repo.findByNameAndWebsiteId(name, websiteId)); } public void getImage(String name, String dateFromChain, String dateToChain, HttpServletResponse response) { final long start = System.currentTimeMillis(); final WebsiteDTO website = (WebsiteDTO) cache.getRequestedWebsite(); - if(website == null) { + if (website == null) { return; } try { @@ -105,23 +133,23 @@ public void getImage(String name, String dateFromChain, String dateToChain, Http File f = new File("ClickMapActivity-web/src/main/resources/images/" + website.getId() + "/" + name); BufferedImage img = ImageIO.read(f); ByteArrayOutputStream outStr = new ByteArrayOutputStream(); - final SubpageDTO subpage = mapper.convertToDTO(repo.findByNameAndWebsiteId(name,website.getId())); - Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); + final SubpageDTO subpage = mapper.convertToDTO(repo.findByNameAndWebsiteId(name, website.getId())); + Collection activities = (Collection) cache.getSubpageActivities(subpage.getId()); List points = new ArrayList<>(); - if(activities != null) { + if (activities != null) { activities.stream() - .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) - .forEach(a -> points.addAll((Collection)cache.getActivityPoints(a.getId()))); + .filter(a -> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .forEach(a -> points.addAll((Collection) cache.getActivityPoints(a.getId()))); } - int [][] clickMatrix = ImageConverter.makeClickMatrix(points,img.getWidth(),img.getHeight()); - img = ImageConverter.fillPointsMap(img,clickMatrix); - ImageIO.write(img,"png",outStr); + int[][] clickMatrix = ImageConverter.makeClickMatrix(points, img.getWidth(), img.getHeight()); + img = ImageConverter.fillPointsMap(img, clickMatrix); + ImageIO.write(img, "png", outStr); InputStream inputStream = new ByteArrayInputStream(outStr.toByteArray()); IOUtils.copy(inputStream, response.getOutputStream()); response.flushBuffer(); inputStream.close(); final long end = System.currentTimeMillis(); - LOGGER.info("Fetched image in: " + (end - start) + "milis"); + LOGGER.info("Fetched image in: " + (end - start) + "milis"); } catch (Exception e) { LOGGER.warn(e.getMessage()); } @@ -129,37 +157,37 @@ public void getImage(String name, String dateFromChain, String dateToChain, Http public Iterable getChartData(String dateFromChain, String dateToChain, String granulation, String name) { final WebsiteDTO website = (WebsiteDTO) cache.getRequestedWebsite(); - if(website == null) { + if (website == null) { return Collections.EMPTY_LIST; } final SubpageDTO subpage = mapper.convertToDTO(repo.findByNameAndWebsiteId(name, website.getId())); if (subpage == null) { return Collections.EMPTY_LIST; } - if("day".equals(granulation)) { + if ("day".equals(granulation)) { return getChartResponseDaily(dateFromChain, dateToChain, subpage); - } else if("hour".equals(granulation)) { + } else if ("hour".equals(granulation)) { return getChartResponseHourly(dateFromChain, dateToChain, subpage); } return Collections.EMPTY_LIST; } private Iterable getChartResponseHourly(String dateFromChain, String dateToChain, SubpageDTO subpage) { - Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); - final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.substring(0,dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); - final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.substring(0,dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + Collection activities = (Collection) cache.getSubpageActivities(subpage.getId()); + final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.substring(0, dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.substring(0, dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); Map periodOccurances = activities.stream() - .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .filter(a -> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) .map(a -> LocalDateTime.parse(a.getDate().toString().replace("T", " ").substring(0, a.getDate().toString().length() - (a.getDate().toString().length() > 16 ? 6 : 3)), DateTimeFormatter.ofPattern("yyyy-MM-dd kk"))) .collect(Collectors.groupingBy(a -> a, Collectors.counting())); long hoursCount = ChronoUnit.HOURS.between(dateFrom, dateTo); List values = new LinkedList<>(); - for(long i = 0; i < hoursCount + 1; i++) { + for (long i = 0; i < hoursCount + 1; i++) { String incrementedDate = dateFrom.plusHours(i).toString(); LocalDateTime parsedDate = magicDateParse(incrementedDate); values.add(new ChartData(parsedDate.toString(), 0)); } - for(long i = 0; i < values.size(); i++) { + for (long i = 0; i < values.size(); i++) { String incrementedDate = dateFrom.plusHours(i).toString(); LocalDateTime parsedDate = magicDateParse(incrementedDate); if (periodOccurances.get(parsedDate) != null) { @@ -177,19 +205,19 @@ private LocalDateTime magicDateParse(String dateToParse) { } private Iterable getChartResponseDaily(String dateFromChain, String dateToChain, SubpageDTO subpage) { - Collection activities = (Collection)cache.getSubpageActivities(subpage.getId()); + Collection activities = (Collection) cache.getSubpageActivities(subpage.getId()); final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.replace(" ", "T")); final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.replace(" ", "T")); Map periodOccurances = activities.stream() - .filter(a-> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) + .filter(a -> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) .collect(Collectors.groupingBy(a -> a.getDate().toLocalDate(), Collectors.counting())); long daysCount = ChronoUnit.DAYS.between(dateFrom, dateTo); List values = new LinkedList<>(); - for(long i = 0; i < daysCount + 1; i++) { + for (long i = 0; i < daysCount + 1; i++) { values.add(new ChartData(dateFrom.plusDays(i).toLocalDate().toString(), 0)); } values.add(new ChartData(dateTo.toLocalDate().toString(), 0)); - for(long i = 0; i < values.size(); i++) { + for (long i = 0; i < values.size(); i++) { final LocalDate date = dateFrom.plusDays(i).toLocalDate(); if (periodOccurances.get(date) != null) { values.get(Math.toIntExact(i)).setY(periodOccurances.get(date)); @@ -199,28 +227,28 @@ private Iterable getChartResponseDaily(String dateFromChain, } public boolean delete(final String name) { - final Long websiteId = ((WebsiteDTO)cache.getRequestedWebsite()).getId(); - try{ + final Long websiteId = ((WebsiteDTO) cache.getRequestedWebsite()).getId(); + try { File file = new File("ClickMapActivity-web/src/main/resources/images/" + websiteId + "/" + name); - if(!file.delete()) { + if (!file.delete()) { return false; } - repo.deleteByNameAndWebsiteId(name,websiteId); + repo.deleteByNameAndWebsiteId(name, websiteId); cache.setWebsiteSubpages(websiteId, StreamSupport.stream(getSubgapesForWebsiteId(websiteId).spliterator(), true) .collect(Collectors.toMap(SubpageDTO::getId, Function.identity())) ); return true; - } catch(Exception e) { + } catch (Exception e) { LOGGER.warn(e.getMessage()); return false; } } public boolean checkIfExists(String name) { - final Long websiteId = ((WebsiteDTO)cache.getRequestedWebsite()).getId(); - return StreamSupport.stream(cache.getWebsiteSubpages(websiteId).spliterator(),false) - .filter(w -> ((SubpageDTO)w).getName().equalsIgnoreCase(name)) + final Long websiteId = ((WebsiteDTO) cache.getRequestedWebsite()).getId(); + return StreamSupport.stream(cache.getWebsiteSubpages(websiteId).spliterator(), false) + .filter(w -> ((SubpageDTO) w).getName().equalsIgnoreCase(name)) .findAny().isPresent(); } diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index 5007aef..01ee032 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -46,8 +46,9 @@ public Iterable getByWebsiteId() { } @RequestMapping(value = "/capture/{subpageUrl:.+}", method = RequestMethod.POST) - public ModelAndView captureSubpage(@PathVariable String subpageUrl) { - return new ModelAndView(service.captureSubpage(subpageUrl) ? + public ModelAndView captureSubpage(@PathVariable String subpageUrl, + RedirectAttributes redAttrs) { + return new ModelAndView(service.captureSubpage(subpageUrl, redAttrs) ? "redirect:/user/#/subpages/{websiteUrl}" : RedirectUrls.ERROR_COULD_NOT_UPLOAD_SUBPAGE); } diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index 984ef30..fdd40cd 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -181,6 +181,7 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route }; $scope.captureSubpage = function (url) { + console.info("Worked!") SubpagesService.captureSubpage({subpageUrl: url}) }; diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index 01a64a8..421902b 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -69,7 +69,7 @@

Add new subpage From 8393305e64a5fc2baf96036885bb2c70e0cb49d0 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Wed, 21 Dec 2016 12:19:22 +0100 Subject: [PATCH 20/21] Done adding subpage by external API --- .../com/academy/service/SubpageService.java | 66 ++++++++++--------- .../web/controller/SubpagesController.java | 11 ++-- .../resources/js/user/subpagesControllers.js | 61 +++++++---------- .../resources/js/user/subpagesServices.js | 5 +- .../resources/templates/user/subpages.html | 12 ++-- 5 files changed, 73 insertions(+), 82 deletions(-) diff --git a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java index 3643df3..33b38ce 100644 --- a/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -56,59 +56,59 @@ public class SubpageService extends AbstractService entity = new HttpEntity<>(headers); - ResponseEntity response = restTemplate.exchange( "http://api.screenshotmachine.com/?key=573ab4&size=F&format=PNG&url=" + subpageUrl, HttpMethod.GET, entity, byte[].class, "1"); - if (response.getStatusCode() == HttpStatus.OK) { - try { - Files.write(Paths.get("ClickMapActivity-web/src/main/resources/images/test.png"), response.getBody()); - return true; - } catch (IOException e) { - LOGGER.warn(e.getMessage()); - redAttrs.addFlashAttribute("message", "Could not upload subpage. Please try again."); - return false; - } + InputStream stream = new ByteArrayInputStream(response.getBody()); + return saveSubpage(name, null, stream, redAttrs); } return false; } @@ -176,6 +176,9 @@ private Iterable getChartResponseHourly(String dateFromChain, Collection activities = (Collection) cache.getSubpageActivities(subpage.getId()); final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.substring(0, dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.substring(0, dateFromChain.length() - 6), DateTimeFormatter.ofPattern("yyyy-MM-dd kk")); + if(activities == null) { + return Collections.EMPTY_LIST; + } Map periodOccurances = activities.stream() .filter(a -> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) .map(a -> LocalDateTime.parse(a.getDate().toString().replace("T", " ").substring(0, a.getDate().toString().length() - (a.getDate().toString().length() > 16 ? 6 : 3)), DateTimeFormatter.ofPattern("yyyy-MM-dd kk"))) @@ -208,6 +211,9 @@ private Iterable getChartResponseDaily(String dateFromChain, Collection activities = (Collection) cache.getSubpageActivities(subpage.getId()); final LocalDateTime dateFrom = LocalDateTime.parse(dateFromChain.replace(" ", "T")); final LocalDateTime dateTo = LocalDateTime.parse(dateToChain.replace(" ", "T")); + if(activities == null) { + return Collections.EMPTY_LIST; + } Map periodOccurances = activities.stream() .filter(a -> a.getDate().isAfter(dateFrom) && a.getDate().isBefore(dateTo)) .collect(Collectors.groupingBy(a -> a.getDate().toLocalDate(), Collectors.counting())); diff --git a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java index 01ee032..5c0e885 100644 --- a/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -34,7 +34,7 @@ public class SubpagesController extends AbstractController getByWebsiteId() { return cache.getWebsiteSubpages(website.getId()); } - @RequestMapping(value = "/capture/{subpageUrl:.+}", method = RequestMethod.POST) - public ModelAndView captureSubpage(@PathVariable String subpageUrl, + @RequestMapping(value = "/capture/{subpageName}/{subpageUrl:.+}", method = RequestMethod.POST) + public ValueWrapper captureSubpage(@PathVariable String subpageUrl, + @PathVariable String subpageName, RedirectAttributes redAttrs) { - return new ModelAndView(service.captureSubpage(subpageUrl, redAttrs) ? - "redirect:/user/#/subpages/{websiteUrl}" - : RedirectUrls.ERROR_COULD_NOT_UPLOAD_SUBPAGE); + return new ValueWrapper<>(service.captureSubpage(subpageName, subpageUrl, redAttrs)); } @RequestMapping(value = "/images/get", method = RequestMethod.GET) diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js index fdd40cd..2269949 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesControllers.js @@ -3,19 +3,21 @@ */ var SubpagesControllers = angular.module('SubpagesControllers', []); -SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route', '$timeout', '$location', '$routeParams', 'SubpagesService', 'WebsitesService', 'WebsitesServiceRepo', - function ($scope, $http, $route, $timeout, $location, $routeParams, SubpagesService, WebsitesService, WebsitesServiceRepo) { +SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route', '$timeout', '$location', '$routeParams', 'SubpagesService', 'WebsitesService', 'WebsitesServiceRepo','toaster', + function ($scope, $http, $route, $timeout, $location, $routeParams, SubpagesService, WebsitesService, WebsitesServiceRepo, toaster) { $scope.shouldShow = true; $scope.subpages = {}; $scope.isSubpageExists = false; $scope.isCaptureMode = false; $scope.websiteUrl = window.location.href.split("/subpages/")[1]; $scope.isFileLoaded = false; + $scope.isFileChoosed = false; $scope.imgName = {}; $scope.displays = {}; $scope.dateTo = moment().format("YYYY-MM-DD HH:mm:ss"); $scope.dateFrom = moment().subtract(7, 'days').format("YYYY-MM-DD HH:mm:ss"); $scope.granulation = {}; + $scope.subpageUrl = ""; $scope.granulationTypes = ["day","hour"]; $scope.data = {}; @@ -50,39 +52,6 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route } }; - function generateData() { - return stream_layers(1,100+Math.random()*50,.1).map(function(data, i) { - console.info(data); - return { - key: 'Stream', - values: data - }; - }); - } - - function stream_layers(n, m, o) { - if (arguments.length < 3) o = 0; - function bump(a) { - var x = 1 / (.1 + Math.random()), - y = 2 * Math.random() - .5, - z = 10 / (.1 + Math.random()); - for (var i = 0; i < m; i++) { - var w = (i / m - y) * z; - a[i] += x * Math.exp(-w * w); - } - } - return d3.range(n).map(function() { - var a = [], i; - for (i = 0; i < m; i++) a[i] = o + o * Math.random(); - for (i = 0; i < 5; i++) bump(a); - return a.map(stream_index); - }); - } - - function stream_index(d, i) { - return {x: i, y: Math.max(0, d)}; - } - SubpagesService.getByWebsiteId(function (subpages) { $scope.subpages = subpages; }); @@ -179,10 +148,26 @@ SubpagesControllers.controller('SubpagesController', ['$scope', '$http', '$route console.error('error fetchin response with chart data.'); }); }; - + + $scope.setCaptureMode = function () { + $scope.isCaptureMode = $scope.subpageUrl.length > 0; + }; + $scope.captureSubpage = function (url) { - console.info("Worked!") - SubpagesService.captureSubpage({subpageUrl: url}) + toaster.pop({ + type: 'success', + title: 'Please wait.', + body: 'Your subpage will be added in less than minute.' + }); + SubpagesService.captureSubpage({subpageName: $scope.subpageName , subpageUrl: url}, function (rsp) { + if(!rsp.value) { + toaster.pop({ + type: 'warning', + title: 'Addding subpage failed', + body: 'Please try again.' + }); + } + }); }; function _arrayBufferToBase64(buffer) { diff --git a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js index 558e5d0..c797e09 100644 --- a/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js +++ b/ClickMapActivity-web/src/main/resources/js/user/subpagesServices.js @@ -14,9 +14,10 @@ SubpagesServices.factory('SubpagesService', [ }, captureSubpage: { - url: '/subpages/capture/:subpageUrl', + url: '/subpages/capture/:subpageName/:subpageUrl', method: 'POST', - params: {subpageUrl: "@subpageUrl"} + params: {subpageUrl: "@subpageUrl", + subpageName: "@subpageName"} }, getChartData: { diff --git a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html index 421902b..ab24923 100644 --- a/ClickMapActivity-web/src/main/resources/templates/user/subpages.html +++ b/ClickMapActivity-web/src/main/resources/templates/user/subpages.html @@ -76,17 +76,17 @@

-
+
+ ng-model="subpageUrl" ng-change="setCaptureMode()" name="subpageUrl">
@@ -94,10 +94,10 @@

ng-model="subpageName" name="subpageName" ng-change="checkIfExists()" required> Subpage with that name already exists. Please type different.
- -
From 6d106e415d835a92843aa9c87678f252b6c62315 Mon Sep 17 00:00:00 2001 From: Daniel Palonek Date: Mon, 16 Jan 2017 22:38:29 +0100 Subject: [PATCH 21/21] Update build scripts --- build.gradle | 24 ++++++++++++------------ settings.gradle | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index c210d1b..84387b7 100644 --- a/build.gradle +++ b/build.gradle @@ -12,17 +12,7 @@ buildscript { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } -apply plugin: 'war' -apply plugin: 'java' apply plugin: 'spring-boot' -apply plugin: 'idea' - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -repositories { - mavenCentral() -} springBoot { mainClass = "ClickMapActivity-web.src.main.java.com.academy.Application" @@ -32,12 +22,17 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-tomcat") compile("org.springframework.boot:spring-boot-starter-actuator") + compile project (':ClickMapActivity-cache') + compile project (':ClickMapActivity-model') + compile project (':ClickMapActivity-repo') + compile project (':ClickMapActivity-service') + compile project (':ClickMapActivity-web') testCompile group: 'junit', name: 'junit', version: '4.11' } -subprojects { +allprojects { apply plugin: 'java' - apply plugin: 'spring-boot' + apply plugin: 'idea' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -45,6 +40,11 @@ subprojects { repositories { mavenCentral() } +} + +subprojects { + + apply plugin: 'spring-boot' dependencies { compile("org.springframework.boot:spring-boot-starter-web") { diff --git a/settings.gradle b/settings.gradle index eb15cf6..b4061b5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,7 @@ rootProject.name = 'ClickMapActivity' -include 'ClickMapActivity-model', - 'ClickMapActivity-cache', - 'ClickMapActivity-repo', - 'ClickMapActivity-service', - 'ClickMapActivity-web' +include ':ClickMapActivity-model', + ':ClickMapActivity-cache', + ':ClickMapActivity-repo', + ':ClickMapActivity-service', + ':ClickMapActivity-web'