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 name: Publish to the Maven Central
on: on:
workflow_dispatch:
release: release:
types: [released] 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="testTimeIso" />
<pattern value="rife.render.TestDateTime" method="testYear" /> <pattern value="rife.render.TestDateTime" method="testYear" />
<pattern value="rife.render.ValueBean" /> <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>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="PDMPlugin"> <component name="PDMPlugin">

View file

@ -22,7 +22,7 @@ This project provides a collection of template renderers.
## Encoding Renderers ## Encoding Renderers
| Renderer | Description | | Renderer | Description |
|:---------------------------------|:--------------------------------------------------------| |:---------------------------------|:-------------------------------------------------------|
| `rife.render.EncodeBase64` | Encodes a template value to Base64 | | `rife.render.EncodeBase64` | Encodes a template value to Base64 |
| `rife.render.EncodeHtml` | Encodes a template value to HTML | | `rife.render.EncodeHtml` | Encodes a template value to HTML |
| `rife.render.EncodeHtmlEntities` | Encodes a template value to HTML decimal entities | | `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.EncodeUnicode` | Encodes a template value to Unicode escape codes |
| `rife.render.EncodeUrl` | URL-encodes a template value | | `rife.render.EncodeUrl` | URL-encodes a template value |
| `rife.render.EncodeXml` | Encodes a template value to XML | | `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 ## Text Renderers

View file

@ -73,7 +73,7 @@ tasks {
this as StandardJavadocDocletOptions this as StandardJavadocDocletOptions
keyWords(true) keyWords(true)
splitIndex(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. * Encodes a string to JavaScript/ECMAScript.
* *
* @param src the source string. * @param src the source string
* @return the enocded string * @return the enocded string
*/ */
public static String encodeJS(String src) { public static String encodeJS(String src) {
@ -96,11 +96,53 @@ public final class RenderUtils {
return Convert.toString(value); 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. * Translates a String to/from ROT13.
* *
* @param src the source String. * @param src the source String
* @return the translated String. * @return the translated String
*/ */
public static String rot13(String src) { public static String rot13(String src) {
if (src == null || src.isBlank()) { if (src == null || src.isBlank()) {
@ -144,7 +186,7 @@ public final class RenderUtils {
* @return the short URL * @return the short URL
*/ */
public static String shortenUrl(String 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; return url;
} }
@ -203,8 +245,8 @@ public final class RenderUtils {
/** /**
* Converts a text string to HTML decimal entities. * Converts a text string to HTML decimal entities.
* *
* @param src the String to convert. * @param src the String to convert
* @return the converted string. * @return the converted String
*/ */
@SuppressWarnings("PMD.AvoidReassigningLoopVariables") @SuppressWarnings("PMD.AvoidReassigningLoopVariables")
public static String toHtmlEntities(String src) { public static String toHtmlEntities(String src) {

View file

@ -19,7 +19,6 @@ package rife.render;
import rife.template.Template; import rife.template.Template;
import rife.template.ValueRenderer; 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> * <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> * </pre>
* *
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a> * @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
= * @since 1.0 * @since 1.0
*/ */
public class ShortenUrl implements ValueRenderer { public class ShortenUrl implements ValueRenderer {
/** /**

View file

@ -100,16 +100,4 @@ class TestEncode {
t.setAttribute(TestCase.FOO, "a test &"); t.setAttribute(TestCase.FOO, "a test &");
assertThat(t.getContent()).isEqualTo("<test>\n <foo>a test &amp;</foo>\n</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/}}