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
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
implementation("io.micronaut:micronaut-http-client")
implementation("io.micronaut.picocli:micronaut-picocli")
implementation("io.micronaut.serde:micronaut-serde-jackson")
testImplementation("net.datafaker:datafaker:2.5.1")
compileOnly("org.projectlombok:lombok")
runtimeOnly("ch.qos.logback:logback-classic")
runtimeOnly("org.yaml:snakeyaml")
Expand Down
103 changes: 102 additions & 1 deletion src/main/resources/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ paths:
description: Bad Request
'500':
description: Internal Server Error
/api/v1/users/securitycontext/bearer:
get:
description: "Retrieves the admin context for a given user (ie org ID's, church unit id's, role levels, etc). if no user is provided, it will return the context for the currently authenticated user"
operationId: getAdminContext
tags:
- User
parameters:
- name: userId
in: query
schema:
type: string
format: uuid
responses:
'200':
description: OK
content: { application/json: { schema: { $ref: '#/components/schemas/SecurityContext' } } }
'401': # No failures for unfound endpoints. querying ID "this is a bad ID" returns the current user's bearer context.
description: Unauthorized
content: { application/json: { schema: { $ref: '#/components/schemas/ProblemDetails' } } }

/api/v1/users/slimSearch:
post:
operationId: userSearchSlim
Expand Down Expand Up @@ -57,6 +77,33 @@ paths:

components:
schemas:
ChurchCivicGeographyUserRole:
type: object
properties:
churchGeographyId:
type: string
format: uuid
unitId:
type: string
nullable: true
civicGeographyId:
type: string
format: uuid
role:
$ref: '#/components/schemas/Role'
additionalProperties: false
ChurchGeographyUserRole:
type: object
properties:
churchGeographyId:
type: string
format: uuid
unitId:
type: string
nullable: true
role:
$ref: '#/components/schemas/Role'
additionalProperties: false
DynamicRoutingDataResponse:
type: object
properties:
Expand All @@ -74,6 +121,15 @@ components:
- Organization
- DisasterRelief
additionalProperties: false
OrganizationUserRole:
type: object
properties:
organizationId:
type: string
format: uuid
role:
$ref: '#/components/schemas/Role'
additionalProperties: false
UserHashRequest:
description: |
A request containing either the email or the userid for a user.
Expand Down Expand Up @@ -358,6 +414,18 @@ components:
deletedOn: { type: string, format: date-time, nullable: true }
deletedBy: { type: string, format: uuid, nullable: true }
additionalProperties: false
OrganizationCivicGeographyUserRole:
type: object
properties:
organizationId:
type: string
format: uuid
role:
$ref: '#/components/schemas/Role'
civicGeographyId:
type: string
format: uuid
additionalProperties: false
Location:
type: object
properties: { latitude: { type: number, format: double },
Expand Down Expand Up @@ -411,4 +479,37 @@ components:
type: integer
format: int32
nullable: true
traceId: { type: string, nullable: true }
traceId: { type: string, nullable: true }
SecurityContext:
type: object
properties:
userId:
type: string
format: uuid
userRepresentativeForOrganizations:
type: array
items:
type: string
format: uuid
nullable: true
churchGeographies:
type: object
additionalProperties:
$ref: '#/components/schemas/ChurchGeographyUserRole'
nullable: true
civicGeographies:
type: object
additionalProperties:
$ref: '#/components/schemas/ChurchCivicGeographyUserRole'
nullable: true
organizationRoles:
type: object
additionalProperties:
$ref: '#/components/schemas/OrganizationUserRole'
nullable: true
organizationCivicGeographyUserRoles:
type: array
items:
$ref: '#/components/schemas/OrganizationCivicGeographyUserRole'
nullable: true
additionalProperties: false
5 changes: 5 additions & 0 deletions src/test/groovy/org/justserve/JustServeSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ package org.justserve
import io.micronaut.context.ApplicationContext
import io.micronaut.context.env.Environment
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import net.datafaker.Faker
import spock.lang.Shared
import spock.lang.Specification

@MicronautTest()
class JustServeSpec extends Specification {

@Shared
Faker faker

@Shared
ApplicationContext ctx, noAuthCtx

@Shared
String userEmail

def setupSpec() {
faker = new Faker()
userEmail = "jimmy@justserve.org"

if (null != System.getenv("JUSTSERVE_TOKEN")) {
Expand Down
34 changes: 31 additions & 3 deletions src/test/groovy/org/justserve/client/UserClientSpec.groovy
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.justserve.client


import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.exceptions.HttpClientResponseException
import org.justserve.JustServeSpec
import org.justserve.model.UserHashRequestByEmail
import spock.lang.Shared

import static io.micronaut.http.HttpStatus.*

class UserClientSpec extends JustServeSpec {

@Shared
Expand All @@ -19,6 +19,34 @@ class UserClientSpec extends JustServeSpec {
userClient = ctx.getBean(UserClient)
}

def "get admin context for #description"() {
when:
def response = null
def thrownException = null
try {
response = client.getAdminContext(UUID.fromString(uid))
} catch (HttpClientResponseException e) {
thrownException = e
}

then:
if (thrownException) {
thrownException.status == expectedStatus
} else {
response.status == expectedStatus
response.body() != null
if (expectedStatus == OK) {
response.body().userId == UUID.fromString(uid)
}
}

where:
description | uid | client | expectedStatus
"a valid user" | "e23d029c-25f6-4c93-aada-dcbdc6d50c2c" | userClient | OK
"an invalid user" | faker.internet().uuid() | userClient | NOT_FOUND
"a valid user no-auth" | "e23d029c-25f6-4c93-aada-dcbdc6d50c2c" | noAuthUserClient | UNAUTHORIZED
}

def "get tempPassword for #email"() {
when:
HttpResponse<String> response = null
Expand Down Expand Up @@ -46,7 +74,7 @@ class UserClientSpec extends JustServeSpec {

where:
expectedResponse | email | expectedException | expectedMessage | client | _
HttpStatus.OK | userEmail | null | null | userClient | _
OK | userEmail | null | null | userClient | _
null | "notanemail@mail.moc" | HttpClientResponseException | "\"status\":500" | userClient | _
null | userEmail | HttpClientResponseException | "\"status\":401" | noAuthUserClient | _
null | "notanemail@mail.moc" | HttpClientResponseException | "\"status\":401" | noAuthUserClient | _
Expand Down