Skip to content

Commit

Permalink
Merge pull request #465 from khoa-nd/master
Browse files Browse the repository at this point in the history
Merged
  • Loading branch information
khoa-nd committed Dec 10, 2015
2 parents c430d57 + 3586f70 commit 4b63535
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public SalaryReviewResultDto reviewSalary(@RequestBody SalaryReviewDto salaryRev
salaryReviewDto = getSalaryReviewCondition(salaryReviewDto, isRequestedFromWidget);
SalaryReviewResultDto salaryReviewResult = salaryReviewService.reviewSalary(salaryReviewDto);

if (!isRequestedFromWidget) {
if (!isRequestedFromWidget && salaryReviewDto.getNetSalary() != null) {
salaryReviewService.saveSalaryReviewResult(salaryReviewResult);
// get top 3 higher salary jobs
List<TopPaidJob> topPaidJobs = salaryReviewService.findTopPaidJob(salaryReviewDto);
Expand All @@ -47,6 +47,11 @@ public SalaryReviewResultDto reviewSalary(@RequestBody SalaryReviewDto salaryRev
List<SimilarSalaryReview> similarSalaryReviews = salaryReviewService.getSimilarSalaryReview(request);
salaryReviewResult.setSimilarSalaryReviews(similarSalaryReviews);
}

boolean hideSalary = salaryReviewDto.getIsSalaryVisible() != null && !salaryReviewDto.getIsSalaryVisible();
if (hideSalary) {
hideSalaryInformation(salaryReviewResult);
}
return salaryReviewResult;
}

Expand Down Expand Up @@ -91,4 +96,12 @@ private SalaryReviewDto getSalaryReviewInfoByJob(JobEntity job) {
return salaryReviewDto;
}

private void hideSalaryInformation(SalaryReviewResultDto salaryReviewResult) {
salaryReviewResult.setNetSalary(null);
SalaryReport salaryReport = salaryReviewResult.getSalaryReport();
if (salaryReport != null) {
salaryReport.setNetSalary(null);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.techlooper.dto.ResourceDto;
import com.techlooper.entity.ChallengeEntity;
import com.techlooper.model.Language;
import com.techlooper.repository.elasticsearch.ChallengeRepository;
import com.techlooper.repository.elasticsearch.ProjectRepository;
import com.techlooper.repository.elasticsearch.SalaryReviewRepository;
Expand Down Expand Up @@ -106,9 +107,9 @@ public Long getUrlResponseCode(@RequestBody ResourceDto resourceDto) {
return 404L;
}

@RequestMapping(value = "report/challenge/final/{challengeId}")
public void renderFinalChallengeReport(@PathVariable Long challengeId, HttpServletRequest request, HttpServletResponse response) throws IOException {
ByteArrayOutputStream os = reportService.generateFinalChallengeReport(request.getRemoteUser(), challengeId);
@RequestMapping(value = "report/challenge/final/{language}/{challengeId}")
public void renderFinalChallengeReport(@PathVariable Language language, @PathVariable Long challengeId, HttpServletRequest request, HttpServletResponse response) throws IOException {
ByteArrayOutputStream os = reportService.generateFinalChallengeReport(request.getRemoteUser(), challengeId, language);
if (os == null) {
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
Expand Down
28 changes: 20 additions & 8 deletions src/main/java/com/techlooper/model/JobSearchBySalaryStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

import com.techlooper.entity.JobEntity;
import com.techlooper.util.DataUtils;
import org.elasticsearch.index.query.*;
import org.apache.commons.collections.CollectionUtils;
import org.elasticsearch.index.query.BoolFilterBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.FilterBuilders.boolFilter;
import static org.elasticsearch.index.query.QueryBuilders.*;

/**
Expand All @@ -33,15 +37,23 @@ protected NativeSearchQueryBuilder getSearchQueryBuilder() {
List<String> jobTitleTokens = DataUtils.preprocessJobTitle(salaryReviewDto.getJobTitle());

BoolQueryBuilder boolQueryBuilder = boolQuery();
BoolFilterBuilder boolFilterBuilder = boolFilter();
jobTitleTokens.forEach(jobTitleToken -> boolQueryBuilder.should(jobTitleQueryBuilder(jobTitleToken.trim())));
FilterBuilder jobIndustriesFilterBuilder = getJobIndustriesFilterBuilder(salaryReviewDto.getJobCategories());
FilterBuilder approvedDateRangeFilterBuilder = getRangeFilterBuilder("approvedDate", "now-6M/M", null);

if (CollectionUtils.isNotEmpty(salaryReviewDto.getJobCategories())) {
FilterBuilder jobIndustriesFilterBuilder = getJobIndustriesFilterBuilder(salaryReviewDto.getJobCategories());
boolFilterBuilder.must(jobIndustriesFilterBuilder);
}
FilterBuilder approvedDateRangeFilterBuilder = getRangeFilterBuilder("approvedDate", "now-6M/M", "now");
boolFilterBuilder.must(approvedDateRangeFilterBuilder);
FilterBuilder salaryRangeFilterBuilder = getSalaryRangeFilterBuilder(MIN_SALARY_ACCEPTABLE, MAX_SALARY_ACCEPTABLE);
boolFilterBuilder.must(salaryRangeFilterBuilder);

queryBuilder.withQuery(filteredQuery(boolQueryBuilder,
boolFilter().must(approvedDateRangeFilterBuilder)
.must(jobIndustriesFilterBuilder)
.must(salaryRangeFilterBuilder)));
QueryBuilder matchQueryBuilder = matchAllQuery();
if (CollectionUtils.isNotEmpty(jobTitleTokens)) {
matchQueryBuilder = boolQueryBuilder;
}
queryBuilder.withQuery(filteredQuery(matchQueryBuilder, boolFilterBuilder));
return queryBuilder;
}

Expand Down
20 changes: 15 additions & 5 deletions src/main/java/com/techlooper/model/JobSearchBySkillStrategy.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.techlooper.model;

import com.techlooper.entity.JobEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolFilterBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
Expand Down Expand Up @@ -35,11 +37,19 @@ public JobSearchBySkillStrategy(ElasticsearchRepository repository, List<String>
protected NativeSearchQueryBuilder getSearchQueryBuilder() {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withTypes("job");

QueryBuilder skillQueryBuilder = skillQueryBuilder(skills);
queryBuilder.withQuery(filteredQuery(skillQueryBuilder,
boolFilter().must(getRangeFilterBuilder("approvedDate", "now-6M/M", "now"))
.must(getJobIndustriesFilterBuilder(jobCategories))
.must(getSalaryRangeFilterBuilder(MIN_SALARY_ACCEPTABLE, MAX_SALARY_ACCEPTABLE))));
QueryBuilder skillQueryBuilder = matchAllQuery();
if (CollectionUtils.isNotEmpty(skills)) {
skillQueryBuilder = skillQueryBuilder(skills);
}

BoolFilterBuilder boolFilterBuilder = boolFilter();
if (CollectionUtils.isNotEmpty(jobCategories)) {
boolFilterBuilder.must(getJobIndustriesFilterBuilder(jobCategories));
}
boolFilterBuilder.must(getRangeFilterBuilder("approvedDate", "now-6M/M", "now"));
boolFilterBuilder.must(getSalaryRangeFilterBuilder(MIN_SALARY_ACCEPTABLE, MAX_SALARY_ACCEPTABLE));

queryBuilder.withQuery(filteredQuery(skillQueryBuilder, boolFilterBuilder));
return queryBuilder;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.techlooper.model;

import com.techlooper.entity.JobEntity;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import static org.elasticsearch.index.query.FilterBuilders.boolFilter;
import static org.elasticsearch.index.query.QueryBuilders.filteredQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;

/**
* Created by NguyenDangKhoa on 12/7/15.
Expand All @@ -25,7 +28,11 @@ public JobSearchByTitleStrategy(ElasticsearchRepository repository, String jobTi
protected NativeSearchQueryBuilder getSearchQueryBuilder() {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withTypes("job");

queryBuilder.withQuery(filteredQuery(jobTitleQueryBuilder(jobTitle),
QueryBuilder matchQueryBuilder = matchAllQuery();
if (StringUtils.isNotEmpty(jobTitle)) {
matchQueryBuilder = jobTitleQueryBuilder(jobTitle);
}
queryBuilder.withQuery(filteredQuery(matchQueryBuilder,
boolFilter().must(getRangeFilterBuilder("approvedDate", "now-6M/M", null))
.must(getSalaryRangeFilterBuilder(MIN_SALARY_ACCEPTABLE, MAX_SALARY_ACCEPTABLE))));
return queryBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import com.techlooper.entity.SalaryReviewEntity;
import com.techlooper.util.DateTimeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolFilterBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.RangeFilterBuilder;
import org.elasticsearch.index.query.TermsFilterBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
Expand All @@ -16,8 +17,7 @@
import java.util.List;

import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.filteredQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.*;

/**
* Created by NguyenDangKhoa on 12/7/15.
Expand All @@ -36,7 +36,11 @@ public SimilarSalaryReviewSearchStrategy(SalaryReviewDto salaryReviewDto, Elasti
@Override
protected NativeSearchQueryBuilder getSearchQueryBuilder() {
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder().withTypes("salaryReview");
MatchQueryBuilder jobTitleQuery = matchQuery("jobTitle", salaryReviewDto.getJobTitle()).minimumShouldMatch("100%");

QueryBuilder queryBuilder = matchAllQuery();
if (StringUtils.isNotEmpty(salaryReviewDto.getJobTitle())) {
queryBuilder = matchQuery("jobTitle", salaryReviewDto.getJobTitle()).minimumShouldMatch("100%");
}

BoolFilterBuilder boolFilterBuilder = boolFilter();
if (CollectionUtils.isNotEmpty(salaryReviewDto.getJobCategories())) {
Expand All @@ -48,7 +52,7 @@ protected NativeSearchQueryBuilder getSearchQueryBuilder() {
Long sixMonthsAgo = DateTimeUtils.minusPeriod(6, ChronoUnit.MONTHS);
RangeFilterBuilder sixMonthsAgoFilter = rangeFilter("createdDateTime").from(sixMonthsAgo);

searchQueryBuilder.withQuery(filteredQuery(jobTitleQuery, boolFilterBuilder.must(netSalaryFilter)
searchQueryBuilder.withQuery(filteredQuery(queryBuilder, boolFilterBuilder.must(netSalaryFilter)
.must(sixMonthsAgoFilter)));
return searchQueryBuilder;
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/techlooper/service/ReportService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.techlooper.service;

import com.techlooper.model.Language;

import java.io.ByteArrayOutputStream;

/**
* Created by phuonghqh on 11/30/15.
*/
public interface ReportService {

ByteArrayOutputStream generateFinalChallengeReport(String challengeAuthorEmail, Long challengeId);
ByteArrayOutputStream generateFinalChallengeReport(String challengeAuthorEmail, Long challengeId, Language language);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.techlooper.service.impl;

import com.lowagie.text.PageSize;
import com.techlooper.dto.FinalChallengeReportDto;
import com.techlooper.dto.PhaseEntry;
import com.techlooper.dto.PhaseEntry.PhaseEntryBuilder;
Expand Down Expand Up @@ -63,7 +62,7 @@ public class ReportServiceImpl implements ReportService {
@Resource
private ITextRenderer reportRender;

public ByteArrayOutputStream generateFinalChallengeReport(String challengeAuthorEmail, Long challengeId) {
public ByteArrayOutputStream generateFinalChallengeReport(String challengeAuthorEmail, Long challengeId, Language language) {
ChallengeEntity challenge = challengeRepository.findOne(challengeId);
if (challenge == null || !challenge.getAuthorEmail().equalsIgnoreCase(challengeAuthorEmail)) {
return null;
Expand Down Expand Up @@ -105,7 +104,7 @@ public ByteArrayOutputStream generateFinalChallengeReport(String challengeAuthor
finalChallengeReportDto.calculateRemainingFields();

try {
Template template = challenge.getLang() == Language.en ? finalChallengeReportEn : finalChallengeReportVi;
Template template = language == Language.en ? finalChallengeReportEn : finalChallengeReportVi;
StringWriter stringWriter = new StringWriter();
template.process(finalChallengeReportDto, stringWriter);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,25 @@ private SalaryReviewResultDto generateSalaryReport(SalaryReviewDto salaryReviewD
salaryReport.setNetSalary(salaryReviewDto.getNetSalary());

double[] salaries = extractSalariesFromJob(jobs);
List<SalaryRange> salaryRanges = new ArrayList<>();
Map<Double, Double> salaryPercentileMap = new HashMap<>();
Percentile percentile = new Percentile();
for (double percent : percents) {
salaryRanges.add(new SalaryRange(percent, Math.floor(percentile.evaluate(salaries, percent))));
salaryPercentileMap.put(Math.floor(percentile.evaluate(salaries, percent)), percent);
}

List<SalaryRange> salaryRanges = new ArrayList<>();
for (Map.Entry<Double, Double> entry : salaryPercentileMap.entrySet()) {
salaryRanges.add(new SalaryRange(entry.getValue(), entry.getKey()));
}
salaryRanges = salaryRanges.stream().sorted((source, destination) ->
Double.valueOf(source.getPercent() - destination.getPercent()).intValue()).collect(Collectors.toList());
salaryReport.setSalaryRanges(salaryRanges);

// Calculate salary percentile rank for user based on list of salary percentiles from above result
double percentRank = calculatePercentPosition(salaryReport);
double percentRank = Double.NaN;
if (salaryReport.getNetSalary() != null) {
percentRank = calculatePercentPosition(salaryReport);
}
salaryReport.setPercentRank(Math.floor(percentRank));
salaryReport.setNumberOfJobs(jobs.size());

Expand All @@ -212,7 +222,7 @@ private double[] extractSalariesFromJob(Set<JobEntity> jobs) {

private double calculatePercentPosition(SalaryReport salaryReport) {
//Remove duplicated percentiles if any
List<SalaryRange> noDuplicatedSalaryRanges = salaryReport.getSalaryRanges().stream().distinct().collect(toList());
List<SalaryRange> noDuplicatedSalaryRanges = salaryReport.getSalaryRanges();
if (noDuplicatedSalaryRanges.size() >= TWO_PERCENTILES) {
int size = noDuplicatedSalaryRanges.size();
int i = 0;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/techlooper/util/DataUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.techlooper.entity.ChallengeCriteria;
import com.techlooper.model.Language;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.FacetedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
Expand Down Expand Up @@ -66,6 +67,10 @@ public static int getRandomNumberInRange(int min, int max) {
}

public static List<String> preprocessJobTitle(String jobTitle) {
if (StringUtils.isEmpty(jobTitle)) {
return Collections.emptyList();
}

String[] tokens;
if (jobTitle.contains("&")) {
tokens = jobTitle.split("&");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@
</table>
</td>
</tr>
<tr>
<td align="left" style="height: 50px;"></td>
</tr>
<tr>
<td align="center">
<br/>
<#if winnersInfo?size != 0>
<span style="font-size: 12px; font-weight: normal"><strong style="font-size: 25px; color:#bf3a2f">${winnersInfo?size}</strong> Trao giải</span>
<span style="font-size: 12px; font-weight: normal"><strong style="font-size: 25px; color:#bf3a2f">${winnersInfo?size}</strong> Người chiến thắng</span>
<#list winnersInfo as winnerInfo>
<br/>
<span style="font-size: 14px; color: #bf3a2f; font-weight: normal">
Expand All @@ -65,15 +68,15 @@
<td align="left" style="height: 1px; background-color: #8d8d8d;"></td>
</tr>
<tr>
<td align="left" style="height: 30px;"></td>
<td align="left" style="height: 5px;"></td>
</tr>
<tr>
<td align="left" width="100%">
<table width="100%" style="background-color:#fff">
<tr>
<td align="left" width="70%">
<h3 style="font-size: 14px; color: #898989; font-weight: 300; margin:0 0 5px 0">Challenge Online</h3>
<span style="font-size: 10px; color: #898989;">Build And Grow Your Developer Community Base With Online Contests.</span>
<h3 style="font-size: 14px; color: #898989; font-weight: 300; margin:0 0 5px 0">Thử Thách Trực Tuyến</h3>
<span style="font-size: 10px; color: #898989;">Xây Dựng Đội Ngũ Phát Triển Sản Phẩm Của Chính Bạn Thông Qua Các Cuộc Thi Trực Tuyến.</span>
</td>
<td align="right" width="30%">
<img src="${baseUrl}images/logo.png" alt="" style="margin: auto; width: 150px"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
techlooper.filter("challengeDetail", function (apiService, $rootScope, jsonValue, $filter, $q, localStorageService) {
techlooper.filter("challengeDetail", function (apiService, $rootScope, jsonValue, $filter, $q, $translate) {
return function (input, type) {
if (!input || input.$isRich) return input;

Expand Down Expand Up @@ -390,6 +390,7 @@ techlooper.filter("challengeDetail", function (apiService, $rootScope, jsonValue

challengeDetail.recalculate();

challengeDetail.$browserLang = $translate.use();
challengeDetail.$isRich = true;
return challengeDetail;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ng-class="{disabled: !contestDetail.winners.length}"
ng-disabled="!contestDetail.winners.length" ng-click="announcementWinner()"
data-toggle="modal" data-target="#emailCompose"></button>
<a href="report/challenge/final/{{contestDetail.challengeId}}" class="export-pdf" title="{{'getFinalReport' | translate}}"></a>
<a href="report/challenge/final/{{contestDetail.$browserLang}}/{{contestDetail.challengeId}}" class="export-pdf" title="{{'getFinalReport' | translate}}"></a>
</div>
</div>
<div class="participant-list">
Expand Down
6 changes: 5 additions & 1 deletion src/main/webapp/assets/modules/post-contest/postContest.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ <h2 translate="yourReward"></h2>
<a translate="goBack" ng-click="toState('challenge')" ng-show="state.status('timeline-tab-class') && !state.status('reward-tab-class')"></a>
<a translate="goBack" ng-click="toState('timeline')" ng-show="state.status('reward-tab-class')"></a>
<button ng-click="nextState()" type="button" class="btn btn-primary btn-flat" translate="next" ng-show="!state.status('reward-tab-class')"/>
<button ng-click="nextState()" type="button" class="btn btn-primary btn-flat" translate="publishChallenge" ng-show="state.status('reward-tab-class')"/>
<button ng-click="nextState()" type="button"
class="btn btn-primary btn-flat" translate="publishChallenge"
ng-disabled="postChallengeSuccess"
ng-class="{disabled: postChallengeSuccess}"
ng-show="state.status('reward-tab-class')"/>
</div>
</div>
</div>
Expand Down

0 comments on commit 4b63535

Please sign in to comment.