From 11cfa08153aeb77a0c1a3f6058c88115fc6b1df0 Mon Sep 17 00:00:00 2001 From: Phuong H Date: Mon, 24 Aug 2015 11:11:57 +0700 Subject: [PATCH 01/17] Validate start date and end date --- .../modules/create-event/create-event.html | 4 ++- .../create-event/createEventController.js | 35 +++++++++++++++---- .../modules/translation/messages_en.json | 3 +- .../modules/translation/messages_vi.json | 3 +- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/main/webapp/assets/modules/create-event/create-event.html b/src/main/webapp/assets/modules/create-event/create-event.html index face602d8..f6550dc69 100644 --- a/src/main/webapp/assets/modules/create-event/create-event.html +++ b/src/main/webapp/assets/modules/create-event/create-event.html @@ -23,7 +23,8 @@

options="uiConfig.fromNowDatetimeConfig" ng-required="true"/>
-
+
+
@@ -34,6 +35,7 @@

class="input-style" ng-required="true"/>
+
diff --git a/src/main/webapp/assets/modules/create-event/createEventController.js b/src/main/webapp/assets/modules/create-event/createEventController.js index 80c3182fd..677d33989 100644 --- a/src/main/webapp/assets/modules/create-event/createEventController.js +++ b/src/main/webapp/assets/modules/create-event/createEventController.js @@ -45,18 +45,41 @@ techlooper.controller("createEventController", function ($scope, $translate, jso } return false; - case "error-event-start-date": + case "error-past-date": if (!$scope.webinar) return false; - if ($scope.webinar.startDate && $scope.webinar.endDate) { + $scope.webinarForm.startDate.$setValidity("past", true); + $scope.webinarForm.endDate.$setValidity("past", true); + + var isPast = false; + + if ($scope.webinar.startDate) { var startDate = moment($scope.webinar.startDate, jsonValue.dateTimeFormat); + isPast |= startDate.isBefore(moment()) || startDate.isBefore(moment()); + $scope.webinarForm.startDate.$setValidity("past", !isPast); + } + + if ($scope.webinar.endDate) { var endDate = moment($scope.webinar.endDate, jsonValue.dateTimeFormat); - var before = endDate.isBefore(startDate); - $scope.webinarForm.startDate.$setValidity("range", !before); - $scope.webinarForm.endDate.$setValidity("range", !before); - return before; + isPast |= endDate.isBefore(moment()) || endDate.isBefore(moment()); + $scope.webinarForm.endDate.$setValidity("past", !isPast); } + + return isPast; + + case "error-range-date": + if (!$scope.webinar) return false; + if ($scope.state("error-past-date")) return false; $scope.webinarForm.startDate.$setValidity("range", true); $scope.webinarForm.endDate.$setValidity("range", true); + + if ($scope.webinar.startDate && $scope.webinar.endDate) { + var startDate = moment($scope.webinar.startDate, jsonValue.dateTimeFormat); + var endDate = moment($scope.webinar.endDate, jsonValue.dateTimeFormat); + var isEndDateBeforeStartDate = endDate.isBefore(startDate); + $scope.webinarForm.startDate.$setValidity("range", !isEndDateBeforeStartDate); + $scope.webinarForm.endDate.$setValidity("range", !isEndDateBeforeStartDate); + return isEndDateBeforeStartDate; + } return false; } diff --git a/src/main/webapp/assets/modules/translation/messages_en.json b/src/main/webapp/assets/modules/translation/messages_en.json index 9ae98a825..546aa59d5 100644 --- a/src/main/webapp/assets/modules/translation/messages_en.json +++ b/src/main/webapp/assets/modules/translation/messages_en.json @@ -682,5 +682,6 @@ "postAnEvent": "Post An Event", "webinar": "Webinar", "allEvents": "All Events", - "whatDoWeOffer": "What do we offer?" + "whatDoWeOffer": "What do we offer?", + "cannotInPast": "This field cannot be in the past." } \ No newline at end of file diff --git a/src/main/webapp/assets/modules/translation/messages_vi.json b/src/main/webapp/assets/modules/translation/messages_vi.json index ac0b8a30b..ceb7cbd35 100644 --- a/src/main/webapp/assets/modules/translation/messages_vi.json +++ b/src/main/webapp/assets/modules/translation/messages_vi.json @@ -682,5 +682,6 @@ "postAnEvent": "Tạo Sự Kiện", "webinar": "Webinar", "allEvents": "Tất cả Sự Kiện", - "whatDoWeOffer": "what do we offer?" + "whatDoWeOffer": "what do we offer?", + "cannotInPast": "Trường này không được ở quá khứ." } From f29612795cdf339193aab8721ea1e131165615f5 Mon Sep 17 00:00:00 2001 From: Phuong H Date: Mon, 24 Aug 2015 11:21:05 +0700 Subject: [PATCH 02/17] Fix email input not required --- .../assets/modules/common/listInput.html | 2 +- .../modules/common/listInputDirective.js | 30 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/webapp/assets/modules/common/listInput.html b/src/main/webapp/assets/modules/common/listInput.html index 630a2e4ef..44eaeb29e 100644 --- a/src/main/webapp/assets/modules/common/listInput.html +++ b/src/main/webapp/assets/modules/common/listInput.html @@ -4,7 +4,7 @@ + name="inputItem" ng-required="true" />
diff --git a/src/main/webapp/assets/modules/common/listInputDirective.js b/src/main/webapp/assets/modules/common/listInputDirective.js index dc090ec3b..033e8c202 100644 --- a/src/main/webapp/assets/modules/common/listInputDirective.js +++ b/src/main/webapp/assets/modules/common/listInputDirective.js @@ -14,11 +14,14 @@ techlooper.directive("listInput", function () { //var oriItems = angular.copy(scope.ngModel); - scope.addItem = function() { + scope.addItem = function () { + //var requiredToInput = (!scope.item || scope.item.length == 0); + //scope.listForm.inputItem.$setValidity("requiredToInput", !requiredToInput); scope.listForm.$setSubmitted(); - if (scope.listForm.$invalid) return; - if (!scope.item || scope.item.length == 0) return; + console.log(scope.listForm); + + if (scope.listForm.$invalid) return; scope.ngModel.push(scope.item); @@ -26,7 +29,7 @@ techlooper.directive("listInput", function () { scope.listForm.$setPristine(); } - scope.removeItem = function(index) { + scope.removeItem = function (index) { scope.ngModel.splice(index, 1); } @@ -36,7 +39,13 @@ techlooper.directive("listInput", function () { return scope.ngModel.indexOf(modelValue) < 0 && scope.organisers.indexOf(modelValue) < 0; }; - scope.status = function(type) { + //scope.listForm.inputItem.$validators.requiredToInput = function (modelValue, viewValue) { + // if (!modelValue) return false; + // //if (modelValue.length == 0) return true; + // return modelValue.length > 0; + //}; + + scope.status = function (type) { switch (type) { case "organiser": var item = arguments[1]; @@ -49,17 +58,6 @@ techlooper.directive("listInput", function () { return false; } - - //scope.$on("bodyClicked", function(targetScope, e) { - // console.log(2); - // if ($(e.target).hasClass("add-item")) { - // console.log(123); - // return; - // } - // console.log(3); - // scope.item = ""; - // scope.listForm.$setPristine(); - //}); } } }); \ No newline at end of file From 289bf4ba3fbffcb0bb52d26aaf7bdf3da1ae16b2 Mon Sep 17 00:00:00 2001 From: khoa-nd Date: Mon, 24 Aug 2015 15:14:45 +0700 Subject: [PATCH 03/17] Implement service to fetch top priority jobs from vietnamwork --- .../com/techlooper/model/JobResponse.java | 45 +++++++ .../techlooper/model/VNWJobSearchRequest.java | 118 +++++++++++------- .../model/VNWJobSearchResponseDataItem.java | 22 ++++ .../service/impl/JobAlertServiceImpl.java | 48 ++++++- 4 files changed, 179 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/techlooper/model/JobResponse.java b/src/main/java/com/techlooper/model/JobResponse.java index 2e98ded1f..4e81d0bdb 100644 --- a/src/main/java/com/techlooper/model/JobResponse.java +++ b/src/main/java/com/techlooper/model/JobResponse.java @@ -23,6 +23,12 @@ public class JobResponse { private String salary; + private Long salaryMin; + + private Long salaryMax; + + private Integer techlooperJobType = 0; + public static class Builder { private JobResponse instance = new JobResponse(); @@ -72,6 +78,21 @@ public Builder withSalary(String salary) { return this; } + public Builder withSalaryMin(Long salaryMin) { + instance.salaryMin = salaryMin; + return this; + } + + public Builder withSalaryMax(Long salaryMax) { + instance.salaryMax = salaryMax; + return this; + } + + public Builder withTechlooperJobType(Integer techlooperJobType) { + instance.techlooperJobType = techlooperJobType; + return this; + } + public JobResponse build() { return instance; } @@ -163,4 +184,28 @@ public String getSalary() { public void setSalary(String salary) { this.salary = salary; } + + public Long getSalaryMin() { + return salaryMin; + } + + public void setSalaryMin(Long salaryMin) { + this.salaryMin = salaryMin; + } + + public Long getSalaryMax() { + return salaryMax; + } + + public void setSalaryMax(Long salaryMax) { + this.salaryMax = salaryMax; + } + + public Integer getTechlooperJobType() { + return techlooperJobType; + } + + public void setTechlooperJobType(Integer techlooperJobType) { + this.techlooperJobType = techlooperJobType; + } } diff --git a/src/main/java/com/techlooper/model/VNWJobSearchRequest.java b/src/main/java/com/techlooper/model/VNWJobSearchRequest.java index d7845d51d..3e41346dd 100644 --- a/src/main/java/com/techlooper/model/VNWJobSearchRequest.java +++ b/src/main/java/com/techlooper/model/VNWJobSearchRequest.java @@ -13,69 +13,91 @@ @JsonInclude(JsonInclude.Include.NON_EMPTY) public class VNWJobSearchRequest { - @JsonProperty(value = "job_title") - private String jobTitle; + @JsonProperty(value = "job_title") + private String jobTitle; - @JsonProperty(value = "job_location") - private String jobLocation; + @JsonProperty(value = "job_location") + private String jobLocation; - @JsonProperty(value = "job_category") - private String jobCategories; + @JsonProperty(value = "job_category") + private String jobCategories; - @JsonProperty(value = "job_level") - private List jobLevel; + @JsonProperty(value = "job_level") + private List jobLevel; - @JsonProperty(value = "page_number") - private String pageNumber; + @JsonProperty(value = "page_number") + private Integer pageNumber; - @JsonProperty(value = "job_salary") - private Integer jobSalary; + @JsonProperty(value = "job_salary") + private Integer jobSalary; - public String getJobTitle() { - return jobTitle; - } + @JsonProperty(value = "tl_type") + private Integer techlooperJobType; - public void setJobTitle(String jobTitle) { - this.jobTitle = jobTitle; - } + @JsonProperty(value = "page_size") + private Integer pageSize; - public String getJobLocation() { - return jobLocation; - } + public String getJobTitle() { + return jobTitle; + } - public void setJobLocation(String jobLocation) { - this.jobLocation = jobLocation; - } + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } - public String getJobCategories() { - return jobCategories; - } + public String getJobLocation() { + return jobLocation; + } - public void setJobCategories(String jobCategories) { - this.jobCategories = jobCategories; - } + public void setJobLocation(String jobLocation) { + this.jobLocation = jobLocation; + } - public List getJobLevel() { - return jobLevel; - } + public String getJobCategories() { + return jobCategories; + } - public void setJobLevel(List jobLevel) { - this.jobLevel = jobLevel; - } + public void setJobCategories(String jobCategories) { + this.jobCategories = jobCategories; + } - public String getPageNumber() { - return pageNumber; - } + public List getJobLevel() { + return jobLevel; + } - public void setPageNumber(String pageNumber) { - this.pageNumber = pageNumber; - } + public void setJobLevel(List jobLevel) { + this.jobLevel = jobLevel; + } - public Integer getJobSalary() { - return jobSalary; - } + public Integer getJobSalary() { + return jobSalary; + } - public void setJobSalary(Integer jobSalary) { - this.jobSalary = jobSalary; - } + public void setJobSalary(Integer jobSalary) { + this.jobSalary = jobSalary; + } + + public Integer getTechlooperJobType() { + return techlooperJobType; + } + + public void setTechlooperJobType(Integer techlooperJobType) { + this.techlooperJobType = techlooperJobType; + } + + public Integer getPageNumber() { + return pageNumber; + } + + public void setPageNumber(Integer pageNumber) { + this.pageNumber = pageNumber; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } } diff --git a/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java b/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java index bbd7f3b65..fe024bc88 100644 --- a/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java +++ b/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java @@ -36,6 +36,12 @@ public class VNWJobSearchResponseDataItem { @JsonProperty(value = "job_video_url") private String videoUrl = ""; + @JsonProperty(value = "salary_min") + private Long salaryMin; + + @JsonProperty(value = "salary_max") + private Long salaryMax; + public String getUrl() { return url; } @@ -100,6 +106,22 @@ public void setLogoUrl(String logoUrl) { this.logoUrl = logoUrl; } + public Long getSalaryMin() { + return salaryMin; + } + + public void setSalaryMin(Long salaryMin) { + this.salaryMin = salaryMin; + } + + public Long getSalaryMax() { + return salaryMax; + } + + public void setSalaryMax(Long salaryMax) { + this.salaryMax = salaryMax; + } + public JobResponse toJobResponse() { final JobResponse.Builder builder = new JobResponse.Builder(); return builder.withCompany(getCompany()) diff --git a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java index 7670b4222..d5c51b772 100644 --- a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java @@ -2,13 +2,11 @@ import com.techlooper.entity.JobAlertRegistrationEntity; import com.techlooper.entity.ScrapeJobEntity; -import com.techlooper.model.JobAlertRegistration; -import com.techlooper.model.JobListingCriteria; -import com.techlooper.model.JobResponse; -import com.techlooper.model.Language; +import com.techlooper.model.*; import com.techlooper.repository.userimport.JobAlertRegistrationRepository; import com.techlooper.repository.userimport.ScrapeJobRepository; import com.techlooper.service.JobAlertService; +import com.techlooper.service.JobSearchService; import freemarker.template.Template; import org.apache.commons.lang3.StringUtils; import org.dozer.Mapper; @@ -53,6 +51,9 @@ public class JobAlertServiceImpl implements JobAlertService { @Value("${jobAlert.launchDate}") private String CONFIGURED_JOB_ALERT_LAUNCH_DATE; + @Value("${vnw.api.configuration.category.it.software.en}") + private String JOB_CATEGORY_IT_SOFTWARE; + @Resource private ScrapeJobRepository scrapeJobRepository; @@ -83,6 +84,9 @@ public class JobAlertServiceImpl implements JobAlertService { @Resource private JavaMailSender mailSender; + @Resource + private JobSearchService vietnamWorksJobSearchService; + @Override public List searchJob(JobAlertRegistrationEntity jobAlertRegistrationEntity) { NativeSearchQueryBuilder searchQueryBuilder = getJobAlertSearchQueryBuilder(jobAlertRegistrationEntity); @@ -163,10 +167,16 @@ public void sendEmail(Long numberOfJobs, JobAlertRegistrationEntity jobAlertRegi @Override public List listJob(JobListingCriteria criteria) { + List result = new ArrayList<>(); + VNWJobSearchRequest vnwJobSearchRequest = getTopPriorityJobSearchRequest(criteria); + VNWJobSearchResponse vnwJobSearchResponse = vietnamWorksJobSearchService.searchJob(vnwJobSearchRequest); + if (vnwJobSearchResponse.hasData()) { + Set vnwJobs = vnwJobSearchResponse.getData().getJobs(); + result.addAll(aggregateJobs(vnwJobs)); + } + NativeSearchQueryBuilder searchQueryBuilder = getJobListingQueryBuilder(criteria); List jobs = scrapeJobRepository.search(searchQueryBuilder.build()).getContent(); - - List result = new ArrayList<>(); if (!jobs.isEmpty()) { for (ScrapeJobEntity jobEntity : jobs) { JobResponse.Builder builder = new JobResponse.Builder(); @@ -182,6 +192,32 @@ public List listJob(JobListingCriteria criteria) { return result; } + private List aggregateJobs(Set vnwJobs) { + List result = new ArrayList<>(); + for(VNWJobSearchResponseDataItem job : vnwJobs) { + JobResponse.Builder builder = new JobResponse.Builder(); + if (job.getSalaryMax() != null && job.getSalaryMax() > 0) { + JobResponse jobResponse = builder.withTitle(job.getTitle()).withUrl(job.getUrl()).withLocation(job.getLocation()) + .withCompany(job.getCompany()).withLevel(job.getLevel()).withLogoUrl(job.getLogoUrl()) + .withPostedOn(job.getPostedOn()).withSalaryMin(job.getSalaryMin()).withSalaryMax(job.getSalaryMax()) + .withTechlooperJobType(1).build(); + result.add(jobResponse); + } + } + return result; + } + + private VNWJobSearchRequest getTopPriorityJobSearchRequest(JobListingCriteria criteria) { + VNWJobSearchRequest vnwJobSearchRequest = new VNWJobSearchRequest(); + vnwJobSearchRequest.setJobTitle(criteria.getKeyword()); + vnwJobSearchRequest.setJobLocation(criteria.getLocation()); + vnwJobSearchRequest.setJobCategories(JOB_CATEGORY_IT_SOFTWARE); + vnwJobSearchRequest.setTechlooperJobType(1); + vnwJobSearchRequest.setPageNumber(1); + vnwJobSearchRequest.setPageSize(20); + return vnwJobSearchRequest; + } + @Override public Long countJob(JobListingCriteria criteria) { NativeSearchQueryBuilder searchQueryBuilder = getJobListingQueryBuilder(criteria); From 0d02b6a9332038023a538efa0a721052cc772f8b Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 15:32:52 +0700 Subject: [PATCH 04/17] Implement html, sass for Events page --- src/main/webapp/assets/images/ic-general.png | Bin 0 -> 2726 bytes .../webapp/assets/modules/events/events.html | 144 ++++++++++++++++-- src/main/webapp/assets/sass/events.sass | 111 ++++++++++++++ 3 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 src/main/webapp/assets/images/ic-general.png diff --git a/src/main/webapp/assets/images/ic-general.png b/src/main/webapp/assets/images/ic-general.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2f3a8841ad75554bb46998b6934b6b38097ebb GIT binary patch literal 2726 zcmcgudpOhkAD^6Dc1(n0=A<=>WM;FCEnC=-GS|5um)X8-tzFuN8AWcDD0L{hieE&b z-=QeQ4{>s-C?R!HF1d8NNv<8vR66JPJe}X4zwh&Xp3nR9d0wyA`}O&JUeEXW9&mSc zf`DOQ5C{Zu-b(e9kA@(Sg1w58yoyy~t(FgZ5(httmmpjc%@6?~JC+~}fIIUT5r8Ma zV8!fe0c=1ZMI#Q~PvS>&AuJV@a zi-hpS(JW{}3c%)Um5Bf^nJb+s<1z^>#1=B#MoN?m@Bj$|F6Hgyi-}Sa;*%~>UN0@9 z5b#eB373TUY|4-34yOo2032s-iDX)!(QrK89F4`{@n|zR#sZB&S;${J5{)I|@I;Ii z{L6!ocN4L~iJnx)FTLb55`ry}2#F|Ebab?Nw57Q~6oEn$2!tgK3Ea7)%a-X<_3h28~8^=8Gi^J`-@Jk`QtYa}I|^w4$IL>@BI*SPae%jdsA< zV=z{Zc)T4IOSQJZP;tv#s(=~E1Nf3 zZ+M{+9IPy@9dU9!!neJA=CZ!wQ*PKgLG3~|PH2V( z&UD+21rOC=)p(V4w=xsb4uba^n_V`oaa2o6G|7M0kf70|s1p_+|3H+faDqHW3u z8nPaB`gKX!9POcR$US;I4uC))41sfLLvU8>+~imz)0nM}1^3a1&fM*&=os!e7Dqm- z=R%OEU{}f9;q$hJ=f2PT!~3=JsJB8z`*)*}?CJ?jQjGd_E!kR_3a#tP643}iaQUvp_xxa9qi_3cpztCE zFDk~A*rpKAk>r=TCOtt>I10r|_xdk%uh{+Rmag-556;!P3r1reweJ|dcjvy(QKj}S za_1%&{k%5T+EN_1+jycb<$4ylFc^Osd8A4cR`_(D9NAyrariu}Fd9c6tGotM@mfg_ zG|eeGSA#WbS{?g#1KX!Kw7VstNLwL4dXLfxdMjhxWPS!5pz>k+W+%2rrAmOQZ$~j* zDQ?ZA(PXM@G-}l2+DGZt&cWc)+^b5k?@33;ydL*Qs4=09&}NHNbUNcx`JztI>x@my zut@Pr!{u_@#b@R1apaJKj|%GoRssvI!zk*)eV2HT{BsL)xtsN~QQf$OT7xzD-n1Wv zi0@p6d^asV(Lip!`=2X)E}`xl<7fJnZ>DV1{g>=urt#RXizSkR+iTMr2_JvUxDiqT zEu>H?WmoW>Dhkb9>sH)O+{*E1Bt^Q@28&2{ePo74@}|?PcI|)5sTzeHw+$b#Hs~SK zx;j0ky8)cb$1W!QomYTC3@C%|0&&*0dzu5%yJ(P`KC!t16KY=d^wO1_+6y!J_EvdM zb}Fnj3LHp3kv35mF&4qL^zKmK6Nc?818v<5K|+pg3W^^;GuK{-hqa`z^%kl$kUip8 zW%}e-)!OZY>jE5KYUEF=)ZG@wkd6Brrb%%}>@oxGCtEk5a)`6Ku8*5cx1Vj`+{+eE zxpQgLiY=-^Dm0F&M$Jdhm`8--V5#yxw>&M$0mqwq!!WGPt}sCvWft@BAtFbe{p@^} z7SnCF${(jp+H^V;Gvm`_c}K*oHKI)9gyrysK;3Pt^kWLvf+%9_2Kzpx86k zC&TJd(gje2&BJSR+J>bltG#7lk0H(Jkcp-^08^O15#M;T z_sMkg>4Y|%jheInsTHa#hFu@%fG(s$r*8Qj*p@xAo8-OfWnePq^ht2z>mb$B(0mg| zM;ID9*uDbp@&stLE+X@p4&t#>0s9AL%@4#n4F`_xnd-KG*fw`j=c>O(p)xk)x0bgpLx=9CCa*!SxpU# zHdzyR&&nLTRazQxu^!%E-+Vn~)D0~C@j$9EcgHHPS?94d?Hp^jR~fz8XP*}p94YPo zed`OfO zVla=eseC}zI9{xM4nmJKxl*IiMKifq){5^l3>bLML9w58;ShyPuu?&5dJ1< cHZVZ}WbBjJYj`ESW$Dk+*};`sW*?gPCpWon#sB~S literal 0 HcmV?d00001 diff --git a/src/main/webapp/assets/modules/events/events.html b/src/main/webapp/assets/modules/events/events.html index 891172c22..ae8f5ca41 100644 --- a/src/main/webapp/assets/modules/events/events.html +++ b/src/main/webapp/assets/modules/events/events.html @@ -1,27 +1,143 @@ -
+

-

-
-
-
- 08:30 PM +
+

Jun, 12 2015

+
+
+
+ +

Owner Name

+
-
- -

+ +
+ +
+
+
+
+
+ +

Owner Name

+
+
+
+ +
    +
  • 08:30 PM +
  • +
  • 34 attendants +
  • +
+
+
+
-
-

Event Name

-

attendants

+
+
+
+ +

Owner Name

+
+
+
+ +
    +
  • 08:30 PM +
  • +
  • 34 attendants +
  • +
+
+
+ +
-
- +
+
+
+ +

Owner Name

+
+
+
+ +
    +
  • 08:30 PM +
  • +
  • 34 attendants +
  • +
+
+
+ +
+
+
+
+
+ +

Owner Name

+
+
+
+ +
    +
  • 08:30 PM +
  • +
  • 34 attendants +
  • +
+
+
+ +
+
+
+
+
+ +

Owner Name

+
+
+ +
+ +
diff --git a/src/main/webapp/assets/sass/events.sass b/src/main/webapp/assets/sass/events.sass index 1fc5246af..354883ae8 100644 --- a/src/main/webapp/assets/sass/events.sass +++ b/src/main/webapp/assets/sass/events.sass @@ -149,3 +149,114 @@ background-color: #337ab7 !important .xdsoft_time_box > div > div.xdsoft_current background-color: #337ab7 !important +.content-page-block.events-page + .content-page-detail + float: left + width: 100% + padding: 20px + .events-list-block + display: inline-block + width: 100% + clear: both + text-align: left + .events-items + display: inline-block + clear: both + width: 100% + padding: 0 + .events-by-date + display: inline-block + clear: both + width: 100% + h3 + font-size: 16px + font-weight: 400 + text-transform: capitalize + color: gray + margin: 0 + padding: 0 0 10px 0 + text-align: left + .events-item + width: 49% + float: left + border-left: 2px solid #337ab7 + -webkit-border-radius: 5px + -moz-border-radius: 5px + border-radius: 5px + background-color: #f4f4f4 + margin: 0 0 2% 1% + max-height: 100px + min-height: 100px + padding: 15px 10px 10px 10px + .left-content + float: left + width: 100px + .owner + display: inline-block + clear: both + width: 100% + text-align: center + img + width: 50px + height: 50px + p + margin: 0 + padding: 5px 0 0 + line-height: 100% + .right-content + width: 290px + float: left + padding-left: 10px + background: url(../images/line-li-gray.png) left top repeat-y + h4 + margin: 0 + padding: 0 + font-size: 14px + font-weight: 500 + text-transform: capitalize + .event-name + height: 30px + display: inline-block + clear: both + width: 100% + + ul + margin: 0 + padding: 10px 0 0 0 + width: 100% + clear: both + display: inline-block + li + width: auto + float: left + padding: 0 15px 0 25px + text-transform: capitalize + color: #808080 + background: url(../images/ic-general.png) left top no-repeat + strong + color: #333 + font-weight: 500 + li.time + background-position: 0 0 + padding-left: 20px + li.register + background-position: 0 -40px + .view-details + width: 50px + float: right + vertical-align: middle + text-align: center + line-height: 71px + background: url(../images/line-li-gray.png) left top repeat-y + padding-left: 5px + i + font-weight: 500 + font-size: 25px + a + color: #333 + display: block + width: 100% + height: 71px + background: url(../images/ic-general.png) center -80px no-repeat + .events-item:nth-child(2n) + margin: 0 1% 2% 0 \ No newline at end of file From 929613dbe898c76899e377b15463e12637fe03d0 Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 15:33:32 +0700 Subject: [PATCH 05/17] make responsive for "Events" page --- .../assets/sass/z-responsive-candidate.sass | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/webapp/assets/sass/z-responsive-candidate.sass b/src/main/webapp/assets/sass/z-responsive-candidate.sass index 715e1a274..bbd5d0f5c 100644 --- a/src/main/webapp/assets/sass/z-responsive-candidate.sass +++ b/src/main/webapp/assets/sass/z-responsive-candidate.sass @@ -1599,6 +1599,29 @@ .error-messages width: 100% clear: both + .content-page-block.events-page + .content-page-detail + padding: 10px + .events-list-block + .events-items + .events-item + width: 100% + margin: 0 0 10px 0 + max-height: inherit + .right-content + background: transparent + width: 75% + ul + li + font-size: 12px + li.register + padding-right: 0 + .left-content + width: 25% + .view-details + display: none + .events-item:nth-child(2n) + margin: 0 0 10px 0 @media (min-width: 640px) .rwd-table From f6cd9b2f04a0478f3ebf5d74ecaa7b0725446bf2 Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 16:27:53 +0700 Subject: [PATCH 06/17] Binding data for Hot Priority Jobs on the Job listing page --- .../modules/job-listing/job-listing.html | 229 +----------------- src/main/webapp/assets/sass/job-listing.sass | 4 + 2 files changed, 13 insertions(+), 220 deletions(-) diff --git a/src/main/webapp/assets/modules/job-listing/job-listing.html b/src/main/webapp/assets/modules/job-listing/job-listing.html index 334b58ab5..b50dc5cd8 100644 --- a/src/main/webapp/assets/modules/job-listing/job-listing.html +++ b/src/main/webapp/assets/modules/job-listing/job-listing.html @@ -64,227 +64,16 @@

-
+
-

Hot Job Name

+

{{job.title}}

    -
  • 12/05/2015
  • -
  • Ho Chi Minh
  • +
  • {{job.postedOn}}
  • +
  • {{job.location}}

: - $10,000

-
-
    -
  • - - - Angular JS - - -
  • -
  • - - - Spring - - -
  • -
  • - - - Photoshop, Illustrator, UI/UX Design - - -
  • -
-
-
-

- -

-
    -
  • 13th salary payment, opportunities to have training in Japan
  • -
  • Premium healthcare insurance
  • -
  • 15 days full paid annual leave per year
  • -
-
-
-
-
    -
  • Company Name
  • -
  • -
  • -
-
-
-
-
-

Hot Job Name

-
    -
  • 12/05/2015
  • -
  • Ho Chi Minh
  • -
-

: - $10,000

-
-
    -
  • - - - Angular JS - - -
  • -
  • - - - Spring - - -
  • -
  • - - - Photoshop, Illustrator, UI/UX Design - - -
  • -
-
-
-

- -

-
    -
  • 13th salary payment, opportunities to have training in Japan
  • -
  • Premium healthcare insurance
  • -
  • 15 days full paid annual leave per year
  • -
-
-
-
-
    -
  • Company Name
  • -
  • -
  • -
-
-
-
-
-

Hot Job Name

-
    -
  • 12/05/2015
  • -
  • Ho Chi Minh
  • -
-

: - $10,000

-
-
    -
  • - - - Angular JS - - -
  • -
  • - - - Spring - - -
  • -
  • - - - Photoshop, Illustrator, UI/UX Design - - -
  • -
-
-
-

- -

-
    -
  • 13th salary payment, opportunities to have training in Japan
  • -
  • Premium healthcare insurance
  • -
  • 15 days full paid annual leave per year
  • -
-
-
-
-
    -
  • Company Name
  • -
  • -
  • -
-
-
-
-
-

Hot Job Name

-
    -
  • 12/05/2015
  • -
  • Ho Chi Minh
  • -
-

: - $10,000

-
-
    -
  • - - - Angular JS - - -
  • -
  • - - - Spring - - -
  • -
  • - - - Photoshop, Illustrator, UI/UX Design - - -
  • -
-
-
-

- -

-
    -
  • 13th salary payment, opportunities to have training in Japan
  • -
  • Premium healthcare insurance
  • -
  • 15 days full paid annual leave per year
  • -
-
-
-
-
    -
  • Company Name
  • -
  • -
  • -
-
-
-
-
-

Hot Job Name

-
    -
  • 12/05/2015
  • -
  • Ho Chi Minh
  • -
-

: - $10,000

+ {{'negotiable' | translate}} + {{job.salary}}

-
+

{{job.title}}

    diff --git a/src/main/webapp/assets/sass/job-listing.sass b/src/main/webapp/assets/sass/job-listing.sass index 126e8da01..c93bff323 100644 --- a/src/main/webapp/assets/sass/job-listing.sass +++ b/src/main/webapp/assets/sass/job-listing.sass @@ -132,6 +132,8 @@ clear: both width: 100% padding: 10px + border-bottom: 0 + border-top: 1px solid #d2d2d2 p margin: 0 padding: 0 @@ -242,6 +244,8 @@ padding: 0 0 5px 0 img max-width: 100px + .job-item:first-child + border-top: 0 .hot-jobs display: inline-block clear: both From 73bf1eb4f7ac731d21bc8d95c5bf52e4a2a8a453 Mon Sep 17 00:00:00 2001 From: khoa-nd Date: Mon, 24 Aug 2015 16:39:11 +0700 Subject: [PATCH 07/17] Add benefits and skills information for vnw top priority job --- .../com/techlooper/model/JobResponse.java | 35 +++++++++++++++++++ .../model/VNWJobSearchResponseDataItem.java | 25 +++++++++++++ .../service/impl/JobAlertServiceImpl.java | 3 +- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/techlooper/model/JobResponse.java b/src/main/java/com/techlooper/model/JobResponse.java index 4e81d0bdb..9b21019c0 100644 --- a/src/main/java/com/techlooper/model/JobResponse.java +++ b/src/main/java/com/techlooper/model/JobResponse.java @@ -1,5 +1,10 @@ package com.techlooper.model; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.techlooper.entity.CompanyBenefit; + +import java.util.List; + /** * Created by phuonghqh on 10/15/14. */ @@ -29,6 +34,10 @@ public class JobResponse { private Integer techlooperJobType = 0; + private List benefits; + + private List skills; + public static class Builder { private JobResponse instance = new JobResponse(); @@ -93,6 +102,16 @@ public Builder withTechlooperJobType(Integer techlooperJobType) { return this; } + public Builder withBenefits(List benefits) { + instance.benefits = benefits; + return this; + } + + public Builder withSkills(List skills) { + instance.skills = skills; + return this; + } + public JobResponse build() { return instance; } @@ -208,4 +227,20 @@ public Integer getTechlooperJobType() { public void setTechlooperJobType(Integer techlooperJobType) { this.techlooperJobType = techlooperJobType; } + + public List getBenefits() { + return benefits; + } + + public void setBenefits(List benefits) { + this.benefits = benefits; + } + + public List getSkills() { + return skills; + } + + public void setSkills(List skills) { + this.skills = skills; + } } diff --git a/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java b/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java index fe024bc88..b03792626 100644 --- a/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java +++ b/src/main/java/com/techlooper/model/VNWJobSearchResponseDataItem.java @@ -3,6 +3,9 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.techlooper.entity.CompanyBenefit; + +import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.ALWAYS) @@ -42,6 +45,12 @@ public class VNWJobSearchResponseDataItem { @JsonProperty(value = "salary_max") private Long salaryMax; + @JsonProperty(value = "benefits") + private List benefits; + + @JsonProperty(value = "skills") + private List skills; + public String getUrl() { return url; } @@ -122,6 +131,22 @@ public void setSalaryMax(Long salaryMax) { this.salaryMax = salaryMax; } + public List getBenefits() { + return benefits; + } + + public void setBenefits(List benefits) { + this.benefits = benefits; + } + + public List getSkills() { + return skills; + } + + public void setSkills(List skills) { + this.skills = skills; + } + public JobResponse toJobResponse() { final JobResponse.Builder builder = new JobResponse.Builder(); return builder.withCompany(getCompany()) diff --git a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java index d5c51b772..e990a4493 100644 --- a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java @@ -200,7 +200,8 @@ private List aggregateJobs(Set vnwJob JobResponse jobResponse = builder.withTitle(job.getTitle()).withUrl(job.getUrl()).withLocation(job.getLocation()) .withCompany(job.getCompany()).withLevel(job.getLevel()).withLogoUrl(job.getLogoUrl()) .withPostedOn(job.getPostedOn()).withSalaryMin(job.getSalaryMin()).withSalaryMax(job.getSalaryMax()) - .withTechlooperJobType(1).build(); + .withTechlooperJobType(1).withSkills(job.getSkills()).withBenefits(job.getBenefits()) + .build(); result.add(jobResponse); } } From 442ac10fcbd872c73ba543caee6cc9e9a890b344 Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 16:46:37 +0700 Subject: [PATCH 08/17] add banner for Job Alert email template --- src/main/resources/template/jobAlert.en.ftl | 203 +++++++++--------- src/main/resources/template/jobAlert.vi.ftl | 11 + .../assets/images/hackathon-job-search.png | Bin 0 -> 55939 bytes 3 files changed, 118 insertions(+), 96 deletions(-) create mode 100644 src/main/webapp/assets/images/hackathon-job-search.png diff --git a/src/main/resources/template/jobAlert.en.ftl b/src/main/resources/template/jobAlert.en.ftl index 779c4e9c9..b5ef4c93c 100644 --- a/src/main/resources/template/jobAlert.en.ftl +++ b/src/main/resources/template/jobAlert.en.ftl @@ -158,6 +158,17 @@ + + + + Job Search Innovation Hackathon + + + + + + + Hey ${email}, @@ -179,115 +190,115 @@ <#list jobs as job> - - - - - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - ${job.jobTitle} -
    - -
    - <#if job.company??>${job.company} -
    - -
    - Location: <#if job.location??>${job.location} -
    - -
    - Salary: <#if job.salary?has_content>${job.salary}<#else>Negotiable -
    - - - - - - - + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + ${job.jobTitle} +
    + +
    + <#if job.company??>${job.company} +
    + +
    + Location: <#if job.location??>${job.location} +
    + +
    + Salary: <#if job.salary?has_content>${job.salary}<#else>Negotiable +
    + + + + + + + - - - - - - - - - - -
    - View More -
    - - - - - -
    - - - -
    -

    FOLLOW US

    +
    - - LinkedIn - + + + + + +
    + View More +
    - - -
    + +
    + + + + + + + +
    +

    FOLLOW US

    +
    + + LinkedIn + +
    + + + + + +
    - - - diff --git a/src/main/resources/template/jobAlert.vi.ftl b/src/main/resources/template/jobAlert.vi.ftl index b5b80f324..6639e9c3b 100644 --- a/src/main/resources/template/jobAlert.vi.ftl +++ b/src/main/resources/template/jobAlert.vi.ftl @@ -158,6 +158,17 @@ + + + + Job Search Innovation Hackathon + + + + + + + Xin chào ${email}, diff --git a/src/main/webapp/assets/images/hackathon-job-search.png b/src/main/webapp/assets/images/hackathon-job-search.png new file mode 100644 index 0000000000000000000000000000000000000000..eba1916fca879c5f64469465adcb78fb9d103f18 GIT binary patch literal 55939 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 Z0RXLB&oBE>WETJc002ovPDHLkV1o2`{{8>} literal 0 HcmV?d00001 From 5a5aa631f2ead0d80f206732e4e2b16875c21c8c Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 17:05:29 +0700 Subject: [PATCH 09/17] mapping icon for bennefit from vietnamworks data --- .../webapp/assets/modules/common/json.val.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/webapp/assets/modules/common/json.val.js b/src/main/webapp/assets/modules/common/json.val.js index 93dddb5f8..48bb60450 100644 --- a/src/main/webapp/assets/modules/common/json.val.js +++ b/src/main/webapp/assets/modules/common/json.val.js @@ -926,6 +926,23 @@ techlooper.factory("jsonValue", function () { {id: 12, name: "19 years"}, {id: 12, name: "> 20 years"} ], + "benefitIcons": [ + {id: '1',iconClass: 'fa-dollar'}, + {id: '2', iconClass: 'fa-user-md'}, + {id: '3', iconClass: 'fa-file-image-o'}, + {id: '4', iconClass: 'fa-graduation-cap'}, + {id: '5', iconClass: 'fa-trophy'}, + {id: '6', iconClass: 'fa-book'}, + {id: '7', iconClass: 'fa-laptop'}, + {id: '8', iconClass: 'fa-mobile'}, + {id: '9', iconClass: 'fa-plane'}, + {id: '10', iconClass: 'fa-glass'}, + {id: '11', iconClass: 'fa-cab'}, + {id: '12', iconClass: 'fa-coffee'}, + {id: '13', iconClass: 'fa-gift'}, + {id: '14', iconClass: 'fa-child'}, + {id: '15', iconClass: 'fa-check-square-o'} + ], "companyPromotion": { "title": "companyTitle", "tagLine": "companyMessages", @@ -971,5 +988,8 @@ techlooper.factory("jsonValue", function () { var currentYear = new Date().getFullYear();//yrs old from 15 to 99 instance.yobs = Array.apply(0, Array(84)).map(function (x, y) { return {value: currentYear - (y + 15)}; }); + instance.benefitIconsMap = {}; + $.each(instance.benefitIcons, function (i, icon) {instance.benefitIconsMap[icon.id] = icon;}); + return instance; }); \ No newline at end of file From 6f7bfa13def2853fb1aa2b5e086a8ed237708470 Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 17:06:16 +0700 Subject: [PATCH 10/17] Binding benefit list for Hot priority Jobs --- .../webapp/assets/modules/job-listing/job-listing.html | 7 ++++--- .../assets/modules/job-listing/jobListingController.js | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/assets/modules/job-listing/job-listing.html b/src/main/webapp/assets/modules/job-listing/job-listing.html index b50dc5cd8..37e272250 100644 --- a/src/main/webapp/assets/modules/job-listing/job-listing.html +++ b/src/main/webapp/assets/modules/job-listing/job-listing.html @@ -104,9 +104,10 @@

    {{job.

      -
    • 13th salary payment, opportunities to have training in Japan
    • -
    • Premium healthcare insurance
    • -
    • 15 days full paid annual leave per year
    • +
    • + + {{offer.benefitValue}} +

diff --git a/src/main/webapp/assets/modules/job-listing/jobListingController.js b/src/main/webapp/assets/modules/job-listing/jobListingController.js index eadfdccf5..26d469368 100644 --- a/src/main/webapp/assets/modules/job-listing/jobListingController.js +++ b/src/main/webapp/assets/modules/job-listing/jobListingController.js @@ -10,6 +10,7 @@ techlooper.controller("jobListingController", function (apiService, $scope, vnwC $scope.totalJob = response.totalJob; $scope.page = response.page; $scope.jobs = response.jobs; + console.log($scope.jobs); }); } else { var searchParams = searchText.split("+"); From 030639571cc6cc3457f435baab64383306920c1b Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 17:16:24 +0700 Subject: [PATCH 11/17] finished binding data for Hot Priority Jobs on Job Listing page --- .../modules/job-listing/job-listing.html | 20 +++---------------- .../job-listing/jobListingController.js | 5 +---- .../job-listing/jobListingDirective.js | 9 +++++++++ 3 files changed, 13 insertions(+), 21 deletions(-) create mode 100644 src/main/webapp/assets/modules/job-listing/jobListingDirective.js diff --git a/src/main/webapp/assets/modules/job-listing/job-listing.html b/src/main/webapp/assets/modules/job-listing/job-listing.html index 37e272250..a521218c6 100644 --- a/src/main/webapp/assets/modules/job-listing/job-listing.html +++ b/src/main/webapp/assets/modules/job-listing/job-listing.html @@ -76,24 +76,10 @@

{{job. {{job.salary}}

    -
  • +
  • - Angular JS - - -
  • -
  • - - - Spring - - -
  • -
  • - - - Photoshop, Illustrator, UI/UX Design + {{skill.skillName}}
  • @@ -104,7 +90,7 @@

    {{job.

      -
    • +
    • {{offer.benefitValue}}
    • diff --git a/src/main/webapp/assets/modules/job-listing/jobListingController.js b/src/main/webapp/assets/modules/job-listing/jobListingController.js index 26d469368..965728f92 100644 --- a/src/main/webapp/assets/modules/job-listing/jobListingController.js +++ b/src/main/webapp/assets/modules/job-listing/jobListingController.js @@ -10,7 +10,6 @@ techlooper.controller("jobListingController", function (apiService, $scope, vnwC $scope.totalJob = response.totalJob; $scope.page = response.page; $scope.jobs = response.jobs; - console.log($scope.jobs); }); } else { var searchParams = searchText.split("+"); @@ -32,9 +31,7 @@ techlooper.controller("jobListingController", function (apiService, $scope, vnwC $scope.searchJob = {keyword : keyword, locationId : locationId, location : location}; } - $('p.offers').on("click", function(){ - $(this).next().toggleClass( "show", 1000); - }); + $scope.getPageRange = function() { var numberOfShownPages = 5; diff --git a/src/main/webapp/assets/modules/job-listing/jobListingDirective.js b/src/main/webapp/assets/modules/job-listing/jobListingDirective.js new file mode 100644 index 000000000..3bb0dccc9 --- /dev/null +++ b/src/main/webapp/assets/modules/job-listing/jobListingDirective.js @@ -0,0 +1,9 @@ +techlooper.directive('showHideBenefits', function() { + return function(scope, element, attrs) { + if (scope.$last){ + $('p.offers').on("click", function(){ + $(this).next().toggleClass( "show", 1000); + }); + } + }; + }); \ No newline at end of file From d47e8343c467a866a9f404cbb7bf12cab66fc1cc Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 17:24:28 +0700 Subject: [PATCH 12/17] hide logo if hot priority job dont have logo --- src/main/webapp/assets/modules/job-listing/job-listing.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/assets/modules/job-listing/job-listing.html b/src/main/webapp/assets/modules/job-listing/job-listing.html index a521218c6..d8ad2f9a9 100644 --- a/src/main/webapp/assets/modules/job-listing/job-listing.html +++ b/src/main/webapp/assets/modules/job-listing/job-listing.html @@ -100,7 +100,9 @@

      {{job. From cc80510943a66b48a714362bfb73e0d37cdbfcc8 Mon Sep 17 00:00:00 2001 From: Phuong H Date: Mon, 24 Aug 2015 17:39:35 +0700 Subject: [PATCH 13/17] List all events --- pom.xml | 2 +- .../techlooper/config/CoreConfiguration.java | 14 +--- .../com/techlooper/entity/WebinarEntity.java | 84 ++++++++++--------- .../service/GoogleCalendarService.java | 3 + .../impl/GoogleCalendarServiceImpl.java | 7 ++ .../modules/common/listInputDirective.js | 2 - 6 files changed, 59 insertions(+), 53 deletions(-) diff --git a/pom.xml b/pom.xml index d485cadb3..a0463dd70 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 2.4.4 1.8.1 1.7.0.RELEASE - 1.2.0.RELEASE + 1.2.2.RELEASE 1.3.0.RELEASE 2.3.2 UTF-8 diff --git a/src/main/java/com/techlooper/config/CoreConfiguration.java b/src/main/java/com/techlooper/config/CoreConfiguration.java index 4ac4b190a..2cf4da62c 100644 --- a/src/main/java/com/techlooper/config/CoreConfiguration.java +++ b/src/main/java/com/techlooper/config/CoreConfiguration.java @@ -2,20 +2,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.client.util.DateTime; -import com.google.api.client.util.store.FileDataStoreFactory; import com.google.api.services.calendar.Calendar; import com.google.api.services.calendar.CalendarScopes; -import com.google.api.services.calendar.model.Event; -import com.google.api.services.calendar.model.EventAttendee; -import com.google.api.services.calendar.model.EventDateTime; import com.techlooper.converter.ListCSVStringConverter; import com.techlooper.converter.LocaleConverter; import com.techlooper.converter.ProfileNameConverter; @@ -56,15 +49,12 @@ import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; -import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.*; -import java.util.stream.Collector; -import java.util.stream.Collectors; @Configuration @ComponentScan(basePackages = "com.techlooper") @@ -181,6 +171,10 @@ protected void configure() { mapping(VnwJobAlert.class, VnwJobAlertRequest.class) .fields("jobLocations", "locationId", FieldsMappingOptions.customConverter(ListCSVStringConverter.class)) .fields("minSalary", "netSalary"); + +// mapping(WebinarInfoDto.class, WebinarEntity.class) +// .fields("startDate", "startDate", FieldsMappingOptions.customConverter(DateTime2BasicOrdinalDateTimeConverter.class)) +// .fields("endDate", "endDate", FieldsMappingOptions.customConverter(DateTime2BasicOrdinalDateTimeConverter.class)); } }); return dozerBeanMapper; diff --git a/src/main/java/com/techlooper/entity/WebinarEntity.java b/src/main/java/com/techlooper/entity/WebinarEntity.java index 29891007b..088855747 100644 --- a/src/main/java/com/techlooper/entity/WebinarEntity.java +++ b/src/main/java/com/techlooper/entity/WebinarEntity.java @@ -3,6 +3,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.*; +import java.util.Collection; import java.util.Date; import java.util.Set; @@ -15,6 +16,7 @@ public class WebinarEntity { @Id private Long createdDateTime = new Date().getTime(); + @Field(type = FieldType.String) private String name; @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd/MM/yyyy hh:mm a") @@ -23,57 +25,27 @@ public class WebinarEntity { @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd/MM/yyyy hh:mm a") private String endDate; + @Field(type = FieldType.String) private String description; - private Set attendees; + @Field(type = FieldType.String) + private Collection attendees; - @Field(index = FieldIndex.not_analyzed) + @Field(type = FieldType.String, index = FieldIndex.not_analyzed) private String organiser; - @Field(index = FieldIndex.not_analyzed) + @Field(type = FieldType.String, index = FieldIndex.not_analyzed) private String where = "Google Hangout"; - @Field(index = FieldIndex.not_analyzed) + @Field(type = FieldType.String, index = FieldIndex.not_analyzed) private String calendarUrl; - - @Field(index = FieldIndex.not_analyzed) + @Field(type = FieldType.String, index = FieldIndex.not_analyzed) private String hangoutLink; + @Field(type = FieldType.String) private String whatEvent; - public String getWhatEvent() { - return whatEvent; - } - - public void setWhatEvent(String whatEvent) { - this.whatEvent = whatEvent; - } - - public String getWhere() { - return where; - } - - public void setWhere(String where) { - this.where = where; - } - - public String getHangoutLink() { - return hangoutLink; - } - - public void setHangoutLink(String hangoutLink) { - this.hangoutLink = hangoutLink; - } - - public String getCalendarUrl() { - return calendarUrl; - } - - public void setCalendarUrl(String calendarUrl) { - this.calendarUrl = calendarUrl; - } - public Long getCreatedDateTime() { return createdDateTime; } @@ -114,11 +86,11 @@ public void setDescription(String description) { this.description = description; } - public Set getAttendees() { + public Collection getAttendees() { return attendees; } - public void setAttendees(Set attendees) { + public void setAttendees(Collection attendees) { this.attendees = attendees; } @@ -129,4 +101,36 @@ public String getOrganiser() { public void setOrganiser(String organiser) { this.organiser = organiser; } + + public String getWhere() { + return where; + } + + public void setWhere(String where) { + this.where = where; + } + + public String getCalendarUrl() { + return calendarUrl; + } + + public void setCalendarUrl(String calendarUrl) { + this.calendarUrl = calendarUrl; + } + + public String getHangoutLink() { + return hangoutLink; + } + + public void setHangoutLink(String hangoutLink) { + this.hangoutLink = hangoutLink; + } + + public String getWhatEvent() { + return whatEvent; + } + + public void setWhatEvent(String whatEvent) { + this.whatEvent = whatEvent; + } } diff --git a/src/main/java/com/techlooper/service/GoogleCalendarService.java b/src/main/java/com/techlooper/service/GoogleCalendarService.java index f056439bd..d65c2dfd4 100644 --- a/src/main/java/com/techlooper/service/GoogleCalendarService.java +++ b/src/main/java/com/techlooper/service/GoogleCalendarService.java @@ -3,6 +3,7 @@ import com.techlooper.dto.WebinarInfoDto; import java.io.IOException; +import java.util.Collection; /** * Created by phuonghqh on 8/17/15. @@ -11,4 +12,6 @@ public interface GoogleCalendarService { WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException; + Collection findNotExpiredWebinars(); + } diff --git a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java index 286189468..e48f9635a 100644 --- a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java @@ -20,6 +20,7 @@ import javax.annotation.Resource; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; /** * Created by phuonghqh on 8/18/15. @@ -73,4 +74,10 @@ public WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String or entity = webinarRepository.save(entity); return dozerMapper.map(entity, WebinarInfoDto.class); } + + public Collection findNotExpiredWebinars() { + + + return null; + } } diff --git a/src/main/webapp/assets/modules/common/listInputDirective.js b/src/main/webapp/assets/modules/common/listInputDirective.js index 033e8c202..a660d720b 100644 --- a/src/main/webapp/assets/modules/common/listInputDirective.js +++ b/src/main/webapp/assets/modules/common/listInputDirective.js @@ -19,8 +19,6 @@ techlooper.directive("listInput", function () { //scope.listForm.inputItem.$setValidity("requiredToInput", !requiredToInput); scope.listForm.$setSubmitted(); - console.log(scope.listForm); - if (scope.listForm.$invalid) return; scope.ngModel.push(scope.item); From 46d1832aedb8bcc47e9162264615b3d2dcb25a60 Mon Sep 17 00:00:00 2001 From: khoa-nd Date: Mon, 24 Aug 2015 18:07:54 +0700 Subject: [PATCH 14/17] REFACTOR JOB ALERT --- .../techlooper/controller/JobAlertController.java | 7 +++++++ .../entity/JobAlertRegistrationEntity.java | 11 +++++++++++ .../WebinarRepository.java | 2 +- .../com/techlooper/service/JobAlertService.java | 2 ++ .../service/impl/JobAlertServiceImpl.java | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) rename src/main/java/com/techlooper/repository/{elasticsearch => userimport}/WebinarRepository.java (88%) diff --git a/src/main/java/com/techlooper/controller/JobAlertController.java b/src/main/java/com/techlooper/controller/JobAlertController.java index ef7e2adbf..fae404612 100644 --- a/src/main/java/com/techlooper/controller/JobAlertController.java +++ b/src/main/java/com/techlooper/controller/JobAlertController.java @@ -4,6 +4,7 @@ import com.techlooper.entity.ScrapeJobEntity; import com.techlooper.model.JobAlertRegistration; import com.techlooper.service.JobAlertService; +import com.techlooper.service.impl.JobAlertServiceImpl; import com.techlooper.util.DateTimeUtils; import org.joda.time.DateTime; import org.joda.time.Days; @@ -19,6 +20,8 @@ import java.util.Date; import java.util.List; +import static com.techlooper.service.impl.JobAlertServiceImpl.*; + @Controller public class JobAlertController { @@ -67,8 +70,12 @@ public void sendJobAlertEmail() throws Exception { List scrapeJobEntities = jobAlertService.searchJob(jobAlertRegistrationEntity); if (!scrapeJobEntities.isEmpty()) { jobAlertService.sendEmail(numberOfJobs, jobAlertRegistrationEntity, scrapeJobEntities); + } else { + jobAlertService.updateSendEmailResultCode(jobAlertRegistrationEntity, JOB_ALERT_JOB_NOT_FOUND); } } + } else { + jobAlertService.updateSendEmailResultCode(jobAlertRegistrationEntity, JOB_ALERT_ALREADY_SENT_ON_TODAY); } } } diff --git a/src/main/java/com/techlooper/entity/JobAlertRegistrationEntity.java b/src/main/java/com/techlooper/entity/JobAlertRegistrationEntity.java index 86d32eb20..613a031ec 100644 --- a/src/main/java/com/techlooper/entity/JobAlertRegistrationEntity.java +++ b/src/main/java/com/techlooper/entity/JobAlertRegistrationEntity.java @@ -37,6 +37,9 @@ public class JobAlertRegistrationEntity { @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd/MM/yyyy HH:mm") private String lastEmailSentDateTime; + @Field(type = Integer) + private Integer lastEmailSentCode; + public Long getJobAlertRegistrationId() { return jobAlertRegistrationId; } @@ -108,4 +111,12 @@ public Integer getLocationId() { public void setLocationId(Integer locationId) { this.locationId = locationId; } + + public Integer getLastEmailSentCode() { + return lastEmailSentCode; + } + + public void setLastEmailSentCode(Integer lastEmailSentCode) { + this.lastEmailSentCode = lastEmailSentCode; + } } diff --git a/src/main/java/com/techlooper/repository/elasticsearch/WebinarRepository.java b/src/main/java/com/techlooper/repository/userimport/WebinarRepository.java similarity index 88% rename from src/main/java/com/techlooper/repository/elasticsearch/WebinarRepository.java rename to src/main/java/com/techlooper/repository/userimport/WebinarRepository.java index 3b9e583df..d0f931194 100644 --- a/src/main/java/com/techlooper/repository/elasticsearch/WebinarRepository.java +++ b/src/main/java/com/techlooper/repository/userimport/WebinarRepository.java @@ -1,4 +1,4 @@ -package com.techlooper.repository.elasticsearch; +package com.techlooper.repository.userimport; import com.techlooper.entity.SalaryReviewEntity; import com.techlooper.entity.WebinarEntity; diff --git a/src/main/java/com/techlooper/service/JobAlertService.java b/src/main/java/com/techlooper/service/JobAlertService.java index 6af13e658..54a92b097 100644 --- a/src/main/java/com/techlooper/service/JobAlertService.java +++ b/src/main/java/com/techlooper/service/JobAlertService.java @@ -27,4 +27,6 @@ public interface JobAlertService { boolean checkIfUserExceedRegistrationLimit(String email); + void updateSendEmailResultCode(JobAlertRegistrationEntity jobAlertRegistrationEntity, Integer code); + } diff --git a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java index e990a4493..a563a2332 100644 --- a/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/JobAlertServiceImpl.java @@ -45,6 +45,12 @@ public class JobAlertServiceImpl implements JobAlertService { private static final long CONFIGURED_JOB_ALERT_LIMIT_REGISTRATION = 5; + public final static int JOB_ALERT_SENT_OK = 200; + + public final static int JOB_ALERT_JOB_NOT_FOUND = 400; + + public final static int JOB_ALERT_ALREADY_SENT_ON_TODAY = 301; + @Value("${jobAlert.period}") private int CONFIGURED_JOB_ALERT_PERIOD; @@ -162,6 +168,7 @@ public void sendEmail(Long numberOfJobs, JobAlertRegistrationEntity jobAlertRegi jobAlertRegistrationEntity.setLastEmailSentDateTime(parseDate2String(new Date(), "dd/MM/yyyy HH:mm")); + jobAlertRegistrationEntity.setLastEmailSentCode(JOB_ALERT_SENT_OK); jobAlertRegistrationRepository.save(jobAlertRegistrationEntity); } @@ -286,6 +293,14 @@ public boolean checkIfUserExceedRegistrationLimit(String email) { return numberOfRegistrations >= CONFIGURED_JOB_ALERT_LIMIT_REGISTRATION; } + @Override + public void updateSendEmailResultCode(JobAlertRegistrationEntity jobAlertRegistrationEntity, Integer code) { + if (jobAlertRegistrationEntity != null) { + jobAlertRegistrationEntity.setLastEmailSentCode(code); + jobAlertRegistrationRepository.save(jobAlertRegistrationEntity); + } + } + private NativeSearchQueryBuilder getJobAlertSearchQueryBuilder(JobAlertRegistrationEntity jobAlertRegistrationEntity) { NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder().withTypes("job"); BoolQueryBuilder queryBuilder = boolQuery(); From bbd1eb9048b06e98d97ed957ff591a3a165c0b20 Mon Sep 17 00:00:00 2001 From: johnsonpham Date: Mon, 24 Aug 2015 18:14:02 +0700 Subject: [PATCH 15/17] update --- src/main/webapp/assets/modules/home-page/home.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/webapp/assets/modules/home-page/home.html b/src/main/webapp/assets/modules/home-page/home.html index b05684514..43906b542 100644 --- a/src/main/webapp/assets/modules/home-page/home.html +++ b/src/main/webapp/assets/modules/home-page/home.html @@ -208,6 +208,7 @@

+

From e7cdca9adf256d6478e01eefa33746dc93283bd2 Mon Sep 17 00:00:00 2001 From: khoa-nd Date: Tue, 25 Aug 2015 09:22:00 +0700 Subject: [PATCH 16/17] Fix compile error due to repository class --- .../impl/GoogleCalendarServiceImpl.java | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java index e48f9635a..4ab0d8eb6 100644 --- a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java @@ -8,8 +8,7 @@ import com.techlooper.dto.WebinarInfoDto; import com.techlooper.entity.WebinarEntity; import com.techlooper.entity.vnw.VnwUser; -import com.techlooper.repository.couchbase.UserRepository; -import com.techlooper.repository.elasticsearch.WebinarRepository; +import com.techlooper.repository.userimport.WebinarRepository; import com.techlooper.repository.vnw.VnwUserRepo; import com.techlooper.service.GoogleCalendarService; import org.dozer.Mapper; @@ -28,56 +27,56 @@ @Service public class GoogleCalendarServiceImpl implements GoogleCalendarService { - @Resource - private WebinarRepository webinarRepository; + @Resource + private WebinarRepository webinarRepository; - @Resource - private Mapper dozerMapper; + @Resource + private Mapper dozerMapper; - @Resource - private Calendar googleCalendar; + @Resource + private Calendar googleCalendar; - @Resource - private VnwUserRepo vnwUserRepo; + @Resource + private VnwUserRepo vnwUserRepo; - private static final String CALENDAR_ID = "techlooperawesome@gmail.com"; + private static final String CALENDAR_ID = "techlooperawesome@gmail.com"; - public WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException { - VnwUser vnwUser = vnwUserRepo.findByUsernameIgnoreCase(organiser); - String organiserEmail = vnwUser != null ? vnwUser.getEmail() : organiser; + public WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException { + VnwUser vnwUser = vnwUserRepo.findByUsernameIgnoreCase(organiser); + String organiserEmail = vnwUser != null ? vnwUser.getEmail() : organiser; - Event event = new Event() - .setSummary(webinarInfoDto.getName()) - .setDescription(webinarInfoDto.getDescription()); + Event event = new Event() + .setSummary(webinarInfoDto.getName()) + .setDescription(webinarInfoDto.getDescription()); - DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm a"); - org.joda.time.DateTime startDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getStartDate()); - org.joda.time.DateTime endDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getEndDate()); - event.setStart(new EventDateTime().setDateTime(new DateTime(startDate.toString()))); - event.setEnd(new EventDateTime().setDateTime(new DateTime(endDate.toString()))); + DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm a"); + org.joda.time.DateTime startDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getStartDate()); + org.joda.time.DateTime endDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getEndDate()); + event.setStart(new EventDateTime().setDateTime(new DateTime(startDate.toString()))); + event.setEnd(new EventDateTime().setDateTime(new DateTime(endDate.toString()))); - webinarInfoDto.getAttendees().add(organiserEmail); - EventAttendee[] attendees = webinarInfoDto.getAttendees().stream() - .map(attEmail -> new EventAttendee().setEmail(attEmail)) - .toArray(EventAttendee[]::new); + webinarInfoDto.getAttendees().add(organiserEmail); + EventAttendee[] attendees = webinarInfoDto.getAttendees().stream() + .map(attEmail -> new EventAttendee().setEmail(attEmail)) + .toArray(EventAttendee[]::new); - event.setAttendees(Arrays.asList(attendees)); + event.setAttendees(Arrays.asList(attendees)); - event = googleCalendar.events().insert(CALENDAR_ID, event).setSendNotifications(true).execute(); + event = googleCalendar.events().insert(CALENDAR_ID, event).setSendNotifications(true).execute(); - WebinarEntity entity = dozerMapper.map(webinarInfoDto, WebinarEntity.class); - entity.setCalendarUrl(event.getHtmlLink()); - entity.setHangoutLink(event.getHangoutLink()); + WebinarEntity entity = dozerMapper.map(webinarInfoDto, WebinarEntity.class); + entity.setCalendarUrl(event.getHtmlLink()); + entity.setHangoutLink(event.getHangoutLink()); - entity.setOrganiser(organiserEmail); + entity.setOrganiser(organiserEmail); - entity = webinarRepository.save(entity); - return dozerMapper.map(entity, WebinarInfoDto.class); - } + entity = webinarRepository.save(entity); + return dozerMapper.map(entity, WebinarInfoDto.class); + } - public Collection findNotExpiredWebinars() { - + public Collection findNotExpiredWebinars() { - return null; - } + + return null; + } } From 7843ac0aa1bd1f8375fdee82652027832ce3ebac Mon Sep 17 00:00:00 2001 From: Phuong H Date: Tue, 25 Aug 2015 10:04:25 +0700 Subject: [PATCH 17/17] Fix security not work correctly --- .../sec/SwitchingAuthenticationProvider.java | 51 ++++++------ .../service/GoogleCalendarService.java | 2 +- .../impl/GoogleCalendarServiceImpl.java | 78 ++++++++++--------- .../webapp/assets/modules/common/json.val.js | 10 +++ .../assets/modules/common/securityService.js | 7 +- .../webapp/assets/modules/common/utils.fac.js | 4 +- 6 files changed, 86 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/techlooper/config/web/sec/SwitchingAuthenticationProvider.java b/src/main/java/com/techlooper/config/web/sec/SwitchingAuthenticationProvider.java index aa71b1fe3..fab2d7832 100644 --- a/src/main/java/com/techlooper/config/web/sec/SwitchingAuthenticationProvider.java +++ b/src/main/java/com/techlooper/config/web/sec/SwitchingAuthenticationProvider.java @@ -12,33 +12,34 @@ public class SwitchingAuthenticationProvider implements AuthenticationProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(SwitchingAuthenticationProvider.class); - - private Map providers; - - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - try { - SocialProvider socialProvider = SocialProvider.valueOf(authentication.getCredentials().toString()); - if (socialProvider != null) { - AuthenticationProvider delegateTo = providers.get(socialProvider); - return delegateTo.authenticate(authentication); - } - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - } - - return providers.get(SocialProvider.VIETNAMWORKS).authenticate(authentication); - } + private static final Logger LOGGER = LoggerFactory.getLogger(SwitchingAuthenticationProvider.class); - public boolean supports(Class authentication) { - return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); - } + private Map providers; - public Map getProviders() { - return providers; + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + try { + SocialProvider socialProvider = SocialProvider.valueOf(authentication.getCredentials().toString()); + if (socialProvider != null) { + AuthenticationProvider delegateTo = providers.get(socialProvider); + return delegateTo.authenticate(authentication); + } } - - public void setProviders(Map providers) { - this.providers = providers; + catch (Exception ex) { + LOGGER.debug(ex.getMessage(), ex); } + + return providers.get(SocialProvider.VIETNAMWORKS).authenticate(authentication); + } + + public boolean supports(Class authentication) { + return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); + } + + public Map getProviders() { + return providers; + } + + public void setProviders(Map providers) { + this.providers = providers; + } } diff --git a/src/main/java/com/techlooper/service/GoogleCalendarService.java b/src/main/java/com/techlooper/service/GoogleCalendarService.java index d65c2dfd4..977503a36 100644 --- a/src/main/java/com/techlooper/service/GoogleCalendarService.java +++ b/src/main/java/com/techlooper/service/GoogleCalendarService.java @@ -12,6 +12,6 @@ public interface GoogleCalendarService { WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException; - Collection findNotExpiredWebinars(); + Collection findAvailableWebinars(); } diff --git a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java index 4ab0d8eb6..8dfa69a99 100644 --- a/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/GoogleCalendarServiceImpl.java @@ -12,8 +12,12 @@ import com.techlooper.repository.vnw.VnwUserRepo; import com.techlooper.service.GoogleCalendarService; import org.dozer.Mapper; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramBuilder; +import org.elasticsearch.search.facet.datehistogram.DateHistogramFacetBuilder; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; +import org.springframework.integration.annotation.Aggregator; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -27,56 +31,56 @@ @Service public class GoogleCalendarServiceImpl implements GoogleCalendarService { - @Resource - private WebinarRepository webinarRepository; + @Resource + private WebinarRepository webinarRepository; - @Resource - private Mapper dozerMapper; + @Resource + private Mapper dozerMapper; - @Resource - private Calendar googleCalendar; + @Resource + private Calendar googleCalendar; - @Resource - private VnwUserRepo vnwUserRepo; + @Resource + private VnwUserRepo vnwUserRepo; - private static final String CALENDAR_ID = "techlooperawesome@gmail.com"; + private static final String CALENDAR_ID = "techlooperawesome@gmail.com"; - public WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException { - VnwUser vnwUser = vnwUserRepo.findByUsernameIgnoreCase(organiser); - String organiserEmail = vnwUser != null ? vnwUser.getEmail() : organiser; + public WebinarInfoDto createWebinarInfo(WebinarInfoDto webinarInfoDto, String organiser) throws IOException { + VnwUser vnwUser = vnwUserRepo.findByUsernameIgnoreCase(organiser); + String organiserEmail = vnwUser != null ? vnwUser.getEmail() : organiser; - Event event = new Event() - .setSummary(webinarInfoDto.getName()) - .setDescription(webinarInfoDto.getDescription()); + Event event = new Event() + .setSummary(webinarInfoDto.getName()) + .setDescription(webinarInfoDto.getDescription()); - DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm a"); - org.joda.time.DateTime startDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getStartDate()); - org.joda.time.DateTime endDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getEndDate()); - event.setStart(new EventDateTime().setDateTime(new DateTime(startDate.toString()))); - event.setEnd(new EventDateTime().setDateTime(new DateTime(endDate.toString()))); + DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm a"); + org.joda.time.DateTime startDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getStartDate()); + org.joda.time.DateTime endDate = dateTimeFormatter.parseDateTime(webinarInfoDto.getEndDate()); + event.setStart(new EventDateTime().setDateTime(new DateTime(startDate.toString()))); + event.setEnd(new EventDateTime().setDateTime(new DateTime(endDate.toString()))); - webinarInfoDto.getAttendees().add(organiserEmail); - EventAttendee[] attendees = webinarInfoDto.getAttendees().stream() - .map(attEmail -> new EventAttendee().setEmail(attEmail)) - .toArray(EventAttendee[]::new); + webinarInfoDto.getAttendees().add(organiserEmail); + EventAttendee[] attendees = webinarInfoDto.getAttendees().stream() + .map(attEmail -> new EventAttendee().setEmail(attEmail)) + .toArray(EventAttendee[]::new); - event.setAttendees(Arrays.asList(attendees)); + event.setAttendees(Arrays.asList(attendees)); - event = googleCalendar.events().insert(CALENDAR_ID, event).setSendNotifications(true).execute(); + event = googleCalendar.events().insert(CALENDAR_ID, event).setSendNotifications(true).execute(); - WebinarEntity entity = dozerMapper.map(webinarInfoDto, WebinarEntity.class); - entity.setCalendarUrl(event.getHtmlLink()); - entity.setHangoutLink(event.getHangoutLink()); + WebinarEntity entity = dozerMapper.map(webinarInfoDto, WebinarEntity.class); + entity.setCalendarUrl(event.getHtmlLink()); + entity.setHangoutLink(event.getHangoutLink()); - entity.setOrganiser(organiserEmail); + entity.setOrganiser(organiserEmail); - entity = webinarRepository.save(entity); - return dozerMapper.map(entity, WebinarInfoDto.class); - } + entity = webinarRepository.save(entity); + return dozerMapper.map(entity, WebinarInfoDto.class); + } - public Collection findNotExpiredWebinars() { + public Collection findAvailableWebinars() { + AggregationBuilders.dateHistogram("availableWebinars").field("startDate").format(""); - - return null; - } + return null; + } } diff --git a/src/main/webapp/assets/modules/common/json.val.js b/src/main/webapp/assets/modules/common/json.val.js index 48bb60450..9d3259603 100644 --- a/src/main/webapp/assets/modules/common/json.val.js +++ b/src/main/webapp/assets/modules/common/json.val.js @@ -229,6 +229,16 @@ techlooper.factory("jsonValue", function () { name: "rootPage", url: "/" }, + { + name: "home", + url: "/home", + ignoreIfLastFoot: true + }, + { + name: "employerDashboard", + url: "/employer-dashboard", + ignoreIfLastFoot: true + }, { name: "postEvent", url: "/post-event", diff --git a/src/main/webapp/assets/modules/common/securityService.js b/src/main/webapp/assets/modules/common/securityService.js index afb46104f..22ae4e61f 100644 --- a/src/main/webapp/assets/modules/common/securityService.js +++ b/src/main/webapp/assets/modules/common/securityService.js @@ -85,10 +85,15 @@ techlooper.factory("securityService", function (apiService, $rootScope, $q, util }, routeByRole: function () { + utils.sendNotification(jsonValue.notifications.loaded); var lastFoot = localStorageService.get("lastFoot"); if (lastFoot) { localStorageService.remove("lastFoot"); - return $location.url(lastFoot); + + var uiView = utils.getUiView(lastFoot); + if (!uiView.ignoreIfLastFoot) { + return $location.url(lastFoot); + } } switch ($rootScope.userInfo.roleName) { diff --git a/src/main/webapp/assets/modules/common/utils.fac.js b/src/main/webapp/assets/modules/common/utils.fac.js index 8c2ae5351..418b2cc56 100644 --- a/src/main/webapp/assets/modules/common/utils.fac.js +++ b/src/main/webapp/assets/modules/common/utils.fac.js @@ -3,8 +3,8 @@ angular.module("Common").factory("utils", function (jsonValue, $location, $rootS var instance = { - getUiView: function () { - var path = $location.path(); + getUiView: function (pth) { + var path = pth || $location.path(); var rs = {}; $.each(jsonValue.uiViews, function (i, view) { if ((view.regex === undefined && view.url === path) ||