Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.linkedout.backend.converter.experience

import com.linkedout.backend.dto.experience.CreateRecommendationExperienceDto
import com.linkedout.proto.dto.experience.CreateRecommendationExperienceDtoOuterClass
import org.springframework.core.convert.converter.Converter

class CreateRecommendationExperienceDtoToProto : Converter<CreateRecommendationExperienceDto, CreateRecommendationExperienceDtoOuterClass.CreateRecommendationExperienceDto.Builder> {
override fun convert(source: CreateRecommendationExperienceDto): CreateRecommendationExperienceDtoOuterClass.CreateRecommendationExperienceDto.Builder {
return CreateRecommendationExperienceDtoOuterClass.CreateRecommendationExperienceDto.newBuilder()
.setId(source.id.toString())
.setProfileId(source.profileId.toString())
.setJobId(source.jobId.toString())
.setJobTitle(source.jobTitle)
.setJobCategory(source.jobCategory.toString())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.linkedout.backend.dto.experience

import java.util.UUID

data class CreateRecommendationExperienceDto(
val id: UUID,
val profileId: UUID,
val jobId: UUID,
val jobTitle: String,
val jobCategory: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.linkedout.backend.model

data class RecommendationProfile(
val id: String
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.linkedout.backend.service

import com.linkedout.backend.converter.experience.CreateExperienceDtoToProto
import com.linkedout.backend.converter.experience.CreateRecommendationExperienceDtoToProto
import com.linkedout.backend.converter.experience.UpdateExperienceDtoToProto
import com.linkedout.backend.dto.experience.CreateExperienceDto
import com.linkedout.backend.dto.experience.CreateRecommendationExperienceDto
import com.linkedout.backend.dto.experience.UpdateExperienceDto
import com.linkedout.backend.model.Address
import com.linkedout.backend.model.Company
Expand All @@ -12,6 +14,7 @@ import com.linkedout.common.service.NatsService
import com.linkedout.common.utils.RequestResponseFactory
import com.linkedout.proto.models.ExperienceOuterClass
import com.linkedout.proto.services.Profile
import com.linkedout.proto.services.Recommendations
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.time.format.DateTimeFormatter
Expand All @@ -22,11 +25,13 @@ class ExperienceService(
private val natsService: NatsService,
private val companyService: CompanyService,
private val jobService: JobService,
private val jobCategoryService: JobCategoryService,
@Value("\${app.services.experience.subjects.createOneOfUser}") private val createOneOfUserSubject: String,
@Value("\${app.services.experience.subjects.deleteOneOfUser}") private val deleteOneOfUserSubject: String,
@Value("\${app.services.experience.subjects.findAllOfUser}") private val findAllOfUserSubject: String,
@Value("\${app.services.experience.subjects.findOneOfUser}") private val findOneOfUserSubject: String,
@Value("\${app.services.experience.subjects.updateOneOfUser}") private val updateOneOfUserSubject: String
@Value("\${app.services.experience.subjects.updateOneOfUser}") private val updateOneOfUserSubject: String,
@Value("\${app.services.recommendation.subjects.createRecommendationExperience}") private val createRecommendationExperience: String
) {
fun findAllOfUser(requestId: String, userId: String): List<Experience> {
// Request experiences from the profile service
Expand Down Expand Up @@ -98,6 +103,32 @@ class ExperienceService(
throw Exception("Invalid response")
}

// Create the experience using the profile service
val requestRecommendation = RequestResponseFactory.newRequest(requestId)
.setCreateRecommendationExperienceRequest(
Recommendations.CreateRecommendationExperienceRequest.newBuilder()
.setExperience(
CreateRecommendationExperienceDtoToProto()
.convert(
CreateRecommendationExperienceDto(
UUID.fromString(response.createUserExperienceResponse.experience.id),
UUID.fromString(userId),
UUID.fromString(job.id),
job.title,
job.category
)
)
)
)
.build()

val responseRecommendation = natsService.requestWithReply(createRecommendationExperience, requestRecommendation)

// Handle the response
if (!responseRecommendation.hasCreateRecommendationExperienceResponse()) {
throw Exception("Invalid response")
}

val createUserExperienceResponse = response.createUserExperienceResponse
return convertExperienceFromProto(createUserExperienceResponse.experience, company, job)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.linkedout.common.utils.RequestResponseFactory
import com.linkedout.proto.models.JobOfferOuterClass
import com.linkedout.proto.services.Jobs
import com.linkedout.proto.services.Jobs.ApplyToJobOfferRequest
import com.linkedout.proto.services.Recommendations
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.time.LocalDate
Expand All @@ -17,25 +18,45 @@ class JobOfferService(
private val natsService: NatsService,
@Value("\${app.services.jobOffers.subjects.findAllForUser}") private val findAllSubject: String,
@Value("\${app.services.jobOffers.subjects.findOneForUser}") private val findOneSubject: String,
@Value("\${app.services.jobOffers.subjects.applyTo}") private val applyToSubject: String
@Value("\${app.services.jobOffers.subjects.findMultiple}") private val findMultipleSubject: String,
@Value("\${app.services.jobOffers.subjects.applyTo}") private val applyToSubject: String,
@Value("\${app.services.recommendation.subjects.findAll}") private val findAll: String

) {
fun findAll(requestId: String, userId: String): List<JobOffer> {
// Request job offers from the job service
val request = RequestResponseFactory.newRequest(requestId)
.setGetUserJobOffersRequest(
Jobs.GetUserJobOffersRequest.newBuilder()
.setGetRecommendationRequest(
Recommendations.GetRecommendationRequest.newBuilder()
.setUserId(userId)
)
.build()

val response = natsService.requestWithReply(findAllSubject, request)
val response = natsService.requestWithReply(findAll, request)

// Handle the response
if (!response.hasGetRecommendationResponse()) {
throw Exception("Invalid response")
}

val recommendationIds = response.getRecommendationResponse.recommendationsList.map { recommendation ->
recommendation.id // Assuming Recommendation has an 'id' field representing its ID
}

val requestJobOffers = RequestResponseFactory.newRequest(requestId)
.setGetMultipleJobOffersRequest(
Jobs.GetMultipleJobOffersRequest.newBuilder()
.addAllIds(recommendationIds)
).build()

val responseJobOffers = natsService.requestWithReply(findMultipleSubject, requestJobOffers)

// Handle the response
if (!response.hasGetUserJobOffersResponse()) {
if (!responseJobOffers.hasGetMultipleJobOffersResponse()) {
throw Exception("Invalid response")
}

val getUserJobOffersResponse = response.getUserJobOffersResponse
val getUserJobOffersResponse = responseJobOffers.getMultipleJobOffersResponse
return getUserJobOffersResponse.jobOffersList.map { jobOffer ->
convertJobOfferFromProto(jobOffer)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class JobService(
}

val getJobResponse = response.getJobResponse

return convertJobFromProto(getJobResponse.job)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.linkedout.backend.model.Address
import com.linkedout.backend.model.Profile
import com.linkedout.common.service.NatsService
import com.linkedout.common.utils.RequestResponseFactory
import com.linkedout.proto.dto.profile.CreateRecommendationProfileDtoOuterClass
import com.linkedout.proto.models.ProfileOuterClass
import com.linkedout.proto.services.Profile.DeleteProfileRequest
import com.linkedout.proto.services.Profile.GetProfilesRequestingDeletionRequest
Expand All @@ -21,6 +22,7 @@ import com.linkedout.proto.services.Profile.SetUserCvRequest
import com.linkedout.proto.services.Profile.SetUserProfilePictureRequest
import com.linkedout.proto.services.Profile.SetUserProfileRequest
import com.linkedout.proto.services.Profile.UpdateUserProfileRequest
import com.linkedout.proto.services.Recommendations
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.time.format.DateTimeFormatter
Expand All @@ -38,7 +40,8 @@ class ProfileService(
@Value("\${app.services.profile.subjects.findOneCvOfUser}") private val findOneCvOfUserSubject: String,
@Value("\${app.services.profile.subjects.saveOneCvOfUser}") private val saveOneCvOfUserSubject: String,
@Value("\${app.services.profile.subjects.findOneProfilePictureOfUser}") private val findOneProfilePictureOfUserSubject: String,
@Value("\${app.services.profile.subjects.saveOneProfilePictureOfUser}") private val saveOneProfilePictureOfUserSubject: String
@Value("\${app.services.profile.subjects.saveOneProfilePictureOfUser}") private val saveOneProfilePictureOfUserSubject: String,
@Value("\${app.services.recommendation.subjects.createRecommendationProfile}") private val createRecommendationProfile: String
) {
fun findOne(requestId: String, userId: String): ProfileWithStatsDto {
// Request profile from the profile service
Expand Down Expand Up @@ -98,6 +101,23 @@ class ProfileService(
throw Exception("Invalid response")
}

// Create the recommendation profile in neo4j
val requestRecommendation = RequestResponseFactory.newRequest(requestId)
.setCreateRecommendationProfileRequest(
Recommendations.CreateRecommendationProfileRequest.newBuilder()
.setProfile(
CreateRecommendationProfileDtoOuterClass.CreateRecommendationProfileDto
.newBuilder().setId(userId)
)
).build()

val responseRecommendation = natsService.requestWithReply(createRecommendationProfile, requestRecommendation)

// Handle the response
if (!responseRecommendation.hasCreateRecommendationProfileResponse()) {
throw Exception("Invalid response")
}

val setUserProfileResponse = response.setUserProfileResponse
return convertProfileFromProto(setUserProfileResponse.profile)
}
Expand Down
3 changes: 3 additions & 0 deletions backend/api_gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ app:
recommendation:
subjects:
findAll: recommendations.findAll
createRecommendationProfile: recommendations.createRecommendationProfile
createRecommendationExperience: recommendations.createRecommendationExperience
jobs:
subjects:
findAll: jobs.findAll
Expand All @@ -26,6 +28,7 @@ app:
jobOffers:
subjects:
findAllForUser: jobs.findAllJobOffersForUser
findMultiple: jobs.findMultipleJobOffers
findOneForUser: jobs.findOneJobOfferForUser
applyTo: jobs.applyToJobOffer
jobCategories:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.linkedout.jobs.function.jobOffers

import com.linkedout.common.utils.RequestResponseFactory
import com.linkedout.common.utils.handleRequestError
import com.linkedout.jobs.converter.jobOffers.JobOfferWithJobAndCompanyToProto
import com.linkedout.jobs.service.JobOfferService
import com.linkedout.proto.RequestOuterClass.Request
import com.linkedout.proto.ResponseOuterClass.Response
import com.linkedout.proto.services.Jobs.GetMultipleJobOffersResponse
import org.springframework.stereotype.Component
import java.util.UUID
import java.util.function.Function

@Component
class GetMultipleJobOffers(private val jobOfferService: JobOfferService) : Function<Request, Response> {
override fun apply(t: Request): Response = handleRequestError {
// Extract the request
val request = t.getMultipleJobOffersRequest
val jobOfferIds = request
.idsList
.map(UUID::fromString)

// Get the requested jobs from the database
val reactiveResponse = jobOfferService.findMultipleWithJobAndCompanyAndApplicationStatus(jobOfferIds)
.map { jobOffer ->
JobOfferWithJobAndCompanyToProto().convert(jobOffer)
}
.reduce(GetMultipleJobOffersResponse.newBuilder()) { builder, jobOffer ->
builder.addJobOffers(jobOffer)
builder
}
.map { builder ->
builder.build()
}

// Block until the response is ready
val response = reactiveResponse.block()
?: return RequestResponseFactory.newSuccessfulResponse()
.setGetMultipleJobOffersResponse(GetMultipleJobOffersResponse.getDefaultInstance())
.build()

return RequestResponseFactory.newSuccessfulResponse()
.setGetMultipleJobOffersResponse(response)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,29 @@ interface JobOfferRepository : ReactiveCrudRepository<JobOffer, UUID> {
"""
)
fun findOneForUserWithJobAndCompany(userId: UUID, jobOfferId: UUID): Mono<JobOfferWithJobAndCompanyAndApplicationStatus>

@Query(
"""
SELECT jo.id as jobOfferId,
jo.job as jobId,
jo.title as jobOfferTitle,
jo.description as jobOfferDescription,
jo.geographicArea as jobOfferGeographicArea,
jo.startdate as jobOfferStartDate,
jo.enddate as jobOfferEndDate,
jo.company as companyId,
c.name as companyName,
jo.salary as jobOfferSalary,
jc.title as jobCategoryTitle,
j.title as jobTitle,
COALESCE(ja.status, -1) as jobApplicationStatus
FROM jobOffer jo
JOIN company c ON jo.company = c.id
JOIN job j ON jo.job = j.id
JOIN jobcategory jc ON j.category = jc.id
LEFT JOIN jobapplication ja ON jo.id = ja.offerid
WHERE jo.id IN (:ids)
"""
)
fun findMultipleWithJobAndCompanyAndApplicationStatus(ids: Iterable<UUID>): Flux<JobOfferWithJobAndCompanyAndApplicationStatus>
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ class JobOfferService(
fun findOneForUser(userId: UUID, jobOfferId: UUID): Mono<JobOfferWithJobAndCompanyAndApplicationStatus> {
return jobOffer.findOneForUserWithJobAndCompany(userId, jobOfferId)
}

fun findMultipleWithJobAndCompanyAndApplicationStatus(ids: Iterable<UUID>): Flux<JobOfferWithJobAndCompanyAndApplicationStatus> {
return jobOffer.findMultipleWithJobAndCompanyAndApplicationStatus(ids)
}
}
10 changes: 9 additions & 1 deletion backend/jobs/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
spring.cloud.function.definition=getJobs;getJob;getMultipleJobs;getJobCategories;getJobCategory;getMultipleJobCategories;getCompanies;getCompany;getMultipleCompanies;ensureCompanyExists;getJobOffersForUser;getJobOfferForUser;applyToJobOffer
spring.cloud.function.definition=getJobs;getJob;getMultipleJobs;getJobCategories;getJobCategory;getMultipleJobCategories;getCompanies;getCompany;getMultipleCompanies;ensureCompanyExists;getJobOffersForUser;getJobOfferForUser;applyToJobOffer;getMultipleJobOffers

spring.cloud.stream.bindings.getJobs-in-0.destination=jobs.findAll
spring.cloud.stream.bindings.getJobs-in-0.group=jobsSvc
Expand Down Expand Up @@ -117,4 +117,12 @@ spring.cloud.stream.bindings.applyToJobOffer-out-0.group=jobsSvc
spring.cloud.stream.bindings.applyToJobOffer-out-0.binder=nats
spring.cloud.stream.bindings.applyToJobOffer-out-0.content-type=application/vnd.linkedout.proto-response

spring.cloud.stream.bindings.getMultipleJobOffers-in-0.destination=jobs.findMultipleJobOffers
spring.cloud.stream.bindings.getMultipleJobOffers-in-0.group=jobsSvc
spring.cloud.stream.bindings.getMultipleJobOffers-in-0.binder=nats
spring.cloud.stream.bindings.getMultipleJobOffers-in-0.content-type=application/vnd.linkedout.proto-request
spring.cloud.stream.bindings.getMultipleJobOffers-out-0.destination=
spring.cloud.stream.bindings.getMultipleJobOffers-out-0.group=jobsSvc
spring.cloud.stream.bindings.getMultipleJobOffers-out-0.binder=nats
spring.cloud.stream.bindings.getMultipleJobOffers-out-0.content-type=application/vnd.linkedout.proto-response
nats.spring.server=nats://localhost:4222
Loading