Skip to content

Commit adb90be

Browse files
authored
Endpoints for Tokens (#461)
* Endpoints for tokens * Typo * Test fixed
1 parent e4a4739 commit adb90be

File tree

11 files changed

+430
-17
lines changed

11 files changed

+430
-17
lines changed

server/docs/postman/xef_postman_collection.json

+201-4
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@
366366
"response": []
367367
},
368368
{
369-
"name": "Get Project",
369+
"name": "Get Projects By Org",
370370
"protocolProfileBehavior": {
371371
"disableBodyPruning": true
372372
},
@@ -393,14 +393,15 @@
393393
}
394394
},
395395
"url": {
396-
"raw": "{{url}}/v1/settings/projects/1",
396+
"raw": "{{url}}/v1/settings/projects/org/1",
397397
"host": [
398398
"{{url}}"
399399
],
400400
"path": [
401401
"v1",
402402
"settings",
403403
"projects",
404+
"org",
404405
"1"
405406
]
406407
}
@@ -423,19 +424,215 @@
423424
"method": "DELETE",
424425
"header": [],
425426
"url": {
426-
"raw": "{{url}}/v1/settings/projects/1",
427+
"raw": "{{url}}/v1/settings/projects/4",
428+
"host": [
429+
"{{url}}"
430+
],
431+
"path": [
432+
"v1",
433+
"settings",
434+
"projects",
435+
"4"
436+
]
437+
}
438+
},
439+
"response": []
440+
}
441+
]
442+
},
443+
{
444+
"name": "Xef Tokens",
445+
"item": [
446+
{
447+
"name": "Create Token",
448+
"request": {
449+
"auth": {
450+
"type": "bearer",
451+
"bearer": [
452+
{
453+
"key": "token",
454+
"value": "{{access_token}}",
455+
"type": "string"
456+
}
457+
]
458+
},
459+
"method": "POST",
460+
"header": [],
461+
"body": {
462+
"mode": "raw",
463+
"raw": "{\n \"name\": \"My Token\",\n \"projectId\": 1\n}",
464+
"options": {
465+
"raw": {
466+
"language": "json"
467+
}
468+
}
469+
},
470+
"url": {
471+
"raw": "{{url}}/v1/settings/tokens",
472+
"host": [
473+
"{{url}}"
474+
],
475+
"path": [
476+
"v1",
477+
"settings",
478+
"tokens"
479+
]
480+
}
481+
},
482+
"response": []
483+
},
484+
{
485+
"name": "Update Token",
486+
"request": {
487+
"auth": {
488+
"type": "bearer",
489+
"bearer": [
490+
{
491+
"key": "token",
492+
"value": "{{access_token}}",
493+
"type": "string"
494+
}
495+
]
496+
},
497+
"method": "PUT",
498+
"header": [],
499+
"body": {
500+
"mode": "raw",
501+
"raw": "{\n \"name\": \"My Token\",\n \"providerConfig\": {\n \"open_ai\": {\n \"token\": \"openai_token\",\n \"url\": null\n },\n \"gcp\": {\n \"token\": \"openai_token\",\n \"project_id\": \"my_project_id\",\n \"location\": \"my_location\"\n }\n }\n}",
502+
"options": {
503+
"raw": {
504+
"language": "json"
505+
}
506+
}
507+
},
508+
"url": {
509+
"raw": "{{url}}/v1/settings/tokens/1",
510+
"host": [
511+
"{{url}}"
512+
],
513+
"path": [
514+
"v1",
515+
"settings",
516+
"tokens",
517+
"1"
518+
]
519+
}
520+
},
521+
"response": []
522+
},
523+
{
524+
"name": "Get Tokens",
525+
"protocolProfileBehavior": {
526+
"disableBodyPruning": true
527+
},
528+
"request": {
529+
"auth": {
530+
"type": "bearer",
531+
"bearer": [
532+
{
533+
"key": "token",
534+
"value": "{{access_token}}",
535+
"type": "string"
536+
}
537+
]
538+
},
539+
"method": "GET",
540+
"header": [],
541+
"body": {
542+
"mode": "raw",
543+
"raw": "",
544+
"options": {
545+
"raw": {
546+
"language": "json"
547+
}
548+
}
549+
},
550+
"url": {
551+
"raw": "{{url}}/v1/settings/tokens",
427552
"host": [
428553
"{{url}}"
429554
],
430555
"path": [
431556
"v1",
432557
"settings",
558+
"tokens"
559+
]
560+
}
561+
},
562+
"response": []
563+
},
564+
{
565+
"name": "Get Tokens by Project",
566+
"protocolProfileBehavior": {
567+
"disableBodyPruning": true
568+
},
569+
"request": {
570+
"auth": {
571+
"type": "bearer",
572+
"bearer": [
573+
{
574+
"key": "token",
575+
"value": "{{access_token}}",
576+
"type": "string"
577+
}
578+
]
579+
},
580+
"method": "GET",
581+
"header": [],
582+
"body": {
583+
"mode": "raw",
584+
"raw": "",
585+
"options": {
586+
"raw": {
587+
"language": "json"
588+
}
589+
}
590+
},
591+
"url": {
592+
"raw": "{{url}}/v1/settings/tokens/projects/1",
593+
"host": [
594+
"{{url}}"
595+
],
596+
"path": [
597+
"v1",
598+
"settings",
599+
"tokens",
433600
"projects",
434601
"1"
435602
]
436603
}
437604
},
438605
"response": []
606+
},
607+
{
608+
"name": "Delete tokens",
609+
"request": {
610+
"auth": {
611+
"type": "bearer",
612+
"bearer": [
613+
{
614+
"key": "token",
615+
"value": "{{access_token}}",
616+
"type": "string"
617+
}
618+
]
619+
},
620+
"method": "DELETE",
621+
"header": [],
622+
"url": {
623+
"raw": "{{url}}/v1/settings/tokens/1",
624+
"host": [
625+
"{{url}}"
626+
],
627+
"path": [
628+
"v1",
629+
"settings",
630+
"tokens",
631+
"1"
632+
]
633+
}
634+
},
635+
"response": []
439636
}
440637
]
441638
},
@@ -472,7 +669,7 @@
472669
"header": [],
473670
"body": {
474671
"mode": "raw",
475-
"raw": "{\n \"name\": \"JC2\",\n \"email\": \"[email protected]\",\n \"password\": \"1234\"\n}",
672+
"raw": "{\n \"name\": \"JC\",\n \"email\": \"[email protected]\",\n \"password\": \"1234\"\n}",
476673
"options": {
477674
"raw": {
478675
"language": "json"

server/src/main/kotlin/com/xebia/functional/xef/server/exceptions/ExceptionsHandler.kt

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ suspend fun ApplicationCall.manageException(cause: XefExceptions) {
2727
is XefExceptions.AuthorizationException -> this.respond(HttpStatusCode.Unauthorized)
2828
is XefExceptions.OrganizationsException -> this.respond(HttpStatusCode.BadRequest, cause.message)
2929
is XefExceptions.ProjectException -> this.respond(HttpStatusCode.BadRequest, cause.message)
30+
is XefExceptions.XefTokenException -> this.respond(HttpStatusCode.BadRequest, cause.message)
3031
is XefExceptions.UserException -> this.respond(HttpStatusCode.BadRequest, cause.message)
3132
}
3233
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.xebia.functional.xef.server.http.routes
2+
3+
import com.xebia.functional.xef.server.models.TokenRequest
4+
import com.xebia.functional.xef.server.models.TokenUpdateRequest
5+
import com.xebia.functional.xef.server.services.TokenRepositoryService
6+
import io.ktor.http.*
7+
import io.ktor.server.application.*
8+
import io.ktor.server.auth.*
9+
import io.ktor.server.request.*
10+
import io.ktor.server.response.*
11+
import io.ktor.server.routing.*
12+
import kotlinx.serialization.json.Json
13+
14+
fun Routing.tokensRoutes(
15+
tokenRepositoryService: TokenRepositoryService
16+
) {
17+
authenticate("auth-bearer") {
18+
get("/v1/settings/tokens") {
19+
val token = call.getToken()
20+
val response = tokenRepositoryService.getTokens(token)
21+
call.respond(response)
22+
}
23+
get("/v1/settings/tokens/projects/{id}") {
24+
val token = call.getToken()
25+
val id = call.getId()
26+
val response = tokenRepositoryService.getTokensByProject(token, id)
27+
call.respond(response)
28+
}
29+
post("/v1/settings/tokens") {
30+
31+
val request = Json.decodeFromString<TokenRequest>(call.receive<String>())
32+
val token = call.getToken()
33+
val response = tokenRepositoryService.createToken(request, token)
34+
call.respond(
35+
status = HttpStatusCode.Created,
36+
response
37+
)
38+
}
39+
put("/v1/settings/tokens/{id}") {
40+
val request = Json.decodeFromString<TokenUpdateRequest>(call.receive<String>())
41+
val token = call.getToken()
42+
val id = call.getId()
43+
val response = tokenRepositoryService.updateToken(token, request, id)
44+
call.respond(
45+
status = HttpStatusCode.NoContent,
46+
response
47+
)
48+
}
49+
delete("/v1/settings/tokens/{id}") {
50+
val token = call.getToken()
51+
val id = call.getId()
52+
val response = tokenRepositoryService.deleteToken(token, id)
53+
call.respond(
54+
status = HttpStatusCode.NoContent,
55+
response
56+
)
57+
}
58+
}
59+
}
60+
61+

server/src/main/kotlin/com/xebia/functional/xef/server/http/routes/XefRoutes.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.xebia.functional.xef.server.http.routes
22

33
import com.xebia.functional.xef.server.services.OrganizationRepositoryService
44
import com.xebia.functional.xef.server.services.ProjectRepositoryService
5+
import com.xebia.functional.xef.server.services.TokenRepositoryService
56
import com.xebia.functional.xef.server.services.UserRepositoryService
6-
import io.ktor.client.*
77
import io.ktor.server.routing.*
88
import org.slf4j.Logger
99

@@ -13,4 +13,5 @@ fun Routing.xefRoutes(
1313
userRoutes(UserRepositoryService(logger))
1414
organizationRoutes(OrganizationRepositoryService(logger))
1515
projectsRoutes(ProjectRepositoryService(logger))
16+
tokensRoutes(TokenRepositoryService(logger))
1617
}

server/src/main/kotlin/com/xebia/functional/xef/server/models/ProvidersConfig.kt

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ import kotlinx.serialization.SerialName
44
import kotlinx.serialization.Serializable
55

66
@Serializable
7-
@SerialName("open_ai")
87
data class OpenAIConf(
9-
val name: String,
108
val token: String,
11-
val url: String
9+
val url: String?
1210
)
1311

1412
@Serializable
15-
@SerialName("gcp")
1613
data class GCPConf(
17-
val name: String,
1814
val token: String,
15+
@SerialName("project_id")
1916
val projectId: String,
2017
val location: String
2118
)
@@ -26,4 +23,8 @@ data class ProvidersConfig(
2623
val openAI: OpenAIConf?,
2724
@SerialName("gcp")
2825
val gcp: GCPConf?
29-
)
26+
) {
27+
companion object {
28+
val empty = ProvidersConfig(null, null)
29+
}
30+
}

server/src/main/kotlin/com/xebia/functional/xef/server/models/Requests.kt

+12
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ data class ProjectUpdateRequest(
3737
val name: String,
3838
val orgId: Int? = null
3939
)
40+
41+
@Serializable
42+
data class TokenRequest(
43+
val name: String,
44+
val projectId: Int
45+
)
46+
47+
@Serializable
48+
data class TokenUpdateRequest(
49+
val name: String,
50+
val providerConfig: ProvidersConfig
51+
)

0 commit comments

Comments
 (0)