applications-tracker/api/src/main/kotlin/com/andr3h3nriqu3s/applications/ApplicationsController.kt

528 lines
17 KiB
Kotlin

package com.andr3h3nriqu3s.applications
import java.sql.ResultSet
import java.util.UUID
import kotlin.collections.emptyList
import kotlin.collections.setOf
import org.springframework.http.MediaType
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Service
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
data class Application(
var id: String,
var url: String,
var original_url: String?,
var unique_url: String?,
var title: String,
var user_id: String,
var extra_data: String,
var payrange: String,
var status: Int,
var company: String,
var recruiter: String,
var message: String,
var flairs: List<Flair>,
var views: List<View>,
) {
companion object : RowMapper<Application> {
override public fun mapRow(rs: ResultSet, rowNum: Int): Application {
return Application(
rs.getString("id"),
rs.getString("url"),
rs.getString("original_url"),
rs.getString("unique_url"),
rs.getString("title"),
rs.getString("user_id"),
rs.getString("extra_data"),
rs.getString("payrange"),
rs.getInt("status"),
rs.getString("company"),
rs.getString("recruiter"),
rs.getString("message"),
emptyList(),
emptyList(),
)
}
}
}
data class SubmitRequest(val text: String)
data class ListRequest(val status: Int?)
data class StatusRequest(val id: String, val status: Int)
data class FlairRequest(val id: String, val text: String)
data class UpdateUrl(val id: String, val url: String)
data class CVData(
val company: String,
val recruiter: String,
val message: String,
val flairs: List<SimpleFlair>
)
@RestController
@ControllerAdvice
@RequestMapping("/api/application")
class ApplicationsController(
val sessionService: SessionService,
val applicationService: ApplicationService,
val flairService: FlairService,
val viewService: ViewService,
) {
@GetMapping(path = ["/cv/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun getCV(@PathVariable id: String, @RequestHeader("token") token: String?): CVData? {
val user = sessionService.verifyToken(token)
val application = applicationService.findApplicationByIdNoUser(id)
if (application == null) return null
if (user == null) {
viewService.create(application.id)
}
val flairs = application.flairs.map { it.toFlairSimple() }
return CVData(application.company, application.recruiter, application.message, flairs)
}
@PostMapping(path = ["/text"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun submitText(
@RequestBody submit: SubmitRequest,
@RequestHeader("token") token: String
): Int {
val user = sessionService.verifyTokenThrow(token)
var text = submit.text.replace("=\n", "")
var urls: List<String> = emptyList()
while (true) {
var index = text.indexOf("href")
if (index == -1) {
break
}
var new_url = StringBuilder()
var found_start = false
while (true) {
if (found_start) {
if (text[index] == '"') {
break
}
new_url.append(text[index])
} else if (text[index] == '"') {
found_start = true
}
index++
}
text = text.substring(index)
urls = urls.plus(new_url.toString().replace("&amp;", "&").replace("=3D", "="))
}
print("found: ")
print(urls.size)
print(" links\n")
// jobListing is for glassdoor urls
// jobs/view is for linkeding urls
urls =
urls.filter { predicate ->
print("url: ")
print(predicate)
print("\n")
predicate.contains("jobListing") || predicate.contains("jobs/view")
}
print("found fileted: ")
print(urls.size)
print(" links\n")
urls = urls.toSet().toList()
print("removed duplicates: ")
print(urls.size)
print(" links\n")
var applications =
urls.map { elm ->
Application(
UUID.randomUUID().toString(),
if (elm.contains("linkedin")) elm.split("?")[0] else elm,
if (elm.contains("linkedin")) elm.split("?")[0] else null,
if (elm.contains("linkedin")) elm.split("?")[0] else null,
"New Aplication",
user.id,
"",
"",
0,
"",
"",
"",
emptyList(),
emptyList(),
)
}
applications =
applications.filter { elm -> applicationService.createApplication(user, elm) }
print("created new: ")
print(applications.size)
print(" links\n")
return applications.size
}
@PostMapping(path = ["/text/flair"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun textFlair(
@RequestBody info: FlairRequest,
@RequestHeader("token") token: String
): Int {
val user = sessionService.verifyTokenThrow(token)
val application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw NotFound()
}
val flairs = flairService.listUser(user)
var count = 0
for (flair: Flair in flairs) {
val regex =
Regex(
".*" + flair.expr + ".*",
setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL)
)
if (regex.matches(info.text)) {
count += 1
flairService.linkFlair(application, flair)
}
}
return count
}
@PostMapping(path = ["/list"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun list(
@RequestBody info: ListRequest,
@RequestHeader("token") token: String
): List<Application> {
val user = sessionService.verifyTokenThrow(token)
return applicationService.findAll(user, info)
}
@GetMapping(path = ["/active"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun active(@RequestHeader("token") token: String): Application? {
val user = sessionService.verifyTokenThrow(token)
val possibleApplications = applicationService.findAll(user, ListRequest(1))
if (possibleApplications.size == 0) {
return null
}
return applicationService.findApplicationById(user, possibleApplications[0].id)
}
@PutMapping(path = ["/status"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun status(
@RequestBody info: StatusRequest,
@RequestHeader("token") token: String,
): Application {
val user = sessionService.verifyTokenThrow(token)
var application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw NotFound()
}
application.status = info.status
applicationService.update(application)
return application
}
@PutMapping(path = ["/update"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun update(
@RequestBody info: Application,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
var application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw NotFound()
}
applicationService.update(info)
return info
}
@PostMapping(path = ["/update/url"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun updateUrl(
@RequestBody info: UpdateUrl,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
var application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw NotFound()
}
if (application.unique_url != null) {
throw BadRequest()
}
application.original_url = application.url
application.url = info.url
application.unique_url = info.url.split("?")[0]
var maybe_exists =
applicationService.findApplicationByUrl(
user,
application.url,
application.unique_url
)
if (maybe_exists != null) {
applicationService.delete(application)
if (maybe_exists.status == 0 && application.status == 1) {
maybe_exists.status = 1
applicationService.update(maybe_exists)
}
maybe_exists.flairs = flairService.listFromLinkApplicationId(maybe_exists.id)
return maybe_exists
}
applicationService.update(application)
application.flairs = flairService.listFromLinkApplicationId(application.id)
return application
}
@PostMapping(path = ["/reset/url/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun updateUrl(
@PathVariable id: String,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
var application = applicationService.findApplicationById(user, id)
if (application == null) {
throw NotFound()
}
if (application.unique_url == null) {
throw BadRequest()
}
application.url = application.original_url!!
application.original_url = null
application.unique_url = null
applicationService.update(application)
application.flairs = flairService.listFromLinkApplicationId(application.id)
return application
}
@DeleteMapping(path = ["/flair/{id}/{flairid}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun delete(
@PathVariable id: String,
@PathVariable flairid: String,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
val application = applicationService.findApplicationById(user, id)
if (application == null) {
throw NotFound()
}
flairService.unlinkFlair(id, flairid)
return applicationService.findApplicationById(user, id)!!
}
@DeleteMapping(path = ["/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun delete(
@PathVariable id: String,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
val application = applicationService.findApplicationById(user, id)
if (application == null) {
throw NotFound()
}
applicationService.delete(application)
return application
}
}
@Service
class ApplicationService(
val db: JdbcTemplate,
val flairService: FlairService,
val viewService: ViewService
) {
public fun findApplicationByUrl(user: UserDb, url: String, unique_url: String?): Application? {
if (unique_url != null) {
val unique: List<Application> =
db.query(
"select * from applications where unique_url=? and user_id=?",
arrayOf(unique_url, user.id),
Application
)
.toList()
if (unique.size != 0) {
return unique[0]
}
}
val applications: List<Application> =
db.query(
"select * from applications where url=? and user_id=?",
arrayOf(url, user.id),
Application
)
.toList()
if (applications.size == 0) {
return null
}
return applications[0]
}
public fun findApplicationById(user: UserDb, id: String): Application? {
var applications =
db.query(
"select * from applications where id=? and user_id=?",
arrayOf(id, user.id),
Application
)
.toList()
if (applications.size == 0) {
return null
}
var application = applications[0]
application.flairs = flairService.listFromLinkApplicationId(application.id)
application.views = viewService.listFromApplicationId(application.id)
return application
}
public fun findApplicationByIdNoUser(id: String): Application? {
var applications =
db.query("select * from applications where id=?", arrayOf(id), Application).toList()
if (applications.size == 0) {
return null
}
var application = applications[0]
// Views are not needed for this request
application.flairs = flairService.listFromLinkApplicationId(application.id)
return application
}
public fun createApplication(user: UserDb, application: Application): Boolean {
if (this.findApplicationByUrl(user, application.url, application.unique_url) != null) {
return false
}
db.update(
"insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status, company, recruiter, message) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
application.id,
application.url,
application.original_url,
application.unique_url,
application.title,
application.user_id,
application.extra_data,
application.payrange,
application.status,
application.company,
application.recruiter,
application.message,
)
return true
}
public fun findAll(user: UserDb, info: ListRequest): List<Application> {
if (info.status == null) {
return db.query(
"select * from applications where user_id=? order by title asc;",
arrayOf(user.id),
Application
)
.toList()
}
return db.query(
"select * from applications where user_id=? and status=? order by title asc;",
arrayOf(user.id, info.status),
Application,
)
.toList()
}
public fun update(application: Application): Application {
db.update(
"update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, status=?, company=?, recruiter=?, message=? where id=?",
application.url,
application.original_url,
application.unique_url,
application.title,
application.user_id,
application.extra_data,
application.payrange,
application.status,
application.company,
application.recruiter,
application.message,
application.id,
)
return application
}
public fun delete(application: Application) {
db.update(
"delete from applications where id=?",
application.id,
)
}
}