Skip to content

Commit

Permalink
Release 3.0.0 updates
Browse files Browse the repository at this point in the history
- CSS cleanup and optimization
- PW strength lang translations
- Proper role lang translations
- UI redesign
- Fixes
- Doc
  • Loading branch information
autumoswitzerland committed Jul 3, 2024
1 parent a4ad34b commit 0b2178c
Show file tree
Hide file tree
Showing 69 changed files with 482 additions and 59,658 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ The Web framework is shipped with the following features ready to use:
- Easy to understand HTML template engine
- HTTPS protocol and TLS for mail if configured
- Bean support with transient and unique fields
- User session are stored when servers are stopped
- User sessions are stored when servers are stopped
- Entities can be served through the JSON REST API
- Logging implementations other than log4j2 supported
- Add, edit, view, list and delete functionality for entities
Expand Down Expand Up @@ -554,6 +554,19 @@ edit- and add-handler or add your new role management by adjusting your `edit.ht
- If you want to see, how role authorization is done in handlers, see `hasAccess`-method, e.g., in the `ch.autumo.beetroot.handler.tasks.TasksAddHandler` class.
- If you want to see, how role authorization is done in the web templates, see, e.g., `web/html/en/home.html` and `web/html/blocks/head.html` template.

Example with an entity (<code>Users</code>) and actions (<code>add</code>, <code>edit</code>):

```Html
{$if-entity=Users:}
{$if-action=add,edit:}
<!-- E.g., limit the use of BootStrap here -->
<link rel="stylesheet" href="/css/bootstrap.min.css">
{$endif-action;}
{$endif-entity;}
```

**Note**: You can cascade web template authorizations in the order `roles` &#x2192; `entity` (only one allowed) &#x2192; `actions` only.

<p align="right">(<a href="#top">back to top</a>)</p>


Expand Down
41 changes: 41 additions & 0 deletions src/main/java/ch/autumo/beetroot/BeetRootWebServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -598,6 +599,12 @@ public Response serve(BeetRootHTTPSession session, HttpServletRequest request) {

return Response.newFixedLengthResponse(Status.OK, "text/css", css);
}

// Parse password strength javas-cript file for translations
if (requestedFile.equals("password-strength.js")) {
final String js = PwsParser.parseAll(fc.getTextData(), userSession);
return Response.newFixedLengthResponse(Status.OK, "application/javascript", js);
}

// Everything else: Text data !
if (MIME.isMimeTypeText(mimeType))
Expand Down Expand Up @@ -1230,5 +1237,39 @@ public void addMappings() {
addRoute(route.getRoute(), route.getPriority(), route.getHandler(), route.getInitParameter());
}
}

/**
* Parser for 'password-strength.js'.
*/
private static class PwsParser {

public static Pattern PATTERN_INFO = Pattern.compile("\\{\\$pw.info\\}");
public static Pattern PATTERN_HIDE = Pattern.compile("\\{\\$pw.hide\\}");
public static Pattern PATTERN_SHOW = Pattern.compile("\\{\\$pw.show\\}");
public static Pattern PATTERN_CHARS = Pattern.compile("\\{\\$pw.chars\\}");
public static Pattern PATTERN_CAPITAL = Pattern.compile("\\{\\$pw.capital\\}");
public static Pattern PATTERN_NUMBER = Pattern.compile("\\{\\$pw.number\\}");
public static Pattern PATTERN_SPECIAL = Pattern.compile("\\{\\$pw.special\\}");
public static Pattern PATTERN_LETTER = Pattern.compile("\\{\\$pw.letter\\}");

/**
* Replace all variables.
*
* @param script java-script file contents
* @param userSession user session
* @return replaced java-script contents
*/
public static String parseAll(String script, Session userSession) {
script = PATTERN_INFO.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.info", userSession));
script = PATTERN_HIDE.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.hide", userSession));
script = PATTERN_SHOW.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.show", userSession));
script = PATTERN_CHARS.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.chars", userSession));
script = PATTERN_CAPITAL.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.capital", userSession));
script = PATTERN_NUMBER.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.number", userSession));
script = PATTERN_SPECIAL.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.special", userSession));
script = PATTERN_LETTER.matcher(script).replaceAll(LanguageManager.getInstance().translate("pw.letter", userSession));
return script;
}
}

}
2 changes: 0 additions & 2 deletions src/main/java/ch/autumo/beetroot/cache/FileCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,6 @@ public Response createResponse(String mimeType) throws IOException {
* @throws IOException IO exception
*/
public Response createResponse() throws IOException {

return this.createResponse(this.contentType.getContentType());
}

Expand Down Expand Up @@ -415,7 +414,6 @@ public String getEncoding() {
* @return file path
*/
public String getFullPath() {

return this.filePath.toAbsolutePath().toString();
}

Expand Down
19 changes: 12 additions & 7 deletions src/main/java/ch/autumo/beetroot/handler/BaseHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ private String processJSON(BeetRootHTTPSession session) {
/**
* Process handlers to get the whole HTML page.
*
* @param session beetroot session
* @param session beetRoot session
* @param origId original DB id
* @return whole parsed HTML page
* @throws Exception exception
Expand Down Expand Up @@ -1411,29 +1411,34 @@ public String[] getSimpleManagementUserRoles() {
*
* @param snippet buffered code snippet
* @param list the list with the associated entities
* @param session beetRoot session
*/
protected void parseAssociatedEntities(StringBuffer snippet, List<Model> list) {
this.parseAssociations("{$assignedRoles}", snippet, list);
protected void parseAssociatedEntities(StringBuffer snippet, List<Model> list, BeetRootHTTPSession session) {
this.parseAssociations("{$assignedRoles}", snippet, list, session);
}

/**
* Parse un-associated list.
*
* @param snippet buffered code snippet
* @param list the list with the un-associated entities
* @param session beetRoot session
*/
protected void parseUnassociatedEntities(StringBuffer snippet, List<Model> list) {
this.parseAssociations("{$unassignedRoles}", snippet, list);
protected void parseUnassociatedEntities(StringBuffer snippet, List<Model> list, BeetRootHTTPSession session) {
this.parseAssociations("{$unassignedRoles}", snippet, list, session);
}

private void parseAssociations(String tag, StringBuffer snippet, List<Model> list) {
private void parseAssociations(String tag, StringBuffer snippet, List<Model> list, BeetRootHTTPSession session) {
final int idx = snippet.indexOf(tag);
if (idx == -1)
return;
String txt = "";
for (Iterator<Model> iterator = list.iterator(); iterator.hasNext();) {
final Model model = iterator.next();
txt += "<li class=\"list-group-item\" draggable=\"true\" ondragstart=\"drag(event)\" data-id=\""+model.getId()+"\">"+model.getDisplayValue()+"</li>\n";
String roleVal = model.getDisplayValue();
if (model.modelClass().equals(Role.class))
roleVal = LanguageManager.getInstance().translateOrDefVal("role."+roleVal, roleVal, session.getUserSession());
txt += "<li class=\"list-group-item\" draggable=\"true\" ondragstart=\"drag(event)\" data-id=\""+model.getId()+"\">"+roleVal+"</li>\n";
}
snippet.replace(idx, idx + tag.length(), txt);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public String extractCustomSingleInputDiv(BeetRootHTTPSession session, String va

final StringBuffer snippet = super.readSnippetResource("web/html/:lang/users/snippets/roles.html", session.getUserSession());

super.parseAssociatedEntities(snippet, associatedRoles);
super.parseUnassociatedEntities(snippet, unassociatedRoles);
super.parseAssociatedEntities(snippet, associatedRoles, session);
super.parseUnassociatedEntities(snippet, unassociatedRoles,session);

return snippet.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ public String extractCustomSingleInputDiv(BeetRootHTTPSession session, String va

final StringBuffer snippet = super.readSnippetResource("web/html/:lang/users/snippets/roles.html", session.getUserSession());

super.parseAssociatedEntities(snippet, associatedRoles);
super.parseUnassociatedEntities(snippet, unassociatedRoles);
super.parseAssociatedEntities(snippet, associatedRoles, session);
super.parseUnassociatedEntities(snippet, unassociatedRoles, session);

return snippet.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public String extractSingleTableData(BeetRootHTTPSession session, ResultSet set,
for (Iterator<Model> iterator = usersRoles.iterator(); iterator.hasNext();) {
final UserRole userRole = (UserRole) iterator.next();
final Role role = (Role) userRole.getAssociatedReference(Role.class);
strRoles += role.getName() + ", ";
String name = role.getName();
name = LanguageManager.getInstance().translateOrDefVal("role."+name, name, session.getUserSession());
strRoles += name + ", ";
}
if (usersRoles.size() > 0)
strRoles = strRoles.substring(0, strRoles.length() - 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ public String extractSingleTableData(BeetRootHTTPSession session, ResultSet set,
for (Iterator<Model> iterator = usersRoles.iterator(); iterator.hasNext();) {
final UserRole userRole = (UserRole) iterator.next();
final Role role = (Role) userRole.getAssociatedReference(Role.class);
strRoles += role.getName() + ", ";
String name = role.getName();
name = LanguageManager.getInstance().translateOrDefVal("role."+name, name, session.getUserSession());
strRoles += name + ", ";
}
if (usersRoles.size() > 0)
strRoles = strRoles.substring(0, strRoles.length() - 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,16 @@ public UsersIndexHandler(String entity, String msg) {

@Override
public String extractSingleTableData(BeetRootHTTPSession session, ResultSet set, String columnName, int idx, Entity entity) throws Exception {

switch (columnName) {

case "username" : return "<td>" + DB.getValue(set, columnName) + "</td>";
case "email" : return "<td>" + DB.getValue(set, columnName) + "</td>";
case "role" : return "<td>" + DB.getValue(set, columnName) + "</td>";

case "role" : String r = DB.getValue(set, columnName);
return "<td>" + LanguageManager.getInstance().translateOrDefVal("role."+r, r, session.getUserSession()) + "</td>";
case "two_fa" : return set.getBoolean(columnName) ?
"<td>" + LanguageManager.getInstance().translate("base.switch.yes", session.getUserSession()) + "</td>" :
"<td>" + LanguageManager.getInstance().translate("base.switch.no", session.getUserSession()) + "</td>";

case "created" : return "<td>" + Time.getGUIDate(set.getTimestamp(columnName)) + "</td>";
case "modified" : return "<td>" + Time.getGUIDate(set.getTimestamp(columnName)) + "</td>";

default : return "<td>" + set.getObject(columnName) + "</td>";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,20 @@ public UsersViewHandler(String entity) {

@Override
public String extractSingleTableData(BeetRootHTTPSession session, ResultSet set, String columnName, int idx, Entity entity) throws Exception {

final User user = (User) entity;

switch (columnName) {

case "username" : userName = set.getString(columnName);
return "<td>"+userName+"</td>";

case "email" : return "<td>" + DB.getValue(set, columnName) + "</td>";
case "role" : return "<td>" + DB.getValue(set, columnName) + "</td>";

case "role" : String r = DB.getValue(set, columnName);
return "<td>" + LanguageManager.getInstance().translateOrDefVal("role."+r, r, session.getUserSession()) + "</td>";
case "two_fa" : return set.getBoolean(columnName) ?
"<td>" + LanguageManager.getInstance().translate("base.switch.yes", session.getUserSession()) + "</td>" :
"<td>" + LanguageManager.getInstance().translate("base.switch.no", session.getUserSession()) + "</td>";

case "created" : return "<td>"+Time.getGUIDate(set.getTimestamp(columnName))+"</td>";
case "modified" : return "<td>"+Time.getGUIDate(set.getTimestamp(columnName))+"</td>";

// transient field 'code'
case "code" : return "<td>"+this.get2FAQRImage(session, user)+"</td>";

default : return "<td>"+set.getObject(columnName)+"</td>";
}
}
Expand Down
37 changes: 18 additions & 19 deletions web/css/base.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions web/css/base.min.css

Large diffs are not rendered by default.

Loading

0 comments on commit 0b2178c

Please sign in to comment.