Commit 2ab03f48 authored by akwizgran's avatar akwizgran

Merge branch '1256-remove-contact' into 'master'

briar-headless: Add endpoint for removing a contact

See merge request briar/briar!962
parents 822597b4 436f4555
......@@ -72,9 +72,16 @@ Returns a JSON array of contacts:
The only workaround is to add a contact to the Briar app running on a rooted Android phone
and then move its database (and key files) to the headless peer.
### Removing a contact
`DELETE /v1/contacts/{contactId}`
The `{contactId}` is the `contactId` of the contact (`1` in the example above).
It returns with a status code `200`, if removal was successful.
### Listing all private messages
`GET /messages/{contactId}`
`GET /v1/messages/{contactId}`
The `{contactId}` is the `contactId` of the contact (`1` in the example above).
It returns a JSON array of private messages:
......@@ -100,7 +107,7 @@ Attention: There can messages of other `type`s where the message `text` is `null
### Writing a private message
`POST /messages/{contactId}`
`POST /v1/messages/{contactId}`
The text of the message should be posted as JSON:
......
plugins {
id 'java'
id 'idea'
id 'org.jetbrains.kotlin.jvm' version '1.2.70'
id 'org.jetbrains.kotlin.kapt' version '1.2.70'
id 'org.jetbrains.kotlin.jvm' version '1.2.71'
id 'org.jetbrains.kotlin.kapt' version '1.2.71'
id 'witness'
}
apply from: 'witness.gradle'
......@@ -14,9 +14,9 @@ dependencies {
implementation project(path: ':briar-core', configuration: 'default')
implementation project(path: ':bramble-java', configuration: 'default')
implementation 'io.javalin:javalin:2.2.0'
implementation 'io.javalin:javalin:2.3.0'
implementation 'org.slf4j:slf4j-simple:1.7.25'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.7'
implementation 'com.github.ajalt:clikt:1.5.0'
kapt 'com.google.dagger:dagger-compiler:2.0.2'
......@@ -24,11 +24,11 @@ dependencies {
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
def junitVersion = '5.2.0'
def junitVersion = '5.3.1'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
testImplementation "io.mockk:mockk:1.8.6"
testImplementation "io.mockk:mockk:1.8.9"
testImplementation "org.skyscreamer:jsonassert:1.5.0"
}
......
......@@ -7,9 +7,11 @@ import io.javalin.Context
import io.javalin.Javalin
import io.javalin.JavalinEvent.SERVER_START_FAILED
import io.javalin.JavalinEvent.SERVER_STOPPED
import io.javalin.NotFoundResponse
import io.javalin.apibuilder.ApiBuilder.*
import io.javalin.core.util.ContextUtil
import io.javalin.core.util.Header.AUTHORIZATION
import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.briar.headless.blogs.BlogController
import org.briarproject.briar.headless.contact.ContactController
import org.briarproject.briar.headless.event.WebSocketController
......@@ -63,6 +65,9 @@ constructor(
path("/v1") {
path("/contacts") {
get { ctx -> contactController.list(ctx) }
path("/:contactId") {
delete { ctx -> contactController.delete(ctx) }
}
}
path("/messages/:contactId") {
get { ctx -> messagingController.list(ctx) }
......@@ -112,6 +117,21 @@ constructor(
}
/**
* Returns a [ContactId] from the "contactId" path parameter.
*
* @throws NotFoundResponse when contactId is not a number.
*/
fun Context.getContactIdFromPathParam(): ContactId {
val contactString = pathParam("contactId")
val contactInt = try {
Integer.parseInt(contactString)
} catch (e: NumberFormatException) {
throw NotFoundResponse()
}
return ContactId(contactInt)
}
/**
* Returns a String from the JSON field or throws [BadRequestResponse] if null or empty.
*/
......
......@@ -5,5 +5,6 @@ import io.javalin.Context
interface ContactController {
fun list(ctx: Context): Context
fun delete(ctx: Context): Context
}
package org.briarproject.briar.headless.contact
import io.javalin.Context
import io.javalin.NotFoundResponse
import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.db.NoSuchContactException
import org.briarproject.briar.headless.getContactIdFromPathParam
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
......@@ -19,4 +22,14 @@ constructor(private val contactManager: ContactManager) : ContactController {
return ctx.json(contacts)
}
override fun delete(ctx: Context): Context {
val contactId = ctx.getContactIdFromPathParam()
try {
contactManager.removeContact(contactId)
} catch (e: NoSuchContactException) {
throw NotFoundResponse()
}
return ctx
}
}
......@@ -26,6 +26,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse
import org.briarproject.briar.headless.event.WebSocketController
import org.briarproject.briar.headless.event.output
import org.briarproject.briar.headless.getContactIdFromPathParam
import org.briarproject.briar.headless.getFromJson
import org.briarproject.briar.headless.json.JsonDict
import java.util.concurrent.Executor
......@@ -84,13 +85,7 @@ constructor(
}
private fun getContact(ctx: Context): Contact {
val contactString = ctx.pathParam("contactId")
val contactInt = try {
Integer.parseInt(contactString)
} catch (e: NumberFormatException) {
throw NotFoundResponse()
}
val contactId = ContactId(contactInt)
val contactId = ctx.getContactIdFromPathParam()
return try {
contactManager.getContact(contactId)
} catch (e: NoSuchContactException) {
......
package org.briarproject.briar.headless.contact
import io.javalin.NotFoundResponse
import io.javalin.json.JavalinJson.toJson
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import org.briarproject.bramble.api.contact.Contact
import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.bramble.api.db.NoSuchContactException
import org.briarproject.bramble.identity.output
import org.briarproject.briar.headless.ControllerTest
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
internal class ContactControllerTest : ControllerTest() {
......@@ -25,6 +31,30 @@ internal class ContactControllerTest : ControllerTest() {
controller.list(ctx)
}
@Test
fun testDelete() {
every { ctx.pathParam("contactId") } returns "1"
every { contactManager.removeContact(ContactId(1)) } just Runs
controller.delete(ctx)
}
@Test
fun testDeleteInvalidContactId() {
every { ctx.pathParam("contactId") } returns "foo"
assertThrows(NotFoundResponse::class.java) {
controller.delete(ctx)
}
}
@Test
fun testDeleteNonexistentContactId() {
every { ctx.pathParam("contactId") } returns "1"
every { contactManager.removeContact(ContactId(1)) } throws NoSuchContactException()
assertThrows(NotFoundResponse::class.java) {
controller.delete(ctx)
}
}
@Test
fun testOutputContact() {
val json = """
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment