Skip to content

Commit

Permalink
Unifying tags (#2373)
Browse files Browse the repository at this point in the history
* Unifying tags

### What's done:
 * Added tag table
 * Added lnk_vulnerability_tag
 * Added general Tag entity - this entity should be linked with another taggable entity
 * Added TagRepository and TagService
 * Supported Tag entity in a field of Vulnerability entity - created LnkVulnerabilityTag
 * Dropped tags column in vulnerability table

 ### TODO:
  * Implement filtering by tag and double-test it
  • Loading branch information
sanyavertolet authored Jul 26, 2023
1 parent 87ff34e commit bba4b66
Show file tree
Hide file tree
Showing 15 changed files with 326 additions and 103 deletions.
2 changes: 2 additions & 0 deletions db/v-2/tables/db.changelog-tables.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
<include file="contest-sample-field.xml" relativeToChangelogFile="true"/>
<include file="vulnerability-date.xml" relativeToChangelogFile="true"/>
<include file="lnk-vulnerability-user.xml" relativeToChangelogFile="true"/>
<include file="tags.xml" relativeToChangelogFile="true"/>
<include file="lnk-vulnerability-tag.xml" relativeToChangelogFile="true"/>

<changeSet id="02-tables" author="frolov">
<tagDatabase tag="v2.0-tables"/>
Expand Down
24 changes: 24 additions & 0 deletions db/v-2/tables/lnk-vulnerability-tag.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

<changeSet id="lnk-vulnerability-tag-1" author="sanyavertolet" context="dev or prod">
<createTable tableName="lnk_vulnerability_tag">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="vulnerability_id" type="bigint">
<constraints foreignKeyName="fk_vulnerability_tag_vulnerability" references="vulnerability(id)" nullable="false" deleteCascade="true"/>
</column>
<column name="tag_id" type="bigint">
<constraints foreignKeyName="fk_lnk_vulnerability_tag_tag" references="tag(id)" nullable="false" deleteCascade="true"/>
</column>
</createTable>

<addUniqueConstraint tableName="lnk_vulnerability_tag" columnNames="tag_id, vulnerability_id"/>
</changeSet>

</databaseChangeLog>
19 changes: 19 additions & 0 deletions db/v-2/tables/tags.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

<changeSet id="tag-1" author="sanyavertolet" context="dev or prod">
<createTable tableName="tag">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(16)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>

</databaseChangeLog>
4 changes: 4 additions & 0 deletions db/v-2/tables/vulnerability.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,8 @@
</addColumn>
</changeSet>

<changeSet id="vulnerability-12" author="sanyavertolet" context="dev or prod">
<dropColumn tableName="vulnerability" columnName="tags"/>
</changeSet>

</databaseChangeLog>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.saveourtool.save.backend.controllers.vulnerability

import com.saveourtool.save.backend.security.VulnerabilityPermissionEvaluator
import com.saveourtool.save.backend.service.TagService
import com.saveourtool.save.backend.service.vulnerability.VulnerabilityService
import com.saveourtool.save.backend.utils.hasRole
import com.saveourtool.save.configs.ApiSwaggerSupport
Expand Down Expand Up @@ -43,6 +44,7 @@ typealias VulnerabilityDtoList = List<VulnerabilityDto>
class VulnerabilityController(
private val vulnerabilityService: VulnerabilityService,
private val vulnerabilityPermissionEvaluator: VulnerabilityPermissionEvaluator,
private val tagService: TagService,
) {
@PostMapping("/by-filters")
@Operation(
Expand Down Expand Up @@ -402,13 +404,13 @@ class VulnerabilityController(
@ApiResponse(responseCode = "404", description = "Requested vulnerability is not found")
fun saveTag(
@RequestParam vulnerabilityName: String,
@RequestParam tag: String,
@RequestParam tagName: String,
authentication: Authentication
) = vulnerabilityName.toMono()
.filter { vulnerabilityPermissionEvaluator.hasPermission(authentication, vulnerabilityName, Permission.WRITE) }
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Not enough permission for managing $vulnerabilityName." }
.flatMap { blockingToMono { vulnerabilityService.addTag(vulnerabilityName, tag) } }
.map { StringResponse.ok("Successfully added tag $tag to vulnerability $vulnerabilityName.") }
.flatMap { blockingToMono { tagService.addVulnerabilityTag(vulnerabilityName, tagName) } }
.map { StringResponse.ok("Successfully added tag $tagName to vulnerability $vulnerabilityName.") }

@DeleteMapping("/delete-tag")
@Operation(
Expand All @@ -422,11 +424,11 @@ class VulnerabilityController(
@ApiResponse(responseCode = "404", description = "Requested vulnerability is not found")
fun deleteTag(
@RequestParam vulnerabilityName: String,
@RequestParam tag: String,
@RequestParam tagName: String,
authentication: Authentication
) = vulnerabilityName.toMono()
.filter { vulnerabilityPermissionEvaluator.hasPermission(authentication, vulnerabilityName, Permission.DELETE) }
.switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Not enough permission for managing $vulnerabilityName." }
.flatMap { blockingToMono { vulnerabilityService.deleteTag(vulnerabilityName, tag) } }
.map { StringResponse.ok("Successfully deleted tag $tag in vulnerability $vulnerabilityName.") }
.flatMap { blockingToMono { tagService.deleteVulnerabilityTag(vulnerabilityName, tagName) } }
.map { StringResponse.ok("Successfully deleted tag $tagName in vulnerability $vulnerabilityName.") }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.saveourtool.save.backend.repository

import com.saveourtool.save.entities.Tag
import com.saveourtool.save.spring.repository.BaseEntityRepository
import org.springframework.stereotype.Repository

/**
* [BaseEntityRepository] for [Tag]s.
*/
@Repository
interface TagRepository : BaseEntityRepository<Tag> {
/**
* Find [Tag] by its [Tag.name]
*
* @param name tag name
* @return [Tag] if found, null otherwise
*/
fun findByName(name: String): Tag?

/**
* Find [Tag]s by their [Tag.name]
*
* @param tagNames [Set] of [Tag.name]
* @return [Set] of [Tag]
*/
fun findByNameIn(tagNames: Set<String>): Set<Tag>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.saveourtool.save.backend.repository.vulnerability

import com.saveourtool.save.entities.vulnerabilities.LnkVulnerabilityTag
import com.saveourtool.save.spring.repository.BaseEntityRepository
import org.springframework.stereotype.Repository

/**
* [BaseEntityRepository] for [LnkVulnerabilityTag]
*/
@Repository
interface LnkVulnerabilityTagRepository : BaseEntityRepository<LnkVulnerabilityTag> {
/**
* @param tagName tag
* @return list of [LnkVulnerabilityTag] links to vulnerability
*/
fun findByTagName(tagName: String): List<LnkVulnerabilityTag>

/**
* @param tagNames [Set] of tags
* @return list of [LnkVulnerabilityTag] links to vulnerability
*/
fun findByTagNameIn(tagNames: Set<String>): List<LnkVulnerabilityTag>

/**
* @param vulnerabilityId id of vulnerability
* @return list of [LnkVulnerabilityTag] links to vulnerability
*/
fun findByVulnerabilityId(vulnerabilityId: Long): List<LnkVulnerabilityTag>

/**
* @param vulnerabilityId id of vulnerability
* @param tagName tag
* @return [LnkVulnerabilityTag]
*/
fun findByVulnerabilityIdAndTagName(vulnerabilityId: Long, tagName: String): LnkVulnerabilityTag?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.saveourtool.save.backend.service

import com.saveourtool.save.backend.repository.TagRepository
import com.saveourtool.save.backend.repository.vulnerability.LnkVulnerabilityTagRepository
import com.saveourtool.save.backend.repository.vulnerability.VulnerabilityRepository
import com.saveourtool.save.entities.Tag
import com.saveourtool.save.entities.vulnerabilities.LnkVulnerabilityTag
import com.saveourtool.save.entities.vulnerabilities.Vulnerability
import com.saveourtool.save.utils.orNotFound
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
* [Service] for [Tag] entity
*
* @property tagRepository
*/
@Service
class TagService(
private val tagRepository: TagRepository,
private val vulnerabilityRepository: VulnerabilityRepository,
private val lnkVulnerabilityTagRepository: LnkVulnerabilityTagRepository,
) {
/**
* @param vulnerabilityName [Vulnerability.name]
* @param tagName tag to add
* @return new [LnkVulnerabilityTag]
*/
@Transactional
fun addVulnerabilityTag(vulnerabilityName: String, tagName: String): LnkVulnerabilityTag {
val vulnerability = vulnerabilityRepository.findByName(vulnerabilityName).orNotFound {
"Could not find vulnerability $vulnerabilityName"
}
val tag = tagRepository.findByName(tagName) ?: tagRepository.save(Tag(tagName))

return lnkVulnerabilityTagRepository.save(
LnkVulnerabilityTag(vulnerability, tag)
)
}

/**
* @param vulnerabilityName [Vulnerability.name]
* @param tagName tag to delete
* @return updated [Vulnerability]
*/
@Transactional
fun deleteVulnerabilityTag(vulnerabilityName: String, tagName: String) {
val vulnerability = vulnerabilityRepository.findByName(vulnerabilityName).orNotFound {
"Could not find vulnerability $vulnerabilityName"
}

val link = lnkVulnerabilityTagRepository.findByVulnerabilityIdAndTagName(
vulnerability.requiredId(),
tagName
).orNotFound { "Tag '$tagName' is not linked with vulnerability $vulnerabilityName." }

lnkVulnerabilityTagRepository.delete(link)
}
}
Loading

0 comments on commit bba4b66

Please sign in to comment.