diff --git a/src/main/java/com/techlooper/config/CoreConfiguration.java b/src/main/java/com/techlooper/config/CoreConfiguration.java index a2d52e915..2aae07624 100644 --- a/src/main/java/com/techlooper/config/CoreConfiguration.java +++ b/src/main/java/com/techlooper/config/CoreConfiguration.java @@ -11,6 +11,10 @@ import com.techlooper.converter.ListCSVStringConverter; import com.techlooper.converter.LocaleConverter; import com.techlooper.converter.ProfileNameConverter; +import com.techlooper.cron.ChallengeTimelineNotifier; +import com.techlooper.cron.DailyChallengeSummaryEmailSender; +import com.techlooper.cron.JobAlertEmailSender; +import com.techlooper.cron.VietnamworksJobImporter; import com.techlooper.dto.WebinarInfoDto; import com.techlooper.entity.*; import com.techlooper.model.*; @@ -61,475 +65,495 @@ @Configuration @ComponentScan(basePackages = "com.techlooper") @PropertySources({ - @PropertySource("classpath:techlooper.properties"), - @PropertySource("classpath:secret.properties")}) + @PropertySource("classpath:techlooper.properties"), + @PropertySource("classpath:secret.properties")}) @EnableScheduling @EnableAspectJAutoProxy @EnableCaching(proxyTargetClass = true) public class CoreConfiguration implements ApplicationContextAware { - @Resource - private Environment environment; - - @Value("${mail.techlooper.form}") - private String mailTechlooperForm; + @Resource + private Environment environment; + + @Value("${mail.techlooper.form}") + private String mailTechlooperForm; - @Value("${mail.techlooper.reply_to}") - private String mailTechlooperReplyTo; + @Value("${mail.techlooper.reply_to}") + private String mailTechlooperReplyTo; - @Value("${mail.form}") - private String mailForm; - - @Value("${mail.reply_to}") - private String mailReplyTo; - - @Value("${mail.citibank.cc_promotion.to}") - private String mailCitibankCreditCardPromotionTo; - - @Value("${mail.citibank.cc_promotion.subject}") - private String mailCitibankCreditCardPromotionSubject; - - @Value("classpath:vnwConfig.json") - private org.springframework.core.io.Resource vnwConfigRes; - - @Value("classpath:google-auth/techLooper.p12") - private org.springframework.core.io.Resource googleApiAuthResource; - - private ApplicationContext applicationContext; - - @Bean - public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); - configurer.setFileEncoding("UTF-8"); - return configurer; - } - - @Bean - public CacheManager cacheManager() { - CompositeCacheManager manager = new CompositeCacheManager(); - manager.setCacheManagers(Arrays.asList( - new ConcurrentMapCacheManager("SOCIAL_CONFIG"), - new ConcurrentMapCacheManager("COMMON_TERM"), - new ConcurrentMapCacheManager("SKILL_CONFIG"))); - return manager; - } - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(clientHttpRequestFactory()); - } - - @Bean - public MultipartResolver multipartResolver() { - CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); - multipartResolver.setMaxUploadSize(500000); - return multipartResolver; - } - - @Bean - public Mapper dozerBeanMapper() { - DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); - dozerBeanMapper.addMapping(new BeanMappingBuilder() { - protected void configure() { - mapping(FacebookProfile.class, com.techlooper.entity.FacebookProfile.class) - .fields("locale", "locale", FieldsMappingOptions.customConverter(LocaleConverter.class)); - - mapping(TwitterProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) - .fields("name", "firstName", FieldsMappingOptions.copyByReference()) - .fields("screenName", "userName", FieldsMappingOptions.copyByReference()); - - mapping(GitHubUserProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) - .fields("name", "firstName", FieldsMappingOptions.copyByReference()) - .fields("email", "emailAddress", FieldsMappingOptions.copyByReference()); - - mapping(Person.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) - .fields("givenName", "firstName", FieldsMappingOptions.copyByReference()) - .fields("familyName", "lastName", FieldsMappingOptions.copyByReference()) - .fields("accountEmail", "emailAddress", FieldsMappingOptions.copyByReference()) - .fields("imageUrl", "profileImageUrl", FieldsMappingOptions.copyByReference()); - - mapping(com.techlooper.entity.FacebookProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) - .fields("email", "emailAddress", FieldsMappingOptions.copyByReference()); - - mapping(LinkedInProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) - .fields("profilePictureUrl", "profileImageUrl", FieldsMappingOptions.copyByReference()); - - mapping(UserEntity.class, UserInfo.class, TypeMappingOptions.oneWay()) - .fields("profiles", "profileNames", FieldsMappingOptions.customConverter(ProfileNameConverter.class)); - - mapping(UserInfo.class, UserEntity.class, TypeMappingOptions.oneWay()) - .fields("profileNames", "profiles", FieldsMappingOptions.customConverter(ProfileNameConverter.class)); - - mapping(UserEntity.class, VnwUserProfile.class).exclude("accessGrant"); - - mapping(SalaryReviewEntity.class, VNWJobSearchRequest.class) - .fields("jobLevelIds", "jobLevel") - .fields("jobCategories", "jobCategories", FieldsMappingOptions.customConverter(ListCSVStringConverter.class)) - .fields("netSalary", "jobSalary") - .fields("locationId", "jobLocation"); - - mapping(VnwJobAlert.class, VnwJobAlertRequest.class) - .fields("jobLocations", "locationId", FieldsMappingOptions.customConverter(ListCSVStringConverter.class)) - .fields("minSalary", "netSalary"); - - mapping(WebinarInfoDto.class, WebinarEntity.class, TypeMappingOptions.oneWay()) - .exclude("createdDateTime"); - - mapping(ScrapeJobEntity.class, VNWJobSearchResponseDataItem.class) - .fields("jobTitle", "title") - .fields("jobTitleUrl", "url") - .fields("companyLogoUrl", "logoUrl") - .fields("createdDateTime", "postedOn"); - - mapping(ScrapeJobEntity.class, JobResponse.class) - .fields("jobTitle", "title") - .fields("jobTitleUrl", "url") - .fields("createdDateTime", "postedOn") - .fields("companyLogoUrl", "logoUrl"); - - mapping(ChallengeEntity.class, ChallengeDto.class) - .fields("startDateTime", "startDate") - .fields("submissionDateTime", "submissionDate") - .fields("registrationDateTime", "registrationDate") - .fields("ideaSubmissionDateTime", "ideaSubmissionDate") - .fields("uxSubmissionDateTime", "uxSubmissionDate") - .fields("prototypeSubmissionDateTime", "prototypeSubmissionDate"); - - mapping(ChallengeRegistrantDto.class, ChallengeRegistrantEntity.class, TypeMappingOptions.oneWay()) - .exclude("activePhase"); - - } - }); - return dozerBeanMapper; - } - - @Bean - public TextEncryptor textEncryptor() { - BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); - textEncryptor.setPassword(environment.getProperty("core.textEncryptor.password")); - return textEncryptor; - } - - @Bean - public JavaMailSender mailSender() { - JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); - mailSender.setHost("localhost"); - mailSender.setPort(25); - - Properties javaMailProperties = new Properties(); - javaMailProperties.put("mail.transport.protocol", "smtp"); - mailSender.setJavaMailProperties(javaMailProperties); - return mailSender; - } - - @Bean - public SimpleMailMessage citibankCreditCardPromotionMailMessage() { - SimpleMailMessage mailMessage = new SimpleMailMessage(); - mailMessage.setFrom(mailForm); - mailMessage.setTo(mailCitibankCreditCardPromotionTo); - mailMessage.setReplyTo(mailReplyTo); - mailMessage.setSubject(mailCitibankCreditCardPromotionSubject); - return mailMessage; - } - - @Bean - public freemarker.template.Configuration freemakerConfig() throws IOException, URISyntaxException { - freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_22); - cfg.setDirectoryForTemplateLoading(Paths.get(this.getClass().getClassLoader().getResource("/template").toURI()).toFile()); - cfg.setDefaultEncoding("UTF-8"); - cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); - return cfg; - } - - @Bean - public Template citibankCreditCardPromotionTemplate(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("citibankCreditCardPromotion.ftl"); - return template; - } - - @Bean - public Map locationMap() { - Map locations = new HashMap<>(); - locations.put(29L, "Ho Chi Minh"); - locations.put(24L, "Ha Noi"); - return locations; - } - - @Bean - public MimeMessage salaryReviewMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public MimeMessage getPromotedMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public MimeMessage postChallengeMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public MimeMessage applyJobMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public MimeMessage jobAlertMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public MimeMessage alertEventOrganiserMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - return mailMessage; - } - - @Bean - public Template salaryReviewReportTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("salaryReviewReport.en.ftl"); - return template; - } - - @Bean - public Template salaryReviewReportTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("salaryReviewReport.vi.ftl"); - return template; - } - - @Bean - public Template getPromotedTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("getPromoted.en.ftl"); - return template; - } - - @Bean - public Template getPromotedTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("getPromoted.vi.ftl"); - return template; - } - - @Bean - public Template postChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("postChallenge.en.ftl"); - return template; - } - - @Bean - public Template notifyChallengeTimelineMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("notifyChallengeTimeline.vi.ftl"); - return template; - } - - @Bean - public Template notifyChallengeTimelineMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("notifyChallengeTimeline.en.ftl"); - return template; - } - - @Bean - public Template postChallengeUpdateMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("updateChallenge.en.ftl"); - return template; - } - - @Bean - public Template postChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("postChallenge.vi.ftl"); - return template; - } - - @Bean - public Template confirmUserJoinChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("confirmUserJoinChallenge.en.ftl"); - return template; - } - - @Bean - public Template confirmUserJoinChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("confirmUserJoinChallenge.vi.ftl"); - return template; - } - - @Bean - public Template alertEmployerChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerChallenge.en.ftl"); - return template; - } - - @Bean - public Template alertEmployerChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerChallenge.vi.ftl"); - return template; - } - - @Bean - public Template alertJobSeekerApplyJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertJobSeekerApplyJob.en.ftl"); - return template; - } - - @Bean - public Template alertJobSeekerApplyJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertJobSeekerApplyJob.vi.ftl"); - return template; - } - - @Bean - public Template alertEmployerApplyJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerApplyJob.en.ftl"); - return template; - } - - @Bean - public Template alertEmployerApplyJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerApplyJob.vi.ftl"); - return template; - } - - @Bean - public Template alertEmployerPostJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerPostJob.vi.ftl"); - return template; - } - - @Bean - public Template alertEmployerPostJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertEmployerPostJob.en.ftl"); - return template; - } - - @Bean - public Template alertTechloopiesPostJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("alertTechloopiesApplyJob.en.ftl"); - return template; - } - - @Bean - public Template jobAlertMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("jobAlert.en.ftl"); - return template; - } - - @Bean - public Template jobAlertMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("jobAlert.vi.ftl"); - return template; - } - - @Bean - public Template alertEventOrganiserMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("webinar.en.ftl"); - return template; - } - - @Bean - public Template alertEventOrganiserMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("webinar.vi.ftl"); - return template; - } - - @Bean - public Template onBoardingMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("onboarding.en.ftl"); - return template; - } - - @Bean - public Template onBoardingMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("onboarding.vi.ftl"); - return template; - } - - @Bean - public Template dailyChallengeSummaryMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("challengeDailySummary.en.ftl"); - return template; - } - - @Bean - public Template dailyChallengeSummaryMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("challengeDailySummary.vi.ftl"); - return template; - } - - @Bean - public JsonNode vietnamworksConfiguration() throws IOException { - return new ObjectMapper().readTree(vnwConfigRes.getInputStream()); - } - - @Bean - @DependsOn("jsonConfigRepository") - public SocialConfig googleSocialConfig() { - return applicationContext.getBean(JsonConfigRepository.class).getSocialConfig().stream() - .filter(socialConfig -> socialConfig.getProvider() == SocialProvider.GOOGLE) - .findFirst().get(); - } - - @Bean - public Calendar googleCalendar() throws GeneralSecurityException, IOException { - JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance(); - HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport(); - SocialConfig googleConfig = googleSocialConfig(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - GoogleCredential credential = new GoogleCredential.Builder() - .setTransport(httpTransport) - .setJsonFactory(jsonFactory) - .setServiceAccountId(googleConfig.getServiceAccountEmail()) - .setServiceAccountPrivateKeyFromP12File(googleApiAuthResource.getFile()) - .setServiceAccountScopes(Collections.singleton(CalendarScopes.CALENDAR)) - .setServiceAccountUser(googleConfig.getCalendarOwner()) - .build(); - - return new Calendar.Builder(transport, jsonFactory, credential) - .setApplicationName("Techlooper").build(); - } - - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - this.applicationContext.getEnvironment().acceptsProfiles(environment.getProperty("spring.profiles.active")); - } - - @Bean - public MimeMessage fromTechlooperMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { - MimeMessage mailMessage = mailSender.createMimeMessage(); - mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); - mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); - return mailMessage; - } - - private ClientHttpRequestFactory clientHttpRequestFactory() { - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - factory.setReadTimeout(5000); - factory.setConnectTimeout(5000); - return factory; - } - - @Bean - public Template challengeEmployerMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("challengeEmployerEmail.en.ftl"); - return template; - } - - @Bean - public Template challengeEmployerMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { - Template template = freemakerConfig.getTemplate("challengeEmployerEmail.vi.ftl"); - return template; - } + @Value("${mail.form}") + private String mailForm; + + @Value("${mail.reply_to}") + private String mailReplyTo; + + @Value("${mail.citibank.cc_promotion.to}") + private String mailCitibankCreditCardPromotionTo; + + @Value("${mail.citibank.cc_promotion.subject}") + private String mailCitibankCreditCardPromotionSubject; + + @Value("classpath:vnwConfig.json") + private org.springframework.core.io.Resource vnwConfigRes; + + @Value("classpath:google-auth/techLooper.p12") + private org.springframework.core.io.Resource googleApiAuthResource; + + private ApplicationContext applicationContext; + + @Bean + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); + configurer.setFileEncoding("UTF-8"); + return configurer; + } + + @Bean + public CacheManager cacheManager() { + CompositeCacheManager manager = new CompositeCacheManager(); + manager.setCacheManagers(Arrays.asList( + new ConcurrentMapCacheManager("SOCIAL_CONFIG"), + new ConcurrentMapCacheManager("COMMON_TERM"), + new ConcurrentMapCacheManager("SKILL_CONFIG"))); + return manager; + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(clientHttpRequestFactory()); + } + + @Bean + public MultipartResolver multipartResolver() { + CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); + multipartResolver.setMaxUploadSize(500000); + return multipartResolver; + } + + @Bean + public Mapper dozerBeanMapper() { + DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); + dozerBeanMapper.addMapping(new BeanMappingBuilder() { + protected void configure() { + mapping(FacebookProfile.class, com.techlooper.entity.FacebookProfile.class) + .fields("locale", "locale", FieldsMappingOptions.customConverter(LocaleConverter.class)); + + mapping(TwitterProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) + .fields("name", "firstName", FieldsMappingOptions.copyByReference()) + .fields("screenName", "userName", FieldsMappingOptions.copyByReference()); + + mapping(GitHubUserProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) + .fields("name", "firstName", FieldsMappingOptions.copyByReference()) + .fields("email", "emailAddress", FieldsMappingOptions.copyByReference()); + + mapping(Person.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) + .fields("givenName", "firstName", FieldsMappingOptions.copyByReference()) + .fields("familyName", "lastName", FieldsMappingOptions.copyByReference()) + .fields("accountEmail", "emailAddress", FieldsMappingOptions.copyByReference()) + .fields("imageUrl", "profileImageUrl", FieldsMappingOptions.copyByReference()); + + mapping(com.techlooper.entity.FacebookProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) + .fields("email", "emailAddress", FieldsMappingOptions.copyByReference()); + + mapping(LinkedInProfile.class, com.techlooper.entity.UserEntity.class, TypeMappingOptions.oneWay()) + .fields("profilePictureUrl", "profileImageUrl", FieldsMappingOptions.copyByReference()); + + mapping(UserEntity.class, UserInfo.class, TypeMappingOptions.oneWay()) + .fields("profiles", "profileNames", FieldsMappingOptions.customConverter(ProfileNameConverter.class)); + + mapping(UserInfo.class, UserEntity.class, TypeMappingOptions.oneWay()) + .fields("profileNames", "profiles", FieldsMappingOptions.customConverter(ProfileNameConverter.class)); + + mapping(UserEntity.class, VnwUserProfile.class).exclude("accessGrant"); + + mapping(SalaryReviewEntity.class, VNWJobSearchRequest.class) + .fields("jobLevelIds", "jobLevel") + .fields("jobCategories", "jobCategories", FieldsMappingOptions.customConverter(ListCSVStringConverter.class)) + .fields("netSalary", "jobSalary") + .fields("locationId", "jobLocation"); + + mapping(VnwJobAlert.class, VnwJobAlertRequest.class) + .fields("jobLocations", "locationId", FieldsMappingOptions.customConverter(ListCSVStringConverter.class)) + .fields("minSalary", "netSalary"); + + mapping(WebinarInfoDto.class, WebinarEntity.class, TypeMappingOptions.oneWay()) + .exclude("createdDateTime"); + + mapping(ScrapeJobEntity.class, VNWJobSearchResponseDataItem.class) + .fields("jobTitle", "title") + .fields("jobTitleUrl", "url") + .fields("companyLogoUrl", "logoUrl") + .fields("createdDateTime", "postedOn"); + + mapping(ScrapeJobEntity.class, JobResponse.class) + .fields("jobTitle", "title") + .fields("jobTitleUrl", "url") + .fields("createdDateTime", "postedOn") + .fields("companyLogoUrl", "logoUrl"); + + mapping(ChallengeEntity.class, ChallengeDto.class) + .fields("startDateTime", "startDate") + .fields("submissionDateTime", "submissionDate") + .fields("registrationDateTime", "registrationDate") + .fields("ideaSubmissionDateTime", "ideaSubmissionDate") + .fields("uxSubmissionDateTime", "uxSubmissionDate") + .fields("prototypeSubmissionDateTime", "prototypeSubmissionDate"); + + mapping(ChallengeRegistrantDto.class, ChallengeRegistrantEntity.class, TypeMappingOptions.oneWay()) + .exclude("activePhase"); + + } + }); + return dozerBeanMapper; + } + + @Bean + public TextEncryptor textEncryptor() { + BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); + textEncryptor.setPassword(environment.getProperty("core.textEncryptor.password")); + return textEncryptor; + } + + @Bean + public JavaMailSender mailSender() { + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost("localhost"); + mailSender.setPort(25); + + Properties javaMailProperties = new Properties(); + javaMailProperties.put("mail.transport.protocol", "smtp"); + mailSender.setJavaMailProperties(javaMailProperties); + return mailSender; + } + + @Bean + public SimpleMailMessage citibankCreditCardPromotionMailMessage() { + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setFrom(mailForm); + mailMessage.setTo(mailCitibankCreditCardPromotionTo); + mailMessage.setReplyTo(mailReplyTo); + mailMessage.setSubject(mailCitibankCreditCardPromotionSubject); + return mailMessage; + } + + @Bean + public freemarker.template.Configuration freemakerConfig() throws IOException, URISyntaxException { + freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_22); + cfg.setDirectoryForTemplateLoading(Paths.get(this.getClass().getClassLoader().getResource("/template").toURI()).toFile()); + cfg.setDefaultEncoding("UTF-8"); + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + return cfg; + } + + @Bean + public Template citibankCreditCardPromotionTemplate(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("citibankCreditCardPromotion.ftl"); + return template; + } + + @Bean + public Map locationMap() { + Map locations = new HashMap<>(); + locations.put(29L, "Ho Chi Minh"); + locations.put(24L, "Ha Noi"); + return locations; + } + + @Bean + public MimeMessage salaryReviewMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public MimeMessage getPromotedMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public MimeMessage postChallengeMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public MimeMessage applyJobMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public MimeMessage jobAlertMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public MimeMessage alertEventOrganiserMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + return mailMessage; + } + + @Bean + public Template salaryReviewReportTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("salaryReviewReport.en.ftl"); + return template; + } + + @Bean + public Template salaryReviewReportTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("salaryReviewReport.vi.ftl"); + return template; + } + + @Bean + public Template getPromotedTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("getPromoted.en.ftl"); + return template; + } + + @Bean + public Template getPromotedTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("getPromoted.vi.ftl"); + return template; + } + + @Bean + public Template postChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("postChallenge.en.ftl"); + return template; + } + + @Bean + public Template notifyChallengeTimelineMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("notifyChallengeTimeline.vi.ftl"); + return template; + } + + @Bean + public Template notifyChallengeTimelineMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("notifyChallengeTimeline.en.ftl"); + return template; + } + + @Bean + public Template postChallengeUpdateMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("updateChallenge.en.ftl"); + return template; + } + + @Bean + public Template postChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("postChallenge.vi.ftl"); + return template; + } + + @Bean + public Template confirmUserJoinChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("confirmUserJoinChallenge.en.ftl"); + return template; + } + + @Bean + public Template confirmUserJoinChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("confirmUserJoinChallenge.vi.ftl"); + return template; + } + + @Bean + public Template alertEmployerChallengeMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerChallenge.en.ftl"); + return template; + } + + @Bean + public Template alertEmployerChallengeMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerChallenge.vi.ftl"); + return template; + } + + @Bean + public Template alertJobSeekerApplyJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertJobSeekerApplyJob.en.ftl"); + return template; + } + + @Bean + public Template alertJobSeekerApplyJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertJobSeekerApplyJob.vi.ftl"); + return template; + } + + @Bean + public Template alertEmployerApplyJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerApplyJob.en.ftl"); + return template; + } + + @Bean + public Template alertEmployerApplyJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerApplyJob.vi.ftl"); + return template; + } + + @Bean + public Template alertEmployerPostJobMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerPostJob.vi.ftl"); + return template; + } + + @Bean + public Template alertEmployerPostJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertEmployerPostJob.en.ftl"); + return template; + } + + @Bean + public Template alertTechloopiesPostJobMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("alertTechloopiesApplyJob.en.ftl"); + return template; + } + + @Bean + public Template jobAlertMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("jobAlert.en.ftl"); + return template; + } + + @Bean + public Template jobAlertMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("jobAlert.vi.ftl"); + return template; + } + + @Bean + public Template alertEventOrganiserMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("webinar.en.ftl"); + return template; + } + + @Bean + public Template alertEventOrganiserMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("webinar.vi.ftl"); + return template; + } + + @Bean + public Template onBoardingMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("onboarding.en.ftl"); + return template; + } + + @Bean + public Template onBoardingMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("onboarding.vi.ftl"); + return template; + } + + @Bean + public Template dailyChallengeSummaryMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("challengeDailySummary.en.ftl"); + return template; + } + + @Bean + public Template dailyChallengeSummaryMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("challengeDailySummary.vi.ftl"); + return template; + } + + @Bean + public JsonNode vietnamworksConfiguration() throws IOException { + return new ObjectMapper().readTree(vnwConfigRes.getInputStream()); + } + + @Bean + @DependsOn("jsonConfigRepository") + public SocialConfig googleSocialConfig() { + return applicationContext.getBean(JsonConfigRepository.class).getSocialConfig().stream() + .filter(socialConfig -> socialConfig.getProvider() == SocialProvider.GOOGLE) + .findFirst().get(); + } + + @Bean + public Calendar googleCalendar() throws GeneralSecurityException, IOException { + JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance(); + HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport(); + SocialConfig googleConfig = googleSocialConfig(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + GoogleCredential credential = new GoogleCredential.Builder() + .setTransport(httpTransport) + .setJsonFactory(jsonFactory) + .setServiceAccountId(googleConfig.getServiceAccountEmail()) + .setServiceAccountPrivateKeyFromP12File(googleApiAuthResource.getFile()) + .setServiceAccountScopes(Collections.singleton(CalendarScopes.CALENDAR)) + .setServiceAccountUser(googleConfig.getCalendarOwner()) + .build(); + + return new Calendar.Builder(transport, jsonFactory, credential) + .setApplicationName("Techlooper").build(); + } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + this.applicationContext.getEnvironment().acceptsProfiles(environment.getProperty("spring.profiles.active")); + } + + @Bean + public MimeMessage fromTechlooperMailMessage(JavaMailSender mailSender) throws MessagingException, UnsupportedEncodingException { + MimeMessage mailMessage = mailSender.createMimeMessage(); + mailMessage.setFrom(new InternetAddress(mailTechlooperForm, "TechLooper", "UTF-8")); + mailMessage.setReplyTo(InternetAddress.parse(mailTechlooperReplyTo)); + return mailMessage; + } + + private ClientHttpRequestFactory clientHttpRequestFactory() { + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setReadTimeout(5000); + factory.setConnectTimeout(5000); + return factory; + } + + @Bean + public Template challengeEmployerMailTemplateEn(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("challengeEmployerEmail.en.ftl"); + return template; + } + + @Bean + public Template challengeEmployerMailTemplateVi(freemarker.template.Configuration freemakerConfig) throws IOException { + Template template = freemakerConfig.getTemplate("challengeEmployerEmail.vi.ftl"); + return template; + } + + @Bean + public ChallengeTimelineNotifier challengeTimelineNotifier() { + return new ChallengeTimelineNotifier(); + } + + @Bean + public DailyChallengeSummaryEmailSender dailyChallengeSummaryEmailSender() { + return new DailyChallengeSummaryEmailSender(); + } + + @Bean + public JobAlertEmailSender jobAlertEmailSender() { + return new JobAlertEmailSender(); + } + + @Bean + public VietnamworksJobImporter vietnamworksJobImporter() { + return new VietnamworksJobImporter(); + } } \ No newline at end of file diff --git a/src/main/java/com/techlooper/controller/ChallengeController.java b/src/main/java/com/techlooper/controller/ChallengeController.java index 8f4bfe809..594bf7a49 100644 --- a/src/main/java/com/techlooper/controller/ChallengeController.java +++ b/src/main/java/com/techlooper/controller/ChallengeController.java @@ -7,6 +7,7 @@ import com.techlooper.entity.vnw.VnwUser; import com.techlooper.model.*; import com.techlooper.repository.elasticsearch.ChallengeRegistrantRepository; +import com.techlooper.service.ChallengeRegistrantService; import com.techlooper.service.ChallengeService; import com.techlooper.service.EmployerService; import com.techlooper.service.LeadAPIService; @@ -20,130 +21,161 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.text.ParseException; +import java.util.ArrayList; import java.util.List; import java.util.Set; @RestController public class ChallengeController { - private final static Logger LOGGER = LoggerFactory.getLogger(ChallengeController.class); - - @Resource - private ChallengeService challengeService; - - @Resource - private EmployerService employerService; - - @Resource - private LeadAPIService leadAPIService; - - @Resource - private ChallengeRegistrantRepository challengeRegistrantRepository; - - @PreAuthorize("hasAuthority('EMPLOYER')") - @RequestMapping(value = "/challenge/publish", method = RequestMethod.POST) - public ChallengeResponse publishChallenge(@RequestBody ChallengeDto challengeDto, HttpServletRequest servletRequest) throws Exception { - int responseCode = 0; - String employerEmail = servletRequest.getRemoteUser(); - challengeDto.setAuthorEmail(employerEmail); - ChallengeEntity challengeEntity = challengeService.savePostChallenge(challengeDto); - boolean newEntity = challengeDto.getChallengeId() == null; - if (newEntity) { - if (challengeEntity != null) { - if (EmailValidator.validate(challengeEntity.getAuthorEmail())) { - challengeService.sendPostChallengeEmailToEmployer(challengeEntity); - } - challengeService.sendPostChallengeEmailToTechloopies(challengeEntity, Boolean.TRUE); - } - - // Call Lead Management API to create new lead on CRM system - try { - VnwUser employer = employerService.findEmployerByUsername(employerEmail); - VnwCompany company = employerService.findCompanyById(employer.getCompanyId()); - if (employer != null && company != null) { - responseCode = leadAPIService.createNewLead( - employer, company, LeadEventEnum.POST_CHALLENGE, challengeEntity.getChallengeName()); - - String logMessage = "Create Lead API Response Code : %d ,EmployerID : %d ,CompanyID : %d"; - LOGGER.info(String.format(logMessage, responseCode, employer.getUserId(), company.getCompanyId())); - } - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - } - } else { - challengeService.sendPostChallengeEmailToTechloopies(challengeEntity, Boolean.FALSE); - } + private final static Logger LOGGER = LoggerFactory.getLogger(ChallengeController.class); - return new ChallengeResponse(challengeEntity.getChallengeId(), responseCode); - } + @Resource + private ChallengeService challengeService; - @RequestMapping(value = "/challenge/{challengeId}", method = RequestMethod.GET) - public ChallengeDetailDto getChallengeDetail(@PathVariable Long challengeId, HttpServletRequest request, HttpServletResponse response) throws Exception { - ChallengeDetailDto challengeDetail = challengeService.getChallengeDetail(challengeId, request.getRemoteUser()); - if (challengeDetail == null) response.setStatus(HttpServletResponse.SC_NOT_FOUND); - return challengeDetail; - } + @Resource + private EmployerService employerService; - @RequestMapping(value = "/challenge/join", method = RequestMethod.POST) - public long joinChallenge(@RequestBody ChallengeRegistrantDto joinChallenge, HttpServletResponse response) throws Exception { - if (!EmailValidator.validate(joinChallenge.getRegistrantEmail())) { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return 0L; - } - return challengeService.joinChallenge(joinChallenge); - } + @Resource + private LeadAPIService leadAPIService; - @RequestMapping(value = "/challenge/list", method = RequestMethod.GET) - public List listChallenges() throws Exception { - return challengeService.listChallenges(); - } + @Resource + private ChallengeRegistrantRepository challengeRegistrantRepository; - @RequestMapping(value = "/challenge/stats", method = RequestMethod.GET) - public ChallengeStatsDto getChallengeStatistics() throws Exception { - ChallengeStatsDto challengeStatsDto = new ChallengeStatsDto(); - challengeStatsDto.setNumberOfChallenges(challengeService.getTotalNumberOfChallenges()); - challengeStatsDto.setNumberOfRegistrants(challengeService.getTotalNumberOfRegistrants()); - challengeStatsDto.setTotalPrizeAmount(challengeService.getTotalAmountOfPrizeValues()); - return challengeStatsDto; - } + @Resource + private ChallengeRegistrantService challengeRegistrantService; - @PreAuthorize("hasAuthority('EMPLOYER')") - @RequestMapping(value = "/challenge/{id}", method = RequestMethod.DELETE) - public void deleteChallengeById(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { - if (!challengeService.delete(id, request.getRemoteUser())) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "/challenge/publish", method = RequestMethod.POST) + public ChallengeResponse publishChallenge(@RequestBody ChallengeDto challengeDto, HttpServletRequest servletRequest) throws Exception { + int responseCode = 0; + String employerEmail = servletRequest.getRemoteUser(); + challengeDto.setAuthorEmail(employerEmail); + ChallengeEntity challengeEntity = challengeService.savePostChallenge(challengeDto); + boolean newEntity = challengeDto.getChallengeId() == null; + if (newEntity) { + if (challengeEntity != null) { + if (EmailValidator.validate(challengeEntity.getAuthorEmail())) { + challengeService.sendPostChallengeEmailToEmployer(challengeEntity); + } + challengeService.sendPostChallengeEmailToTechloopies(challengeEntity, Boolean.TRUE); + } + + // Call Lead Management API to create new lead on CRM system + try { + VnwUser employer = employerService.findEmployerByUsername(employerEmail); + VnwCompany company = employerService.findCompanyById(employer.getCompanyId()); + if (employer != null && company != null) { + responseCode = leadAPIService.createNewLead( + employer, company, LeadEventEnum.POST_CHALLENGE, challengeEntity.getChallengeName()); + + String logMessage = "Create Lead API Response Code : %d ,EmployerID : %d ,CompanyID : %d"; + LOGGER.info(String.format(logMessage, responseCode, employer.getUserId(), company.getCompanyId())); } + } + catch (Exception ex) { + LOGGER.error(ex.getMessage(), ex); + } } - - @RequestMapping(value = "/challenges/{challengeId}", method = RequestMethod.GET) - public ChallengeDto findChallengeById(@PathVariable Long challengeId, HttpServletRequest request) throws Exception { - return challengeService.findChallengeById(challengeId, request.getRemoteUser()); + else { + challengeService.sendPostChallengeEmailToTechloopies(challengeEntity, Boolean.FALSE); } - @PreAuthorize("hasAuthority('EMPLOYER')") - @RequestMapping(value = "/challenges/{challengeId}/registrants", method = RequestMethod.POST) - public Set getRegistrantsById(@PathVariable Long challengeId, @RequestBody RegistrantFilterCondition condition, - HttpServletRequest request, HttpServletResponse response) throws ParseException { - String owner = request.getRemoteUser(); - if (!challengeService.isOwnerOfChallenge(owner, challengeId)) { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - condition.setAuthorEmail(owner); - return challengeService.findRegistrantsByOwner(condition); + return new ChallengeResponse(challengeEntity.getChallengeId(), responseCode); + } + + @RequestMapping(value = "/challenge/{challengeId}", method = RequestMethod.GET) + public ChallengeDetailDto getChallengeDetail(@PathVariable Long challengeId, HttpServletRequest request, HttpServletResponse response) throws Exception { + ChallengeDetailDto challengeDetail = challengeService.getChallengeDetail(challengeId, request.getRemoteUser()); + if (challengeDetail == null) response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return challengeDetail; + } + + @RequestMapping(value = "/challenge/join", method = RequestMethod.POST) + public long joinChallenge(@RequestBody ChallengeRegistrantDto joinChallenge, HttpServletResponse response) throws Exception { + if (!EmailValidator.validate(joinChallenge.getRegistrantEmail())) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return 0L; } - - - @PreAuthorize("hasAuthority('EMPLOYER')") - @RequestMapping(value = "/challengeDetail/registrant", method = RequestMethod.POST) - public ChallengeRegistrantDto saveRegistrant(@RequestBody ChallengeRegistrantDto dto, HttpServletRequest request) { - return challengeService.saveRegistrant(request.getRemoteUser(), dto); + return challengeService.joinChallenge(joinChallenge); + } + + @RequestMapping(value = "/challenge/list", method = RequestMethod.GET) + public List listChallenges() throws Exception { + return challengeService.listChallenges(); + } + + @RequestMapping(value = "/challenge/stats", method = RequestMethod.GET) + public ChallengeStatsDto getChallengeStatistics() throws Exception { + ChallengeStatsDto challengeStatsDto = new ChallengeStatsDto(); + challengeStatsDto.setNumberOfChallenges(challengeService.getTotalNumberOfChallenges()); + challengeStatsDto.setNumberOfRegistrants(challengeService.getTotalNumberOfRegistrants()); + challengeStatsDto.setTotalPrizeAmount(challengeService.getTotalAmountOfPrizeValues()); + return challengeStatsDto; + } + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "/challenge/{id}", method = RequestMethod.DELETE) + public void deleteChallengeById(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { + if (!challengeService.delete(id, request.getRemoteUser())) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } - - @PreAuthorize("hasAuthority('EMPLOYER')") - @RequestMapping(value = "challengeRegistrant/fullName/{registrantId}", method = RequestMethod.GET) - public String getChallengeRegistrant(@PathVariable Long registrantId) { - ChallengeRegistrantEntity registrantEntity = challengeRegistrantRepository.findOne(registrantId); - return registrantEntity.getRegistrantFirstName() + " " + registrantEntity.getRegistrantLastName(); + } + + @RequestMapping(value = "/challenges/{challengeId}", method = RequestMethod.GET) + public ChallengeDto findChallengeById(@PathVariable Long challengeId, HttpServletRequest request) throws Exception { + return challengeService.findChallengeById(challengeId, request.getRemoteUser()); + } + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "/challenges/{challengeId}/registrants", method = RequestMethod.POST) + public Set getRegistrantsById(@PathVariable Long challengeId, @RequestBody RegistrantFilterCondition condition, + HttpServletRequest request, HttpServletResponse response) throws ParseException { + String owner = request.getRemoteUser(); + if (!challengeService.isOwnerOfChallenge(owner, challengeId)) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + condition.setAuthorEmail(owner); + return challengeService.findRegistrantsByOwner(condition); + } + + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "/challengeDetail/registrant", method = RequestMethod.POST) + public ChallengeRegistrantDto saveRegistrant(@RequestBody ChallengeRegistrantDto dto, HttpServletRequest request) { + return challengeService.saveRegistrant(request.getRemoteUser(), dto); + } + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "challengeRegistrant/fullName/{registrantId}", method = RequestMethod.GET) + public String getChallengeRegistrant(@PathVariable Long registrantId) { + ChallengeRegistrantEntity registrantEntity = challengeRegistrantRepository.findOne(registrantId); + return registrantEntity.getRegistrantFirstName() + " " + registrantEntity.getRegistrantLastName(); + } + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "/challenges/{challengeId}/registrantFunnel", method = RequestMethod.GET) + public List getChallengeRegistrantFunnel(@PathVariable Long challengeId, + HttpServletRequest request, HttpServletResponse response) { + List funnel = new ArrayList<>(); + if (challengeService.isOwnerOfChallenge(request.getRemoteUser(), challengeId)) { + funnel = challengeService.getChallengeRegistrantFunnel(challengeId); + } + else { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + } + return funnel; + } + + @PreAuthorize("hasAuthority('EMPLOYER')") + @RequestMapping(value = "challenge/{challengeId}/registrants/{phase}", method = RequestMethod.GET) + public Set getChallengeRegistrantsByPhase(@PathVariable Long challengeId, @PathVariable ChallengePhaseEnum phase, + HttpServletRequest request, HttpServletResponse response) { + Set registrants = challengeRegistrantService.findRegistrantsByChallengeIdAndPhase(challengeId, phase, request.getRemoteUser()); + if (registrants == null) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } + return registrants; + } } diff --git a/src/main/java/com/techlooper/controller/ChallengeSubmissionController.java b/src/main/java/com/techlooper/controller/ChallengeSubmissionController.java index a1695efe3..001deb481 100644 --- a/src/main/java/com/techlooper/controller/ChallengeSubmissionController.java +++ b/src/main/java/com/techlooper/controller/ChallengeSubmissionController.java @@ -1,12 +1,12 @@ package com.techlooper.controller; +import com.techlooper.entity.ChallengeRegistrantEntity; import com.techlooper.entity.ChallengeSubmissionEntity; +import com.techlooper.model.ChallengePhaseEnum; import com.techlooper.model.ChallengeSubmissionDto; +import com.techlooper.service.ChallengeService; import com.techlooper.service.ChallengeSubmissionService; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -16,12 +16,23 @@ @RestController public class ChallengeSubmissionController { - @Resource - private ChallengeSubmissionService challengeSubmissionService; + @Resource + private ChallengeSubmissionService challengeSubmissionService; - @RequestMapping(value = "user/challengeSubmission", method = RequestMethod.POST) - public ChallengeSubmissionEntity submitMyResult(@RequestBody ChallengeSubmissionDto challengeSubmissionDto) { - return challengeSubmissionService.submitMyResult(challengeSubmissionDto); - } + @Resource + private ChallengeService challengeService; + + @RequestMapping(value = "user/challengeSubmission", method = RequestMethod.POST) + public ChallengeSubmissionEntity submitMyResult(@RequestBody ChallengeSubmissionDto challengeSubmissionDto) { + return challengeSubmissionService.submitMyResult(challengeSubmissionDto); + } + + @RequestMapping(value = "user/challengeSubmissionPhase/{registrantEmail}/{challengeId}", method = RequestMethod.GET) + public ChallengePhaseEnum challengeSubmissionPhase(@PathVariable String registrantEmail, @PathVariable Long challengeId) { + ChallengeRegistrantEntity registrantEntity = + challengeService.findRegistrantByChallengeIdAndEmail(challengeId, registrantEmail); + return (registrantEntity != null && registrantEntity.getActivePhase() != null) ? + registrantEntity.getActivePhase() : ChallengePhaseEnum.REGISTRATION; + } } diff --git a/src/main/java/com/techlooper/cron/ChallengeTimelineNotifier.java b/src/main/java/com/techlooper/cron/ChallengeTimelineNotifier.java index a6b770935..6d053f793 100644 --- a/src/main/java/com/techlooper/cron/ChallengeTimelineNotifier.java +++ b/src/main/java/com/techlooper/cron/ChallengeTimelineNotifier.java @@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Arrays; @@ -23,7 +22,6 @@ import static com.techlooper.util.DateTimeUtils.*; -@Service public class ChallengeTimelineNotifier { private final static Logger LOGGER = LoggerFactory.getLogger(ChallengeTimelineNotifier.class); diff --git a/src/main/java/com/techlooper/cron/DailyChallengeSummaryEmailSender.java b/src/main/java/com/techlooper/cron/DailyChallengeSummaryEmailSender.java index 0d3974501..1a149200d 100644 --- a/src/main/java/com/techlooper/cron/DailyChallengeSummaryEmailSender.java +++ b/src/main/java/com/techlooper/cron/DailyChallengeSummaryEmailSender.java @@ -9,7 +9,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Arrays; @@ -18,7 +17,6 @@ import static com.techlooper.util.DateTimeUtils.*; -@Service public class DailyChallengeSummaryEmailSender { private final static Logger LOGGER = LoggerFactory.getLogger(DailyChallengeSummaryEmailSender.class); diff --git a/src/main/java/com/techlooper/cron/JobAlertEmailSender.java b/src/main/java/com/techlooper/cron/JobAlertEmailSender.java index 0409924cf..2ce82d8e3 100644 --- a/src/main/java/com/techlooper/cron/JobAlertEmailSender.java +++ b/src/main/java/com/techlooper/cron/JobAlertEmailSender.java @@ -11,7 +11,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Date; @@ -27,7 +26,6 @@ * @author Khoa Nguyen * @version v0.0-beta9.Release39, 09/09/2015 */ -@Service public class JobAlertEmailSender { private final static Logger LOGGER = LoggerFactory.getLogger(JobAlertEmailSender.class); diff --git a/src/main/java/com/techlooper/cron/VietnamworksJobImporter.java b/src/main/java/com/techlooper/cron/VietnamworksJobImporter.java index 13d47748f..d765272b1 100644 --- a/src/main/java/com/techlooper/cron/VietnamworksJobImporter.java +++ b/src/main/java/com/techlooper/cron/VietnamworksJobImporter.java @@ -7,7 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -17,7 +16,6 @@ * @author Khoa Nguyen * @version v0.0-beta9.Release39, 09/09/2015 */ -@Service public class VietnamworksJobImporter { private final static Logger LOGGER = LoggerFactory.getLogger(VietnamworksJobImporter.class); diff --git a/src/main/java/com/techlooper/entity/ChallengeSubmissionEntity.java b/src/main/java/com/techlooper/entity/ChallengeSubmissionEntity.java index 1ec4de309..fde23ee4c 100644 --- a/src/main/java/com/techlooper/entity/ChallengeSubmissionEntity.java +++ b/src/main/java/com/techlooper/entity/ChallengeSubmissionEntity.java @@ -1,10 +1,8 @@ package com.techlooper.entity; +import com.techlooper.model.ChallengePhaseEnum; import org.springframework.data.annotation.Id; -import org.springframework.data.elasticsearch.annotations.DateFormat; -import org.springframework.data.elasticsearch.annotations.Document; -import org.springframework.data.elasticsearch.annotations.Field; -import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.data.elasticsearch.annotations.*; import static org.springframework.data.elasticsearch.annotations.FieldType.Long; import static org.springframework.data.elasticsearch.annotations.FieldType.String; @@ -12,139 +10,155 @@ @Document(indexName = "techlooper", type = "challengeSubmission") public class ChallengeSubmissionEntity { - @Id - private Long challengeSubmissionId; + @Id + private Long challengeSubmissionId; - @Field(type = Long) - private Long registrantId; + @Field(type = Long) + private Long registrantId; - @Field(type = String) - private String registrantName; + @Field(type = String) + private String registrantName; - @Field(type = Long) - private Long challengeId; + @Field(type = Long) + private Long challengeId; - @Field(type = String) - private String submissionURL; + @Field(type = String) + private String submissionURL; - @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd/MM/yyyy") - private String submissionDateTime; + @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd/MM/yyyy") + private String submissionDateTime; - @Field(type = String) - private String submissionDescription; + @Field(type = String) + private String submissionDescription; - public java.lang.Long getRegistrantId() { - return registrantId; - } + @Field(type = String, index = FieldIndex.not_analyzed) + private ChallengePhaseEnum submissionPhase; - public void setRegistrantId(java.lang.Long registrantId) { - this.registrantId = registrantId; - } - - public java.lang.Long getChallengeSubmissionId() { - return challengeSubmissionId; - } - - public void setChallengeSubmissionId(java.lang.Long challengeSubmissionId) { - this.challengeSubmissionId = challengeSubmissionId; - } - - public java.lang.String getRegistrantName() { - return registrantName; - } - - public void setRegistrantName(java.lang.String registrantName) { - this.registrantName = registrantName; - } - - public java.lang.Long getChallengeId() { - return challengeId; - } - - public void setChallengeId(java.lang.Long challengeId) { - this.challengeId = challengeId; - } - - public java.lang.String getSubmissionURL() { - return submissionURL; - } - - public void setSubmissionURL(java.lang.String submissionURL) { - this.submissionURL = submissionURL; - } - - public java.lang.String getSubmissionDateTime() { - return submissionDateTime; - } + public java.lang.Long getRegistrantId() { + return registrantId; + } - public void setSubmissionDateTime(java.lang.String submissionDateTime) { - this.submissionDateTime = submissionDateTime; - } + public void setRegistrantId(java.lang.Long registrantId) { + this.registrantId = registrantId; + } - public java.lang.String getSubmissionDescription() { - return submissionDescription; - } + public java.lang.Long getChallengeSubmissionId() { + return challengeSubmissionId; + } - public void setSubmissionDescription(java.lang.String submissionDescription) { - this.submissionDescription = submissionDescription; - } + public void setChallengeSubmissionId(java.lang.Long challengeSubmissionId) { + this.challengeSubmissionId = challengeSubmissionId; + } - public static class ChallengeSubmissionEntityBuilder { - private ChallengeSubmissionEntity challengeSubmissionEntity; + public java.lang.String getRegistrantName() { + return registrantName; + } - private ChallengeSubmissionEntityBuilder() { - challengeSubmissionEntity = new ChallengeSubmissionEntity(); + public void setRegistrantName(java.lang.String registrantName) { + this.registrantName = registrantName; } - private ChallengeSubmissionEntityBuilder(ChallengeSubmissionEntity challengeSubmissionEntity) { - this.challengeSubmissionEntity = challengeSubmissionEntity; + public java.lang.Long getChallengeId() { + return challengeId; } - public ChallengeSubmissionEntityBuilder withChallengeSubmissionId(Long challengeSubmissionId) { - challengeSubmissionEntity.challengeSubmissionId = challengeSubmissionId; - return this; + public void setChallengeId(java.lang.Long challengeId) { + this.challengeId = challengeId; } - public ChallengeSubmissionEntityBuilder withRegistrantId(Long registrantId) { - challengeSubmissionEntity.registrantId = registrantId; - return this; + public java.lang.String getSubmissionURL() { + return submissionURL; } - public ChallengeSubmissionEntityBuilder withRegistrantName(String registrantName) { - challengeSubmissionEntity.registrantName = registrantName; - return this; + public void setSubmissionURL(java.lang.String submissionURL) { + this.submissionURL = submissionURL; } - public ChallengeSubmissionEntityBuilder withChallengeId(Long challengeId) { - challengeSubmissionEntity.challengeId = challengeId; - return this; + public java.lang.String getSubmissionDateTime() { + return submissionDateTime; } - public ChallengeSubmissionEntityBuilder withSubmissionURL(String submissionURL) { - challengeSubmissionEntity.submissionURL = submissionURL; - return this; + public void setSubmissionDateTime(java.lang.String submissionDateTime) { + this.submissionDateTime = submissionDateTime; } - public ChallengeSubmissionEntityBuilder withSubmissionDateTime(String submissionDateTime) { - challengeSubmissionEntity.submissionDateTime = submissionDateTime; - return this; + public java.lang.String getSubmissionDescription() { + return submissionDescription; } - public ChallengeSubmissionEntityBuilder withSubmissionDescription(String submissionDescription) { - challengeSubmissionEntity.submissionDescription = submissionDescription; - return this; + public void setSubmissionDescription(java.lang.String submissionDescription) { + this.submissionDescription = submissionDescription; } - public static ChallengeSubmissionEntityBuilder challengeSubmissionEntity() { - return new ChallengeSubmissionEntityBuilder(); + public ChallengePhaseEnum getSubmissionPhase() { + return submissionPhase; } - public static ChallengeSubmissionEntityBuilder challengeSubmissionEntity(ChallengeSubmissionEntity entity) { - return new ChallengeSubmissionEntityBuilder(entity); + public void setSubmissionPhase(ChallengePhaseEnum submissionPhase) { + this.submissionPhase = submissionPhase; } - public ChallengeSubmissionEntity build() { - return challengeSubmissionEntity; + public static class ChallengeSubmissionEntityBuilder { + private ChallengeSubmissionEntity challengeSubmissionEntity; + + private ChallengeSubmissionEntityBuilder() { + challengeSubmissionEntity = new ChallengeSubmissionEntity(); + } + + private ChallengeSubmissionEntityBuilder(ChallengeSubmissionEntity challengeSubmissionEntity) { + this.challengeSubmissionEntity = challengeSubmissionEntity; + } + + public ChallengeSubmissionEntityBuilder withChallengeSubmissionId(Long challengeSubmissionId) { + challengeSubmissionEntity.challengeSubmissionId = challengeSubmissionId; + return this; + } + + public ChallengeSubmissionEntityBuilder withRegistrantId(Long registrantId) { + challengeSubmissionEntity.registrantId = registrantId; + return this; + } + + public ChallengeSubmissionEntityBuilder withRegistrantName(String registrantName) { + challengeSubmissionEntity.registrantName = registrantName; + return this; + } + + public ChallengeSubmissionEntityBuilder withChallengeId(Long challengeId) { + challengeSubmissionEntity.challengeId = challengeId; + return this; + } + + public ChallengeSubmissionEntityBuilder withSubmissionURL(String submissionURL) { + challengeSubmissionEntity.submissionURL = submissionURL; + return this; + } + + public ChallengeSubmissionEntityBuilder withSubmissionDateTime(String submissionDateTime) { + challengeSubmissionEntity.submissionDateTime = submissionDateTime; + return this; + } + + public ChallengeSubmissionEntityBuilder withSubmissionDescription(String submissionDescription) { + challengeSubmissionEntity.submissionDescription = submissionDescription; + return this; + } + + public ChallengeSubmissionEntityBuilder withSubmissionPhase(ChallengePhaseEnum submissionPhase) { + challengeSubmissionEntity.submissionPhase = submissionPhase; + return this; + } + + public static ChallengeSubmissionEntityBuilder challengeSubmissionEntity() { + return new ChallengeSubmissionEntityBuilder(); + } + + public static ChallengeSubmissionEntityBuilder challengeSubmissionEntity(ChallengeSubmissionEntity entity) { + return new ChallengeSubmissionEntityBuilder(entity); + } + + public ChallengeSubmissionEntity build() { + return challengeSubmissionEntity; + } } - } } diff --git a/src/main/java/com/techlooper/model/ChallengePhaseEnum.java b/src/main/java/com/techlooper/model/ChallengePhaseEnum.java index 935ab98b2..79613fa0c 100644 --- a/src/main/java/com/techlooper/model/ChallengePhaseEnum.java +++ b/src/main/java/com/techlooper/model/ChallengePhaseEnum.java @@ -5,47 +5,61 @@ */ public enum ChallengePhaseEnum { - ALL_PHASES("startDateTime", "registrationDateTime", "ALL_PHASE"), - REGISTRATION("startDateTime", "registrationDateTime", "REGISTRATION"), - IN_PROGRESS("registrationDateTime", "submissionDateTime", "IN_PROGRESS"), - IDEA("registrationDateTime", "ideaSubmissionDateTime", "IDEA"), - UIUX("ideaSubmissionDateTime", "uxSubmissionDateTime", "UIUX"), - PROTOTYPE("uxSubmissionDateTime", "prototypeSubmissionDateTime", "PROTOTYPE"), - FINAL("prototypeSubmissionDateTime", "submissionDateTime", "FINAL"); + ALL_PHASES("startDateTime", "registrationDateTime", "ALL_PHASE", 0), + REGISTRATION("startDateTime", "registrationDateTime", "REGISTRATION", 1), + IN_PROGRESS("registrationDateTime", "submissionDateTime", "IN_PROGRESS", 2), + IDEA("registrationDateTime", "ideaSubmissionDateTime", "IDEA", 3), + UIUX("ideaSubmissionDateTime", "uxSubmissionDateTime", "UIUX", 4), + PROTOTYPE("uxSubmissionDateTime", "prototypeSubmissionDateTime", "PROTOTYPE", 5), + FINAL("prototypeSubmissionDateTime", "submissionDateTime", "FINAL", 6), + WINNER("prototypeSubmissionDateTime", "submissionDateTime", "WINNER", 7); - private String fromDateTimeField; + private String fromDateTimeField; - private String toDateTimeField; + private String toDateTimeField; - private String value; + private String value; - ChallengePhaseEnum(String fromDateTimeField, String toDateTimeField, String value) { - this.fromDateTimeField = fromDateTimeField; - this.toDateTimeField = toDateTimeField; - this.value = value; - } + private Integer order; - public String getFromDateTimeField() { - return fromDateTimeField; - } + public static ChallengePhaseEnum[] ALL_CHALLENGE_PHASES = {REGISTRATION, IDEA, UIUX, PROTOTYPE, FINAL}; - public void setFromDateTimeField(String fromDateTimeField) { - this.fromDateTimeField = fromDateTimeField; - } + ChallengePhaseEnum(String fromDateTimeField, String toDateTimeField, String value, Integer order) { + this.fromDateTimeField = fromDateTimeField; + this.toDateTimeField = toDateTimeField; + this.value = value; + this.order = order; + } - public String getToDateTimeField() { - return toDateTimeField; - } + public String getFromDateTimeField() { + return fromDateTimeField; + } - public void setToDateTimeField(String toDateTimeField) { - this.toDateTimeField = toDateTimeField; - } + public void setFromDateTimeField(String fromDateTimeField) { + this.fromDateTimeField = fromDateTimeField; + } - public String getValue() { - return value; - } + public String getToDateTimeField() { + return toDateTimeField; + } - public void setValue(String value) { - this.value = value; - } + public void setToDateTimeField(String toDateTimeField) { + this.toDateTimeField = toDateTimeField; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Integer getOrder() { + return order; + } + + public void setOrder(Integer order) { + this.order = order; + } } diff --git a/src/main/java/com/techlooper/model/ChallengeRegistrantFunnelItem.java b/src/main/java/com/techlooper/model/ChallengeRegistrantFunnelItem.java new file mode 100644 index 000000000..baeb7ce1a --- /dev/null +++ b/src/main/java/com/techlooper/model/ChallengeRegistrantFunnelItem.java @@ -0,0 +1,46 @@ +package com.techlooper.model; + +/** + * Created by NguyenDangKhoa on 10/26/15. + */ +public class ChallengeRegistrantFunnelItem { + + private ChallengePhaseEnum phase; + + private Long participant; + + private Long submission; + + public ChallengeRegistrantFunnelItem() { + } + + public ChallengeRegistrantFunnelItem(ChallengePhaseEnum phase, Long participant, Long submission) { + this.phase = phase; + this.participant = participant; + this.submission = submission; + } + + public ChallengePhaseEnum getPhase() { + return phase; + } + + public void setPhase(ChallengePhaseEnum phase) { + this.phase = phase; + } + + public Long getParticipant() { + return participant; + } + + public void setParticipant(Long participant) { + this.participant = participant; + } + + public Long getSubmission() { + return submission; + } + + public void setSubmission(Long submission) { + this.submission = submission; + } +} diff --git a/src/main/java/com/techlooper/model/ChallengeRegistrantPhaseItem.java b/src/main/java/com/techlooper/model/ChallengeRegistrantPhaseItem.java new file mode 100644 index 000000000..05275bca0 --- /dev/null +++ b/src/main/java/com/techlooper/model/ChallengeRegistrantPhaseItem.java @@ -0,0 +1,36 @@ +package com.techlooper.model; + +/** + * Created by NguyenDangKhoa on 10/26/15. + */ +public class ChallengeRegistrantPhaseItem { + + private ChallengePhaseEnum phase; + + private Long registration; + + public ChallengeRegistrantPhaseItem() { + } + + public ChallengeRegistrantPhaseItem(ChallengePhaseEnum phase, Long registration) { + this.phase = phase; + this.registration = registration; + } + + public ChallengePhaseEnum getPhase() { + return phase; + } + + public void setPhase(ChallengePhaseEnum phase) { + this.phase = phase; + } + + public Long getRegistration() { + return registration; + } + + public void setRegistration(Long registration) { + this.registration = registration; + } + +} diff --git a/src/main/java/com/techlooper/model/ChallengeSubmissionPhaseItem.java b/src/main/java/com/techlooper/model/ChallengeSubmissionPhaseItem.java new file mode 100644 index 000000000..e145a4103 --- /dev/null +++ b/src/main/java/com/techlooper/model/ChallengeSubmissionPhaseItem.java @@ -0,0 +1,35 @@ +package com.techlooper.model; + +/** + * Created by NguyenDangKhoa on 10/26/15. + */ +public class ChallengeSubmissionPhaseItem { + + private ChallengePhaseEnum phase; + + private Long submission; + + public ChallengeSubmissionPhaseItem() { + } + + public ChallengeSubmissionPhaseItem(ChallengePhaseEnum phase, Long submission) { + this.phase = phase; + this.submission = submission; + } + + public ChallengePhaseEnum getPhase() { + return phase; + } + + public void setPhase(ChallengePhaseEnum phase) { + this.phase = phase; + } + + public Long getSubmission() { + return submission; + } + + public void setSubmission(Long submission) { + this.submission = submission; + } +} diff --git a/src/main/java/com/techlooper/service/ChallengeRegistrantService.java b/src/main/java/com/techlooper/service/ChallengeRegistrantService.java new file mode 100644 index 000000000..c1ce547c1 --- /dev/null +++ b/src/main/java/com/techlooper/service/ChallengeRegistrantService.java @@ -0,0 +1,18 @@ +package com.techlooper.service; + +import com.techlooper.entity.ChallengeRegistrantDto; +import com.techlooper.entity.ChallengeRegistrantEntity; +import com.techlooper.model.ChallengePhaseEnum; +import com.techlooper.model.ChallengeRegistrantPhaseItem; + +import java.util.Map; +import java.util.Set; + +public interface ChallengeRegistrantService { + + Map countNumberOfRegistrantsByPhase(Long challengeId); + + Long countNumberOfWinners(Long challengeId); + + Set findRegistrantsByChallengeIdAndPhase(Long challengeId, ChallengePhaseEnum phase, String ownerEmail); +} diff --git a/src/main/java/com/techlooper/service/ChallengeService.java b/src/main/java/com/techlooper/service/ChallengeService.java index 8e4d5022a..a35e5ead7 100644 --- a/src/main/java/com/techlooper/service/ChallengeService.java +++ b/src/main/java/com/techlooper/service/ChallengeService.java @@ -20,89 +20,92 @@ */ public interface ChallengeService { - ChallengeEntity savePostChallenge(ChallengeDto challengeDto) throws Exception; + ChallengeEntity savePostChallenge(ChallengeDto challengeDto) throws Exception; - void sendPostChallengeEmailToEmployer(ChallengeEntity challengeEntity) - throws MessagingException, IOException, TemplateException; + void sendPostChallengeEmailToEmployer(ChallengeEntity challengeEntity) + throws MessagingException, IOException, TemplateException; - void sendPostChallengeEmailToTechloopies(ChallengeEntity challengeEntity, Boolean isNewChallenge) - throws MessagingException, IOException, TemplateException; + void sendPostChallengeEmailToTechloopies(ChallengeEntity challengeEntity, Boolean isNewChallenge) + throws MessagingException, IOException, TemplateException; - void sendEmailNotifyRegistrantAboutChallengeTimeline(ChallengeEntity challengeEntity, - ChallengeRegistrantEntity challengeRegistrantEntity, ChallengePhaseEnum challengePhase) throws Exception; + void sendEmailNotifyRegistrantAboutChallengeTimeline(ChallengeEntity challengeEntity, + ChallengeRegistrantEntity challengeRegistrantEntity, ChallengePhaseEnum challengePhase) throws Exception; - ChallengeDetailDto getChallengeDetail(Long challengeId, String loginEmail); + ChallengeDetailDto getChallengeDetail(Long challengeId, String loginEmail); - Long getNumberOfRegistrants(Long challengeId); + Long getNumberOfRegistrants(Long challengeId); - void sendApplicationEmailToContestant(ChallengeEntity challengeEntity, ChallengeRegistrantEntity challengeRegistrantEntity) - throws MessagingException, IOException, TemplateException; + void sendApplicationEmailToContestant(ChallengeEntity challengeEntity, ChallengeRegistrantEntity challengeRegistrantEntity) + throws MessagingException, IOException, TemplateException; - void sendApplicationEmailToEmployer(ChallengeEntity challengeEntity, ChallengeRegistrantEntity challengeRegistrantEntity) - throws MessagingException, IOException, TemplateException; + void sendApplicationEmailToEmployer(ChallengeEntity challengeEntity, ChallengeRegistrantEntity challengeRegistrantEntity) + throws MessagingException, IOException, TemplateException; - ChallengeRegistrantEntity joinChallengeEntity(ChallengeRegistrantDto challengeRegistrantDto); + ChallengeRegistrantEntity joinChallengeEntity(ChallengeRegistrantDto challengeRegistrantDto); - long joinChallenge(ChallengeRegistrantDto challengeRegistrantDto); + long joinChallenge(ChallengeRegistrantDto challengeRegistrantDto); - List listChallenges(); + List listChallenges(); - List listChallenges(String ownerEmail); + List listChallenges(String ownerEmail); - List listChallengesByPhase(ChallengePhaseEnum challengePhase); + List listChallengesByPhase(ChallengePhaseEnum challengePhase); - Long getTotalNumberOfChallenges(); + Long getTotalNumberOfChallenges(); - Double getTotalAmountOfPrizeValues(); + Double getTotalAmountOfPrizeValues(); - Long getTotalNumberOfRegistrants(); + Long getTotalNumberOfRegistrants(); - ChallengeDetailDto getTheLatestChallenge(); + ChallengeDetailDto getTheLatestChallenge(); - Collection findByOwnerAndCondition(String owner, Predicate condition); + Collection findByOwnerAndCondition(String owner, Predicate condition); - Collection findInProgressChallenges(String owner); + Collection findInProgressChallenges(String owner); // Collection findRegistrantsByChallengeId(Long challengeId); - Long countRegistrantsByChallengeId(Long challengeId); + Long countRegistrantsByChallengeId(Long challengeId); - boolean delete(Long id, String ownerEmail); + boolean delete(Long id, String ownerEmail); - ChallengeDto findChallengeById(Long id, String ownerEmail); + ChallengeDto findChallengeById(Long id, String ownerEmail); - Set findRegistrantsByOwner(RegistrantFilterCondition condition) throws ParseException; + Set findRegistrantsByOwner(RegistrantFilterCondition condition) throws ParseException; - ChallengeRegistrantDto saveRegistrant(String ownerEmail, ChallengeRegistrantDto challengeRegistrantDto); + ChallengeRegistrantDto saveRegistrant(String ownerEmail, ChallengeRegistrantDto challengeRegistrantDto); - List findChallengeRegistrantWithinPeriod( - Long challengeId, Long currentDateTime, TimePeriodEnum period); + List findChallengeRegistrantWithinPeriod( + Long challengeId, Long currentDateTime, TimePeriodEnum period); - List filterChallengeRegistrantByDate(RegistrantFilterCondition condition) throws ParseException; + List filterChallengeRegistrantByDate(RegistrantFilterCondition condition) throws ParseException; - List findChallengeSubmissionWithinPeriod( - Long challengeId, Long currentDateTime, TimePeriodEnum period); + List findChallengeSubmissionWithinPeriod( + Long challengeId, Long currentDateTime, TimePeriodEnum period); - void sendDailySummaryEmailToChallengeOwner(ChallengeEntity challengeEntity) throws Exception; + void sendDailySummaryEmailToChallengeOwner(ChallengeEntity challengeEntity) throws Exception; - boolean isOwnerOfChallenge(String ownerEmail, Long challengeId); + boolean isOwnerOfChallenge(String ownerEmail, Long challengeId); - ChallengeEntity findChallengeIdAndOwnerEmail(Long challengeId, String ownerEmail); + ChallengeEntity findChallengeIdAndOwnerEmail(Long challengeId, String ownerEmail); - boolean sendEmailToDailyChallengeRegistrants(String challengeOwner, Long challengeId, Long now, EmailContent emailContent); + boolean sendEmailToDailyChallengeRegistrants(String challengeOwner, Long challengeId, Long now, EmailContent emailContent); - boolean sendEmailToRegistrant(String challengeOwner, Long challengeId, Long registrantId, EmailContent emailContent); + boolean sendEmailToRegistrant(String challengeOwner, Long challengeId, Long registrantId, EmailContent emailContent); - List findChallengeSubmissionByRegistrant(Long challengeId, Long registrantId); + List findChallengeSubmissionByRegistrant(Long challengeId, Long registrantId); - void updateSendEmailToContestantResultCode(ChallengeRegistrantEntity challengeRegistrantEntity, EmailSentResultEnum code); + void updateSendEmailToContestantResultCode(ChallengeRegistrantEntity challengeRegistrantEntity, EmailSentResultEnum code); - void updateSendEmailToChallengeOwnerResultCode(ChallengeEntity challengeEntity, EmailSentResultEnum code); + void updateSendEmailToChallengeOwnerResultCode(ChallengeEntity challengeEntity, EmailSentResultEnum code); - Set findRegistrantByChallengeSubmissionDate(Long challengeId, String fromDate, String toDate); + Set findRegistrantByChallengeSubmissionDate(Long challengeId, String fromDate, String toDate); - ChallengeRegistrantDto acceptRegistrant(String ownerEmail, Long registrantId); + ChallengeRegistrantDto acceptRegistrant(String ownerEmail, Long registrantId); - void calculateChallengePhases(ChallengeDetailDto challengeDetailDto); + void calculateChallengePhases(ChallengeDetailDto challengeDetailDto); + ChallengeRegistrantEntity findRegistrantByChallengeIdAndEmail(Long challengeId, String email); + + List getChallengeRegistrantFunnel(Long challengeId); } diff --git a/src/main/java/com/techlooper/service/ChallengeSubmissionService.java b/src/main/java/com/techlooper/service/ChallengeSubmissionService.java index 5820d07b7..c6ab02abd 100644 --- a/src/main/java/com/techlooper/service/ChallengeSubmissionService.java +++ b/src/main/java/com/techlooper/service/ChallengeSubmissionService.java @@ -1,14 +1,19 @@ package com.techlooper.service; import com.techlooper.entity.ChallengeSubmissionEntity; +import com.techlooper.model.ChallengePhaseEnum; import com.techlooper.model.ChallengeSubmissionDto; +import com.techlooper.model.ChallengeSubmissionPhaseItem; + +import java.util.Map; /** * Created by phuonghqh on 10/9/15. */ public interface ChallengeSubmissionService { - ChallengeSubmissionEntity submitMyResult(ChallengeSubmissionDto challengeSubmissionDto); + ChallengeSubmissionEntity submitMyResult(ChallengeSubmissionDto challengeSubmissionDto); + Map countNumberOfSubmissionsByPhase(Long challengeId); } diff --git a/src/main/java/com/techlooper/service/impl/ChallengeRegistrantServiceImpl.java b/src/main/java/com/techlooper/service/impl/ChallengeRegistrantServiceImpl.java new file mode 100644 index 000000000..2d0f84ceb --- /dev/null +++ b/src/main/java/com/techlooper/service/impl/ChallengeRegistrantServiceImpl.java @@ -0,0 +1,122 @@ +package com.techlooper.service.impl; + +import com.techlooper.entity.ChallengeRegistrantDto; +import com.techlooper.model.ChallengePhaseEnum; +import com.techlooper.model.ChallengeRegistrantPhaseItem; +import com.techlooper.repository.elasticsearch.ChallengeRegistrantRepository; +import com.techlooper.service.ChallengeRegistrantService; +import com.techlooper.service.ChallengeService; +import org.dozer.Mapper; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.index.query.BoolFilterBuilder; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.FilterBuilders; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.*; + +import static com.techlooper.model.ChallengePhaseEnum.*; +import static org.elasticsearch.index.query.FilterBuilders.*; +import static org.elasticsearch.index.query.QueryBuilders.*; + +@Service +public class ChallengeRegistrantServiceImpl implements ChallengeRegistrantService { + + @Resource + private ElasticsearchTemplate elasticsearchTemplate; + + private final List CHALLENGE_PHASES = Arrays.asList(FINAL, PROTOTYPE, UIUX, IDEA); + + @Resource + private ChallengeService challengeService; + + @Resource + private ChallengeRegistrantRepository challengeRegistrantRepository; + + @Resource + private Mapper dozerMapper; + + public Map countNumberOfRegistrantsByPhase(Long challengeId) { + Map numberOfRegistrantsByPhase = new HashMap<>(); + + NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder().withIndices("techlooper") + .withTypes("challengeRegistrant").withSearchType(SearchType.COUNT); + searchQueryBuilder.withQuery(termQuery("challengeId", challengeId)); + + Long numberOfRegistrants = elasticsearchTemplate.count(searchQueryBuilder.build()); + numberOfRegistrantsByPhase.put(REGISTRATION, new ChallengeRegistrantPhaseItem(REGISTRATION, numberOfRegistrants)); + + searchQueryBuilder.addAggregation(AggregationBuilders.terms("sumOfRegistrants").field("activePhase")); + Aggregations aggregations = elasticsearchTemplate.query(searchQueryBuilder.build(), SearchResponse::getAggregations); + Terms terms = aggregations.get("sumOfRegistrants"); + + + Long previousPhase = 0L; + for (ChallengePhaseEnum phaseEnum : CHALLENGE_PHASES) { + Terms.Bucket bucket = terms.getBucketByKey(phaseEnum.getValue()); + if (bucket != null) { + numberOfRegistrantsByPhase.put(phaseEnum, new ChallengeRegistrantPhaseItem(phaseEnum, + bucket.getDocCount() + previousPhase)); + previousPhase = bucket.getDocCount() + previousPhase; + } else { + bucket = terms.getBucketByKey(phaseEnum.getValue().toLowerCase()); + if (bucket != null) { + numberOfRegistrantsByPhase.put(phaseEnum, new ChallengeRegistrantPhaseItem(phaseEnum, + bucket.getDocCount() + previousPhase)); + previousPhase = bucket.getDocCount() + previousPhase; + } else { + numberOfRegistrantsByPhase.put(phaseEnum, new ChallengeRegistrantPhaseItem(phaseEnum, previousPhase)); + } + } + } + return numberOfRegistrantsByPhase; + } + + public Long countNumberOfWinners(Long challengeId) { + NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder().withIndices("techlooper") + .withTypes("challengeRegistrant").withSearchType(SearchType.COUNT); + + BoolFilterBuilder boolFilterBuilder = boolFilter(); + boolFilterBuilder.must(termFilter("challengeId", challengeId)); + boolFilterBuilder.must(termFilter("activePhase", ChallengePhaseEnum.FINAL.getValue())); + boolFilterBuilder.mustNot(missingFilter("criteria")); + + searchQueryBuilder.withQuery(filteredQuery(matchAllQuery(), boolFilterBuilder)); + return elasticsearchTemplate.count(searchQueryBuilder.build()); + } + + public Set findRegistrantsByChallengeIdAndPhase(Long challengeId, ChallengePhaseEnum phase, String ownerEmail) { + if (!challengeService.isOwnerOfChallenge(ownerEmail, challengeId)) { + return null; + } + + BoolQueryBuilder challengeQuery = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("challengeId", challengeId)); + BoolQueryBuilder toPhaseQuery = QueryBuilders.boolQuery(); + challengeQuery.must(toPhaseQuery); + + if (phase == REGISTRATION) { + toPhaseQuery.should(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.missingFilter("activePhase"))); + } + for (int i = ChallengePhaseEnum.ALL_CHALLENGE_PHASES.length - 1; i >= 0; i--) { + toPhaseQuery.should(QueryBuilders.termQuery("activePhase", ALL_CHALLENGE_PHASES[i])); + if (phase == ALL_CHALLENGE_PHASES[i]) break; + } + + Set registrantDtos = new HashSet<>(); + challengeRegistrantRepository.search(challengeQuery).forEach(entity -> { + ChallengeRegistrantDto dto = dozerMapper.map(entity, ChallengeRegistrantDto.class); + dto.setSubmissions(challengeService.findChallengeSubmissionByRegistrant(challengeId, entity.getRegistrantId())); + registrantDtos.add(dto); + }); + + return registrantDtos; + } +} diff --git a/src/main/java/com/techlooper/service/impl/ChallengeServiceImpl.java b/src/main/java/com/techlooper/service/impl/ChallengeServiceImpl.java index 648fbef10..16e2edf8c 100644 --- a/src/main/java/com/techlooper/service/impl/ChallengeServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/ChallengeServiceImpl.java @@ -6,10 +6,7 @@ import com.techlooper.repository.elasticsearch.ChallengeRegistrantRepository; import com.techlooper.repository.elasticsearch.ChallengeRepository; import com.techlooper.repository.elasticsearch.ChallengeSubmissionRepository; -import com.techlooper.service.ChallengeService; -import com.techlooper.service.CurrencyService; -import com.techlooper.service.EmailService; -import com.techlooper.service.EmployerService; +import com.techlooper.service.*; import com.techlooper.util.DataUtils; import freemarker.template.Template; import freemarker.template.TemplateException; @@ -190,6 +187,12 @@ public class ChallengeServiceImpl implements ChallengeService { @Resource private CurrencyService currencyService; + @Resource + private ChallengeRegistrantService challengeRegistrantService; + + @Resource + private ChallengeSubmissionService challengeSubmissionService; + public ChallengeEntity savePostChallenge(ChallengeDto challengeDto) throws Exception { ChallengeEntity challengeEntity = dozerMapper.map(challengeDto, ChallengeEntity.class); if (challengeDto.getChallengeId() == null) { @@ -468,14 +471,22 @@ private List sortChallengesByDescendingStartDate(List 0); + List registrantEntities = DataUtils.getAllEntities(challengeRegistrantRepository, searchQueryBuilder); + if (!registrantEntities.isEmpty()) { + return registrantEntities.get(0); + } + return null; + } + + public boolean checkIfChallengeRegistrantExist(Long challengeId, String email) { + return findRegistrantByChallengeIdAndEmail(challengeId, email) != null; } @Override @@ -998,4 +1009,29 @@ public ChallengeRegistrantDto acceptRegistrant(String ownerEmail, Long registran return dozerMapper.map(registrant, ChallengeRegistrantDto.class); } + @Override + public List getChallengeRegistrantFunnel(Long challengeId) { + List funnel = new ArrayList<>(); + Map numberOfRegistrantsByPhase = + challengeRegistrantService.countNumberOfRegistrantsByPhase(challengeId); + Map numberOfSubmissionsByPhase = + challengeSubmissionService.countNumberOfSubmissionsByPhase(challengeId); + + for (Map.Entry entry : numberOfRegistrantsByPhase.entrySet()) { + ChallengePhaseEnum phase = entry.getKey(); + Long participant = entry.getValue().getRegistration(); + Long submission = 0L; + if (numberOfSubmissionsByPhase.get(phase) != null) { + submission = numberOfSubmissionsByPhase.get(phase).getSubmission(); + } + funnel.add(new ChallengeRegistrantFunnelItem(phase, participant, submission)); + } + +// Long numberOfWinners = challengeRegistrantService.countNumberOfWinners(challengeId); +// funnel.add(new ChallengeRegistrantFunnelItem(ChallengePhaseEnum.WINNER, numberOfWinners, numberOfWinners)); + + Comparator sortByPhaseComparator = (item1, item2) -> + item1.getPhase().getOrder() - item2.getPhase().getOrder(); + return funnel.stream().sorted(sortByPhaseComparator).collect(toList()); + } } diff --git a/src/main/java/com/techlooper/service/impl/ChallengeSubmissionServiceImpl.java b/src/main/java/com/techlooper/service/impl/ChallengeSubmissionServiceImpl.java index ba8df4002..f1359e2f8 100644 --- a/src/main/java/com/techlooper/service/impl/ChallengeSubmissionServiceImpl.java +++ b/src/main/java/com/techlooper/service/impl/ChallengeSubmissionServiceImpl.java @@ -4,22 +4,32 @@ import com.techlooper.entity.ChallengeRegistrantEntity; import com.techlooper.entity.ChallengeSubmissionEntity; import com.techlooper.entity.ChallengeSubmissionEntity.ChallengeSubmissionEntityBuilder; +import com.techlooper.model.ChallengePhaseEnum; import com.techlooper.model.ChallengeSubmissionDto; -import com.techlooper.repository.elasticsearch.ChallengeRegistrantRepository; +import com.techlooper.model.ChallengeSubmissionPhaseItem; import com.techlooper.repository.elasticsearch.ChallengeSubmissionRepository; import com.techlooper.service.ChallengeService; import com.techlooper.service.ChallengeSubmissionService; import com.techlooper.util.DateTimeUtils; import org.dozer.Mapper; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchType; import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.index.query.MatchQueryBuilder; -import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.Iterator; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import static org.elasticsearch.index.query.QueryBuilders.*; +import static com.techlooper.model.ChallengePhaseEnum.*; /** * Created by phuonghqh on 10/9/15. @@ -27,34 +37,63 @@ @Service public class ChallengeSubmissionServiceImpl implements ChallengeSubmissionService { - @Resource - private ChallengeRegistrantRepository challengeRegistrantRepository; + @Resource + private ChallengeService challengeService; - @Resource - private ChallengeService challengeService; + @Resource + private Mapper dozerMapper; - @Resource - private Mapper dozerMapper; + @Resource + private ChallengeSubmissionRepository challengeSubmissionRepository; - @Resource - private ChallengeSubmissionRepository challengeSubmissionRepository; + @Resource + private ElasticsearchTemplate elasticsearchTemplate; - public ChallengeSubmissionEntity submitMyResult(ChallengeSubmissionDto challengeSubmissionDto) { - MatchQueryBuilder registrantEmailQuery = matchQuery("registrantEmail", challengeSubmissionDto.getRegistrantEmail()).minimumShouldMatch("100%"); - TermQueryBuilder challengeQuery = termQuery("challengeId", challengeSubmissionDto.getChallengeId()); - Iterator registrantIterator = challengeRegistrantRepository.search( - boolQuery().must(registrantEmailQuery).must(challengeQuery)).iterator(); + private final List CHALLENGE_PHASES = Arrays.asList(REGISTRATION, IDEA, UIUX, PROTOTYPE, FINAL); - ChallengeRegistrantEntity registrant = registrantIterator.hasNext() ? registrantIterator.next() : - challengeService.joinChallengeEntity(dozerMapper.map(challengeSubmissionDto, ChallengeRegistrantDto.class)); + public ChallengeSubmissionEntity submitMyResult(ChallengeSubmissionDto challengeSubmissionDto) { + ChallengeRegistrantEntity registrant = challengeService.findRegistrantByChallengeIdAndEmail( + challengeSubmissionDto.getChallengeId(), challengeSubmissionDto.getRegistrantEmail()); + if (registrant == null) { + registrant = challengeService.joinChallengeEntity(dozerMapper.map(challengeSubmissionDto, ChallengeRegistrantDto.class)); + } + ChallengePhaseEnum activePhase = registrant.getActivePhase() == null ? ChallengePhaseEnum.REGISTRATION : registrant.getActivePhase(); - ChallengeSubmissionEntity challengeSubmissionEntity = dozerMapper.map(challengeSubmissionDto, ChallengeSubmissionEntity.class); - ChallengeSubmissionEntityBuilder.challengeSubmissionEntity(challengeSubmissionEntity) - .withChallengeSubmissionId(DateTime.now().getMillis()) - .withRegistrantId(registrant.getRegistrantId()) - .withRegistrantName(String.format("%s %s", registrant.getRegistrantFirstName(), registrant.getRegistrantLastName())) - .withSubmissionDateTime(DateTimeUtils.currentDate()); + ChallengeSubmissionEntity challengeSubmissionEntity = dozerMapper.map(challengeSubmissionDto, ChallengeSubmissionEntity.class); + ChallengeSubmissionEntityBuilder.challengeSubmissionEntity(challengeSubmissionEntity) + .withChallengeSubmissionId(DateTime.now().getMillis()) + .withRegistrantId(registrant.getRegistrantId()) + .withRegistrantName(String.format("%s %s", registrant.getRegistrantFirstName(), registrant.getRegistrantLastName())) + .withSubmissionDateTime(DateTimeUtils.currentDate()) + .withSubmissionPhase(activePhase); - return challengeSubmissionRepository.save(challengeSubmissionEntity); - } + return challengeSubmissionRepository.save(challengeSubmissionEntity); + } + + @Override + public Map countNumberOfSubmissionsByPhase(Long challengeId) { + Map numberOfSubmissionsByPhase = new HashMap<>(); + + NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder().withIndices("techlooper") + .withTypes("challengeSubmission").withSearchType(SearchType.COUNT); + searchQueryBuilder.withQuery(QueryBuilders.termQuery("challengeId", challengeId)); + searchQueryBuilder.addAggregation(AggregationBuilders.terms("sumOfSubmissions").field("submissionPhase")); + Aggregations aggregations = elasticsearchTemplate.query(searchQueryBuilder.build(), SearchResponse::getAggregations); + + Terms terms = aggregations.get("sumOfSubmissions"); + for (ChallengePhaseEnum phaseEnum : CHALLENGE_PHASES) { + Terms.Bucket bucket = terms.getBucketByKey(phaseEnum.getValue()); + if (bucket != null) { + numberOfSubmissionsByPhase.put(phaseEnum, new ChallengeSubmissionPhaseItem(phaseEnum, bucket.getDocCount())); + } else { + bucket = terms.getBucketByKey(phaseEnum.getValue().toLowerCase()); + if (bucket != null) { + numberOfSubmissionsByPhase.put(phaseEnum, new ChallengeSubmissionPhaseItem(phaseEnum, bucket.getDocCount())); + } else { + numberOfSubmissionsByPhase.put(phaseEnum, new ChallengeSubmissionPhaseItem(phaseEnum, 0L)); + } + } + } + return numberOfSubmissionsByPhase; + } } diff --git a/src/main/resources/template/challengeDailySummary.en.ftl b/src/main/resources/template/challengeDailySummary.en.ftl index 00ec33cbe..a94527000 100644 --- a/src/main/resources/template/challengeDailySummary.en.ftl +++ b/src/main/resources/template/challengeDailySummary.en.ftl @@ -207,17 +207,17 @@ <#list latestRegistrants as registrant> - - - + + + - - - + + + - <#if latestSubmissions?has_content> + <#if latestSubmissions?has_content> - +
- - - -
+ + + +
${registrant_index + 1}${registrant.registrantFirstName} ${registrant.registrantLastName}
${registrant_index + 1}${registrant.registrantFirstName} ${registrant.registrantLastName}
@@ -292,7 +292,7 @@
@@ -315,35 +315,38 @@ <#list latestSubmissions as latestSubmission> + + + + + + + - @@ -356,7 +359,7 @@
+ +
+ + + + + +
${latestSubmission_index + 1}${latestSubmission.registrantName}
+
- - - - - -
${latestSubmission_index + 1}${latestSubmission.registrantName}
- + -
+ - - -
- Review - Feedback - - Accept + + Review All
diff --git a/src/main/resources/template/challengeDailySummary.vi.ftl b/src/main/resources/template/challengeDailySummary.vi.ftl index 0556b68af..423121848 100644 --- a/src/main/resources/template/challengeDailySummary.vi.ftl +++ b/src/main/resources/template/challengeDailySummary.vi.ftl @@ -2,412 +2,416 @@ - - - - - - + @media (device-width: 320px) { + body { + max-width: 100% !important; + } + [class=hidden] { + display: none + } + [class=body-content] { + max-width: 100% !important; + width: 100% !important; + } + p[class=bottom-links] span { + display: block; + } + [class=cta-large] { + font-size: 24px !important; + } + [class=candidate] td { + font-size: 24px !important; + line-height: 30px !important; + } + [class=content-padding] { + padding: 20px !important; + } + [class=email] { + color: #00b9f2; + display: inline-block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + vertical-align: middle; + width: 240px; + } + [class=small-text] { + font-size: 13px !important; + white-space: nowrap !important + } + [class=logo] img { + width: 100px; + } + [class=fullWidth] { + width: 100% !important; + } + [class=btnFull] { + width: 100% !important; + padding: 10px 0 !important + } + .fullWidth { + width: 100% !important; + } + } + + - -
- - - + +
+ + + + +
+
+ + - +
-
- - + + + +
+ + + + + + + +
+ + + + + +
+
+ + + - + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+

Thử Thách Trực Tuyến

+
+

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.

+
+ +
+

Xin chào,

+
+ +
+

Dưới đây là báo cáo hằng ngày cho thử thách ${challengeName} trong vòng 24 giờ qua

+
+ +
+ + + + + + + + + + + + + + <#if latestSubmissions?has_content> + + - - + + + + + + + + + + + + +
+ - - + -
Thử thách của bạn mở rộng như thế nào trong 24 giờ qua
- - +
+ - - - + -
- - - - - - + +
- - - - + + <#if latestRegistrants?has_content> + + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <#if latestSubmissions?has_content> - - - - - - - - - - - - - + + + +
-

Thử Thách Trực Tuyến

-
-

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.

-
- -
-

Xin chào,

-
- -
-

Dưới đây là báo cáo hằng ngày cho thử thách ${challengeName} trong vòng 24 giờ qua

-
- -
- - - - - <#if latestRegistrants?has_content> - - - - - - - -
- - - - -
Thử thách của bạn mở rộng như thế nào trong 24 giờ qua
- - - - - - - -
- -
- Bạn nhận được thêm ${numberOfRegistrants} đăng ký mới -
- <#if latestRegistrants?has_content> - - <#list latestRegistrants as registrant> - - - - - - - - - - - - - -
- - - -
${registrant_index + 1}${registrant.registrantFirstName} ${registrant.registrantLastName}
- - - -
- -
- - - - -
- Gửi Email Cho Tất Cả -
-
- -
-
- -
- - - - -
- - - - -
Đây có phải là thời điểm để quảng bá cho thử thách của bạn?
- - - - - - - - - - -
- -
Nếu bạn muốn nhận thêm nhiều lượt đăng ký, trả lời email này để chúng tôi có thể hỗ trợ bạn.
- -
-
-
- -
- - - - - - - - -
- - - - -
Khám phá số lượng bài nộp mới vào thử thách
- - - - - - - - <#list latestSubmissions as latestSubmission> - - - - - - - -
- -
- Bạn nhận được thêm ${numberOfSubmissions} bài nộp mới : -
- -
- - - - - -
${latestSubmission_index + 1}${latestSubmission.registrantName}
- - - - - - -
- Xem Trước - Phản Hồi - - Đi Tiếp -
-
-
- -
-
- -
- - - - -
- -
-
- - - - - - - -
-

KẾT NỐI VỚI CHÚNG TÔI

-
- - LinkedIn - -
- - - - - -
-
+ Bạn nhận được thêm ${numberOfRegistrants} đăng ký mới +
+ <#if latestRegistrants?has_content> + + <#list latestRegistrants as registrant> + + + + + + + + + + + + + +
+ + + +
${registrant_index + 1}${registrant.registrantFirstName} ${registrant.registrantLastName}
+ + + +
+ +
+ + + + +
+ Gửi Email Cho Tất Cả +
+
+ +
+
+ +
+ + + + +
+ + + + +
Đây có phải là thời điểm để quảng bá cho thử thách của bạn?
+ + + + + + + + + + +
+ +
Nếu bạn muốn nhận thêm nhiều lượt đăng ký, trả lời email này để chúng tôi có thể hỗ trợ bạn.
+ +
+
+
+ +
+ + + + + + + +
+ + + + +
Khám phá số lượng bài nộp mới vào thử thách
+ + + + + + + + <#list latestSubmissions as latestSubmission> + + + + + + + + + + + + - + + +
+ +
+ Bạn nhận được thêm ${numberOfSubmissions} bài nộp mới : +
+ +
+ + + + + +
${latestSubmission_index + 1}${latestSubmission.registrantName}
+
+ +
+ + + +
+ Xem Tất Cả +
-
+
+ +
-
+ +
+ + + + +
+ +
+
+ + + + + + + +
+

KẾT NỐI VỚI CHÚNG TÔI

+
+ + LinkedIn + +
+ + + + + +
+
+
-
+
diff --git a/src/main/webapp/assets/modules/common/apiService.js b/src/main/webapp/assets/modules/common/apiService.js index 6d5ee90a8..f576a3617 100644 --- a/src/main/webapp/assets/modules/common/apiService.js +++ b/src/main/webapp/assets/modules/common/apiService.js @@ -30,12 +30,16 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht //}, getSocialLoginUrl: function (provider) { - return $http.get("social/" + provider + "/loginUrl", {transformResponse: function (d, h) {return d;}}); + return $http.get("social/" + provider + "/loginUrl", { + transformResponse: function (d, h) { + return d; + } + }); }, getContestDetail: function (id) { return $http.get("challenge/" + id) - .success(function(data) { + .success(function (data) { $filter("challengeDetail")(data); }); }, @@ -49,16 +53,20 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht registrantEmail: registrantEmail, lang: lang }, - {transformResponse: function (d, h) {return d;}}); + { + transformResponse: function (d, h) { + return d; + } + }); }, searchContests: function () { return $http.get("challenge/list"); - //.success(function (contests) { - // $.each(contests, function (i, contest) { - // $filter("progress")(contest, "challenge"); - // }); - //}); + //.success(function (contests) { + // $.each(contests, function (i, contest) { + // $filter("progress")(contest, "challenge"); + // }); + //}); }, getSuggestSkills: function (text) { @@ -97,7 +105,11 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht projectId: projectId, registrantFirstName: firstName, registrantLastName: lastName, registrantEmail: email, registrantPhoneNumber: phoneNumber, resumeLink: resumeLink, lang: lang }, - {transformResponse: function (d, h) {return d;}}); + { + transformResponse: function (d, h) { + return d; + } + }); }, /** @@ -202,8 +214,8 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht * */ getChallengeRegistrants: function (registrantFilterCondition) { return $http.post("challenges/" + registrantFilterCondition.challengeId + "/registrants", registrantFilterCondition) - .success(function(registrants) { - $.each(registrants, function(i, registrant) { + .success(function (registrants) { + $.each(registrants, function (i, registrant) { $filter("challengeRegistrant")(registrant); }); }); @@ -235,7 +247,11 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht * @see com.techlooper.controller.ChallengeController.getChallengeRegistrant * */ getChallengeRegistrantFullName: function (challengeRegistrantId) { - return $http.get("challengeRegistrant/fullName/" + challengeRegistrantId, {transformResponse: function (d, h) {return d;}}); + return $http.get("challengeRegistrant/fullName/" + challengeRegistrantId, { + transformResponse: function (d, h) { + return d; + } + }); }, /** @@ -264,7 +280,11 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht * @see com.techlooper.controller.SharingController.getUrlResponseCode * */ getUrlResponseCode: function (url) { - return $http.post("resource/getUrlResponseCode", {url: url}, {transformResponse: function (d, h) {return d;}}); + return $http.post("resource/getUrlResponseCode", {url: url}, { + transformResponse: function (d, h) { + return d; + } + }); }, saveEmailSetting: function (emailSetting) { @@ -275,33 +295,53 @@ techlooper.factory("apiService", function ($rootScope, $location, jsonValue, $ht return $http.get("user/employer/emailSetting"); }, - getAvailableEmailTemplates : function () { + getAvailableEmailTemplates: function () { return $http.get("emailTemplates"); }, - getTemplateById : function (templateId) { + getTemplateById: function (templateId) { return $http.get("emailTemplates/" + templateId); }, /** * @see com.techlooper.controller.ChallengeCriteriaController.saveChallengeCriteria * */ - saveChallengeCriteria: function(criteria) { + saveChallengeCriteria: function (criteria) { return $http.post("challenge/criteria", criteria); }, /** * @see com.techlooper.controller.ChallengeCriteriaController.saveChallengeRegistrantCriteria * */ - saveChallengeRegistrantCriteria: function(criteria) { + saveChallengeRegistrantCriteria: function (criteria) { return $http.post("challengeRegistrant/criteria", criteria); }, /** * @see com.techlooper.controller.ChallengeCriteriaController.findByChallengeRegistrantId * */ - findRegistrantCriteriaByRegistrantId: function(registrantId) { + findRegistrantCriteriaByRegistrantId: function (registrantId) { return $http.get("challengeRegistrant/" + registrantId + "/criteria"); + }, + + findRegistrantActivePhase: function (challengeId, registrantEmail) { + return $http.get("user/challengeSubmissionPhase/" + registrantEmail + "/" + challengeId); + }, + + getRegistrantFunnel: function (id) { + return $http.get("challenges/"+ id + "/registrantFunnel"); + }, + + /** + * @see com.techlooper.controller.ChallengeController.getChallengeRegistrantsByPhase + * */ + getChallengeRegistrantsByPhase: function(challengeId, phase) { + return $http.get("challenge/" + challengeId + "/registrants/" + phase) + .success(function(registrants) { + $.each(registrants, function (i, registrant) { + $filter("challengeRegistrant")(registrant, phase); + }); + }); } }; diff --git a/src/main/webapp/assets/modules/common/challenge/submissionChallenge.html b/src/main/webapp/assets/modules/common/challenge/submissionChallenge.html index b08cc2c72..080f58446 100644 --- a/src/main/webapp/assets/modules/common/challenge/submissionChallenge.html +++ b/src/main/webapp/assets/modules/common/challenge/submissionChallenge.html @@ -8,6 +8,10 @@ {{submission.registrantEmail}}
+
+ + {{submission.submissionPhase | textTruncate: 'lowercase' | translate}} +