Skip to content

Commit

Permalink
Editing view preparations: propagating of edit flag to children compo…
Browse files Browse the repository at this point in the history
…nents

### What's done:
- Minor Spring Security Timeout update (not tested)
- Propagating edit button actions to have a common editable page
- Adding creation date to timeline (so it's always shown)
- Adding ribbon for approved/not approved
- Fix for editing short and long description
- Minor fixes
  • Loading branch information
orchestr7 committed Sep 6, 2023
1 parent 13d4ade commit 1d520c2
Show file tree
Hide file tree
Showing 15 changed files with 295 additions and 117 deletions.
5 changes: 5 additions & 0 deletions api-gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,8 @@ spring:
scope:
- user_info
---
# logout timeout
server:
servlet:
session:
timeout: 15m
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ class VulnerabilityController(
)
@ApiResponse(responseCode = "200", description = "Successfully updated vulnerability")
@RequiresAuthorizationSourceHeader
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN')")
fun update(
@RequestBody vulnerabilityDto: VulnerabilityDto,
authentication: Authentication,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,16 +296,17 @@ class VulnerabilityService(

val vulnerability = vulnerabilityRepository.findByIdentifier(vulnerabilityDto.identifier).orNotFound()

if (!authentication.hasRole(Role.SUPER_ADMIN) && (userId != vulnerability.userId || vulnerability.status == VulnerabilityStatus.APPROVED)) {
// only Super Users and owners of unapproved vuln. can edit it
if (authentication.hasRole(Role.SUPER_ADMIN) || (userId == vulnerability.userId && vulnerability.status != VulnerabilityStatus.APPROVED)) {
val vulnerabilityUpdate = vulnerability.apply {
progress = vulnerabilityDto.progress
description = vulnerabilityDto.description.orEmpty()
status = vulnerabilityDto.status
}
vulnerabilityRepository.save(vulnerabilityUpdate)
} else {
throw ResponseStatusException(HttpStatus.FORBIDDEN)
}

val vulnerabilityUpdate = vulnerability.apply {
progress = vulnerabilityDto.progress
description = vulnerabilityDto.description.orEmpty()
status = vulnerabilityDto.status
}
vulnerabilityRepository.save(vulnerabilityUpdate)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ enum class VulnerabilityDateType(val value: String) {
* Date from [com.saveourtool.osv4k.OsvSchema.withdrawn] in COSV schema
*/
WITHDRAWN("Withdrawn"),

/**

Check failure

Code scanning / ktlint

[ENUMS_SEPARATED] enum is incorrectly formatted: last enum entry must end with a comma Error

[ENUMS_SEPARATED] enum is incorrectly formatted: last enum entry must end with a comma
* Date when the vuln was submitted to our archive, our platform specific
*/
SUBMITTED("Submitted")
;

override fun toString(): String = value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.saveourtool.save.frontend.externals.animations.ringLoader
import com.saveourtool.save.info.UserInfo

import js.core.jso
import kotlinx.browser.window
import org.w3c.fetch.Response
import react.*
import react.dom.html.ReactHTML.button
Expand Down Expand Up @@ -102,7 +103,8 @@ val requestModalHandler: FC<RequestModalProps> = FC { props ->
onClick = {
if (response?.status == 401.toShort()) {
// if 401 - change current URL to the main page (with login screen)
navigate("/")
navigate(to = "/")
window.location.reload()
}
setResponse(null)
setModalState(modalState.copy(isErrorModalOpen = false))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

package com.saveourtool.save.frontend.components.basic

import com.saveourtool.save.entities.vulnerability.VulnerabilityDateType
import com.saveourtool.save.entities.vulnerability.VulnerabilityDto
import com.saveourtool.save.frontend.utils.buttonBuilder
import react.*
import react.dom.html.ReactHTML.div
Expand All @@ -12,45 +14,53 @@ import kotlinx.datetime.LocalDateTime
const val HOVERABLE_CONST = "hoverable"

val timelineComponent: FC<TimelineComponentProps> = FC { props ->
val hoverable = props.onNodeClick?.let { HOVERABLE_CONST }.orEmpty()
console.log(props.dates)

Check failure

Code scanning / ktlint

[DEBUG_PRINT] use a dedicated logging library: found console.log() (cannot be auto-corrected) Error

[DEBUG_PRINT] use a dedicated logging library: found console.log() (cannot be auto-corrected)
if (props.dates != undefined) {
val hoverable = props.onNodeClick?.let { HOVERABLE_CONST }.orEmpty()

div {
className = ClassName("mb-3")
props.title?.let { title ->
div {
className = ClassName("mt-3 mb-3 text-xs text-center font-weight-bold text-primary text-uppercase")
+title
div {
className = ClassName("mb-3")
props.title?.let { title ->
div {
className = ClassName("mt-3 mb-3 text-xs text-center font-weight-bold text-primary text-uppercase")
+title
}
}
}

props.onAddClick?.let { onClickCallback ->
buttonBuilder(
label = "Add date",
style = "secondary",
isOutline = true,
classes = "btn btn-primary"
) {
onClickCallback()
props.onAddClick?.let { onClickCallback ->
buttonBuilder(
label = "Add date",
style = "secondary",
isOutline = true,
classes = "btn btn-sm btn-primary"
) {
onClickCallback()
}
}
}

if (props.dates.isNotEmpty()) {
div {
className = ClassName("p-0 timeline-container")
div {
className = ClassName("steps-container")
div {
className = ClassName("line")
}
props.dates.toList()
props.dates
.plus(
VulnerabilityDateType.SUBMITTED.value to
(props.vulnerability.creationDateTime ?: LocalDateTime(0, 1, 1, 0, 0, 0, 0))
)
.toList()
.sortedBy { it.second }
.forEach { (label, dateTime) ->
div {
className = ClassName("step $hoverable")
props.onNodeClick?.let { onClickCallback ->
onClick = { onClickCallback(dateTime, label) }
className =
ClassName(if (!label.isSubmittedType()) "step $hoverable" else "step-non-editable")

Check failure

Code scanning / ktlint

[WRONG_INDENTATION] only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed): expected 40 but was 36 Error

[WRONG_INDENTATION] only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed): expected 40 but was 36
if (!label.isSubmittedType()) {
props.onNodeClick?.let { onClickCallback ->
onClick = { onClickCallback(dateTime, label) }
}
}

div {
className = ClassName("text-label")
+label
Expand All @@ -70,9 +80,13 @@ val timelineComponent: FC<TimelineComponentProps> = FC { props ->
}
}
}
} else {

Check failure

Code scanning / ktlint

[EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected) Error

[EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected)

}

Check warning

Code scanning / detekt

Empty block of code detected. As they serve no purpose they should be removed. Warning

This empty block of code can be removed.
}

private fun String.isSubmittedType() = this == VulnerabilityDateType.SUBMITTED.value

Check failure

Code scanning / ktlint

[TOP_LEVEL_ORDER] the declaration part of a top level elements should be in the proper order: private fun String.isSubmittedType() = this == VulnerabilityDateType.SUBMITTED.value Error

[TOP_LEVEL_ORDER] the declaration part of a top level elements should be in the proper order: private fun String.isSubmittedType() = this == VulnerabilityDateType.SUBMITTED.value

/**
* [Props] of [timelineComponent]
*/
Expand All @@ -97,4 +111,9 @@ external interface TimelineComponentProps : Props {
*/
@Suppress("TYPE_ALIAS")
var onNodeClick: ((LocalDateTime, String) -> Unit)?

/**
* Vulnerability dto of vulnerability
*/
var vulnerability: VulnerabilityDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.saveourtool.save.info.UserInfo
import com.saveourtool.save.validation.FrontendRoutes

import js.core.jso
import kotlinx.browser.window
import react.*
import react.dom.html.ReactHTML.button
import react.dom.html.ReactHTML.div
Expand Down Expand Up @@ -54,6 +55,7 @@ val userSettingsView: FC<SettingsProps> = FC { props ->
type = ButtonType.button
onClick = {
useNavigate(to = "/")
window.location.reload()
}
+"Proceed to login page"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.saveourtool.save.frontend.components.views.vuln

import com.saveourtool.save.entities.vulnerability.VulnerabilityDto
import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus
import com.saveourtool.save.frontend.components.basic.renderAvatar
import com.saveourtool.save.frontend.components.basic.renderUserAvatarWithName
import com.saveourtool.save.frontend.components.basic.userBoard
import com.saveourtool.save.frontend.externals.fontawesome.*
import com.saveourtool.save.frontend.utils.*
import com.saveourtool.save.info.UserInfo
import com.saveourtool.save.utils.toUnixCalendarFormat
import js.core.jso

import react.*
import react.dom.html.ReactHTML.div
Expand All @@ -22,20 +24,21 @@ import web.cssom.rem
import kotlinx.datetime.TimeZone
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import react.dom.html.ReactHTML.p
import web.cssom.Color
import web.cssom.TextDecoration.Companion.underline

/**
* [FC] that is used to display some general vulnerability information
*/
@Suppress("EMPTY_BLOCK_STRUCTURE_ERROR", "MAGIC_NUMBER")
val vulnerabilityGeneralInfo: FC<VulnerabilityGeneralInfo> = FC { props ->
val (vulnerability, setVulnerability) = useStateFromProps(props.vulnerability)

val enrollRequest = useDeferredRequest {
post(
"$apiUrl/vulnerabilities/update",
jsonHeaders,
Json.encodeToString(vulnerability),
loadingHandler = ::noopLoadingHandler,
Json.encodeToString(props.vulnerability),
loadingHandler = ::loadingHandler,
)
}

Expand All @@ -55,13 +58,21 @@ val vulnerabilityGeneralInfo: FC<VulnerabilityGeneralInfo> = FC { props ->
}
}
if (props.isEditDisabled) {
if (props.userInfo?.isSuperAdmin() == true || props.userInfo?.name == userInfo.name) {
// only Super Users and owners of unapproved vuln. can edit it
if (props.userInfo?.isSuperAdmin() == true ||
(props.userInfo?.name == userInfo.name && props.vulnerability.status != VulnerabilityStatus.APPROVED)) {

Check failure

Code scanning / ktlint

[WRONG_INDENTATION] only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed): expected 32 but was 28 Error

[WRONG_INDENTATION] only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed): expected 32 but was 28
buttonBuilder(
labelBuilder = {
+"Edit "
fontAwesomeIcon(icon = faEdit)
p {
className = ClassName("mb-0")
style = jso {
textDecoration = underline;

Check failure

Code scanning / ktlint

[REDUNDANT_SEMICOLON] there should be no redundant semicolon at the end of lines: textDecoration = underline; Error

[REDUNDANT_SEMICOLON] there should be no redundant semicolon at the end of lines: textDecoration = underline;
}
+"Edit "
fontAwesomeIcon(icon = faEdit)
}
},
"link", isOutline = true, classes = "text-xs text-muted text-left ml-auto"
isOutline = true, classes = "text-xs text-left ml-auto"
) {
props.setIsEditDisabled(false)
}
Expand All @@ -72,33 +83,36 @@ val vulnerabilityGeneralInfo: FC<VulnerabilityGeneralInfo> = FC { props ->
props.setIsEditDisabled(true)
}
buttonBuilder(faTimesCircle, null, isOutline = true) {
setVulnerability(props.vulnerability)
props.setVulnerability(props.vulnerability)
props.setIsEditDisabled(true)
}
}
}
textarea {
className = ClassName("auto_height form-control-plaintext pt-0 pb-0 text-gray-900")
className = ClassName("auto_height form-control-plaintext px-2 pt-0 pb-0 text-gray-900")
value = shortDescription
disabled = props.isEditDisabled
rows = 2
if (!props.isEditDisabled) {
style = borderEditStyle()
}
onChange = { event ->
props.setVulnerability { vulnerability ->
vulnerability.copy(
shortDescription = event.target.value
)
}
}
}
hr { }
div {
className = ClassName("d-flex justify-content-between align-items-center")
label {
className = ClassName("m-0")
+"Creation time:"
}
label {
className = ClassName("m-0")
+creationDateTime?.toUnixCalendarFormat(TimeZone.currentSystemDefault())
}
}
div {
className = ClassName("d-flex justify-content-between align-items-center")
label {
className = ClassName("m-0")
+"Last updated time:"
+"Last update time:"
}
label {
className = ClassName("m-0")
Expand All @@ -111,12 +125,15 @@ val vulnerabilityGeneralInfo: FC<VulnerabilityGeneralInfo> = FC { props ->
+"Description"
}
textarea {
className = ClassName("auto_height form-control-plaintext pt-0 pb-0 text-gray-900")
className = ClassName("auto_height form-control-plaintext px-2 pt-0 pb-0 text-gray-900")
value = description
disabled = props.isEditDisabled
rows = 8
if (!props.isEditDisabled) {
style = borderEditStyle()
}
onChange = { event ->
setVulnerability { vulnerability ->
props.setVulnerability { vulnerability ->
vulnerability.copy(
description = event.target.value
)
Expand All @@ -136,6 +153,7 @@ val vulnerabilityGeneralInfo: FC<VulnerabilityGeneralInfo> = FC { props ->
this.vulnerability = props.vulnerability
fetchVulnerability = props.fetchVulnerability
canEditVulnerability = props.canEditVulnerability
isEditDisabled = props.isEditDisabled
}
}
}
Expand Down Expand Up @@ -202,6 +220,11 @@ external interface VulnerabilityGeneralInfo : Props {
*/
var vulnerability: VulnerabilityDto

/**

Check failure

Code scanning / ktlint

[KDOC_EMPTY_KDOC] KDoc should never be empty: setVulnerability (cannot be auto-corrected) Error

[KDOC_EMPTY_KDOC] KDoc should never be empty: setVulnerability (cannot be auto-corrected)
*
*/
var setVulnerability: StateSetter<VulnerabilityDto>

/**
* Callback to fetch updated vulnerability
*/
Expand Down
Loading

0 comments on commit 1d520c2

Please sign in to comment.