briar-headless: Add endpoint for removing a contact

This commit is contained in:
Torsten Grote
2018-10-24 12:12:33 -03:00
parent 822597b4c6
commit 51209b5eec
6 changed files with 75 additions and 9 deletions

View File

@@ -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 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. 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 ### Listing all private messages
`GET /messages/{contactId}` `GET /v1/messages/{contactId}`
The `{contactId}` is the `contactId` of the contact (`1` in the example above). The `{contactId}` is the `contactId` of the contact (`1` in the example above).
It returns a JSON array of private messages: 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 ### Writing a private message
`POST /messages/{contactId}` `POST /v1/messages/{contactId}`
The text of the message should be posted as JSON: The text of the message should be posted as JSON:

View File

@@ -7,9 +7,11 @@ import io.javalin.Context
import io.javalin.Javalin import io.javalin.Javalin
import io.javalin.JavalinEvent.SERVER_START_FAILED import io.javalin.JavalinEvent.SERVER_START_FAILED
import io.javalin.JavalinEvent.SERVER_STOPPED import io.javalin.JavalinEvent.SERVER_STOPPED
import io.javalin.NotFoundResponse
import io.javalin.apibuilder.ApiBuilder.* import io.javalin.apibuilder.ApiBuilder.*
import io.javalin.core.util.ContextUtil import io.javalin.core.util.ContextUtil
import io.javalin.core.util.Header.AUTHORIZATION 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.blogs.BlogController
import org.briarproject.briar.headless.contact.ContactController import org.briarproject.briar.headless.contact.ContactController
import org.briarproject.briar.headless.event.WebSocketController import org.briarproject.briar.headless.event.WebSocketController
@@ -63,6 +65,9 @@ constructor(
path("/v1") { path("/v1") {
path("/contacts") { path("/contacts") {
get { ctx -> contactController.list(ctx) } get { ctx -> contactController.list(ctx) }
path("/:contactId") {
delete { ctx -> contactController.delete(ctx) }
}
} }
path("/messages/:contactId") { path("/messages/:contactId") {
get { ctx -> messagingController.list(ctx) } 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. * Returns a String from the JSON field or throws [BadRequestResponse] if null or empty.
*/ */

View File

@@ -5,5 +5,6 @@ import io.javalin.Context
interface ContactController { interface ContactController {
fun list(ctx: Context): Context fun list(ctx: Context): Context
fun delete(ctx: Context): Context
} }

View File

@@ -1,7 +1,10 @@
package org.briarproject.briar.headless.contact package org.briarproject.briar.headless.contact
import io.javalin.Context import io.javalin.Context
import io.javalin.NotFoundResponse
import org.briarproject.bramble.api.contact.ContactManager 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.annotation.concurrent.Immutable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@@ -19,4 +22,14 @@ constructor(private val contactManager: ContactManager) : ContactController {
return ctx.json(contacts) 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
}
} }

View File

@@ -26,6 +26,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse
import org.briarproject.briar.headless.event.WebSocketController import org.briarproject.briar.headless.event.WebSocketController
import org.briarproject.briar.headless.event.output import org.briarproject.briar.headless.event.output
import org.briarproject.briar.headless.getContactIdFromPathParam
import org.briarproject.briar.headless.getFromJson import org.briarproject.briar.headless.getFromJson
import org.briarproject.briar.headless.json.JsonDict import org.briarproject.briar.headless.json.JsonDict
import java.util.concurrent.Executor import java.util.concurrent.Executor
@@ -84,13 +85,7 @@ constructor(
} }
private fun getContact(ctx: Context): Contact { private fun getContact(ctx: Context): Contact {
val contactString = ctx.pathParam("contactId") val contactId = ctx.getContactIdFromPathParam()
val contactInt = try {
Integer.parseInt(contactString)
} catch (e: NumberFormatException) {
throw NotFoundResponse()
}
val contactId = ContactId(contactInt)
return try { return try {
contactManager.getContact(contactId) contactManager.getContact(contactId)
} catch (e: NoSuchContactException) { } catch (e: NoSuchContactException) {

View File

@@ -1,10 +1,16 @@
package org.briarproject.briar.headless.contact package org.briarproject.briar.headless.contact
import io.javalin.NotFoundResponse
import io.javalin.json.JavalinJson.toJson import io.javalin.json.JavalinJson.toJson
import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just
import org.briarproject.bramble.api.contact.Contact 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.bramble.identity.output
import org.briarproject.briar.headless.ControllerTest import org.briarproject.briar.headless.ControllerTest
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
internal class ContactControllerTest : ControllerTest() { internal class ContactControllerTest : ControllerTest() {
@@ -25,6 +31,30 @@ internal class ContactControllerTest : ControllerTest() {
controller.list(ctx) 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 @Test
fun testOutputContact() { fun testOutputContact() {
val json = """ val json = """