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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ object WebUserRouteConfig : RouteConfig
contentType = ContentTypes.json)
.json()
.transform()
.secure(usersManage)
.secure(usersManage),
WebEndpoint("/typeahead/emails/",
UserController::class, "getUserEmails",
contentType = ContentTypes.json)
.json()
.transform()
.secure(usersManage)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ class UserController(context: ActionContext,
.sortedBy { it.displayName.toLowerCase() }
}

fun getUserEmails(): List<String>
{
return userRepo.getUserEmails()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're assuming that we always have a manageable number of users to be able to return the full list on each call? No value in doing an initial filter with first few letters here? Probably not for the number we have in Montagu, would just make the UI less responsive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, yeah. The number of users would have to be pretty high for this to be a problem.

}

private fun report(): String = context.params(":report")
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ interface UserRepository
{
fun addUser(email: String, username: String, displayName: String, source: UserSource)
fun getUser(email: String): UserDetails?
fun getUserEmails(): List<String>
fun getScopedIndividualReportReaders(reportName: String): List<User>
fun getGlobalReportReaderGroups(): List<UserGroup>
fun getScopedReportReaderGroups(reportName: String): List<UserGroup>
}

class OrderlyUserRepository() : UserRepository
{
override fun getUserEmails(): List<String>
{
return JooqContext().use {
it.dsl.select(ORDERLYWEB_USER.EMAIL)
.from(ORDERLYWEB_USER)
.fetchInto(String::class.java)
}
}

private fun reportReadingGroupsQuery(db: JooqContext) = db.dsl.select(ORDERLYWEB_USER_GROUP.ID,
ORDERLYWEB_USER.USERNAME,
ORDERLYWEB_USER.DISPLAY_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ class UserRepositoryTests : CleanDatabaseTests()
assertThat(nullResult).isNull()
}

@Test
fun `gets user emails in alphabetical order`()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this test name misleading? I can't see ordering code, and I didn't think containsExactlyElementsOf checked order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

containsExactlyElementsOf is order sensitive. Seems sqlite returns the records in alphabetical order, hence no extra ordering logic.

{
val sut = OrderlyUserRepository()

insertUser("[email protected]", "some.name")
insertUser("[email protected]", "test.name")
insertUser("[email protected]", "test.name")

val result = sut.getUserEmails()
assertThat(result).containsExactlyElementsOf(listOf("[email protected]", "[email protected]", "[email protected]"))
}

@Test
fun `addUser can create new github user`()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ class UsersTests : IntegrationTest()
JSONValidator.validateAgainstSchema(response.text, "UserGroups")
}

@Test
fun `only user managers can get user emails`()
{
val url = "/typeahead/emails/"

assertWebUrlSecured(url, setOf(ReifiedPermission("users.manage", Scope.Global())),
contentType = ContentTypes.json)
}

@Test
fun `can get scoped report reading groups`()
Expand All @@ -67,6 +75,7 @@ class UsersTests : IntegrationTest()
ContentTypes.json)

JSONValidator.validateAgainstSchema(response.text, "UserGroups")

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ import org.vaccineimpact.orderlyweb.test_helpers.TeamcityTests

class UserControllerTests : TeamcityTests()
{
@Test
fun `gets user emails`()
{
val repo = mock<UserRepository> {
on { this.getUserEmails() } doReturn (listOf("one", "two"))
}

val sut = UserController(mock(), repo)

assertThat(sut.getUserEmails()).containsExactlyElementsOf(listOf("one", "two"))
}

@Test
fun `gets individual scoped report readers`()
{
Expand Down
3 changes: 3 additions & 0 deletions src/app/static/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ module.exports = {
"globals": {
"appUrl": "http://app"
},
"transformIgnorePatterns": [
"node_modules/(?!(vue-bootstrap-typeahead)/)"
],
"moduleFileExtensions": [
"js",
"json",
Expand Down
202 changes: 202 additions & 0 deletions src/app/static/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/app/static/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"babel-loader": "^8.0.5",
"bootstrap": "^4.3.1",
"bootstrap-toggle": "^2.2.2",
"css-loader": "^3.0.0",
"datatables.net-bs4": "^1.10.19",
"datatables.net-dt": "^1.10.19",
"gulp": "^4.0.0",
Expand All @@ -40,6 +41,7 @@
"through": "^2.3.8",
"treetables": "^1.1.3",
"vue": "^2.6.8",
"vue-bootstrap-typeahead": "^0.2.6",
"vue-jest": "^3.0.4",
"vue-loader": "^15.7.0",
"vue-template-compiler": "^2.6.8",
Expand Down
Loading