Skip to content

Commit

Permalink
Merge branch 'master' of github.com:moqui/moqui-framework
Browse files Browse the repository at this point in the history
  • Loading branch information
jonesde committed Apr 11, 2023
2 parents 3a3089a + 8a9feba commit c95e6a3
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 23 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Written in 2020 by Jacob Barnes - Tellan
Written in 2020 by Amir Anjomshoaa - amiranjom
Written in 2021 by Deepak Dixit - dixitdeepak
Written in 2021 by Taher Alkhateeb - pythys
Written in 2022 by Zhang Wei - hellozhangwei

===========================================================================

Expand Down Expand Up @@ -106,5 +107,6 @@ Written in 2020 by Jacob Barnes - Tellan
Written in 2020 by Amir Anjomshoaa - amiranjom
Written in 2021 by Deepak Dixit - dixitdeepak
Written in 2021 by Taher Alkhateeb - pythys
Written in 2022 by Zhang Wei - hellozhangwei

===========================================================================
1 change: 1 addition & 0 deletions framework/entity/SecurityEntities.xml
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ along with this software (see the LICENSE.md file). If not, see
<entity entity-name="NotificationMessage" package="moqui.security.user" use="nontransactional" cache="never">
<field name="notificationMessageId" type="id" is-pk="true"/>
<field name="topic" type="text-medium"/>
<field name="subTopic" type="text-medium"/>
<field name="userGroupId" type="id"/>
<field name="sentDate" type="date-time"/>
<field name="messageJson" type="text-very-long"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class ElasticFacadeImpl implements ElasticFacade {
requestFactory.init()

// try connecting and get server info
int retries = clusterHost == 'localhost' && !"true".equals(System.getProperty("moqui.elasticsearch.started")) ? 1 : 20
int retries = ((clusterHost == 'localhost' || clusterHost == '127.0.0.1') && !"true".equals(System.getProperty("moqui.elasticsearch.started"))) ? 1 : 20
for (int i = 1; i <= retries; i++) {
try {
serverInfo = getServerInfo()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,10 @@ class ExecutionContextFactoryImpl implements ExecutionContextFactory {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(workerQueueSize)

int coreSize = (toolsNode.attribute("worker-pool-core") ?: "16") as int
int maxSize = (toolsNode.attribute("worker-pool-max") ?: "24") as int
int availableProcessorsSize = Runtime.getRuntime().availableProcessors() * 2
int maxSize = (toolsNode.attribute("worker-pool-max") ?: "32") as int
int availableProcessorsSize = Runtime.getRuntime().availableProcessors() * 3
if (availableProcessorsSize > maxSize) {
logger.info("Setting worker pool size to ${availableProcessorsSize} based on available processors * 2")
logger.info("Setting worker pool size to ${availableProcessorsSize} based on available processors * 3")
maxSize = availableProcessorsSize
}
long aliveTime = (toolsNode.attribute("worker-pool-alive") ?: "60") as long
Expand All @@ -467,9 +467,9 @@ class ExecutionContextFactoryImpl implements ExecutionContextFactory {
boolean waitWorkerPoolEmpty(int retryLimit) {
ThreadPoolExecutor jobWorkerPool = serviceFacade.jobWorkerPool
int count = 0
logger.warn("Wait for workerPool and jobWorkerPool empty: worker queue size ${workerPool.getQueue().size()} active ${workerPool.getActiveCount()}; service job queue size ${jobWorkerPool.getQueue().size()} active ${jobWorkerPool.getActiveCount()}")
while (count < retryLimit && (workerPool.getQueue().size() > 0 || workerPool.getActiveCount() > 0 ||
jobWorkerPool.getQueue().size() > 0 || jobWorkerPool.getActiveCount() > 0)) {
if (count % 10 == 0) logger.warn("Wait for workerPool and jobWorkerPool empty: worker queue size ${workerPool.getQueue().size()} active ${workerPool.getActiveCount()} max threads ${workerPool.getMaximumPoolSize()}; service job queue size ${jobWorkerPool.getQueue().size()} active ${jobWorkerPool.getActiveCount()}")
Thread.sleep(100)
count++
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,15 @@ public String formatCurrency(Object amount, String uomId, Integer fractionDigits
}
}

Currency currency = uomId != null && uomId.length() > 0 ? Currency.getInstance(uomId) : null;
Currency currency = null;
if (uomId != null && uomId.length() > 0) {
try {
currency = Currency.getInstance(uomId);
} catch (Exception e) {
if (logger.isTraceEnabled()) logger.trace("Ignoring IllegalArgumentException for Currency parse: " + e.toString());
}
}

if (locale == null) locale = getLocale();
if (currency != null) {
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
private Set<String> userIdSet = new HashSet()
private String userGroupId = (String) null
private String topic = (String) null
private String subTopic = (String) null
private transient EntityValue notificationTopic = (EntityValue) null
private String messageJson = (String) null
private transient Map<String, Object> messageMap = (Map<String, Object>) null
Expand Down Expand Up @@ -144,6 +145,9 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
@Override NotificationMessage topic(String topic) { this.topic = topic; notificationTopic = null; return this }
@Override String getTopic() { topic }

@Override String getSubTopic() { subTopic }
@Override NotificationMessage subTopic(String st) { subTopic = st; return this }

@Override NotificationMessage message(String messageJson) { this.messageJson = messageJson; messageMap = null; return this }
@Override NotificationMessage message(Map message) {
this.messageMap = Collections.unmodifiableMap(message) as Map<String, Object>
Expand All @@ -169,16 +173,18 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
@Override NotificationMessage title(String title) { titleTemplate = title; return this }
@Override String getTitle() {
if (titleText == null) {
EntityValue localNotTopic = getNotificationTopic()
if (localNotTopic != null) {
if (type == danger && localNotTopic.errorTitleTemplate) {
titleText = ecfi.resource.expand((String) localNotTopic.errorTitleTemplate, "", getMessageMap(), true)
} else if (localNotTopic.titleTemplate) {
titleText = ecfi.resource.expand((String) localNotTopic.titleTemplate, "", getMessageMap(), true)
if (titleTemplate != null && !titleTemplate.isEmpty())
titleText = ecfi.resource.expand(titleTemplate, "", getMessageMap(), true)
if (titleText == null || titleText.isEmpty()) {
EntityValue localNotTopic = getNotificationTopic()
if (localNotTopic != null) {
if (type == danger && localNotTopic.errorTitleTemplate) {
titleText = ecfi.resource.expand((String) localNotTopic.errorTitleTemplate, "", getMessageMap(), true)
} else if (localNotTopic.titleTemplate) {
titleText = ecfi.resource.expand((String) localNotTopic.titleTemplate, "", getMessageMap(), true)
}
}
}
if ((titleText == null || titleText.isEmpty()) && titleTemplate != null && !titleTemplate.isEmpty())
titleText = ecfi.resource.expand(titleTemplate, "", getMessageMap(), true)
}
return titleText
}
Expand Down Expand Up @@ -305,7 +311,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
boolean beganTransaction = tfi.begin(null)
try {
Map createResult = ecfi.service.sync().name("create", "moqui.security.user.NotificationMessage")
.parameters([topic:this.topic, userGroupId:this.userGroupId, sentDate:this.sentDate,
.parameters([topic:this.topic, subTopic:this.subTopic, userGroupId:this.userGroupId, sentDate:this.sentDate,
messageJson:this.getMessageJson(), titleText:this.getTitle(), linkText:this.getLink(),
typeString:this.getType(), showAlert:(this.showAlert ? 'Y' : 'N')])
.disableAuthz().call()
Expand Down Expand Up @@ -450,7 +456,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {

@Override Map<String, Object> getWrappedMessageMap() {
EntityValue localNotTopic = getNotificationTopic()
return [topic:topic, sentDate:sentDate, notificationMessageId:notificationMessageId, topicDescription:localNotTopic?.description,
return [topic:topic, subTopic:subTopic, sentDate:sentDate, notificationMessageId:notificationMessageId, topicDescription:localNotTopic?.description,
message:getMessageMap(), title:getTitle(), link:getLink(), type:getType(), persistOnSend:isPersistOnSend(),
showAlert:isShowAlert(), alertNoAutoHide:isAlertNoAutoHide()]
}
Expand All @@ -467,6 +473,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
void populateFromValue(EntityValue nmbu) {
this.notificationMessageId = nmbu.notificationMessageId
this.topic = nmbu.topic
this.subTopic = nmbu.subTopic
this.sentDate = nmbu.getTimestamp("sentDate")
this.userGroupId = nmbu.userGroupId
this.messageJson = nmbu.messageJson
Expand All @@ -486,6 +493,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
out.writeObject(userIdSet)
out.writeObject(userGroupId)
out.writeUTF(topic)
out.writeObject(subTopic)
out.writeUTF(getMessageJson())
out.writeObject(notificationMessageId)
out.writeObject(sentDate)
Expand All @@ -500,6 +508,7 @@ class NotificationMessageImpl implements NotificationMessage, Externalizable {
userIdSet = (Set<String>) objectInput.readObject()
userGroupId = (String) objectInput.readObject()
topic = objectInput.readUTF()
subTopic = objectInput.readObject()
messageJson = objectInput.readUTF()
notificationMessageId = (String) objectInput.readObject()
sentDate = (Timestamp) objectInput.readObject()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ class UserFacadeImpl implements UserFacade {
// user found in session so no login needed, but make sure hasLoggedOut != "Y"
EntityValue userAccount = (EntityValue) null
if (sesUsername != null && !sesUsername.isEmpty()) {
EntityCondition usernameCond = eci.entityFacade.getConditionFactory()
.makeCondition("username", EntityCondition.ComparisonOperator.EQUALS, username).ignoreCase()
userAccount = eci.getEntity().find("moqui.security.UserAccount")
.condition("username", sesUsername).useCache(false).disableAuthz().one()
.condition(usernameCond).useCache(false).disableAuthz().one()
}

if (userAccount != null && "Y".equals(userAccount.getNoCheckSimple("hasLoggedOut"))) {
Expand Down Expand Up @@ -1051,8 +1053,10 @@ class UserFacadeImpl implements UserFacade {

EntityValueBase ua = (EntityValueBase) null
if (username != null && username.length() > 0) {
EntityCondition usernameCond = ufi.eci.entityFacade.getConditionFactory()
.makeCondition("username", EntityCondition.ComparisonOperator.EQUALS, username).ignoreCase()
ua = (EntityValueBase) ufi.eci.getEntity().find("moqui.security.UserAccount")
.condition("username", username).useCache(false).disableAuthz().one()
.condition(usernameCond).useCache(false).disableAuthz().one()
}
if (ua != null) {
userAccount = ua
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class ElasticDatasourceFactory implements EntityDatasourceFactory {
if (checkedEntityIndexSet.contains(indexName)) return

ElasticFacade.ElasticClient elasticClient = efi.ecfi.elasticFacade.getClient(clusterName)
if (elasticClient == null) throw new IllegalStateException("No ElasticClient found for cluster name " + clusterName)
if (!elasticClient.indexExists(indexName)) {
Map mapping = makeElasticEntityMapping(ed)
// logger.warn("Creating ES Index ${indexName} with mapping: ${JsonOutput.prettyPrint(JsonOutput.toJson(mapping))}")
Expand All @@ -170,7 +171,11 @@ class ElasticDatasourceFactory implements EntityDatasourceFactory {
checkedEntityIndexSet.add(indexName)
}

ElasticFacade.ElasticClient getElasticClient() { efi.ecfi.elasticFacade.getClient(clusterName) }
ElasticFacade.ElasticClient getElasticClient() {
ElasticFacade.ElasticClient client = efi.ecfi.elasticFacade.getClient(clusterName)
if (client == null) throw new IllegalStateException("No ElasticClient found for cluster name " + clusterName)
return client
}
String getIndexName(EntityDefinition ed) {
return indexPrefix + ed.getTableNameLowerCase()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,19 @@ class ScreenRenderImpl implements ScreenRender {
return activePath
}

// TODO: This may not be the actual place we decided on, but due to lost work this is my best guess
// Get the first screen path of the parent screens with a transition specified of the currently rendered screen
String getScreenPathHasTransition(String transitionName) {
int screenPathDefListSize = screenUrlInfo.screenPathDefList.size()
for (int i = 0; i < screenPathDefListSize; i++) {
ScreenDefinition screenDef = (ScreenDefinition) screenUrlInfo.screenPathDefList.get(i)
if (screenDef.hasTransition(transitionName)) {
return '/' + screenUrlInfo.fullPathNameList.subList(0,i).join('/') + (i == 0 ? '' : '/')
}
}
return null
}

String renderSubscreen() {
// first see if there is another screen def in the list
if (!getActiveScreenHasNext()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ class ScreenUrlInfo {
ArrayDeque<ArtifactExecutionInfoImpl> artifactExecutionInfoStack = new ArrayDeque<ArtifactExecutionInfoImpl>()

int screenPathDefListSize = screenPathDefList.size()
boolean allowedByScreenDefinitionView = false
boolean allowedByScreenDefinitionAll = false
boolean allowedByScreenDefinition = false
for (int i = 0; i < screenPathDefListSize; i++) {
AuthzAction curActionEnum = (i == (screenPathDefListSize - 1)) ? actionEnum : ArtifactExecutionInfo.AUTHZA_VIEW
ScreenDefinition screenDef = (ScreenDefinition) screenPathDefList.get(i)
Expand All @@ -285,9 +288,15 @@ class ScreenUrlInfo {
MNode screenNode = screenDef.getScreenNode()

String requireAuthentication = screenNode.attribute('require-authentication')
allowedByScreenDefinitionView = "anonymous-view".equals(requireAuthentication)
allowedByScreenDefinitionAll = "anonymous-all".equals(requireAuthentication)
if (actionEnum == ArtifactExecutionInfo.AUTHZA_VIEW) {
allowedByScreenDefinition = allowedByScreenDefinition || allowedByScreenDefinitionView || allowedByScreenDefinitionAll
} else if (actionEnum == ArtifactExecutionInfo.AUTHZA_ALL)
allowedByScreenDefinition = allowedByScreenDefinition || allowedByScreenDefinitionAll
if (!aefi.isPermitted(aeii, lastAeii,
isLast ? (!requireAuthentication || "true".equals(requireAuthentication)) : false, false, false, artifactExecutionInfoStack)) {
// logger.warn("TOREMOVE user ${username} is NOT allowed to view screen at path ${this.fullPathNameList} because of screen at ${screenDef.location}")
//logger.warn("TOREMOVE user ${userId} is NOT allowed to view screen at path ${this.fullPathNameList} because of screen at ${screenDef.location}")
if (permittedCacheKey != null) aefi.screenPermittedCache.put(permittedCacheKey, false)
return false
}
Expand All @@ -296,7 +305,7 @@ class ScreenUrlInfo {
}

// see if the transition is permitted
if (transitionItem != null) {
if (!allowedByScreenDefinition && transitionItem != null) {
ScreenDefinition lastScreenDef = (ScreenDefinition) screenPathDefList.get(screenPathDefList.size() - 1)
ArtifactExecutionInfoImpl aeii = new ArtifactExecutionInfoImpl("${lastScreenDef.location}/${transitionItem.name}",
ArtifactExecutionInfo.AT_XML_SCREEN_TRANS, ArtifactExecutionInfo.AUTHZA_VIEW, null)
Expand All @@ -317,10 +326,16 @@ class ScreenUrlInfo {
if (authzAction == null) authzAction = ServiceDefinition.verbAuthzActionEnumMap.get(ServiceDefinition.getVerbFromName(serviceName))
if (authzAction == null) authzAction = ArtifactExecutionInfo.AUTHZA_ALL

boolean allowedByServiceDefinition = false
if (authzAction == ArtifactExecutionInfo.AUTHZA_VIEW) {
allowedByServiceDefinition = allowedByScreenDefinitionView || (sd != null && ("anonymous-view".equals(sd.authenticate) || "anonymous-all".equals(sd.authenticate)))
} else if (authzAction in [ArtifactExecutionInfo.AUTHZA_ALL, ArtifactExecutionInfo.AUTHZA_CREATE, ArtifactExecutionInfo.AUTHZA_UPDATE, ArtifactExecutionInfo.AUTHZA_DELETE]) {
allowedByServiceDefinition = allowedByScreenDefinitionAll || (sd != null && "anonymous-all".equals(sd.authenticate))
}
ArtifactExecutionInfoImpl aeii = new ArtifactExecutionInfoImpl(serviceName, ArtifactExecutionInfo.AT_SERVICE, authzAction, null)

ArtifactExecutionInfoImpl lastAeii = (ArtifactExecutionInfoImpl) artifactExecutionInfoStack.peekFirst()
if (!aefi.isPermitted(aeii, lastAeii, true, false, false, null)) {
if (!aefi.isPermitted(aeii, lastAeii, !allowedByServiceDefinition, false, false, null)) {
// logger.warn("TOREMOVE user ${username} is NOT allowed to run transition at path ${this.fullPathNameList} because of screen at ${screenDef.location}")
if (permittedCacheKey != null) aefi.screenPermittedCache.put(permittedCacheKey, false)
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ enum NotificationType { info, success, warning, danger }
NotificationMessage topic(String topic);
String getTopic();

NotificationMessage subTopic(String subTopic);
String getSubTopic();

/** Set the message as a JSON String. The top-level should be a Map (JSON Object).
* @param messageJson The message as a JSON string containing a Map (JSON Object)
* @return Self-reference for convenience
Expand Down
2 changes: 1 addition & 1 deletion framework/src/main/resources/MoquiDefaultConf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<default-property name="kibana_host" value="127.0.0.1"/>
<default-property name="kibana_port" value="5601"/>

<tools empty-db-load="${entity_empty_db_load}" worker-queue="65535" worker-pool-core="8" worker-pool-max="24" worker-pool-alive="60">
<tools empty-db-load="${entity_empty_db_load}" worker-queue="65535" worker-pool-core="16" worker-pool-max="32" worker-pool-alive="60">
<tool-factory class="org.moqui.impl.tools.MCacheToolFactory" init-priority="03" disabled="false"/>
<!-- Apache Commons JCS, an alternative for distributed caches (cannot be used as local cache as requires Serializable keys/values just like Hazelcast) -->
<!-- <tool-factory class="org.moqui.impl.tools.JCSCacheToolFactory" init-priority="09" disabled="true"/> -->
Expand Down
2 changes: 2 additions & 0 deletions framework/template/XmlActions.groovy.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import static org.moqui.util.ObjectUtilities.*
import static org.moqui.util.CollectionUtilities.*
import static org.moqui.util.StringUtilities.*
import java.sql.Timestamp
import java.sql.Time
import java.time.*
// these are in the context by default: ExecutionContext ec, Map<String, Object> context, Map<String, Object> result
<#visit xmlActionsRoot/>

Expand Down

0 comments on commit c95e6a3

Please sign in to comment.