Skip to content

Commit

Permalink
feat(webinterface): add user friendly error handling (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhellmeier authored Jul 15, 2024
1 parent 42b0d6a commit b097fff
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -400,9 +400,10 @@ class TextWatermarker(
"'${char.toUnicodeRepresentation()}'"
}

return "The file contains characters of the watermark " +
"transcoding alphabet. Adding a Watermarking would potentially make the " +
"file unusable! Maybe the file already contains a watermark?\n\n" +
return "The input contains characters of the watermark " +
"transcoding alphabet. It is only possible to add a watermark to and input " +
"that doesn't contain any watermark. Adding another watermark would potentially " +
"make the input unusable! Maybe the input already contains a watermark?\n\n" +
"Contained Chars:\n" +
"$containedChars."
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,10 @@ class TextWatermarkerTest {
// Arrange
val error = TextWatermarker.ContainsAlphabetCharsError(sequenceOf('a', 'b'))
val expected =
"Error (TextWatermarker.addWatermark): The file contains characters of the watermark " +
"transcoding alphabet. Adding a Watermarking would potentially make the file " +
"unusable! Maybe the file already contains a watermark?\n" +
"Error (TextWatermarker.addWatermark): The input contains characters of the watermark" +
" transcoding alphabet. It is only possible to add a watermark to and input that" +
" doesn't contain any watermark. Adding another watermark would potentially make " +
"the input unusable! Maybe the input already contains a watermark?\n" +
"\n" +
"Contained Chars:\n" +
"['\\u0061','\\u0062']."
Expand Down
64 changes: 41 additions & 23 deletions webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import de.fraunhofer.isst.trend.watermarker.Watermarker
import de.fraunhofer.isst.trend.watermarker.fileWatermarker.TextWatermarker
import de.fraunhofer.isst.trend.watermarker.returnTypes.Result
import de.fraunhofer.isst.trend.watermarker.watermarks.TextWatermark
import de.fraunhofer.isst.trend.watermarker.watermarks.Watermark
import io.kvision.core.Placement
import io.kvision.core.TooltipOptions
Expand Down Expand Up @@ -170,23 +172,45 @@ class WatermarkTextEmbedTab : SimplePanel() {
submitButton.onClick {
if (textFormPanel.validate()) {
// Modal
val watermarkedText =
val modal = Modal("Result")

val watermarkedResult =
addWatermarkToText(
textFormPanel.getData().watermark,
textFormPanel.getData().text,
)

val modal = Modal("Successful")
modal.add(span("The following text includes your watermark:"))
modal.add(div(watermarkedText, className = "selectable card-text"))
modal.addButton(
Button("Copy to Clipboard") {
onClick {
window.navigator.clipboard.writeText(watermarkedText)
Toast.success("Successful copied to clipboard!")
}
},
)
if (watermarkedResult.isSuccess) {
val watermarkedText = watermarkedResult.value ?: ""

modal.add(
div(
"Successfully embedded your watermark in the " +
"cover text",
className = "alert alert-success",
),
)
modal.add(span("The following text includes your watermark:"))
modal.add(div(watermarkedText, className = "selectable card-text"))
modal.addButton(
Button("Copy to Clipboard") {
onClick {
window.navigator.clipboard.writeText(watermarkedText)
Toast.success("Successful copied to clipboard!")
}
},
)
} else {
modal.add(
div(
"An error occurs during the watermarking " +
"process: <br />" + watermarkedResult.getMessage(),
rich = true,
className = "alert alert-danger",
),
)
}

modal.addButton(
Button("Close") {
onClick {
Expand Down Expand Up @@ -249,20 +273,14 @@ class WatermarkTextEmbedTab : SimplePanel() {
(if (watermarkerInput.value == null) min else capacityObservable.value)
}

/** Adds a [watermark] string to [text] and returns the watermarked text */
/** Adds a [watermarkString] string to [text] and returns the watermarked text result */
private fun addWatermarkToText(
watermark: String,
watermarkString: String,
text: String,
): String {
): Result<String> {
val watermarker = Watermarker()
val result = watermarker.textAddWatermark(text, watermark.encodeToByteArray().asList())

return if (result.isSuccess) {
result.value ?: ""
} else {
// TODO: Proper error handling
result.toString()
}
val watermark = TextWatermark.new(watermarkString)
return watermarker.textAddWatermark(text, watermark)
}

/**
Expand Down
183 changes: 170 additions & 13 deletions webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,36 @@
*/

import de.fraunhofer.isst.trend.watermarker.Watermarker
import de.fraunhofer.isst.trend.watermarker.fileWatermarker.DefaultTranscoding
import de.fraunhofer.isst.trend.watermarker.helper.toUnicodeRepresentation
import de.fraunhofer.isst.trend.watermarker.returnTypes.Result
import de.fraunhofer.isst.trend.watermarker.watermarks.TextWatermark
import de.fraunhofer.isst.trend.watermarker.watermarks.Watermark
import de.fraunhofer.isst.trend.watermarker.watermarks.toTextWatermarks
import io.kvision.collapse.collapse
import io.kvision.collapse.forCollapse
import io.kvision.core.Placement
import io.kvision.core.TooltipOptions
import io.kvision.core.Trigger
import io.kvision.core.enableTooltip
import io.kvision.form.FormMethod
import io.kvision.form.formPanel
import io.kvision.form.text.TextArea
import io.kvision.html.Button
import io.kvision.html.ButtonStyle
import io.kvision.html.br
import io.kvision.html.button
import io.kvision.html.div
import io.kvision.html.li
import io.kvision.html.p
import io.kvision.html.span
import io.kvision.modal.Alert
import io.kvision.html.strong
import io.kvision.html.ul
import io.kvision.modal.Confirm
import io.kvision.modal.Modal
import io.kvision.panel.HPanel
import io.kvision.panel.SimplePanel
import io.kvision.panel.simplePanel
import io.kvision.utils.em
import kotlinx.serialization.Serializable

Expand Down Expand Up @@ -66,11 +82,120 @@ class WatermarkTextExtractTab : SimplePanel() {
onClick {
if (extractTextFormPanel.validate()) {
println("Starting watermark extraction process ...")
val watermarkedText =
val watermarkedResult =
extractWatermark(
extractTextFormPanel.getData().text,
).toTextWatermarks()

val modal = Modal("Result")

// Success
if (watermarkedResult.status.isSuccess) {
if (watermarkedResult.value.isNullOrEmpty()) {
modal.add(
div(
"Could not find any valid watermark in the" +
"text.",
className = "alert alert-secondary",
),
)
} else {
modal.add(
div(
"Successfully extracted the watermark(s)!",
className = "alert alert-success",
),
)

val countedWatermarkList =
getWatermarkStringList(watermarkedResult)
.groupingBy { it }
.eachCount()

// Most frequent watermark
modal.add(
span(
"<strong>Most frequent " +
"watermark: </strong>" +
countedWatermarkList.maxByOrNull {
it.value
}?.key + "<br /><br />",
rich = true,
),
)

// Details section
val watermarkDetailsPanel =
simplePanel {
button(
"More details",
style = ButtonStyle.SECONDARY,
).forCollapse("watermark-details")

collapse("watermark-details") {
// Print all watermarks
strong("Detailed watermark list:")
ul {
for ((key, value) in countedWatermarkList) {
li("$key ($value times)")
}
}
br()

// Show watermarking type
strong("Watermarking type(s): ")
p(
watermarkedResult.value!!.map { watermark ->
watermark.finish().getSource()
}.toSet().toString(),
)

// Show input text with hidden chars
strong(
"Raw data with hidden alphabet chars:",
)
br()
span(
showWatermarkChars(
extractTextFormPanel.getData().text,
),
rich = true,
className = "break-all",
)
}
}
modal.add(watermarkDetailsPanel)
}
// Warning
} else if (watermarkedResult.status.isWarning) {
modal.add(
div(
"Some problems occur during the extraction: " +
watermarkedResult.status.getMessage(),
className = "alert alert-warning",
),
)
modal.add(strong("Extracted Data: "))
modal.add(p(getWatermarkStringList(watermarkedResult).toString()))
// Error
} else if (watermarkedResult.status.isError) {
modal.add(
div(
"An error occurs during the extraction: " +
watermarkedResult.status.getMessage(),
className = "alert alert-danger",
),
)
Alert.show("Successful", watermarkedText)
}

modal.addButton(
Button("Close") {
onClick {
modal.hide()
}
},
)
modal.show()
}
}
}
Expand All @@ -91,17 +216,49 @@ class WatermarkTextExtractTab : SimplePanel() {
}

/** Extracts a watermark from a [text] and returns it */
private fun extractWatermark(text: String): String {
private fun extractWatermark(text: String): Result<List<Watermark>> {
val watermarker = Watermarker()
val result = watermarker.textGetWatermarks(text)

return if (result.isSuccess) {
result.value!!.map { watermark ->
watermark.watermarkContent.toByteArray().decodeToString()
}.toString()
} else {
// TODO: Proper error handling
result.toString()
return watermarker.textGetWatermarks(text, squash = false)
}

/**
* Replaces all whitespaces of the transcoding alphabet of the watermarking library in
* [watermarkedText] with its Unicode representation. [html] defines if the result is a
* styled HTML string (true) or a plain text without formatting (false).
*/
private fun showWatermarkChars(
watermarkedText: String,
html: Boolean = true,
): String {
val alphabet = DefaultTranscoding.alphabet + DefaultTranscoding.SEPARATOR_CHAR
var resultText = watermarkedText
var className: String

for (char in alphabet) {
if (html) {
className =
if (char == DefaultTranscoding.SEPARATOR_CHAR) {
"separator-highlight"
} else {
"whitespace-highlight"
}

resultText =
resultText.replace(
char.toString(),
"<span class=\"$className\">" +
"${char.toUnicodeRepresentation()}</span>",
)
} else {
resultText = resultText.replace(char.toString(), char.toUnicodeRepresentation())
}
}
return resultText
}

/** Creates a list of Strings based on a [watermarkedResult] */
private fun getWatermarkStringList(watermarkedResult: Result<List<TextWatermark>>) =
watermarkedResult.value!!.map { watermark ->
watermark.text
}
}
15 changes: 15 additions & 0 deletions webinterface/src/jsMain/resources/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,18 @@
padding: 1em;
margin-top: 0.5em;
}

.break-all {
word-break: break-all;
}

.whitespace-highlight {
background-color: lightblue;
padding: 1px;
}

.separator-highlight {
background-color: black;
color: white;
padding: 1px;
}

0 comments on commit b097fff

Please sign in to comment.