101 projectInfo.project, |
101 projectInfo.project, |
102 selectedVersion, |
102 selectedVersion, |
103 selectedComponent |
103 selectedComponent |
104 ) |
104 ) |
105 |
105 |
106 sealed class LookupResult<T> { |
106 private sealed interface LookupResult<T> |
107 class NotFound<T> : LookupResult<T>() |
107 private class NotFound<T> : LookupResult<T> |
108 data class Found<T>(val elem: T?) : LookupResult<T>() |
108 private data class Found<T>(val elem: T?) : LookupResult<T> |
109 } |
|
110 |
109 |
111 private fun <T : HasNode> HttpRequest.lookupPathParam(paramName: String, list: List<T>): LookupResult<T> { |
110 private fun <T : HasNode> HttpRequest.lookupPathParam(paramName: String, list: List<T>): LookupResult<T> { |
112 val node = pathParams[paramName] |
111 val node = pathParams[paramName] |
113 return if (node == null || node == "-") { |
112 return if (node == null || node == "-") { |
114 LookupResult.Found(null) |
113 Found(null) |
115 } else { |
114 } else { |
116 val result = list.find { it.node == node } |
115 val result = list.find { it.node == node } |
117 if (result == null) { |
116 if (result == null) { |
118 LookupResult.NotFound() |
117 NotFound() |
119 } else { |
118 } else { |
120 LookupResult.Found(result) |
119 Found(result) |
121 } |
120 } |
122 } |
121 } |
123 } |
122 } |
124 |
123 |
125 private fun obtainProjectInfo(http: HttpRequest, dao: DataAccessObject): ProjectInfo? { |
124 private fun obtainProjectInfo(http: HttpRequest, dao: DataAccessObject): ProjectInfo? { |
145 } |
144 } |
146 } |
145 } |
147 |
146 |
148 private fun feedPath(project: Project) = "feed/${project.node}/issues.rss" |
147 private fun feedPath(project: Project) = "feed/${project.node}/issues.rss" |
149 |
148 |
150 data class PathInfos( |
149 private data class PathInfos( |
151 val projectInfo: ProjectInfo, |
150 val projectInfo: ProjectInfo, |
152 val version: Version?, |
151 val version: Version?, |
153 val component: Component? |
152 val component: Component? |
154 ) { |
153 ) { |
155 val project = projectInfo.project |
154 val project = projectInfo.project |
162 http.response.sendError(404) |
161 http.response.sendError(404) |
163 return null |
162 return null |
164 } |
163 } |
165 |
164 |
166 val version = when (val result = http.lookupPathParam("version", projectInfo.versions)) { |
165 val version = when (val result = http.lookupPathParam("version", projectInfo.versions)) { |
167 is LookupResult.NotFound -> { |
166 is NotFound -> { |
168 http.response.sendError(404) |
167 http.response.sendError(404) |
169 return null |
168 return null |
170 } |
169 } |
171 is LookupResult.Found -> { |
170 is Found -> { |
172 result.elem |
171 result.elem |
173 } |
172 } |
174 } |
173 } |
175 val component = when (val result = http.lookupPathParam("component", projectInfo.components)) { |
174 val component = when (val result = http.lookupPathParam("component", projectInfo.components)) { |
176 is LookupResult.NotFound -> { |
175 is NotFound -> { |
177 http.response.sendError(404) |
176 http.response.sendError(404) |
178 return null |
177 return null |
179 } |
178 } |
180 is LookupResult.Found -> { |
179 is Found -> { |
181 result.elem |
180 result.elem |
182 } |
181 } |
183 } |
182 } |
184 |
183 |
185 return PathInfos(projectInfo, version, component) |
184 return PathInfos(projectInfo, version, component) |
229 http.styleSheets = listOf("projects") |
228 http.styleSheets = listOf("projects") |
230 http.render("project-form") |
229 http.render("project-form") |
231 } |
230 } |
232 |
231 |
233 private fun projectCommit(http: HttpRequest, dao: DataAccessObject) { |
232 private fun projectCommit(http: HttpRequest, dao: DataAccessObject) { |
234 // TODO: replace defaults with throwing validator exceptions |
|
235 val project = Project(http.param("id")?.toIntOrNull() ?: -1).apply { |
233 val project = Project(http.param("id")?.toIntOrNull() ?: -1).apply { |
236 name = http.param("name") ?: "" |
234 name = http.param("name") ?: "" |
237 node = http.param("node") ?: "" |
235 node = http.param("node") ?: "" |
238 description = http.param("description") ?: "" |
236 description = http.param("description") ?: "" |
239 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
237 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
286 return |
284 return |
287 } |
285 } |
288 |
286 |
289 val version: Version |
287 val version: Version |
290 when (val result = http.lookupPathParam("version", projectInfo.versions)) { |
288 when (val result = http.lookupPathParam("version", projectInfo.versions)) { |
291 is LookupResult.NotFound -> { |
289 is NotFound -> { |
292 http.response.sendError(404) |
290 http.response.sendError(404) |
293 return |
291 return |
294 } |
292 } |
295 is LookupResult.Found -> { |
293 is Found -> { |
296 version = result.elem ?: Version(-1, projectInfo.project.id) |
294 version = result.elem ?: Version(-1, projectInfo.project.id) |
297 } |
295 } |
298 } |
296 } |
299 |
297 |
300 with(http) { |
298 with(http) { |
308 styleSheets = listOf("projects") |
306 styleSheets = listOf("projects") |
309 render("version-form") |
307 render("version-form") |
310 } |
308 } |
311 } |
309 } |
312 |
310 |
313 private fun versionCommit(http: HttpRequest, dao: DataAccessObject) { |
311 private fun obtainIdAndProject(http: HttpRequest, dao:DataAccessObject): Pair<Int, Project>? { |
314 val id = http.param("id")?.toIntOrNull() |
312 val id = http.param("id")?.toIntOrNull() |
315 val projectid = http.param("projectid")?.toIntOrNull() ?: -1 |
313 val projectid = http.param("projectid")?.toIntOrNull() ?: -1 |
316 val project = dao.findProject(projectid) |
314 val project = dao.findProject(projectid) |
317 if (id == null || project == null) { |
315 return if (id == null || project == null) { |
318 http.response.sendError(400) |
316 http.response.sendError(400) |
319 return |
317 null |
320 } |
318 } else { |
321 |
319 Pair(id, project) |
322 // TODO: replace defaults with throwing validator exceptions |
320 } |
323 val version = Version(id, projectid).apply { |
321 } |
|
322 |
|
323 private fun versionCommit(http: HttpRequest, dao: DataAccessObject) { |
|
324 val idParams = obtainIdAndProject(http, dao) ?: return |
|
325 val (id, project) = idParams |
|
326 |
|
327 val version = Version(id, project.id).apply { |
324 name = http.param("name") ?: "" |
328 name = http.param("name") ?: "" |
325 node = http.param("node") ?: "" |
329 node = http.param("node") ?: "" |
326 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
330 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
327 status = http.param("status")?.let(VersionStatus::valueOf) ?: VersionStatus.Future |
331 status = http.param("status")?.let(VersionStatus::valueOf) ?: VersionStatus.Future |
328 // intentional defaults |
332 // intentional defaults |
370 return |
374 return |
371 } |
375 } |
372 |
376 |
373 val component: Component |
377 val component: Component |
374 when (val result = http.lookupPathParam("component", projectInfo.components)) { |
378 when (val result = http.lookupPathParam("component", projectInfo.components)) { |
375 is LookupResult.NotFound -> { |
379 is NotFound -> { |
376 http.response.sendError(404) |
380 http.response.sendError(404) |
377 return |
381 return |
378 } |
382 } |
379 is LookupResult.Found -> { |
383 is Found -> { |
380 component = result.elem ?: Component(-1, projectInfo.project.id) |
384 component = result.elem ?: Component(-1, projectInfo.project.id) |
381 } |
385 } |
382 } |
386 } |
383 |
387 |
384 with(http) { |
388 with(http) { |
393 render("component-form") |
397 render("component-form") |
394 } |
398 } |
395 } |
399 } |
396 |
400 |
397 private fun componentCommit(http: HttpRequest, dao: DataAccessObject) { |
401 private fun componentCommit(http: HttpRequest, dao: DataAccessObject) { |
398 val id = http.param("id")?.toIntOrNull() |
402 val idParams = obtainIdAndProject(http, dao) ?: return |
399 val projectid = http.param("projectid")?.toIntOrNull() ?: -1 |
403 val (id, project) = idParams |
400 val project = dao.findProject(projectid) |
404 |
401 if (id == null || project == null) { |
405 val component = Component(id, project.id).apply { |
402 http.response.sendError(400) |
|
403 return |
|
404 } |
|
405 |
|
406 // TODO: replace defaults with throwing validator exceptions |
|
407 val component = Component(id, projectid).apply { |
|
408 name = http.param("name") ?: "" |
406 name = http.param("name") ?: "" |
409 node = http.param("node") ?: "" |
407 node = http.param("node") ?: "" |
410 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
408 ordinal = http.param("ordinal")?.toIntOrNull() ?: 0 |
411 color = WebColor(http.param("color") ?: "#000000") |
409 color = WebColor(http.param("color") ?: "#000000") |
412 description = http.param("description") |
410 description = http.param("description") |
504 if (issue == null) { |
502 if (issue == null) { |
505 http.response.sendError(404) |
503 http.response.sendError(404) |
506 return |
504 return |
507 } |
505 } |
508 |
506 |
509 // TODO: throw validator exception instead of using a default |
|
510 |
|
511 val commentId = http.param("commentid")?.toIntOrNull() ?: -1 |
507 val commentId = http.param("commentid")?.toIntOrNull() ?: -1 |
512 if (commentId > 0) { |
508 if (commentId > 0) { |
513 val comment = dao.findComment(commentId) |
509 val comment = dao.findComment(commentId) |
514 val originalAuthor = comment?.author?.username |
510 val originalAuthor = comment?.author?.username |
515 if (originalAuthor != null && originalAuthor == http.remoteUser) { |
511 if (originalAuthor != null && originalAuthor == http.remoteUser) { |
531 } |
527 } |
532 } |
528 } |
533 |
529 |
534 private fun issueCommit(http: HttpRequest, dao: DataAccessObject) { |
530 private fun issueCommit(http: HttpRequest, dao: DataAccessObject) { |
535 withPathInfo(http, dao)?.run { |
531 withPathInfo(http, dao)?.run { |
536 // TODO: throw validator exception instead of using defaults |
|
537 val issue = Issue( |
532 val issue = Issue( |
538 http.param("id")?.toIntOrNull() ?: -1, |
533 http.param("id")?.toIntOrNull() ?: -1, |
539 project |
534 project |
540 ).apply { |
535 ).apply { |
541 component = dao.findComponent(http.param("component")?.toIntOrNull() ?: -1) |
536 component = dao.findComponent(http.param("component")?.toIntOrNull() ?: -1) |