Added formatCreditCard
This commit is contained in:
parent
9e9d2d6885
commit
625c211b62
10 changed files with 168 additions and 34 deletions
1
.github/workflows/publish.yml
vendored
1
.github/workflows/publish.yml
vendored
|
@ -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
3
.idea/misc.xml
generated
|
@ -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">
|
||||||
|
|
10
README.md
10
README.md
|
@ -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
|
||||||
|
|
|
@ -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/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
lib/src/main/java/rife/render/FormatCreditCard.java
Normal file
44
lib/src/main/java/rife/render/FormatCreditCard.java
Normal 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>
|
||||||
|
* <!--v render:rife.render.FormatCreditCard:valueId/-->
|
||||||
|
* {{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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 &</foo>\n</test>");
|
assertThat(t.getContent()).isEqualTo("<test>\n <foo>a test &</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>");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
50
lib/src/test/java/rife/render/TestFormat.java
Normal file
50
lib/src/test/java/rife/render/TestFormat.java
Normal 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>");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1
lib/src/test/resources/templates/formatCreditCard.txt
Normal file
1
lib/src/test/resources/templates/formatCreditCard.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{v render:rife.render.FormatCreditCard:foo/}}
|
Loading…
Add table
Add a link
Reference in a new issue