src/main/kotlin/jetbrains/buildServer/notification/slackNotifier/UserSlackNotifierSettingsController.kt (144 lines of code) (raw):
package jetbrains.buildServer.notification.slackNotifier
import jetbrains.buildServer.controllers.BaseController
import jetbrains.buildServer.controllers.BasePropertiesBean
import jetbrains.buildServer.notification.slackNotifier.notification.VerboseMessageBuilderFactory
import jetbrains.buildServer.notification.slackNotifier.slack.AggregatedSlackApi
import jetbrains.buildServer.notification.slackNotifier.slack.SlackResponseError
import jetbrains.buildServer.notification.slackNotifier.slack.User
import jetbrains.buildServer.serverSide.ProjectManager
import jetbrains.buildServer.serverSide.WebLinks
import jetbrains.buildServer.serverSide.auth.Permission
import jetbrains.buildServer.serverSide.oauth.OAuthConnectionsManager
import jetbrains.buildServer.users.SUser
import jetbrains.buildServer.users.UserModel
import jetbrains.buildServer.web.NotificationRulesExtension
import jetbrains.buildServer.web.openapi.PluginDescriptor
import jetbrains.buildServer.web.openapi.WebControllerManager
import jetbrains.buildServer.web.util.SessionUser
import jetbrains.buildServer.web.util.WebUtil
import org.springframework.context.annotation.Conditional
import org.springframework.stereotype.Service
import org.springframework.web.servlet.ModelAndView
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Service
@Conditional(SlackNotifierEnabled::class)
class UserSlackNotifierSettingsController(
private val pluginDescriptor: PluginDescriptor,
private val projectManager: ProjectManager,
private val oAuthConnectionsManager: OAuthConnectionsManager,
private val webControllerManager: WebControllerManager,
private val descriptor: UserSlackNotifierDescriptor,
private val userModel: UserModel,
private val aggregatedSlackApi: AggregatedSlackApi,
private val webLinks: WebLinks
) : BaseController() {
private val userNotificationSettingsURL = pluginDescriptor.getPluginResourcesPath("userNotificationSettingsURL.html")
init {
webControllerManager.registerController(descriptor.editParametersUrl, this)
registerUserSettingsPageExtension()
registerUserNotificationSettingsController()
}
private fun registerUserSettingsPageExtension() {
val extensionUrl = pluginDescriptor.getPluginResourcesPath("notificationRulesMessage.html")
NotificationRulesExtension(
descriptor.type,
extensionUrl,
webControllerManager
).register()
webControllerManager.registerController(extensionUrl, object : BaseController() {
override fun doHandle(request: HttpServletRequest, response: HttpServletResponse): ModelAndView? {
val user = SessionUser.getUser(request) ?: return null
val mv = ModelAndView(pluginDescriptor.getPluginResourcesPath("notificationRulesMessage.jsp"))
mv.model["editConnectionUrl"] = webLinks.getEditProjectPageUrl("_Root") + "&tab=oauthConnections"
mv.model["user"] = user
mv.model["rootProject"] = projectManager.rootProject
return mv
}
})
}
private fun registerUserNotificationSettingsController() {
webControllerManager.registerController(userNotificationSettingsURL, object : BaseController() {
override fun doHandle(request: HttpServletRequest, response: HttpServletResponse): ModelAndView? {
val user = getUser(request, response) ?: return null
for (property in SlackProperties.notificationProperties) {
val value = request.getParameter(property.key)
user.setUserProperty(property, value)
}
return null
}
})
}
override fun doHandle(request: HttpServletRequest, response: HttpServletResponse): ModelAndView? {
val mv = ModelAndView(pluginDescriptor.getPluginResourcesPath("editUserSlackNotifierSettings.jsp"))
val user = getUser(request, response) ?: return null
val currentUser = SessionUser.getUser(request)
if (currentUser == null) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthenticated")
return null
}
val slackUserId = user.getPropertyValue(SlackProperties.channelProperty)
val selectedConnectionId = user.getPropertyValue(SlackProperties.connectionProperty) ?: ""
val availableConnections = projectManager.projects.filter {
user.isPermissionGrantedForProject(it.projectId, Permission.VIEW_PROJECT)
}.flatMap { project ->
oAuthConnectionsManager.getAvailableConnectionsOfType(project, SlackConnection.type)
}.distinctBy { it.id }
val selectedConnection = availableConnections.find { it.id == selectedConnectionId }
val slackUsername = selectedConnection?.let { connection ->
connection.parameters["secure:token"]?.let { token ->
val users = try {
aggregatedSlackApi.getUsersList(token)
} catch (e: TimeoutException) {
emptyList<User>()
} catch (e: ExecutionException) {
emptyList<User>()
} catch (e: SlackResponseError) {
emptyList<User>()
}
val slackUser = users.find {
it.id == slackUserId
}
if (slackUser == null && !slackUserId.isNullOrEmpty()) {
user.getPropertyValue(SlackProperties.displayNameProperty)
} else {
slackUser?.displayName
}
}
}
val defaultProperties = mapOf(
SlackProperties.maximumNumberOfChangesProperty.key to VerboseMessageBuilderFactory.defaultMaximumNumberOfChanges.toString()
)
mv.model["connectionsBean"] = SlackConnectionsBean(availableConnections, aggregatedSlackApi)
mv.model["propertiesBean"] = BasePropertiesBean(user.properties.filter {
it.key != SlackProperties.channelProperty
}.map {
it.key.key to it.value
}.toMap(), defaultProperties)
mv.model["properties"] = SlackProperties()
mv.model["user"] = user
mv.model["slackUsername"] = slackUsername ?: ""
mv.model["selectedConnection"] = selectedConnectionId
mv.model["displaySettings"] = currentUser.id == user.id
mv.model["rootUrl"] = WebUtil.getRootUrl(request)
mv.model["editConnectionUrl"] = webLinks.getEditProjectPageUrl("_Root") + "&tab=oauthConnections"
mv.model["editNotificationSettingsUrl"] = userNotificationSettingsURL
mv.model["rootProject"] = projectManager.rootProject
return mv
}
private fun getUser(request: HttpServletRequest, response: HttpServletResponse): SUser? {
val userId = request.getParameter("holderId")
if (userId == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "'holderId' parameter is required")
return null
}
val user = userModel.findUserById(userId.toLong())
if (user == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "User with id '$userId' not found")
return null
}
return user
}
}