Added formatCreditCard

This commit is contained in:
Erik C. Thauvin 2023-03-17 05:56:38 -07:00
parent 9e9d2d6885
commit 625c211b62
10 changed files with 168 additions and 34 deletions

View file

@ -1,6 +1,7 @@
name: Publish to the Maven Central
on:
workflow_dispatch:
release:
types: [released]

3
.idea/misc.xml generated
View file

@ -44,6 +44,9 @@
<pattern value="rife.render.TestDateTime" method="testTimeIso" />
<pattern value="rife.render.TestDateTime" method="testYear" />
<pattern value="rife.render.ValueBean" />
<pattern value="rife.render.RenderUtils" method="formatCreditCard" />
<pattern value="rife.render.RenderUtils" />
<pattern value="rife.render.RenderUtils" method="RenderUtils" />
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="PDMPlugin">

View file

@ -22,7 +22,7 @@ This project provides a collection of template renderers.
## Encoding Renderers
| Renderer | Description |
|:---------------------------------|:--------------------------------------------------------|
|:---------------------------------|:-------------------------------------------------------|
| `rife.render.EncodeBase64` | Encodes a template value to Base64 |
| `rife.render.EncodeHtml` | Encodes a template value to HTML |
| `rife.render.EncodeHtmlEntities` | Encodes a template value to HTML decimal entities |
@ -32,7 +32,13 @@ This project provides a collection of template renderers.
| `rife.render.EncodeUnicode` | Encodes a template value to Unicode escape codes |
| `rife.render.EncodeUrl` | URL-encodes a template value |
| `rife.render.EncodeXml` | Encodes a template value to XML |
| `rife.render.ShorteUrl` | Shortens a template value using [is.gd](https://is.gd/) |
## Format Renderers
| Renderer | Description |
|:---------------------------------|:-----------------------------------------------------------------|
| `rife.render.formatCreditcard` | Formats a template credit card number value to the last 4 digits |
| `rife.render.ShorteUrl` | Shortens a template value using [is./gd](https://is.gd/) |
## Text Renderers

View file

@ -73,7 +73,7 @@ tasks {
this as StandardJavadocDocletOptions
keyWords(true)
splitIndex(true)
links()
links("https://rife2.github.io/rife2/")
}
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rife.render;
import rife.template.Template;
import rife.template.ValueRenderer;
/**
* Formats a template credit card number value to the last 4 digits.
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.FormatCreditCard:valueId/--&gt;
* {{v render:rife.render.FormatCreditCard:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.0
*/
public class FormatCreditCard implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
return RenderUtils.formatCreditCard(RenderUtils.fetchValue(template, differentiator));
}
}

View file

@ -53,7 +53,7 @@ public final class RenderUtils {
/**
* Encodes a string to JavaScript/ECMAScript.
*
* @param src the source string.
* @param src the source string
* @return the enocded string
*/
public static String encodeJS(String src) {
@ -96,11 +96,53 @@ public final class RenderUtils {
return Convert.toString(value);
}
/**
* Returns the last 4 digits a credit card number. The number must satisfy the Luhn algorithm.
* Non-digits are stripped from the number.
*
* @param src the credit card number
* @return the last 4 digits of the credit card number or empty
*/
public static String formatCreditCard(String src) {
if (src == null || src.isBlank()) {
return src;
}
try {
var cc = src.replaceAll("[^0-9]", "");
var len = cc.length();
if (len >= 4) {
// Luhn algorithm
var sum = 0;
boolean isSecond = false;
int digit;
for (int i = len - 1; i >= 0; i--) {
digit = cc.charAt(i) - '0';
if (isSecond) {
digit = digit * 2;
}
sum += digit / 10;
sum += digit % 10;
isSecond = !isSecond;
}
if (sum % 10 == 0) {
return cc.substring(len - 4);
}
}
} catch (NumberFormatException ignore) {
// do nothing
}
return "";
}
/**
* Translates a String to/from ROT13.
*
* @param src the source String.
* @return the translated String.
* @param src the source String
* @return the translated String
*/
public static String rot13(String src) {
if (src == null || src.isBlank()) {
@ -144,7 +186,7 @@ public final class RenderUtils {
* @return the short URL
*/
public static String shortenUrl(String url) {
if (url == null || url.isBlank() || !url.matches("^[Hh][Tt][Tt][Pp][Ss]?:\\/\\/\\w.*")) {
if (url == null || url.isBlank() || !url.matches("^[Hh][Tt][Tt][Pp][Ss]?://\\w.*")) {
return url;
}
@ -203,8 +245,8 @@ public final class RenderUtils {
/**
* Converts a text string to HTML decimal entities.
*
* @param src the String to convert.
* @return the converted string.
* @param src the String to convert
* @return the converted String
*/
@SuppressWarnings("PMD.AvoidReassigningLoopVariables")
public static String toHtmlEntities(String src) {

View file

@ -19,7 +19,6 @@ package rife.render;
import rife.template.Template;
import rife.template.ValueRenderer;
import rife.tools.StringUtils;
/**
* <p>Shortens a template value using <a href="https://is.gd/">is.gid</a>. The value must a valid http or https URL.</p>
@ -34,7 +33,7 @@ import rife.tools.StringUtils;
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
= * @since 1.0
* @since 1.0
*/
public class ShortenUrl implements ValueRenderer {
/**

View file

@ -100,16 +100,4 @@ class TestEncode {
t.setAttribute(TestCase.FOO, "a test &");
assertThat(t.getContent()).isEqualTo("<test>\n <foo>a test &amp;</foo>\n</test>");
}
@Test
void testShortenUrl() {
var t = TemplateFactory.HTML.get("shortenUrl");
var url = "https://example.com/";
var shortUrl = "https://is.gd/AG3Hwv";
t.setValue(TestCase.FOO, url);
assertThat(t.getContent()).isEqualTo(String.format("<a href=\"%s\">%s</a>", shortUrl, url));
t.setValue(TestCase.FOO, TestCase.FOO);
assertThat(t.getContent()).isEqualTo("<a href=\"foo\">foo</a>");
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rife.render;
import org.junit.jupiter.api.Test;
import rife.template.TemplateFactory;
import static org.assertj.core.api.Assertions.assertThat;
class TestFormat {
@Test
void testFormatCreditCard() {
var t = TemplateFactory.TXT.get("formatCreditCard");
t.setAttribute(TestCase.FOO, "4342 2565 6244 0179");
assertThat(t.getContent()).as("US VISA").isEqualTo("0179");
t.setAttribute(TestCase.FOO, "5130-3899-9169-8324");
assertThat(t.getContent()).as("FR MASTERCARD").isEqualTo("8324");
t.setAttribute(TestCase.FOO, "374380141731053");
assertThat(t.getContent()).as("UK AMEX").isEqualTo("1053");
t.setAttribute(TestCase.FOO, "000000000000001");
assertThat(t.getContent()).isEmpty();
}
@Test
void testShortenUrl() {
var t = TemplateFactory.HTML.get("shortenUrl");
var url = "https://example.com/";
var shortUrl = "https://is.gd/AG3Hwv";
t.setValue(TestCase.FOO, url);
assertThat(t.getContent()).isEqualTo(String.format("<a href=\"%s\">%s</a>", shortUrl, url));
t.setValue(TestCase.FOO, TestCase.FOO);
assertThat(t.getContent()).isEqualTo("<a href=\"foo\">foo</a>");
}
}

View file

@ -0,0 +1 @@
{{v render:rife.render.FormatCreditCard:foo/}}