diff --git a/.gitignore b/.gitignore index 9a600c9..eaf1f56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -C:\Users\DankessS\workspace\ClickMapActivity\.idea +\ClickMapActivity\.idea /.idea/ +\ClickMapActivity-web\src\main\resources\js\bower_components diff --git a/ClickMapActivity-cache/build.gradle b/ClickMapActivity-cache/build.gradle new file mode 100644 index 0000000..7ef086b --- /dev/null +++ b/ClickMapActivity-cache/build.gradle @@ -0,0 +1,18 @@ +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") + compile ("org.springframework.boot:spring-boot-starter-web") +} 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..0e566c0 --- /dev/null +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/AbstractCacheSupplier.java @@ -0,0 +1,24 @@ +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; + +/** + * Created by Daniel Palonek on 2016-09-17. + */ +public abstract class AbstractCacheSupplier { + + @Autowired + private HazelcastInstance hazelcastInstance; + + protected ConcurrentMap getUserContext() { + return hazelcastInstance.getUserContext(); + } + + protected IMap getMap(String mapName) { + return hazelcastInstance.getMap(mapName); + } +} diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/CacheConstants.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/CacheConstants.java new file mode 100644 index 0000000..c448ae2 --- /dev/null +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/CacheConstants.java @@ -0,0 +1,15 @@ +package com.academy.cache; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +public class CacheConstants { + + static final String LOGGED_USERNAME = "loggedUsername"; + static final String USER_WEBSITES = "userWebsites"; + static final String REQUESTED_WEBSITE = "requestedWebsite"; + static final String WEBSITE_SUBPAGES = "websiteSubpages"; + static final String ACTIVITIES = "activities"; + static final String POINTS = "points"; + +} diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/HazelcastConfiguration.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/HazelcastConfiguration.java new file mode 100644 index 0000000..50ff8a7 --- /dev/null +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/HazelcastConfiguration.java @@ -0,0 +1,21 @@ +package com.academy.cache; + +import com.hazelcast.config.Config; +import com.hazelcast.config.XmlConfigBuilder; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.io.FileNotFoundException; + +/** + * Created by Daniel Palonek on 2016-09-05. + */ +@Configuration +public class HazelcastConfiguration { + @Bean + public HazelcastInstance config() { + return Hazelcast.newHazelcastInstance(); + } +} diff --git a/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java new file mode 100644 index 0000000..6300301 --- /dev/null +++ b/ClickMapActivity-cache/src/main/java/com/academy/cache/UserCache.java @@ -0,0 +1,107 @@ +package com.academy.cache; + +import org.springframework.stereotype.Component; + +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. + */ +@Component +public class UserCache extends AbstractCacheSupplier { + + public String getLoggedUsername() { + return (String)getUserContext().getOrDefault(CacheConstants.LOGGED_USERNAME,null); + } + + public void setLoggedUsername(String username) { + getUserContext().put(CacheConstants.LOGGED_USERNAME,username); + } + + public void removeLoggedUsername() { + getUserContext().remove(CacheConstants.LOGGED_USERNAME); + } + + public void setUserWebsites(Iterable websites) { + getMap(CacheConstants.USER_WEBSITES).set(getLoggedUsername(),websites); + } + + public Iterable getUserWebsites() { + return (Iterable)getMap(CacheConstants.USER_WEBSITES).get(getLoggedUsername()); + } + + public void removeUserWebsites() { + getMap(CacheConstants.USER_WEBSITES).remove(getLoggedUsername()); + } + + public void setRequestedWebsite(Object website) { + getUserContext().put(CacheConstants.REQUESTED_WEBSITE,website); + } + + public Object getRequestedWebsite() { + return getUserContext().getOrDefault(CacheConstants.REQUESTED_WEBSITE,null); + } + + public void setWebsiteSubpages(Long websiteId, Map subpages) { + getMap(CacheConstants.WEBSITE_SUBPAGES).set(websiteId, 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); + } + + 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) { + getMap(CacheConstants.WEBSITE_SUBPAGES).removeAsync(websiteId); + } + + 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); + } + + 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); + } + +} \ No newline at end of file diff --git a/ClickMapActivity-cache/src/main/resources/hazelcast.xml b/ClickMapActivity-cache/src/main/resources/hazelcast.xml new file mode 100644 index 0000000..5e52783 --- /dev/null +++ b/ClickMapActivity-cache/src/main/resources/hazelcast.xml @@ -0,0 +1,192 @@ + + + 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 + 24000 + 24000 + LRU + 0 + com.hazelcast.map.merge.PutIfAbsentMapMergePolicy + INDEX-ONLY + + + BINARY + 1 + 0 + 24000 + 24000 + LRU + 0 + com.hazelcast.map.merge.PutIfAbsentMapMergePolicy + INDEX-ONLY + + + BINARY + 1 + 0 + 24000 + 24000 + LRU + 0 + com.hazelcast.map.merge.PutIfAbsentMapMergePolicy + INDEX-ONLY + + + BINARY + 1 + 0 + 24000 + 24000 + 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-model/build.gradle b/ClickMapActivity-model/build.gradle index 520ffde..e8ee3d7 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' + compile group: 'org.hibernate', name: 'hibernate-java8', version: '5.2.1.Final' } 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-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-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/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/Account.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Account.java similarity index 88% 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..73348b1 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; @@ -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-model/src/main/java/com/academy/model/Activity.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Activity.java similarity index 69% 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..41d9ef1 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,6 +1,7 @@ -package com.academy.model; +package com.academy.model.dao; import javax.persistence.*; +import java.time.LocalDateTime; import java.util.Date; import java.util.Set; @@ -14,11 +15,12 @@ public class Activity { @GeneratedValue private Long id; - @OneToMany(mappedBy = "activity") + @OneToMany(mappedBy = "activity", cascade = {CascadeType.ALL}) private Set points; - private Date date; - @ManyToOne + private LocalDateTime date; + + @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) private Subpage subpage; public Long getId() { @@ -37,11 +39,11 @@ public void setPoints(Set points) { this.points = points; } - public Date getDate() { + public LocalDateTime getDate() { return date; } - public void setDate(Date date) { + public void setDate(LocalDateTime date) { this.date = 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 86% 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..3f53ad5 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; @@ -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/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/Website.java b/ClickMapActivity-model/src/main/java/com/academy/model/dao/Website.java similarity index 89% 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..b9d06a0 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; @@ -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/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..f165e88 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/ActivityDTO.java @@ -0,0 +1,42 @@ +package com.academy.model.dto; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class ActivityDTO implements Serializable { + + private Long id; + private LocalDateTime date; + private Long subpageId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public LocalDateTime getDate() { + return date; + } + + public void setDate(LocalDateTime date) { + this.date = date; + } + + public Long getSubpageId() { + return subpageId; + } + + 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 new file mode 100644 index 0000000..4c00adb --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/PointsDTO.java @@ -0,0 +1,37 @@ +package com.academy.model.dto; + +import java.io.Serializable; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class PointsDTO implements Serializable { + + 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..a558698 --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/SubpageDTO.java @@ -0,0 +1,73 @@ +package com.academy.model.dto; + +import java.io.Serializable; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class SubpageDTO implements Serializable { + + private Long id; + private String name; + private Integer resX; + private Integer resY; + private Long lastUpdateEpoch; + private Long displays; + 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; + } + + 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-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-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..21c7dae --- /dev/null +++ b/ClickMapActivity-model/src/main/java/com/academy/model/dto/WebsiteDTO.java @@ -0,0 +1,37 @@ +package com.academy.model.dto; + +import java.io.Serializable; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +public class WebsiteDTO implements Serializable { + + 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-repo/build.gradle b/ClickMapActivity-repo/build.gradle index 6f128ce..92900bf 100644 --- a/ClickMapActivity-repo/build.gradle +++ b/ClickMapActivity-repo/build.gradle @@ -1,14 +1,7 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' + compile("org.springframework.boot:spring-boot-starter-data-jpa") + compile project (':ClickMapActivity-model') } 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..5eaf6bf 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,12 @@ 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 { + + Account findAccountByUserName(String username); } 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..c6a3c16 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/ActivityRepo.java @@ -0,0 +1,13 @@ +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 { + + Iterable findBySubpageId(Long subpageId); + +} 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..3e509b4 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/PointsRepo.java @@ -0,0 +1,17 @@ +package com.academy.repo; + +import com.academy.model.dao.Points; +import org.springframework.data.repository.CrudRepository; + +import java.util.Set; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface PointsRepo extends CrudRepository { + + Iterable findByActivityId(Long activityId); + + Iterable findByActivityIdIn(Set activityIdSet); + +} 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..5ebc1f9 --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/SubpageRepo.java @@ -0,0 +1,17 @@ +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 { + + Iterable getByWebsiteId(Long websiteId); + + void deleteByNameAndWebsiteId(String name, Long websiteId); + + Subpage findByNameAndWebsiteId(String name, Long websiteId); + +} 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-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..e465e0e --- /dev/null +++ b/ClickMapActivity-repo/src/main/java/com/academy/repo/WebsiteRepo.java @@ -0,0 +1,15 @@ +package com.academy.repo; + +import com.academy.model.dao.Website; +import com.academy.model.dto.WebsiteDTO; +import org.springframework.data.repository.CrudRepository; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +public interface WebsiteRepo extends CrudRepository { + Iterable findByAccountId(Long accountId); + void deleteById(Long websiteId); + Website findByUrl(String name); + +} diff --git a/ClickMapActivity-service/build.gradle b/ClickMapActivity-service/build.gradle index 7ce2fb6..09a535c 100644 --- a/ClickMapActivity-service/build.gradle +++ b/ClickMapActivity-service/build.gradle @@ -1,14 +1,10 @@ group 'com.academy.engineer' version '1.0-SNAPSHOT' -apply plugin: 'java' - -sourceCompatibility = 1.5 - -repositories { - mavenCentral() -} - dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'org.springframework.boot:spring-boot-starter-web', + 'org.springframework.boot:spring-boot-starter-security', + 'com.hazelcast:hazelcast:3.7.1' + compile project(':ClickMapActivity-repo') + compile project(':ClickMapActivity-cache') } 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 new file mode 100644 index 0000000..ace9237 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/AccountService.java @@ -0,0 +1,56 @@ +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; +import com.academy.service.mappers.AccountMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@Service +public class AccountService extends AbstractService { + + @Autowired + UserService userService; + + @Autowired + UserCache cache; + + public boolean checkIfAccountWithGivenUsernameExists(String username) { + return !(repo.findAccountByUserName(username) == null); + } + + public boolean saveAccount(RegisterRequestBody data) { + + if(findAccountIdByUsername(data.getUsername()) != -1L) { + return false; + } + + AccountDTO accountDTO = new AccountDTO(); + 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.getUsername(), data.getPassword()); + return true; + } + + public Long findAccountIdByUsername(String username) { + Account account = repo.findAccountByUserName(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/ActivityService.java b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java new file mode 100644 index 0000000..d5db3e5 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/ActivityService.java @@ -0,0 +1,121 @@ +package com.academy.service; + +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.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.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +@Service +public class ActivityService extends AbstractService { + + private final static Logger LOGGER = LogManager.getLogger(ActivityService.class); + + @Autowired + private UserCache cache; + + @Autowired + private WebsiteService websiteService; + + @Autowired + private SubpageService subpageService; + + @Autowired + private PointsService pointsService; + + @Autowired + private PointsMapper pointsMapper; + + public void logActivity(String websiteName, String subpageName, String resolution, Iterable 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; + } + final SubpageDTO subpageDTO = subpageService.getByNameAndWebsiteId(subpageName, websiteDTO.getId()); + if (subpageDTO == null) { + LOGGER.warn("Request from authorized site [" + websiteName + "], but from unauthorized subpage [" + subpageName + "]"); + return; + } + 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; + } + final Long activityId = activity.getId(); + 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 subX, Integer subY, String pointsRes, List points) { + String[] separatedRes = pointsRes.split("x"); + List convertedPoints = new ArrayList<>(); + try { + 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) { + 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: " + + subX.toString() + "x" + subY.toString() + ", points resolution: " + pointsRes); + throw e; + } + return convertedPoints; + } + + + public Activity insertActivity(LocalDateTime date, Long subpageId) { + ActivityDTO activityDTO = new ActivityDTO(); + activityDTO.setDate(date); + activityDTO.setSubpageId(subpageId); + 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/CustUserDetailsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java new file mode 100644 index 0000000..beef21c --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/CustUserDetailsService.java @@ -0,0 +1,35 @@ +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.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/PointsService.java b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java new file mode 100644 index 0000000..7c04454 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/PointsService.java @@ -0,0 +1,36 @@ +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; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Service; + +import java.util.Set; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +@Service +public class PointsService extends AbstractService { + + private static final Logger LOGGER = LogManager.getLogger(PointsService.class); + + public Points addPointsCouple(Long activityId, String pointsCouple) { + PointsDTO pointsDTO = new PointsDTO(); + pointsDTO.setActivityId(activityId); + pointsDTO.setPairValue(pointsCouple); + return repo.save(mapper.convertToDAO(pointsDTO)); + } + + 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-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..33b38ce --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/SubpageService.java @@ -0,0 +1,261 @@ +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.SubpageRepo; +import com.academy.service.mappers.SubpageMapper; +import com.academy.service.tools.ImageConverter; +import org.apache.log4j.Logger; +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; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +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; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Created by Daniel Palonek on 2016-08-19. + */ +@Service +@Transactional +public class SubpageService extends AbstractService { + + private static final Logger LOGGER = org.apache.log4j.LogManager.getLogger(SubpageService.class); + + @Autowired + UserCache cache; + + @Autowired + PointsService pointsService; + + public boolean saveSubpage(String name, MultipartFile file, InputStream stream, RedirectAttributes redAttr) { + WebsiteDTO websiteDTO = (WebsiteDTO) cache.getRequestedWebsite(); + try { + if (stream == null) { + stream = file.getInputStream(); + } + if (websiteDTO != null) { + File f = new File("ClickMapActivity-web/src/main/resources/images/" + websiteDTO.getId()); + if (!f.exists()) + f.mkdirs(); + f = new File("ClickMapActivity-web/src/main/resources/images/" + websiteDTO.getId() + "/" + name); + processSubpage(name, websiteDTO, f, stream); + redAttr.addAttribute("websiteUrl", websiteDTO.getUrl()); + return true; + } + } catch (IOException e) { + LOGGER.warn(e.getMessage()); + redAttr.addFlashAttribute("message", "Could not upload subpage. Please try again."); + return false; + } + redAttr.addFlashAttribute("message", "Could not upload subpage. Please try again."); + return false; + } + + private void processSubpage(String name, WebsiteDTO websiteDTO, File f, InputStream stream) throws IOException { + SubpageDTO subpageDTO = new SubpageDTO(); + BufferedImage img = ImageIO.read(stream); + img = ImageConverter.grayScale(img); + ImageIO.write(img, "png", f); + subpageDTO.setName(name); + subpageDTO.setResX(img.getWidth()); + subpageDTO.setResY(img.getHeight()); + subpageDTO.setWebsiteId(((WebsiteDTO) cache.getRequestedWebsite()).getId()); + subpageDTO = mapper.convertToDTO(repo.save(mapper.convertToDAO(subpageDTO))); + cache.updateWebsiteSubpage(websiteDTO.getId(), subpageDTO.getId(), subpageDTO); + } + + public boolean captureSubpage(String name, String subpageUrl, RedirectAttributes redAttrs) { + if (!subpageUrl.startsWith("http://")) { + subpageUrl = "http://" + subpageUrl; + } + RestTemplate restTemplate = new RestTemplate(); + restTemplate.getMessageConverters().add( + new ByteArrayHttpMessageConverter()); + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM)); + HttpEntity 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) { + InputStream stream = new ByteArrayInputStream(response.getBody()); + return saveSubpage(name, null, stream, redAttrs); + } + return false; + } + + public Iterable getSubgapesForWebsiteId(final Long websiteId) { + return mapper.convertToDTO(repo.getByWebsiteId(websiteId)); + } + + public SubpageDTO getByNameAndWebsiteId(String name, Long 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) { + 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(); + 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() + .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); + 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"); + } catch (Exception e) { + LOGGER.warn(e.getMessage()); + } + } + + 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")); + 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"))) + .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)).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))); + } + + 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")); + 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())); + 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 { + File file = new File("ClickMapActivity-web/src/main/resources/images/" + websiteId + "/" + name); + if (!file.delete()) { + return false; + } + 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) { + 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)) + .findAny().isPresent(); + } + +} 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/WebsiteService.java b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java new file mode 100644 index 0000000..701027a --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/WebsiteService.java @@ -0,0 +1,49 @@ +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; + +/** + * 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.setUserWebsites(getUserWebsites()); + return true; + } + + public boolean delete(Long websiteId) { + repo.delete(websiteId); + cache.setUserWebsites(getUserWebsites()); + return true; + } + + public WebsiteDTO getByName(String name) { + return mapper.convertToDTO(repo.findByUrl(name)); + } + +} 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..b896932 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/AccountMapper.java @@ -0,0 +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. + */ +@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..51869b3 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/ActivityMapper.java @@ -0,0 +1,47 @@ +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 org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@Component +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 ? LocalDateTime.now() : 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..e6eee97 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/Mapper.java @@ -0,0 +1,26 @@ +package com.academy.service.mappers; + +import java.util.ArrayList; +import java.util.Collection; +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(m -> (DAO)convertToDAO(m)).collect(Collectors.toList()); + } + + default Iterable convertToDTO(Iterable dao) { + 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/PointsMapper.java b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java new file mode 100644 index 0000000..1e061ec --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/PointsMapper.java @@ -0,0 +1,44 @@ +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.ActivityRepo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@Component +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..89610a0 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/SubpageMapper.java @@ -0,0 +1,52 @@ +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; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@Component +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()); + dto.setDisplays(0L); + dto.setLastUpdateEpoch(0L); + if(dao.getWebsite() != null) { + dto.setWebsiteId(dao.getWebsite().getId()); + } + return dto; + } + +} 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-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..5e0e58a --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/mappers/WebsiteMapper.java @@ -0,0 +1,44 @@ +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; +import org.springframework.stereotype.Component; + +/** + * Created by Daniel Palonek on 2016-08-18. + */ +@Component +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; + } + +} 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 new file mode 100644 index 0000000..a984d13 --- /dev/null +++ b/ClickMapActivity-service/src/main/java/com/academy/service/tools/ImageConverter.java @@ -0,0 +1,82 @@ +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; +import java.util.List; + +/** + * Created by Daniel Palonek on 2016-10-21. + */ +public class ImageConverter { + + public static BufferedImage grayScale(BufferedImage original) { + int alpha, red, green, blue, newPixel; + BufferedImage avg_gray = new BufferedImage(original.getWidth(), original.getHeight(), original.getType()); + 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; + }); + return clickMatrix; + } + +} diff --git a/ClickMapActivity-web/build.gradle b/ClickMapActivity-web/build.gradle index b268ac7..fcff7a3 100644 --- a/ClickMapActivity-web/build.gradle +++ b/ClickMapActivity-web/build.gradle @@ -1,27 +1,13 @@ 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-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 project(':ClickMapActivity-model') - compile project(':ClickMapActivity-repo') - testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'org.springframework.boot:spring-boot-starter-data-jpa', + 'org.springframework.boot:spring-boot-starter-security', + 'org.springframework.boot:spring-boot-starter-websocket', + 'org.apache.tomcat.embed:tomcat-embed-websocket', + 'org.springframework.boot:spring-boot-starter-thymeleaf', + 'mysql:mysql-connector-java', + 'com.hazelcast:hazelcast:3.7.1' + compile project(':ClickMapActivity-service') } 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 new file mode 100644 index 0000000..d8f89a6 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/CacheLoader.java @@ -0,0 +1,81 @@ +package com.academy.web.config; + +import com.academy.cache.UserCache; +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; +import com.academy.service.WebsiteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.time.ZoneOffset; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Created by Daniel Palonek on 2016-10-20. + */ +@Component +public class CacheLoader { + + @Autowired + UserCache cache; + + @Autowired + WebsiteService websiteService; + + @Autowired + SubpageService subpageService; + + @Autowired + ActivityService activityService; + + @Autowired + PointsService pointsService; + + @Async + 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.parallelStream() + .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(), StreamSupport.stream(subpages.spliterator(), false).collect(Collectors.toMap(SubpageDTO::getId, Function.identity()))); + }); + } + + public void clean() { + cache.getUserWebsites().forEach(w -> { + 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(); + cache.removeLoggedUsername(); + } +} 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..f58ddfa --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LoginAuthenticationSuccessHandler.java @@ -0,0 +1,52 @@ +package com.academy.web.config; + +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; +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 + CacheLoader cacheLoader; + + @Autowired + WebsiteService websiteService; + + 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/#"); + cacheLoader.load(auth.getName()); + break; + } + } +// stringBuilder.append(url); + redirectStrategy.sendRedirect(req,rsp,stringBuilder.toString()); + } + + +} 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 new file mode 100644 index 0000000..5005f79 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/LogoutAuthenticationSuccessHandler.java @@ -0,0 +1,28 @@ +package com.academy.web.config; + +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; +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 + CacheLoader cacheLoader; + + @Override + public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse rsp, Authentication auth) + throws IOException, ServletException { + cacheLoader.clean(); + } +} 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..930305a --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/RedirectUrls.java @@ -0,0 +1,14 @@ +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"; + public static final String ERROR_COULD_NOT_UPLOAD_SUBPAGE = HOME + ERROR + "subpageNotUploaded"; + +} \ 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 a9e998f..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("/image/**").addResourceLocations("classpath:/image/"); + 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..7df7b28 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/config/WebSecurityConfig.java @@ -0,0 +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. + */ +@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/controller/AbstractController.java b/ClickMapActivity-web/src/main/java/com/academy/web/controller/AbstractController.java new file mode 100644 index 0000000..b214060 --- /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 model, @PathVariable int id) { + service.delete(model); + } + + @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 511db00..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,38 @@ package com.academy.web.controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.text.ParseException; /** * Created by Daniel Palonek on 2016-08-04. */ @RestController -public class AccountController { +@RequestMapping("/account") +public class AccountController extends AbstractController{ + + @Autowired + UserCache cache; + + @RequestMapping(value = "/logged/name") + public ValueWrapper getLoggedUsername() { + return new ValueWrapper(cache.getLoggedUsername()); + } + + @RequestMapping(value = "/register", method = RequestMethod.POST) + public ValueWrapper register(@RequestBody RegisterRequestBody data) throws ParseException { + return new ValueWrapper<>(service.saveAccount(data)); + } - @RequestMapping("/index") - public String index() { - return "Test Spring Boot"; + @RequestMapping(value = "/exist/{username}", method = RequestMethod.GET) + public ValueWrapper checkIfUserAlreadyExist(@PathVariable("username") String username) { + return new ValueWrapper<>(service.checkIfAccountWithGivenUsernameExists(username)); } } 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 new file mode 100644 index 0000000..bacad86 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/ActivitiesController.java @@ -0,0 +1,26 @@ +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.*; + +/** + * Created by Daniel Palonek on 2016-10-25. + */ +@RestController +@RequestMapping("/activities") +public class ActivitiesController { + + @Autowired + private ActivityService activityService; + + @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, + @RequestBody PointsWrapper points) { + activityService.logActivity(websiteName, subpageName, resolution, points.getPoints()); + } + +} 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..4d1d6a4 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/Controller.java @@ -0,0 +1,22 @@ +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"); + } + + @RequestMapping("/user/") + public ModelAndView getUserIndex() { + return new ModelAndView("user/userIndex"); + } +} 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..5c0e885 --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/SubpagesController.java @@ -0,0 +1,81 @@ +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; +import com.academy.model.dto.WebsiteDTO; +import com.academy.service.SubpageService; +import com.academy.web.config.RedirectUrls; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +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.servlet.http.HttpServletResponse; + +/** + * Created by Daniel Palonek on 2016-10-06. + */ +@RestController +@RequestMapping("/subpages") +public class SubpagesController extends AbstractController { + + private static final Logger LOGGER = LogManager.getLogger(SubpagesController.class); + + @Autowired + UserCache cache; + + @RequestMapping(value = "/add", headers = "content-type=multipart/*", method = RequestMethod.POST) + public ModelAndView addSubpage(@RequestParam("file") MultipartFile file, + @RequestParam("subpageName") String name, + RedirectAttributes redAttr) { + return new ModelAndView(service.saveSubpage(name, file, null, redAttr) ? + "redirect:/user/#/subpages/{websiteUrl}" + : RedirectUrls.ERROR_COULD_NOT_UPLOAD_SUBPAGE); + } + + @RequestMapping(value = "/getByWebsiteId", method = RequestMethod.GET) + public Iterable getByWebsiteId() { + final WebsiteDTO website = (WebsiteDTO) cache.getRequestedWebsite(); + return cache.getWebsiteSubpages(website.getId()); + } + + @RequestMapping(value = "/capture/{subpageName}/{subpageUrl:.+}", method = RequestMethod.POST) + public ValueWrapper captureSubpage(@PathVariable String subpageUrl, + @PathVariable String subpageName, + RedirectAttributes redAttrs) { + return new ValueWrapper<>(service.captureSubpage(subpageName, subpageUrl, redAttrs)); + } + + @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); + } + + @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)); + } + + @RequestMapping(value = "/checkIfExists/{name}", method = RequestMethod.GET) + public ValueWrapper checkIfSubpageExists(@PathVariable("name") String name) { + return new ValueWrapper<>(service.checkIfExists(name)); + } + +} 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..d167e8c --- /dev/null +++ b/ClickMapActivity-web/src/main/java/com/academy/web/controller/WebsitesController.java @@ -0,0 +1,46 @@ +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)); + } + + @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/app.properties b/ClickMapActivity-web/src/main/resources/app.properties index 8be8415..f25c722 100644 --- a/ClickMapActivity-web/src/main/resources/app.properties +++ b/ClickMapActivity-web/src/main/resources/app.properties @@ -5,13 +5,14 @@ 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 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/images/Thumbs.db b/ClickMapActivity-web/src/main/resources/images/Thumbs.db new file mode 100644 index 0000000..86fc20b Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/Thumbs.db differ diff --git a/ClickMapActivity-web/src/main/resources/images/blankPage.png b/ClickMapActivity-web/src/main/resources/images/blankPage.png new file mode 100644 index 0000000..4f347af Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/blankPage.png differ diff --git a/ClickMapActivity-web/src/main/resources/images/foto.jpg b/ClickMapActivity-web/src/main/resources/images/foto.jpg new file mode 100644 index 0000000..bf5bcc3 Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/foto.jpg differ diff --git a/ClickMapActivity-web/src/main/resources/images/foto.png b/ClickMapActivity-web/src/main/resources/images/foto.png new file mode 100644 index 0000000..a79e7d9 Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/foto.png differ diff --git a/ClickMapActivity-web/src/main/resources/images/foto2.jpg b/ClickMapActivity-web/src/main/resources/images/foto2.jpg new file mode 100644 index 0000000..34dab6c Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/foto2.jpg differ diff --git a/ClickMapActivity-web/src/main/resources/images/foto3.jpg b/ClickMapActivity-web/src/main/resources/images/foto3.jpg new file mode 100644 index 0000000..c2413ee Binary files /dev/null and b/ClickMapActivity-web/src/main/resources/images/foto3.jpg differ diff --git a/ClickMapActivity-web/src/main/resources/js/bower.json b/ClickMapActivity-web/src/main/resources/js/bower.json new file mode 100644 index 0000000..28c0873 --- /dev/null +++ b/ClickMapActivity-web/src/main/resources/js/bower.json @@ -0,0 +1,37 @@ +{ + "name": "ClickMapActivity", + "description": "Bower dependency config", + "main": "index.html", + "authors": [ + "DankessS " + ], + "license": "MIT", + "homepage": "https://github.com/DankessS/ClickMapActivity", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "1.5.5", + "angular-route": "latest", + "angular-animate": "latest", + "angular-resource": "latest", + "angular-ui-grid": "latest", + "angularjs-toaster": "latest", + "angular-loading-bar": "latest", + "angular-modal-service": "latest", + "angular-file-model": "latest", + "bootstrap": "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/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 += '