lot of changes

This commit is contained in:
2024-11-21 12:19:43 +00:00
parent dd047c0bcf
commit 26301d1a13
32 changed files with 1740 additions and 311 deletions

View File

@@ -2,6 +2,7 @@ spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://kronos.home:5432/applications
spring.datasource.username=applications
spring.datasource.password=applications
spring-boot.run.jvmArguments=-Duser.timezone=UTC
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Disable the trace on the error responses

View File

@@ -33,8 +33,10 @@ data class Application(
var extra_data: String,
var payrange: String,
var status: Int,
var status_id: String?,
var company: String,
var recruiter: String,
var agency: Boolean,
var message: String,
var linked_application: String,
var status_history: String,
@@ -56,8 +58,10 @@ data class Application(
rs.getString("extra_data"),
rs.getString("payrange"),
rs.getInt("status"),
rs.getString("status_id"),
rs.getString("company"),
rs.getString("recruiter"),
rs.getBoolean("agency"),
rs.getString("message"),
rs.getString("linked_application"),
rs.getString("status_history"),
@@ -85,6 +89,7 @@ data class CVData(
val company: String,
val recruiter: String,
val message: String,
val agency: Boolean,
val flairs: List<SimpleFlair>
)
@@ -113,7 +118,7 @@ class ApplicationsController(
val flairs = application.flairs.map { it.toFlairSimple() }
return CVData(application.company, application.recruiter, application.message, flairs)
return CVData(application.company, application.recruiter, application.message, application.agency, flairs)
}
/** Create a new application from the link */
@@ -135,8 +140,10 @@ class ApplicationsController(
"",
"",
0,
null,
"",
"",
false,
"",
"",
"",
@@ -263,8 +270,10 @@ class ApplicationsController(
"",
"",
0,
null,
"",
"",
false,
"",
"",
"",
@@ -535,8 +544,9 @@ class ApplicationService(
}
// Create time is auto created by the database
// The default status is null
db.update(
"insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status, company, recruiter, message, linked_application, status_history, application_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
"insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status, company, recruiter, message, linked_application, status_history, application_time, agency) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
application.id,
application.url,
application.original_url,
@@ -552,6 +562,7 @@ class ApplicationService(
application.linked_application,
application.status_history,
application.application_time,
application.agency,
)
eventService.create(application.id, EventType.Creation)
@@ -595,7 +606,16 @@ class ApplicationService(
return iter.toList()
}
public fun findAllByUserStatusId(statusId: String, user: UserDb): List<Application> {
return db.query(
"select * from applications where status_id=? and user_id=? order by title asc;",
arrayOf(statusId, user.id),
Application
)
}
// Update the stauts on the application object before giving it to this function
// TODO how status history works
public fun updateStatus(application: Application): Application {
val status_string = "${application.status}"
@@ -627,7 +647,7 @@ class ApplicationService(
public fun update(application: Application): Application {
// I don't want ot update create_time
db.update(
"update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, company=?, recruiter=?, message=?, linked_application=? where id=?",
"update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, company=?, recruiter=?, message=?, linked_application=?, agency=? where id=?",
application.url,
application.original_url,
application.unique_url,
@@ -639,6 +659,7 @@ class ApplicationService(
application.recruiter,
application.message,
application.linked_application,
application.agency,
application.id,
)
return application

View File

@@ -0,0 +1,301 @@
package com.andr3h3nriqu3s.applications
import java.sql.ResultSet
import java.util.UUID
import org.springframework.http.HttpStatus
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
import org.springframework.web.server.ResponseStatusException
data class UserStatusNode(
var id: String,
var user_id: String,
var name: String,
var icon: String,
var x: Int,
var y: Int,
var width: Int,
var height: Int,
var permission: Int
) {
companion object : RowMapper<UserStatusNode> {
override public fun mapRow(rs: ResultSet, rowNum: Int): UserStatusNode {
return UserStatusNode(
rs.getString("id"),
rs.getString("user_id"),
rs.getString("name"),
rs.getString("icon"),
rs.getInt("x"),
rs.getInt("y"),
rs.getInt("width"),
rs.getInt("height"),
rs.getInt("permission"),
)
}
}
}
data class UserStatusLink(
var id: String,
var user_id: String,
var source_node: String?,
var target_node: String?,
var bi: Boolean,
var source_x: Int,
var source_y: Int,
var target_x: Int,
var target_y: Int,
) {
companion object : RowMapper<UserStatusLink> {
override public fun mapRow(rs: ResultSet, rowNum: Int): UserStatusLink {
return UserStatusLink(
rs.getString("id"),
rs.getString("user_id"),
rs.getString("source_node"),
rs.getString("target_node"),
rs.getBoolean("bi"),
rs.getInt("source_x"),
rs.getInt("source_y"),
rs.getInt("target_x"),
rs.getInt("target_y"),
)
}
}
}
@RestController
@ControllerAdvice
@RequestMapping("/api/user/status")
class UserApplicationStatusController(
val sessionService: SessionService,
val userStatusNodeService: UserStatusNodeService,
val userStatusLinkService: UserStatusLinkService,
val applicationService: ApplicationService,
) {
//
// Nodes
//
@GetMapping(path = ["/node"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun listAll(@RequestHeader("token") token: String): List<UserStatusNode> {
val user = sessionService.verifyTokenThrow(token)
return userStatusNodeService.findAllByUserId(user.id)
}
@PostMapping(path = ["/node"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun create(
@RequestBody node: UserStatusNode,
@RequestHeader("token") token: String
): UserStatusNode {
val user = sessionService.verifyTokenThrow(token)
node.user_id = user.id
return userStatusNodeService.create(node)
}
@PutMapping(path = ["/node"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun put(
@RequestBody node: UserStatusNode,
@RequestHeader("token") token: String
): UserStatusNode? {
val user = sessionService.verifyTokenThrow(token)
if (userStatusNodeService.findById(node.id, user) == null) {
throw NotFound()
}
return userStatusNodeService.update(node)
}
@DeleteMapping(path = ["/node/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun delete(@PathVariable id: String, @RequestHeader("token") token: String): Boolean {
val user = sessionService.verifyTokenThrow(token)
val node = userStatusNodeService.findById(id, user)
if (node == null) {
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Could not find a node")
}
val applications = applicationService.findAllByUserStatusId(id, user)
if (applications.size > 0) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Applications exist with this user status!")
}
userStatusLinkService.deleteByNode(user, node)
userStatusNodeService.delete(node, user)
return true
}
//
// Link
//
@GetMapping(path = ["/link"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun listAllLinks(@RequestHeader("token") token: String): List<UserStatusLink> {
val user = sessionService.verifyTokenThrow(token)
return userStatusLinkService.findAllByUserId(user)
}
@PutMapping(path = ["/link"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun createLink(
@RequestBody link: UserStatusLink,
@RequestHeader("token") token: String
): UserStatusLink {
val user = sessionService.verifyTokenThrow(token)
if (link.source_node == link.target_node) {
throw ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Request Node and Target Not can not be the same"
)
}
if (link.source_node != null &&
userStatusNodeService.findById(link.source_node!!, user) == null
) {
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Request source not found")
}
if (link.target_node != null &&
userStatusNodeService.findById(link.target_node!!, user) == null
) {
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Request target not found")
}
link.user_id = user.id
return userStatusLinkService.create(link)
}
}
@Service
public class UserStatusNodeService(val db: JdbcTemplate) {
public fun findById(id: String, user: UserDb): UserStatusNode? {
var nodes =
db.query(
"select * from user_status_node where id=? and user_id=?",
arrayOf(id, user.id),
UserStatusNode
)
if (nodes.size == 0) {
return null
}
return nodes[0]
}
public fun findAllByUserId(user_id: String): List<UserStatusNode> {
return db.query(
"select * from user_status_node where user_id=?",
arrayOf(user_id),
UserStatusNode
)
.toList()
}
public fun update(node: UserStatusNode): UserStatusNode {
db.update(
"update user_status_node set name=?, icon=?, x=?, y=?, width=?, height=?, permission=? where id=?;",
node.name,
node.icon,
node.x,
node.y,
node.width,
node.height,
node.permission,
node.id,
)
return node
}
public fun create(node: UserStatusNode): UserStatusNode {
val id = UUID.randomUUID().toString()
node.id = id
db.update(
"insert into user_status_node (id, user_id, name, icon, x, y, width, height, permission) values (?, ?, ?, ?, ?, ?, ?, ?, ?);",
node.id,
node.user_id,
node.name,
node.icon,
node.x,
node.y,
node.width,
node.height,
node.permission
)
return node
}
public fun delete(node: UserStatusNode, user: UserDb) {
db.update("delete from user_status_node where id=? and user_id=?;", node.id, user.id)
}
}
@Service
public class UserStatusLinkService(val db: JdbcTemplate) {
public fun findById(id: String, user: UserDb): UserStatusLink? {
val links =
db.query(
"select * from user_status_link where user_id=? and id=?;",
arrayOf(id, user.id),
UserStatusLink
)
if (links.size == 0) {
return null
}
return links[0]
}
public fun findAllByUserId(user: UserDb): List<UserStatusLink> {
return db.query(
"select * from user_status_link where user_id=?",
arrayOf(user.id),
UserStatusLink
)
.toList()
}
public fun deleteByNode(user: UserDb, node: UserStatusNode) {
db.update("delete from user_status_link where (target_node=? or source_node=?) and user_id=?;", node.id, node.id, user.id)
}
public fun create(link: UserStatusLink): UserStatusLink {
val id = UUID.randomUUID().toString()
link.id = id
db.update(
"insert into user_status_link (id, user_id, source_node, target_node, bi, source_x, source_y, target_x, target_y) values (?, ?, ?, ?, ?, ?, ?, ?, ?);",
link.id,
link.user_id,
link.source_node,
link.target_node,
link.bi,
link.source_x,
link.source_y,
link.target_x,
link.target_y,
)
return link
}
}

View File

@@ -23,16 +23,20 @@ create table if not exists applications (
status_history text default '',
user_id text,
extra_data text,
-- this status will be deprecated in favor of the node style status
status integer,
status_id text default null,
linked_application text default '',
application_time text default '',
agency boolean default false,
create_time timestamp default now()
);
-- Views are deprecated will be removed in the future
create table if not exists views (
id text primary key,
application_id text not null,
time timestamp default current_timestamp
time timestamp default now()
);
create table if not exists flair (
@@ -65,5 +69,41 @@ create table if not exists events (
-- This only matters when event_type == 1
new_status integer,
time timestamp default current_timestamp
time timestamp default now()
);
--
-- User Controlled Status
--
create table if not exists user_status_node (
id text primary key,
user_id text not null,
name text not null,
icon text not null,
x integer default 0,
y integer default 0,
width integer default 0,
height integer default 0,
permission integer default 0
);
create table if not exists user_status_link (
id text primary key,
-- You technically can get this by loking a the source and target nodes but that seams more complicated
user_id text not null,
-- This can be null because null means creation
source_node text,
-- This can be null because null means creation
target_node text,
source_x integer default 0,
source_y integer default 0,
target_x integer default 0,
target_y integer default 0,
-- If this link is bidiretoral
bi boolean
);