Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: saveourtool/save-cloud
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b352477c7e5dc522a96159b68bca405a53a04c2a
Choose a base ref
..
head repository: saveourtool/save-cloud
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 497fcc332bac87aae0f281f864e1c10ec3974895
Choose a head ref
Original file line number Diff line number Diff line change
@@ -111,6 +111,9 @@ class WebSecurityConfig(
"/api/$v1/contests/*/*/best",
"/demo/api/*/run",
"/api/$v1/vulnerabilities/get-all-public",
// `fossGraphView` is public page
"/api/$v1/vulnerabilities/by-name-with-description",
"/api/$v1/comments/get-all",
)
}
}
Original file line number Diff line number Diff line change
@@ -9,10 +9,7 @@ import com.saveourtool.save.domain.Role
import com.saveourtool.save.domain.UserSaveStatus
import com.saveourtool.save.entities.User
import com.saveourtool.save.info.UserInfo
import com.saveourtool.save.utils.StringResponse
import com.saveourtool.save.utils.blockingToFlux
import com.saveourtool.save.utils.orNotFound
import com.saveourtool.save.utils.switchIfEmptyToResponseException
import com.saveourtool.save.utils.*
import com.saveourtool.save.v1

import org.springframework.http.HttpStatus
@@ -41,15 +38,14 @@ class UsersDetailsController(
*/
@GetMapping("/{userName}")
@PreAuthorize("permitAll()")
fun findByName(@PathVariable userName: String): Mono<UserInfo> =
userRepository.findByName(userName)
?.toMonoOrNotFound()?.map { it.toUserInfo() }
?: run {
originalLoginRepository.findByName(userName)
.toMonoOrNotFound()
.map { it.user }
.map { it.toUserInfo() }
}
fun findByName(@PathVariable userName: String): Mono<UserInfo> = userRepository.findByName(userName)
?.toMonoOrNotFound()?.map { it.toUserInfo() }
?: run {
blockingToMono { originalLoginRepository.findByName(userName) }
.orNotFound()
.map { it.user }
.map { it.toUserInfo() }
}

/**
* @return list of [UserInfo] info about user's
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ class VulnerabilityController(
@RequestParam name: String,
): Mono<VulnerabilityDto> = blockingToMono {
vulnerabilityService.getVulnerabilityWithDescriptionByName(name)
}
}.switchIfEmptyToNotFound { "Could not find vulnerability with name $name" }

@GetMapping("/by-user-and-active")
@Operation(
Original file line number Diff line number Diff line change
@@ -133,7 +133,7 @@ class VulnerabilityService(
* @param name name of vulnerability
* @return vulnerability dto by name with description
*/
fun getVulnerabilityWithDescriptionByName(name: String): VulnerabilityDto = vulnerabilityRepository.findByName(name)?.toDtoWithDescription() ?: VulnerabilityDto.empty
fun getVulnerabilityWithDescriptionByName(name: String): VulnerabilityDto? = vulnerabilityRepository.findByName(name)?.toDtoWithDescription()

/**
* @param vulnerabilityDto dto of new vulnerability
2 changes: 1 addition & 1 deletion save-cloud-charts/save-cloud/Chart.lock
Original file line number Diff line number Diff line change
@@ -15,4 +15,4 @@ dependencies:
repository: https://helm.neo4j.com/neo4j
version: 5.9.0
digest: sha256:c7aa8b099b2bbe3adb90370972187543d6671c1eddbadab11511e332a18297e5
generated: "2023-07-03T08:39:30.274188997Z"
generated: "2023-07-03T10:02:16.445820359Z"
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ package com.saveourtool.save.frontend.components.basic

import com.saveourtool.save.entities.CommentDto
import com.saveourtool.save.frontend.components.inputform.InputTypes
import com.saveourtool.save.frontend.externals.fontawesome.faPaperPlane
import com.saveourtool.save.frontend.utils.*
import com.saveourtool.save.frontend.utils.AVATAR_PLACEHOLDER
import com.saveourtool.save.info.UserInfo
@@ -19,6 +20,7 @@ import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.form
import react.dom.html.ReactHTML.h1
import react.dom.html.ReactHTML.img
import react.dom.html.ReactHTML.span
import react.dom.html.ReactHTML.textarea
import react.useState
import web.cssom.*
@@ -37,7 +39,6 @@ import kotlinx.serialization.json.Json
)
val newCommentWindow: FC<NewCommentWindowProps> = FC { props ->
val (comment, setComment) = useState(CommentDto.empty)
val (user, setUser) = useStateFromProps(props.currentUserInfo ?: UserInfo("Unknown"))

val enrollRequest = useDeferredRequest {
val commentNew = comment.copy(section = window.location.hash)
@@ -50,71 +51,78 @@ val newCommentWindow: FC<NewCommentWindowProps> = FC { props ->
)
if (response.ok) {
props.addComment()
setComment(CommentDto.empty)
}
}

div {
className = ClassName("row no-gutters mx-auto border-secondary")
renderLeftColumn(
user.avatar,
user.name,
user.rating,
)
className = ClassName("shadow col mx-auto border border-secondary card card-body p-0")
div {
className = ClassName("card col-10 input-group needs-validation")
textarea {
className = ClassName("form-control")
style = jso {
width = "100%".unsafeCast<Width>()
height = "100%".unsafeCast<Height>()
}
onChange = { event ->
setComment { it.copy(message = event.target.value) }
className = ClassName("row no-gutters mx-auto input-group px-0 shadow-none")
renderLeftColumn(
props.currentUserInfo.avatar,
props.currentUserInfo.name,
props.currentUserInfo.rating,
"#e1e9ed"
)
div {
className = ClassName("col")
textarea {
className = ClassName("form-control p-3 border-0")
style = jso {
width = "100%".unsafeCast<Width>()
height = "100%".unsafeCast<Height>()
}
onChange = { event -> setComment { it.copy(message = event.target.value) } }
value = comment.message
ariaDescribedBy = "${InputTypes.COMMENT.name}Span"
rows = 5
id = InputTypes.COMMENT.name
required = true
placeholder = "Write a comment"
}
ariaDescribedBy = "${InputTypes.COMMENT.name}Span"
rows = 5
id = InputTypes.COMMENT.name
required = true
}
}
}
div {
className = ClassName("d-flex justify-content-end")
buttonBuilder(label = "Comment") {
enrollRequest()
div {
className = ClassName("d-flex justify-content-end p-2")
style = jso { background = "#e1e9ed".unsafeCast<Background>() }
buttonBuilder(
faPaperPlane,
isDisabled = comment.message.isBlank(),
classes = "rounded-circle btn-sm",
isOutline = true,
) {
enrollRequest()
}
}
}
}

/**
* @return a function component
* [FC] for comment displaying
*/
@Suppress(
"GENERIC_VARIABLE_WRONG_DECLARATION",
"MAGIC_NUMBER",
)
@Suppress("GENERIC_VARIABLE_WRONG_DECLARATION", "MAGIC_NUMBER")
val commentWindow: FC<CommentWindowProps> = FC { props ->

val columnCard = cardComponent(isBordered = false, hasBg = true, isNoPadding = false, isPaddingBottomNull = true, isFilling = true)

div {
className = ClassName("row no-gutters mx-auto border-secondary")
className = ClassName("shadow input-group row no-gutters mx-auto border-secondary")
renderLeftColumn(
props.comment.userAvatar,
props.comment.userName,
props.comment.userRating,
)
div {
className = ClassName("card col-10 text-left border-secondary")
className = ClassName("shadow-none card col-10 text-left border-0")
val comment = props.comment
div {
className = ClassName("col")
style = jso {
background = "#F1F1F1".unsafeCast<Background>()
className = ClassName("flex-wrap")
style = jso { background = "#f1f1f1".unsafeCast<Background>() }
span {
className = ClassName("ml-1")
+(comment.createDate?.toUnixCalendarFormat(TimeZone.currentSystemDefault()) ?: "Unknown")
}
+(comment.createDate?.toUnixCalendarFormat(TimeZone.currentSystemDefault()) ?: "Unknown")
}
columnCard {
div {
className = ClassName("shadow-none card card-body border-0")
markdown(comment.message.split("\n").joinToString("\n\n"))
}
}
@@ -143,40 +151,36 @@ external interface NewCommentWindowProps : PropsWithChildren {
/**
* Information about current user
*/
var currentUserInfo: UserInfo?
var currentUserInfo: UserInfo
}

@Suppress(
"MAGIC_NUMBER",
)
@Suppress("MAGIC_NUMBER")
private fun ChildrenBuilder.renderLeftColumn(
userAvatar: String?,
name: String,
rating: Long,
color: String = "#f1f1f1",
) {
val (avatar, setAvatar) = useState(userAvatar?.let { "/api/$v1/avatar$it" } ?: "img/undraw_profile.svg")

div {
className = ClassName("card card-body col-2 border-secondary")
className = ClassName("input-group-prepend col-2")
style = jso {
background = "#e1e9ed".unsafeCast<Background>()
background = color.unsafeCast<Background>()
}
div {
className = ClassName("mb-0 font-weight-bold text-gray-800")
form {
div {
className = ClassName("row justify-content-center g-3 ml-3 mr-3 pb-2 pt-2 border-bottom")
className = ClassName("row justify-content-center g-3 ml-3 mr-3 pb-2 pt-2 border-bottom-0")
div {
className = ClassName("md-4 pl-0 pr-0")
img {
className =
ClassName("avatar avatar-user width-full border color-bg-default rounded-circle")
className = ClassName("avatar avatar-user width-full border color-bg-default rounded-circle")
src = avatar
height = 80.0
width = 80.0
onError = {
setAvatar(AVATAR_PLACEHOLDER)
}
onError = { setAvatar(AVATAR_PLACEHOLDER) }
}
}
div {
Original file line number Diff line number Diff line change
@@ -49,7 +49,6 @@ val fossGraph: FC<FossGraphViewProps> = FC { props ->
val navigate = useNavigate()

val (vulnerability, setVulnerability) = useState(VulnerabilityDto.empty)
val (user, setUser) = useState(props.currentUserInfo)
val (selectedMenu, setSelectedMenu) = useState(VulnerabilityTab.INFO)

val enrollUpdateRequest = useDeferredRequest {
@@ -87,15 +86,6 @@ val fossGraph: FC<FossGraphViewProps> = FC { props ->
}

setVulnerability(vulnerabilityNew)

val userInfo: UserInfo = get(
url = "$apiUrl/users/${props.currentUserInfo?.name}",
headers = jsonHeaders,
loadingHandler = ::noopLoadingHandler,
)
.decodeFromJsonString()

setUser(userInfo)
}

displayModal(
@@ -118,7 +108,7 @@ val fossGraph: FC<FossGraphViewProps> = FC { props ->
className = ClassName("")

val isSuperAdmin = props.currentUserInfo?.globalRole?.isHigherOrEqualThan(Role.SUPER_ADMIN) == true
val isOwner = user?.id == vulnerability.userId
val isOwner = props.currentUserInfo?.id == vulnerability.userId

div {
className = ClassName("d-flex align-items-center justify-content-center mb-4")
@@ -226,7 +216,7 @@ val fossGraph: FC<FossGraphViewProps> = FC { props ->
}
VulnerabilityTab.COMMENTS -> vulnerabilityCommentTab {
this.vulnerability = vulnerability
this.currentUserInfo = user
this.currentUserInfo = props.currentUserInfo
}
}
}
Original file line number Diff line number Diff line change
@@ -9,18 +9,31 @@ import com.saveourtool.save.frontend.components.basic.newCommentWindow
import com.saveourtool.save.frontend.utils.*
import com.saveourtool.save.info.UserInfo

import js.core.jso
import react.FC
import react.Props
import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.h4
import react.useState
import web.cssom.ClassName
import web.cssom.Cursor

import kotlinx.browser.window

val vulnerabilityCommentTab: FC<VulnerabilityCommentTabProps> = FC { props ->
private const val DEFAULT_MAX_COMMENT_AMOUNT = 5

val vulnerabilityCommentTab: FC<VulnerabilityCommentTabProps> = FC { props ->
val (comments, setComments) = useState(emptyList<CommentDto>())
val (user, setUser) = useStateFromProps(props.currentUserInfo ?: UserInfo("Unknown"))
val (isAllCommentsShown, setIsAllCommentsShown) = useState(false)

val display: List<CommentDto>.() -> Unit = {
forEach { message ->
div {
className = ClassName("col-12 mt-4")
commentWindow { comment = message }
}
}
}

useRequest {
val newComments = post(
@@ -48,21 +61,36 @@ val vulnerabilityCommentTab: FC<VulnerabilityCommentTabProps> = FC { props ->
setComments(newComments)
}

div {
className = ClassName("col-12 mt-4")
newCommentWindow {
addComment = { enrollCommentsRequest() }
currentUserInfo = user
if (comments.size > DEFAULT_MAX_COMMENT_AMOUNT && !isAllCommentsShown) {
comments.take(DEFAULT_MAX_COMMENT_AMOUNT / 2).display()
div {
className = ClassName("col-12 mt-4")
onClick = { setIsAllCommentsShown(true) }
style = jso { cursor = "pointer".unsafeCast<Cursor>() }
h4 {
className = ClassName("text-center card p-2 shadow")
+"Show all ${comments.size} comments"
}
}
comments.takeLast(DEFAULT_MAX_COMMENT_AMOUNT / 2).display()
} else {
comments.display()
}

comments.forEach { message ->
props.currentUserInfo?.let { userInfo ->
div {
className = ClassName("col-12 mt-4")
commentWindow {
comment = message
className = ClassName("col-12 mt-5")
newCommentWindow {
addComment = { enrollCommentsRequest() }
currentUserInfo = userInfo
}
}
} ?: div {
className = ClassName("col-12 mt-4")
h4 {
className = ClassName("text-center card p-2 shadow")
+"Authorize in order to write comments"
}
}
}

Original file line number Diff line number Diff line change
@@ -227,3 +227,7 @@ external val faGlobe: FontAwesomeIconModule
@JsModule("@fortawesome/free-solid-svg-icons/faLink")
@JsNonModule
external val faLink: FontAwesomeIconModule

@JsModule("@fortawesome/free-solid-svg-icons/faPaperPlane")
@JsNonModule
external val faPaperPlane: FontAwesomeIconModule