Solving Merge Conflicts Before Google CodeIn'17

This commit is contained in:
Sanyam96
2017-11-27 21:00:18 +05:30
202 changed files with 13623 additions and 301 deletions
+242
View File
@@ -2629,6 +2629,30 @@
<td></td>
</tr>
<tr>
<td><a href="#twofactor">Two-Factor Authentication</a></td>
<td>twofactor</td>
<td><a href="#twofactor_request">Request OTP</a></td>
<td><a href="#twofactor_deliverymethods">List OTP delivery methods</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>twofactor/validate</td>
<td><a href="#twofactor_validate">Validate OTP</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>twofactor/invalidate</td>
<td><a href="#twofactor_invalidate">Invalidate Access Token</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="#users">User</a></td>
<td>users</td>
<td><a href="#users_create">Create a User</a></td>
@@ -2942,6 +2966,16 @@
external service Configuration</a></td>
<td></td>
</tr>
<tr>
<td><a href="#twofactor_config_get">Two-Factor Configuration</a></td>
<td>twofactor/configure</td>
<td></td>
<td><a href="#twofactor_config_get">Retrieve
Two-Factor Configuration</a></td>
<td><a href="#twofactor_config_update">Update
Two-Factor Configuration</a></td>
<td></td>
</tr>
</table>
</div>
</div>
@@ -3930,6 +3964,11 @@
Default authentication is using HTTP Basic Auth. Oauth2 can be enabled by using <i>-Psecurity=oauth</i> option on gradle build command , refer
the platform setup <a href="https://github.com/openMF/mifosx/wiki/Launching-platform-server-locally-from-the-command-line#choosing-authentication-mechanism"> wiki</a> for additional details.
</p>
<p>
Optionally, two-factor authentication can be enabled by using
<i>-Ptwofactor=enabled</i> on gradle build.
Details of the authentication workflow with two-factor authentication enabled can be found <a href="#twofactor">here</a>.
</p>
<p>
The platform has been configured to reject plain HTTP requests and
to expect all API requests to be made over <a
@@ -4057,6 +4096,142 @@ function executeAjaxRequest(url, verbType, jsonData, authKey, successFunction, e
</code>
</div>
</div>
<a id="twofactor" name="twofactor" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Two-Factor Authentication</h3>
<p>
Two-Factor authentication is supported by requesting & verifying
one-time passwords(OTP). OTPs are sent via SMS & email.
</p>
<p>
By default, two-factor authentication is disabled by default.
More information on how to enable TFA can be found <a href="#authentication_overview">here</a>.
</p>
<p>
Two-factor authentication workflow:
<ol class="normalli">
<li class="normalli">User authticates via BasicAuth / oAauth</li>
<li>Client requests a list of supported OTP delivery methods for the authenticated user(<a href="#twofactor_deliverymethods">Get Delivery Methods</a>)</li>
<li>User selects an OTP delivery method and client sends a request for OTP(<a href="#twofactor_request">Request OTP</a>)</li>
<li>User receives an OTP and the client sends it for verification(<a href="#twofactor_validate">Validate OTP</a>)</li>
<li>If the OTP is valid, an access token is returned</li>
<li>The access token is sent in following requestes to the server as a header <i>Fineract-Platform-TFA-Token</i></li>
<li>On session end, the access token should be invalidated<a href="#twofactor_invalidate">Invalidate Access Token</a>)</li>
</ol>
</p>
<p>
Two-Factor authentication and delivery methods can be configured via
the <a href="#twofactor_configure"<i>/twofactor/configure</i> endpoint.</a>
</p>
</div>
<div class="method-example">
</div>
</div>
<a id="twofactor_deliverymethods" name="twofactor_deliverymethods" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Get Delivery Methods</h4>
<p>Returns a list of possible OTP delivery methods for the current user</p>
<p>Requires first-factor authenticated user.</p>
</div>
<div class="method-example">
<code class="method-declaration">GET https://DomainName/api/v1/twofactor</code>
<code class="method-response">
[
{
"name": "sms",
"target": "08888888888"
},
{
"name": "email",
"target": "user@example.com"
}
]</code>
</div>
</div>
<a id="twofactor_request" name="twofactor_request" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Request OTP</h4>
<p>Requests an OTP.</p>
<p>Requires first-factor authenticated user.</p>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>deliveryMethod</dt>
<dd>
String<span> mandatory, the delivery method name</span>
</dd>
<dt>extendedToken</dt>
<dd>
boolean<span> optional, whether to request an extended token, default false</span>
</dd>
</dl>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/twofactor?deliveryMethod=sms&extendedToken=false</code>
<code class="method-response">
{
"requestTime": 1500000000000,
"tokenLiveTimeInSec": 300,
"extendedAccessToken": false,
"deliveryMethod": {
"name": "sms",
"target": "08888888888"
}
}</code>
</div>
</div>
<a id="twofactor_validate" name="twofactor_validate" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Validate OTP</h4>
<p>Validates an OTP. If the OTP is valid, an access token is created.</p>
<p>The returned access token is later sent as a header <i>Fineract-Platform-TFA-Token</i>.</p>
<p>Requires first-factor authenticated user.</p>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>token</dt>
<dd>
String<span> mandatory, the OTP to validate</span>
</dd>
</dl>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/twofactor/validate?token=YYYYY</code>
<code class="method-response">
{
"token": "cb0bb6e33fc540709d50a16eb2e555f9",
"validFrom": 1501530702801,
"validTo": 1501617102801
}</code>
</div>
</div>
<a id="twofactor_invalidate" name="twofactor_invalidate" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Invalidate Access Token</h4>
<p>Invalidates an access token.</p>
<p>Two factor access tokens should be invalidated on logout.</p>
<p>Requires fully authenticated user.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/twofactor/invalidate</code>
<code class="method-request">
{
"token": "cb0bb6e33fc540709d50a16eb2e555f9"
}</code>
<code class="method-response">
{
"resourceIdentifier": "cb0bb6e33fc540709d50a16eb2e555f9"
}</code>
</div>
</div>
<a id="batch_api" name="batch_api" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
@@ -19391,6 +19566,73 @@ Content-Type: application/json
</div>
</div>
<a id="twofactor_config" name="twofactor_config"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Two-Factor Configuration</h3>
<p>The following section describes the way to configure two-factor authentication</p>
<p>Two-Factor Authentication has to be enabled by either building with Gradle arguments
<i>-Ptwofactor=enabled</i> or enabling the <i>twofactor</i> profile via env. variable
</p>
<p>In order for SMS to be enabled an SMS bridge has to be setup with the message-gateway service.</p>
</div>
<div class="method-example">
</div>
</div>
<a id="twofactor_config_get" name="twofactor_config_get" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve Two-Factor Configuration</h4>
<p>Returns available two-factor configuration.</p>
</div>
<div class="method-example">
<code class="method-declaration"> GET https://DomainName/api/v1/twofactor/configure
</code>
<code class="method-response">
{
"otp-delivery-email-body": "Hello {{username}}.\n\nYour OTP login token is {{token}}.",
"otp-delivery-sms-enable": true,
"otp-delivery-sms-provider": 6,
"otp-delivery-email-subject": "Fineract Two-Factor Authentication Token",
"otp-token-length": 5,
"access-token-live-time-extended": 604800,
"otp-delivery-email-enable": true,
"otp-token-live-time": 300,
"otp-delivery-sms-text": "Your authentication token for Fineract is {{token}}.",
"access-token-live-time": 86400
}
</code>
</div>
</div>
<a id="twofactor_config_update" name="twofactor_config_update" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update Two-Factor Configuration</h4>
<p>Update two-factor configuration.</p>
</div>
<div class="method-example">
<code class="method-declaration"> PUT https://DomainName/api/v1/twofactor/configure
</code>
<code class="method-request">
{
"otp-delivery-sms-provider": 7
"otp-delivery-sms-enable": false
}
</code>
<code class="method-response">
{
"changes": {
"otp-delivery-sms-enable": false,
"otp-delivery-sms-provider": 7
}
}
</code>
</div>
</div>
<!-- Fund starts here -->
<a id="funds" name="funds" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
+4
View File
@@ -745,4 +745,8 @@ ul.field li {
tt {
font-size: 9.5pt;
}
ol.normalli li {
list-style-type: decimal;
}
+26 -10
View File
@@ -195,17 +195,33 @@ if (project.hasProperty('env') && project.getProperty('env') == 'dev') {
/* Enable Oauth2 authentication based on environment, default to HTTP basic auth */
if (project.hasProperty('security') && project.getProperty('security') == 'oauth') {
copy {
from './properties/oauth/'
into 'src/main/resources/'
include '*.properties'
}
if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') {
copy {
from './properties/oauth/twofactor/'
into 'src/main/resources/'
include '*.properties'
}
} else {
copy {
from './properties/oauth/'
into 'src/main/resources/'
include '*.properties'
}
}
} else {
copy {
from './properties/basicauth/'
into 'src/main/resources/'
include '*.properties'
}
if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') {
copy {
from './properties/basicauth/twofactor/'
into 'src/main/resources/'
include '*.properties'
}
} else {
copy {
from './properties/basicauth/'
into 'src/main/resources/'
include '*.properties'
}
}
}
task dist(type:Zip){
@@ -0,0 +1,21 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.
#
spring.profiles.default=basicauth
spring.profiles.active=basicauth,twofactor
@@ -0,0 +1,21 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.
#
spring.profiles.default=basicauth
spring.profiles.active=oauth,twofactor
@@ -59,7 +59,7 @@ public class HolidayHelper {
map.put("fromDate", "01 April 2013");
map.put("toDate", "01 April 2013");
map.put("repaymentsRescheduledTo", "08 April 2013");
map.put("reschedulingType", 2);
String HolidayCreateJson = new Gson().toJson(map);
System.out.println(HolidayCreateJson);
return HolidayCreateJson;
@@ -2929,7 +2929,7 @@ public class CommandWrapperBuilder {
this.href = "/smscampaigns/"+resourceId;
return this;
}
public CommandWrapperBuilder holdAmount(final Long accountId) {
this.actionName = "HOLDAMOUNT";
this.entityName = "SAVINGSACCOUNT";
@@ -3039,6 +3039,97 @@ public class CommandWrapperBuilder {
this.entityId = adHocId;
this.href = "/adhocquery/" + adHocId;
this.json = "{}";
return this ;
}
public CommandWrapperBuilder createEmail() {
this.actionName = "CREATE";
this.entityName = "EMAIL";
this.entityId = null;
this.href = "/emailcampaigns/template";
return this;
}
public CommandWrapperBuilder updateEmail(final Long resourceId) {
this.actionName = "UPDATE";
this.entityName = "EMAIL";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId;
return this;
}
public CommandWrapperBuilder deleteEmail(final Long resourceId) {
this.actionName = "DELETE";
this.entityName = "EMAIL";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId;
return this;
}
public CommandWrapperBuilder createEmailCampaign() {
this.actionName = "CREATE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = null;
this.href = "/emailcampaigns/campaign";
return this;
}
public CommandWrapperBuilder updateEmailCampaign(final Long resourceId) {
this.actionName = "UPDATE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId;
return this;
}
public CommandWrapperBuilder deleteEmailCampaign(final Long resourceId) {
this.actionName = "DELETE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId;
return this;
}
public CommandWrapperBuilder activateEmailCampaign(final Long resourceId) {
this.actionName = "ACTIVATE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId + "?command=activate";
return this;
}
public CommandWrapperBuilder closeEmailCampaign(final Long resourceId) {
this.actionName = "CLOSE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId + "?command=close";
return this;
}
public CommandWrapperBuilder reactivateEmailCampaign(final Long resourceId) {
this.actionName = "REACTIVATE";
this.entityName = "EMAIL_CAMPAIGN";
this.entityId = resourceId;
this.href = "/emailcampaigns/"+resourceId + "?command=reactivate";
return this;
}
public CommandWrapperBuilder updateEmailConfiguration() {
this.actionName = "UPDATE";
this.entityName = "EMAIL_CONFIGURATION";
this.href = "/emailcampaigns/configuration/";
return this;
}
public CommandWrapperBuilder invalidateTwoFactorAccessToken() {
this.actionName = "INVALIDATE";
this.entityName = "TWOFACTOR_ACCESSTOKEN";
this.href = "/twofactor/invalidate";
return this;
}
public CommandWrapperBuilder updateTwoFactorConfiguration() {
this.actionName = "UPDATE";
this.entityName = "TWOFACTOR_CONFIGURATION";
this.href = "/twofactor/configure";
return this;
}
}
@@ -21,7 +21,7 @@ package org.apache.fineract.infrastructure.campaigns.constants;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public enum CampaignType {
INVALID(0, "campaignType.invalid"), SMS(1, "campaignType.sms");
INVALID(0, "campaignType.invalid"), SMS(1, "campaignType.sms"), NOTIFICATION(2, "campaignType.notification");
private Integer value;
private String code;
@@ -48,6 +48,9 @@ public enum CampaignType {
case 1:
type = SMS;
break;
case 2:
type = NOTIFICATION;
break;
}
return type;
}
@@ -66,6 +69,9 @@ public enum CampaignType {
case SMS:
optionData = new EnumOptionData(CampaignType.SMS.getValue().longValue(), CampaignType.SMS.getCode(), "SMS");
break;
case NOTIFICATION:
optionData = new EnumOptionData(CampaignType.NOTIFICATION.getValue().longValue(), CampaignType.NOTIFICATION.getCode(), "NOTIFICATION");
break;
}
return optionData;
}
@@ -73,4 +79,8 @@ public enum CampaignType {
public boolean isSms() {
return this.value.equals(CampaignType.SMS.getValue());
}
public boolean isNotificaion() {
return this.value.equals(CampaignType.NOTIFICATION.getValue());
}
}
@@ -0,0 +1,54 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class EmailApiConstants {
public static final String RESOURCE_NAME = "email";
// general
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
// request parameters
public static final String idParamName = "id";
public static final String groupIdParamName = "groupId";
public static final String clientIdParamName = "clientId";
public static final String staffIdParamName = "staffId";
public static final String subjectParamName = "emailSubject";
public static final String messageParamName = "emailMessage";
// response parameters
public static final String statusParamName = "status";
public static final Set<String> CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, groupIdParamName, clientIdParamName, staffIdParamName, messageParamName));
public static final Set<String> UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(messageParamName));
public static final String SMTP_SERVER = "SMTP_SERVER";
public static final String SMTP_PORT = "SMTP_PORT";
public static final String SMTP_USERNAME = "SMTP_USERNAME";
public static final String SMTP_PASSWORD = "SMTP_PASSWORD";
}
@@ -0,0 +1,82 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class ScheduledEmailConstants {
// define the API resource entity name
public static final String SCHEDULED_EMAIL_ENTITY_NAME = "SCHEDULEDEMAIL";
// general API resource request parameter constants
public static final String LOCALE_PARAM_NAME = "locale";
public static final String DATE_FORMAT_PARAM_NAME = "dateFormat";
// parameter constants for create/update entity API request
public static final String NAME_PARAM_NAME = "name";
public static final String DESCRIPTION_PARAM_NAME = "description";
public static final String START_DATE_TIME_PARAM_NAME = "startDateTime";
public static final String RECURRENCE_PARAM_NAME = "recurrence";
public static final String EMAIL_RECIPIENTS_PARAM_NAME = "emailRecipients";
public static final String EMAIL_SUBJECT_PARAM_NAME = "emailSubject";
public static final String EMAIL_MESSAGE_PARAM_NAME = "emailMessage";
public static final String EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME = "emailAttachmentFileFormatId";
public static final String STRETCHY_REPORT_ID_PARAM_NAME = "stretchyReportId";
public static final String STRETCHY_REPORT_PARAM_MAP_PARAM_NAME = "stretchyReportParamMap";
public static final String IS_ACTIVE_PARAM_NAME = "isActive";
// other parameter constants
public static final String ID_PARAM_NAME = "id";
public static final String EMAIL_ATTACHMENT_FILE_FORMAT_PARAM_NAME = "emailAttachmentFileFormat";
public static final String PREVIOUS_RUN_DATE_TIME_PARAM_NAME = "previousRunDateTime";
public static final String NEXT_RUN_DATE_TIME_PARAM_NAME = "nextRunDateTime";
public static final String PREVIOUS_RUN_STATUS = "previousRunStatus";
public static final String PREVIOUS_RUN_ERROR_LOG = "previousRunErrorLog";
public static final String PREVIOUS_RUN_ERROR_MESSAGE = "previousRunErrorMessage";
public static final String NUMBER_OF_RUNS = "numberOfRuns";
public static final String STRETCHY_REPORT_PARAM_NAME = "stretchyReport";
// list of permitted parameters for the create report mailing job request
public static final Set<String> CREATE_REQUEST_PARAMETERS = new HashSet<>(Arrays.asList(LOCALE_PARAM_NAME, DATE_FORMAT_PARAM_NAME,
NAME_PARAM_NAME, DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME,
EMAIL_MESSAGE_PARAM_NAME, EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, STRETCHY_REPORT_ID_PARAM_NAME,
STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME, START_DATE_TIME_PARAM_NAME));
// list of permitted parameters for the update report mailing job request
public static final Set<String> UPDATE_REQUEST_PARAMETERS = new HashSet<>(Arrays.asList(LOCALE_PARAM_NAME, DATE_FORMAT_PARAM_NAME,
NAME_PARAM_NAME, DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME,
EMAIL_MESSAGE_PARAM_NAME, EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, STRETCHY_REPORT_ID_PARAM_NAME,
STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME, START_DATE_TIME_PARAM_NAME));
// list of parameters that represent the properties of a report mailing job
public static final Set<String> REPORT_MAILING_JOB_DATA_PARAMETERS = new HashSet<>(Arrays.asList(ID_PARAM_NAME, NAME_PARAM_NAME,
DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME, EMAIL_MESSAGE_PARAM_NAME,
EMAIL_ATTACHMENT_FILE_FORMAT_PARAM_NAME, STRETCHY_REPORT_PARAM_NAME, STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME,
START_DATE_TIME_PARAM_NAME, PREVIOUS_RUN_DATE_TIME_PARAM_NAME, NEXT_RUN_DATE_TIME_PARAM_NAME, PREVIOUS_RUN_STATUS,
PREVIOUS_RUN_ERROR_LOG, PREVIOUS_RUN_ERROR_MESSAGE, NUMBER_OF_RUNS));
// report mailing job configuration names
public static final String GMAIL_SMTP_SERVER = "GMAIL_SMTP_SERVER";
public static final String GMAIL_SMTP_PORT = "GMAIL_SMTP_PORT";
public static final String GMAIL_SMTP_USERNAME = "GMAIL_SMTP_USERNAME";
public static final String GMAIL_SMTP_PASSWORD = "GMAIL_SMTP_PASSWORD";
}
@@ -0,0 +1,185 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.api;
import org.apache.fineract.accounting.journalentry.api.DateParam;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailData;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import java.util.Collection;
import java.util.Date;
@Path("/email")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Component
@Scope("singleton")
public class EmailApiResource {
private final String resourceNameForPermissions = "Email";
private final PlatformSecurityContext context;
private final EmailReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<EmailData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
public EmailApiResource(final PlatformSecurityContext context, final EmailReadPlatformService readPlatformService,
final DefaultToApiJsonSerializer<EmailData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.readPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
@GET
public String retrieveAllEmails(@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<EmailData> emailMessages = this.readPlatformService.retrieveAll();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessages);
}
@GET
@Path("pendingEmail")
public String retrievePendingEmail(@QueryParam("sqlSearch") final String sqlSearch, @QueryParam("offset") final Integer offset,
@QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
@QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final SearchParameters searchParameters = SearchParameters.forEmailCampaign(sqlSearch, offset, limit, orderBy, sortOrder);
Collection<EmailData> emailMessages = this.readPlatformService.retrieveAllPending(searchParameters);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessages);
}
@GET
@Path("sentEmail")
public String retrieveSentEmail(@QueryParam("sqlSearch") final String sqlSearch, @QueryParam("offset") final Integer offset,
@QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
@QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final SearchParameters searchParameters = SearchParameters.forEmailCampaign(sqlSearch, offset, limit, orderBy, sortOrder);
Collection<EmailData> emailMessages = this.readPlatformService.retrieveAllSent(searchParameters);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessages);
}
@GET
@Path("messageByStatus")
public String retrieveAllEmailByStatus(@QueryParam("sqlSearch") final String sqlSearch, @QueryParam("offset") final Integer offset,
@QueryParam("limit") final Integer limit, @QueryParam("status") final Integer status,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder,
@QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam,
@QueryParam("locale") final String locale, @QueryParam("dateFormat") final String dateFormat, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
Date fromDate = null;
if (fromDateParam != null) {
fromDate = fromDateParam.getDate("fromDate", dateFormat, locale);
}
Date toDate = null;
if (toDateParam != null) {
toDate = toDateParam.getDate("toDate", dateFormat, locale);
}
Page<EmailData> emailMessages = this.readPlatformService.retrieveEmailByStatus(limit, status, fromDate, toDate);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessages);
}
@GET
@Path("failedEmail")
public String retrieveFailedEmail(@QueryParam("sqlSearch") final String sqlSearch, @QueryParam("offset") final Integer offset,
@QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
@QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final SearchParameters searchParameters = SearchParameters.forEmailCampaign(sqlSearch, offset, limit, orderBy, sortOrder);
Collection<EmailData> emailMessages = this.readPlatformService.retrieveAllFailed(searchParameters);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessages);
}
@POST
public String create(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createEmail().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Path("{resourceId}")
public String retrieveOne(@PathParam("resourceId") final Long resourceId, @Context final UriInfo uriInfo) {
final EmailData emailMessage = this.readPlatformService.retrieveOne(resourceId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, emailMessage);
}
@PUT
@Path("{resourceId}")
public String update(@PathParam("resourceId") final Long resourceId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateEmail(resourceId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@DELETE
@Path("{resourceId}")
public String delete(@PathParam("resourceId") final Long resourceId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteEmail(resourceId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -0,0 +1,230 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.api;
import com.google.gson.JsonElement;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.campaigns.email.data.PreviewCampaignMessage;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailBusinessRulesData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignData;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignReadPlatformService;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import java.util.Collection;
import java.util.HashSet;
/**
* Created with IntelliJ IDEA.
* User: andrew
* Date: 19-5-14
* Time: 15:17
* To change this template use File | Settings | File Templates.
*/
@Path("/email/campaign")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Component
@Scope("singleton")
public class EmailCampaignApiResource {
//change name to email campaign
private final String resourceNameForPermissions = "EMAIL_CAMPAIGN";
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<EmailBusinessRulesData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final EmailCampaignReadPlatformService emailCampaignReadPlatformService;
private final FromJsonHelper fromJsonHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final DefaultToApiJsonSerializer<EmailCampaignData> emailCampaignDataDefaultToApiJsonSerializer;
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
private final DefaultToApiJsonSerializer<PreviewCampaignMessage> previewCampaignMessageDefaultToApiJsonSerializer;
@Autowired
public EmailCampaignApiResource(final PlatformSecurityContext context,final DefaultToApiJsonSerializer<EmailBusinessRulesData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final EmailCampaignReadPlatformService emailCampaignReadPlatformService, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final DefaultToApiJsonSerializer<EmailCampaignData> emailCampaignDataDefaultToApiJsonSerializer,
final FromJsonHelper fromJsonHelper, final EmailCampaignWritePlatformService emailCampaignWritePlatformService,
final DefaultToApiJsonSerializer<PreviewCampaignMessage> previewCampaignMessageDefaultToApiJsonSerializer) {
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.emailCampaignReadPlatformService = emailCampaignReadPlatformService;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.emailCampaignDataDefaultToApiJsonSerializer = emailCampaignDataDefaultToApiJsonSerializer;
this.fromJsonHelper = fromJsonHelper;
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
this.previewCampaignMessageDefaultToApiJsonSerializer = previewCampaignMessageDefaultToApiJsonSerializer;
}
@GET
@Path("{resourceId}")
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveOneCampaign(@PathParam("resourceId") final Long resourceId,@Context final UriInfo uriInfo){
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
EmailCampaignData emailCampaignData = this.emailCampaignReadPlatformService.retrieveOne(resourceId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.emailCampaignDataDefaultToApiJsonSerializer.serialize(settings,emailCampaignData);
}
@GET
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllCampaign(@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<EmailCampaignData> emailCampaignDataCollection = this.emailCampaignReadPlatformService.retrieveAllCampaign();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.emailCampaignDataDefaultToApiJsonSerializer.serialize(settings,emailCampaignDataCollection);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createCampaign(final String apiRequestBodyAsJson,@Context final UriInfo uriInfo){
final CommandWrapper commandRequest = new CommandWrapperBuilder().createEmailCampaign().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{resourceId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateCampaign(@PathParam("resourceId") final Long campaignId,final String apiRequestBodyAsJson,@Context final UriInfo uriInfo){
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateEmailCampaign(campaignId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("{resourceId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String activate(@PathParam("resourceId") final Long campaignId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson){
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
CommandWrapper commandRequest = null;
if (is(commandParam, "activate")) {
commandRequest = builder.activateEmailCampaign(campaignId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}else if (is(commandParam, "close")){
commandRequest = builder.closeEmailCampaign(campaignId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}else if (is(commandParam, "reactivate")){
commandRequest = builder.reactivateEmailCampaign(campaignId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("preview")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String preview(final String apiRequestBodyAsJson,@Context final UriInfo uriInfo){
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
PreviewCampaignMessage campaignMessage = null;
final JsonElement parsedQuery = this.fromJsonHelper.parse(apiRequestBodyAsJson);
final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, this.fromJsonHelper);
campaignMessage = this.emailCampaignWritePlatformService.previewMessage(query);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.previewCampaignMessageDefaultToApiJsonSerializer.serialize(settings,campaignMessage, new HashSet<String>());
}
@GET()
@Path("template")
public String template(@Context final UriInfo uriInfo){
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<EmailBusinessRulesData> emailBusinessRulesDataCollection = this.emailCampaignReadPlatformService.retrieveAll();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings,emailBusinessRulesDataCollection);
}
@GET
@Path("template/{resourceId}")
public String retrieveOneTemplate(@PathParam("resourceId") final Long resourceId,@Context final UriInfo uriInfo){
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final EmailBusinessRulesData emailBusinessRulesData = this.emailCampaignReadPlatformService.retrieveOneTemplate(resourceId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings,emailBusinessRulesData);
}
@DELETE
@Path("{resourceId}")
public String delete(@PathParam("resourceId") final Long resourceId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteEmailCampaign(resourceId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
}
@@ -0,0 +1,94 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.api;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailConfigurationData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailData;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailConfigurationReadPlatformService;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailReadPlatformService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import java.util.Collection;
@Path("/email/configuration")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Component
@Scope("singleton")
public class EmailConfigurationApiResource {
private final String resourceNameForPermissions = "EMAIL_CONFIGURATION";
private final PlatformSecurityContext context;
private final EmailReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<EmailConfigurationData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final EmailConfigurationReadPlatformService emailConfigurationReadPlatformService;
@Autowired
public EmailConfigurationApiResource(final PlatformSecurityContext context, final EmailReadPlatformService readPlatformService,
final DefaultToApiJsonSerializer<EmailConfigurationData> toApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final EmailConfigurationReadPlatformService emailConfigurationReadPlatformService) {
this.context = context;
this.readPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.emailConfigurationReadPlatformService = emailConfigurationReadPlatformService;
}
@GET
public String retrieveAll(@Context final UriInfo uriInfo){
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<EmailConfigurationData> configuration = this.emailConfigurationReadPlatformService.retrieveAll();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, configuration);
}
@PUT
public String updateConfiguration(@Context final UriInfo uriInfo, final String apiRequestBodyAsJson){
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateEmailConfiguration().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -0,0 +1,96 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import java.util.Map;
public class EmailBusinessRulesData {
@SuppressWarnings("unused")
private final Long reportId;
@SuppressWarnings("unused")
private final String reportName;
@SuppressWarnings("unused")
private final String reportType;
@SuppressWarnings("unused")
private final String reportSubType;
@SuppressWarnings("unused")
private final String reportDescription;
@SuppressWarnings("unused")
private final Map<String,Object> reportParamName;
public EmailBusinessRulesData(final Long reportId, final String reportName,final String reportType, final Map<String,Object> reportParamName,
final String reportSubType, final String reportDescription) {
this.reportId = reportId;
this.reportName = reportName;
this.reportType = reportType;
this.reportParamName = reportParamName;
this.reportDescription = reportDescription;
this.reportSubType = reportSubType;
}
public static EmailBusinessRulesData instance(final Long reportId, final String reportName, final String reportType, final Map<String,Object> reportParamName,
final String reportSubType, final String reportDescription){
return new EmailBusinessRulesData(reportId,reportName,reportType,reportParamName,reportSubType,reportDescription);
}
public Map<String, Object> getReportParamName() {
return reportParamName;
}
public String getReportType() {
return reportType;
}
public String getReportName() {
return reportName;
}
public Long getReportId() {
return reportId;
}
public String getReportDescription() {
return reportDescription;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EmailBusinessRulesData that = (EmailBusinessRulesData) o;
return reportId != null ? reportId.equals(that.reportId) : that.reportId == null;
}
@Override
public int hashCode() {
return reportId != null ? reportId.hashCode() : 0;
}
}
@@ -0,0 +1,144 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public class EmailCampaignData {
@SuppressWarnings("unused")
private Long id;
@SuppressWarnings("unused")
private final String campaignName;
@SuppressWarnings("unused")
private final Integer campaignType;
@SuppressWarnings("unused")
private final Long businessRuleId;
@SuppressWarnings("unused")
private final String paramValue;
@SuppressWarnings("unused")
private final EnumOptionData campaignStatus;
@SuppressWarnings("unused")
private final String emailSubject;
@SuppressWarnings("unused")
private final String emailMessage;
@SuppressWarnings("unused")
private final String emailAttachmentFileFormat;
@SuppressWarnings("unused")
private final Long stretchyReportId;
@SuppressWarnings("unused")
private final String stretchyReportParamMap;
@SuppressWarnings("unused")
private final DateTime nextTriggerDate;
@SuppressWarnings("unused")
private final LocalDate lastTriggerDate;
@SuppressWarnings("unused")
private final EmailCampaignTimeLine emailCampaignTimeLine;
@SuppressWarnings("unused")
private final DateTime recurrenceStartDate;
private final String recurrence;
private EmailCampaignData(final Long id, final String campaignName, final Integer campaignType, final Long businessRuleId,
final String paramValue, final EnumOptionData campaignStatus, final String emailSubject,
final String message, final String emailAttachmentFileFormat, final Long stretchyReportId,
final String stretchyReportParamMap, final DateTime nextTriggerDate, final LocalDate lastTriggerDate,
final EmailCampaignTimeLine emailCampaignTimeLine, final DateTime recurrenceStartDate, final String recurrence) {
this.id = id;
this.campaignName = campaignName;
this.campaignType = campaignType;
this.businessRuleId = businessRuleId;
this.paramValue = paramValue;
this.campaignStatus =campaignStatus;
this.emailSubject = emailSubject;
this.emailMessage = message;
this.emailAttachmentFileFormat = emailAttachmentFileFormat;
this.stretchyReportId = stretchyReportId;
this.stretchyReportParamMap = stretchyReportParamMap;
if(nextTriggerDate !=null){
this.nextTriggerDate = nextTriggerDate;
}else{
this.nextTriggerDate = null;
}
if(lastTriggerDate !=null){
this.lastTriggerDate = lastTriggerDate;
}else{
this.lastTriggerDate = null;
}
this.emailCampaignTimeLine =emailCampaignTimeLine;
this.recurrenceStartDate = recurrenceStartDate;
this.recurrence = recurrence;
}
public static EmailCampaignData instance(final Long id, final String campaignName, final Integer campaignType, final Long runReportId,
final String paramValue, final EnumOptionData campaignStatus, final String emailSubject,
final String message, final String emailAttachmentFileFormat, final Long stretchyReportId,
final String stretchyReportParamMap, final DateTime nextTriggerDate, final LocalDate lastTriggerDate,
final EmailCampaignTimeLine emailCampaignTimeLine,
final DateTime recurrenceStartDate, final String recurrence){
return new EmailCampaignData(id,campaignName,campaignType,runReportId,paramValue,
campaignStatus,emailSubject,message,emailAttachmentFileFormat,stretchyReportId,stretchyReportParamMap,nextTriggerDate,lastTriggerDate,emailCampaignTimeLine,recurrenceStartDate,recurrence);
}
public Long getId() {
return id;
}
public String getCampaignName() {
return this.campaignName;
}
public Integer getCampaignType() {
return this.campaignType;
}
public Long getRunReportId() {
return this.businessRuleId;
}
public String getParamValue() {
return this.paramValue;
}
public EnumOptionData getCampaignStatus() {
return this.campaignStatus;
}
public String getEmailSubject() { return this.emailSubject; }
public String getMessage() {
return this.emailMessage;
}
public DateTime getNextTriggerDate() {
return this.nextTriggerDate;
}
public LocalDate getLastTriggerDate() {
return this.lastTriggerDate;
}
public String getRecurrence() {return this.recurrence;}
public DateTime getRecurrenceStartDate() {return this.recurrenceStartDate;}
}
@@ -0,0 +1,40 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import org.joda.time.LocalDate;
public class EmailCampaignTimeLine {
private final LocalDate submittedOnDate;
private final String submittedByUsername;
private final LocalDate activatedOnDate;
private final String activatedByUsername;
private final LocalDate closedOnDate;
private final String closedByUsername;
public EmailCampaignTimeLine(final LocalDate submittedOnDate, final String submittedByUsername,
final LocalDate activatedOnDate, final String activatedByUsername, final LocalDate closedOnDate, final String closedByUsername) {
this.submittedOnDate = submittedOnDate;
this.submittedByUsername = submittedByUsername;
this.activatedOnDate = activatedOnDate;
this.activatedByUsername = activatedByUsername;
this.closedOnDate = closedOnDate;
this.closedByUsername = closedByUsername;
}
}
@@ -0,0 +1,259 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Type;
import java.util.*;
@Component
public class EmailCampaignValidator {
public static final String RESOURCE_NAME = "email";
public static final String campaignName = "campaignName";
public static final String campaignType = "campaignType";
public static final String businessRuleId = "businessRuleId";
public static final String stretchyReportId = "stretchyReportId";
public static final String stretchyReportParamMap = "stretchyReportParamMap";
public static final String paramValue = "paramValue";
public static final String emailSubject = "emailSubject";
public static final String emailMessage = "emailMessage";
public static final String emailAttachmentFileFormatId = "emailAttachmentFileFormatId";
public static final String activationDateParamName = "activationDate";
public static final String recurrenceStartDate = "recurrenceStartDate";
public static final String submittedOnDateParamName = "submittedOnDate";
public static final String closureDateParamName = "closureDate";
public static final String recurrenceParamName = "recurrence";
public static final String statusParamName = "status";
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
private final FromJsonHelper fromApiJsonHelper;
public static final Set<String> supportedParams = new HashSet<String>(Arrays.asList(campaignName, campaignType,localeParamName,dateFormatParamName,
businessRuleId,paramValue,emailMessage,recurrenceStartDate,activationDateParamName,submittedOnDateParamName,closureDateParamName,recurrenceParamName,
emailSubject,stretchyReportId,stretchyReportParamMap,emailAttachmentFileFormatId));
public static final Set<String> supportedParamsForUpdate = new HashSet<>(Arrays.asList(campaignName, campaignType,localeParamName,dateFormatParamName,
businessRuleId,paramValue,emailMessage,recurrenceStartDate,activationDateParamName,recurrenceParamName));
public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, activationDateParamName));
public static final Set<String> CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, closureDateParamName));
public static final Set<String> PREVIEW_REQUEST_DATA_PARAMETERS= new HashSet<String>(Arrays.asList(paramValue,emailMessage));
@Autowired
public EmailCampaignValidator(FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateCreate(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.supportedParams);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final String campaignName = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.campaignName,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.campaignName).value(campaignName).notBlank().notExceedingLengthOf(100);
final Long campaignType = this.fromApiJsonHelper.extractLongNamed(EmailCampaignValidator.campaignType,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.campaignType).value(campaignType).notNull().integerGreaterThanZero();
if(campaignType.intValue() == EmailCampaignType.SCHEDULE.getValue()){
final String recurrenceParamName = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.recurrenceParamName, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.recurrenceParamName).value(recurrenceParamName).notBlank();
final String recurrenceStartDate = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.recurrenceStartDate, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.recurrenceStartDate).value(recurrenceStartDate).notBlank();
}
final Long businessRuleId = this.fromApiJsonHelper.extractLongNamed(EmailCampaignValidator.businessRuleId,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.businessRuleId).value(businessRuleId).notNull().integerGreaterThanZero();
final String emailSubject = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.emailSubject, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.emailSubject).value(emailSubject).notBlank().notExceedingLengthOf(50);
final String emailMessage = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.emailMessage, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.emailMessage).value(emailMessage).notBlank().notExceedingLengthOf(480);
final String paramValue = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.paramValue, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.paramValue).value(paramValue).notBlank();
if (this.fromApiJsonHelper.parameterExists(EmailCampaignValidator.submittedOnDateParamName, element)) {
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(EmailCampaignValidator.submittedOnDateParamName,
element);
baseDataValidator.reset().parameter(EmailCampaignValidator.submittedOnDateParamName).value(submittedOnDate).notNull();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.supportedParamsForUpdate);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final String campaignName = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.campaignName,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.campaignName).value(campaignName).notBlank().notExceedingLengthOf(100);
final Long campaignType = this.fromApiJsonHelper.extractLongNamed(EmailCampaignValidator.campaignType,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.campaignType).value(campaignType).notNull().integerGreaterThanZero();
if(campaignType.intValue() == EmailCampaignType.SCHEDULE.getValue()){
final String recurrenceParamName = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.recurrenceParamName, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.recurrenceParamName).value(recurrenceParamName).notBlank();
final String recurrenceStartDate = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.recurrenceStartDate, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.recurrenceStartDate).value(recurrenceStartDate).notBlank();
}
final Long runReportId = this.fromApiJsonHelper.extractLongNamed(EmailCampaignValidator.businessRuleId,element);
baseDataValidator.reset().parameter(EmailCampaignValidator.businessRuleId).value(runReportId).notNull().integerGreaterThanZero();
final String message = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.emailMessage, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.emailMessage).value(message).notBlank().notExceedingLengthOf(480);
final String paramValue = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.paramValue, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.paramValue).value(paramValue).notBlank();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validatePreviewMessage(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.PREVIEW_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final String paramValue = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.paramValue, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.paramValue).value(paramValue).notBlank();
final String message = this.fromApiJsonHelper.extractStringNamed(EmailCampaignValidator.emailMessage, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.emailMessage).value(message).notBlank().notExceedingLengthOf(480);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateClosedDate(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.CLOSE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate closeDate = this.fromApiJsonHelper.extractLocalDateNamed(EmailCampaignValidator.closureDateParamName, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.closureDateParamName).value(closeDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateActivation(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.ACTIVATION_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate activationDate = this.fromApiJsonHelper.extractLocalDateNamed(EmailCampaignValidator.activationDateParamName, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.activationDateParamName).value(activationDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void ValidateClosure(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailCampaignValidator.CLOSE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailCampaignValidator.RESOURCE_NAME);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate closeDate = this.fromApiJsonHelper.extractLocalDateNamed(EmailCampaignValidator.closureDateParamName, element);
baseDataValidator.reset().parameter(EmailCampaignValidator.closureDateParamName).value(closeDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -0,0 +1,63 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
/**
* Immutable data object representing an Email configuration.
*/
public class EmailConfigurationData {
@SuppressWarnings("unused")
private final Long id;
private final String name;
private final String value;
/**
* @return an instance of the EmailConfigurationData class
**/
public static EmailConfigurationData instance(Long id, String name, String value) {
return new EmailConfigurationData(id, name, value);
}
/**
* EmailConfigurationData constructor
**/
private EmailConfigurationData(Long id, String name, String value) {
this.id = id;
this.name = name;
this.value = value;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
}
@@ -0,0 +1,111 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailConfigurationSMTPUsernameNotValid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Type;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class EmailConfigurationValidator {
private final FromJsonHelper fromApiJsonHelper;
private static final String EMAIL_REGEX = "^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
public static final Set<String> supportedParams = new HashSet<String>(Arrays.asList(EmailApiConstants.SMTP_PORT,EmailApiConstants.SMTP_PASSWORD,
EmailApiConstants.SMTP_USERNAME,EmailApiConstants.SMTP_SERVER));
@Autowired
private EmailConfigurationValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateUpdateConfiguration(String json){
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, EmailConfigurationValidator.supportedParams);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(EmailApiConstants.RESOURCE_NAME);
final String smtpUsername = this.fromApiJsonHelper.extractStringNamed(EmailApiConstants.SMTP_USERNAME,element);
baseDataValidator.reset().parameter(EmailApiConstants.SMTP_USERNAME).value(smtpUsername).notBlank().notExceedingLengthOf(150);
final String smtpPassword = this.fromApiJsonHelper.extractStringNamed(EmailApiConstants.SMTP_PASSWORD,element);
baseDataValidator.reset().parameter(EmailApiConstants.SMTP_PASSWORD).value(smtpPassword).notBlank().notExceedingLengthOf(50);
final String smtpServer = this.fromApiJsonHelper.extractStringNamed(EmailApiConstants.SMTP_SERVER,element);
baseDataValidator.reset().parameter(EmailApiConstants.SMTP_SERVER).value(smtpServer).notBlank().notExceedingLengthOf(100);
final Long smtpPort = this.fromApiJsonHelper.extractLongNamed(EmailApiConstants.SMTP_PORT,element);
baseDataValidator.reset().parameter(EmailApiConstants.SMTP_PORT).value(smtpPort).notNull().integerGreaterThanZero();
this.throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public boolean isValidEmail(String email) {
// this is the easiest check
if (email == null) {
return false;
}else if (email.endsWith(".")) {
return false;
}
// Check the whole email address structure
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
// check if the Matcher matches the email pattern
if (!emailMatcher.matches()) {
return false;
}
return true;
}
}
@@ -0,0 +1,160 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.dataqueries.data.ReportData;
import java.util.List;
/**
* Immutable data object representing a SMS message.
*/
public class EmailData {
private final Long id;
private final Long groupId;
private final Long clientId;
private final Long staffId;
private final EnumOptionData status;
private final String emailAddress;
private final String emailSubject;
private final String emailMessage;
private final EnumOptionData emailAttachmentFileFormat;
private final ReportData stretchyReport;
private final String stretchyReportParamMap;
private final List<EnumOptionData> emailAttachmentFileFormatOptions;
private final List<EnumOptionData> stretchyReportParamDateOptions;
private final String campaignName;
private final LocalDate sentDate;
private final String errorMessage;
public static EmailData instance(final Long id,final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status,
final String emailAddress, final String emailSubject,
final String message, final EnumOptionData emailAttachmentFileFormat, final ReportData stretchyReport,
final String stretchyReportParamMap, final List<EnumOptionData> emailAttachmentFileFormatOptions,
final List<EnumOptionData> stretchyReportParamDateOptions, final String campaignName, final LocalDate sentDate,final String errorMessage) {
return new EmailData(id, groupId, clientId, staffId, status, emailAddress, emailSubject, message,
emailAttachmentFileFormat,stretchyReport,stretchyReportParamMap,emailAttachmentFileFormatOptions,
stretchyReportParamDateOptions,campaignName,sentDate,errorMessage);
}
private EmailData(final Long id,final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status, final String emailAddress, final String emailSubject, final String message,
final EnumOptionData emailAttachmentFileFormat, final ReportData stretchyReport, final String stretchyReportParamMap,
final List<EnumOptionData> emailAttachmentFileFormatOptions, final List<EnumOptionData> stretchyReportParamDateOptions,
final String campaignName,final LocalDate sentDate,final String errorMessage) {
this.id = id;
this.groupId = groupId;
this.clientId = clientId;
this.staffId = staffId;
this.status = status;
this.emailAddress = emailAddress;
this.emailSubject = emailSubject;
this.emailMessage = message;
this.emailAttachmentFileFormat = emailAttachmentFileFormat;
this.stretchyReport = stretchyReport;
this.stretchyReportParamMap = stretchyReportParamMap;
this.emailAttachmentFileFormatOptions = emailAttachmentFileFormatOptions;
this.stretchyReportParamDateOptions = stretchyReportParamDateOptions;
this.campaignName = campaignName;
this.sentDate = sentDate;
this.errorMessage = errorMessage;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @return the groupId
*/
public Long getGroupId() {
return groupId;
}
/**
* @return the clientId
*/
public Long getClientId() {
return clientId;
}
/**
* @return the staffId
*/
public Long getStaffId() {
return staffId;
}
/**
* @return the status
*/
public EnumOptionData getStatus() {
return status;
}
public String getErrorMessage() {return this.errorMessage;}
/**
* @return the emailAddress
*/
public String getEmailAddress() {
return emailAddress;
}
/**
* @return the message
*/
public String getMessage() {
return emailMessage;
}
public String getCampaignName() {return this.campaignName;}
public LocalDate getSentDate() { return this.sentDate; }
public String getEmailSubject() {
return emailSubject;
}
public EnumOptionData getEmailAttachmentFileFormat() {
return emailAttachmentFileFormat;
}
public ReportData getStretchyReport() {
return stretchyReport;
}
public String getStretchyReportParamMap() {
return stretchyReportParamMap;
}
public List<EnumOptionData> getEmailAttachmentFileFormatOptions() {
return emailAttachmentFileFormatOptions;
}
public List<EnumOptionData> getStretchyReportParamDateOptions() {
return stretchyReportParamDateOptions;
}
}
@@ -0,0 +1,307 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.infrastructure.campaigns.email.ScheduledEmailConstants;
import org.apache.fineract.infrastructure.campaigns.email.domain.ScheduledEmailAttachmentFileFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Type;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public final class EmailDataValidator {
private final FromJsonHelper fromApiJsonHelper;
private static final String EMAIL_REGEX = "^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
@Autowired
public EmailDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
/**
* validate the request to create a new report mailing job
*
* @param jsonCommand -- the JSON command object (instance of the JsonCommand class)
* @return None
**/
public void validateCreateRequest(final JsonCommand jsonCommand) {
final String jsonString = jsonCommand.json();
final JsonElement jsonElement = jsonCommand.parsedJson();
if (StringUtils.isBlank(jsonString)) {
throw new InvalidJsonException();
}
final Type typeToken = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeToken, jsonString,
ScheduledEmailConstants.CREATE_REQUEST_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors).
resource(StringUtils.lowerCase(ScheduledEmailConstants.SCHEDULED_EMAIL_ENTITY_NAME));
final String name = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.NAME_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.NAME_PARAM_NAME).value(name).notBlank().notExceedingLengthOf(100);
final String startDateTime = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.START_DATE_TIME_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.START_DATE_TIME_PARAM_NAME).value(startDateTime).notBlank();
final Integer stretchyReportId = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(ScheduledEmailConstants.STRETCHY_REPORT_ID_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.STRETCHY_REPORT_ID_PARAM_NAME).value(stretchyReportId).notNull().
integerGreaterThanZero();
final String emailRecipients = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_RECIPIENTS_PARAM_NAME).value(emailRecipients).notBlank();
final String emailSubject = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_SUBJECT_PARAM_NAME).value(emailSubject).notBlank().notExceedingLengthOf(100);
final String emailMessage = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_MESSAGE_PARAM_NAME).value(emailMessage).notBlank();
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME, jsonElement)) {
final Boolean isActive = this.fromApiJsonHelper.extractBooleanNamed(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME).value(isActive).notNull();
}
final Integer emailAttachmentFileFormatId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).
value(emailAttachmentFileFormatId).notNull();
if (emailAttachmentFileFormatId != null) {
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).value(emailAttachmentFileFormatId).
isOneOfTheseValues(ScheduledEmailAttachmentFileFormat.validValues());
}
final String dateFormat = jsonCommand.dateFormat();
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).notBlank();
if (StringUtils.isNotEmpty(dateFormat)) {
try {
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(dateFormat).withLocale(jsonCommand.extractLocale());
// try to parse the date time string
LocalDateTime.parse(startDateTime, dateTimeFormatter);
}
catch(IllegalArgumentException ex) {
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).failWithCode("invalid.date.format");
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
/**
* validate the request to update a report mailing job
*
* @param jsonCommand -- the JSON command object (instance of the JsonCommand class)
* @return None
**/
public void validateUpdateRequest(final JsonCommand jsonCommand) {
final String jsonString = jsonCommand.json();
final JsonElement jsonElement = jsonCommand.parsedJson();
if (StringUtils.isBlank(jsonString)) {
throw new InvalidJsonException();
}
final Type typeToken = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeToken, jsonString,
ScheduledEmailConstants.UPDATE_REQUEST_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors).
resource(StringUtils.lowerCase(ScheduledEmailConstants.SCHEDULED_EMAIL_ENTITY_NAME));
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.NAME_PARAM_NAME, jsonElement)) {
final String name = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.NAME_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.NAME_PARAM_NAME).value(name).notBlank().notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.STRETCHY_REPORT_ID_PARAM_NAME, jsonElement)) {
final Integer stretchyReportId = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(ScheduledEmailConstants.STRETCHY_REPORT_ID_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.STRETCHY_REPORT_ID_PARAM_NAME).value(stretchyReportId).notNull().
integerGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement)) {
final String emailRecipients = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_RECIPIENTS_PARAM_NAME).value(emailRecipients).notBlank();
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement)) {
final String emailSubject = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_SUBJECT_PARAM_NAME).value(emailSubject).notBlank().notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement)) {
final String emailMessage = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_MESSAGE_PARAM_NAME).value(emailMessage).notBlank();
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME, jsonElement)) {
final Boolean isActive = this.fromApiJsonHelper.extractBooleanNamed(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.IS_ACTIVE_PARAM_NAME).value(isActive).notNull();
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement)) {
final Integer emailAttachmentFileFormatId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).
value(emailAttachmentFileFormatId).notNull();
if (emailAttachmentFileFormatId != null) {
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).value(emailAttachmentFileFormatId).
isOneOfTheseValues(ScheduledEmailAttachmentFileFormat.validValues());
}
}
if (this.fromApiJsonHelper.parameterExists(ScheduledEmailConstants.START_DATE_TIME_PARAM_NAME, jsonElement)) {
final String dateFormat = jsonCommand.dateFormat();
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).notBlank();
final String startDateTime = this.fromApiJsonHelper.extractStringNamed(ScheduledEmailConstants.START_DATE_TIME_PARAM_NAME,
jsonElement);
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.START_DATE_TIME_PARAM_NAME).value(startDateTime).notBlank();
if (StringUtils.isNotEmpty(dateFormat)) {
try {
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(dateFormat).withLocale(jsonCommand.extractLocale());
// try to parse the date time string
LocalDateTime.parse(startDateTime, dateTimeFormatter);
}
catch(IllegalArgumentException ex) {
dataValidatorBuilder.reset().parameter(ScheduledEmailConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).failWithCode("invalid.date.format");
}
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
/**
* check if string is a valid email address
*
* @param email -- string to be validated
* @return true if string is a valid email address
**/
public boolean isValidEmail(String email) {
// this is the easiest check
if (email == null) {
return false;
}
// this is another easy check
if (email.endsWith(".")) {
return false;
}
// Check the whole email address structure
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
// check if the Matcher matches the email pattern
if (!emailMatcher.matches()) {
return false;
}
return true;
}
/**
* Validate the email recipients string
*
* @param emailRecipients -- the email recipients string to be validated
* @return a hashset containing valid email addresses
**/
public Set<String> validateEmailRecipients(String emailRecipients) {
Set<String> emailRecipientsSet = new HashSet<>();
if (emailRecipients != null) {
String[] split = emailRecipients.split(",");
for (String emailAddress : split) {
emailAddress = emailAddress.trim();
if (this.isValidEmail(emailAddress)) {
emailRecipientsSet.add(emailAddress);
}
}
}
return emailRecipientsSet;
}
/**
* validate the stretchy report param json string
*
* @param stretchyReportParamMap -- json string to be validated
* @return if string is valid or empty, a HashMap object, else null
**/
public HashMap<String,String> validateStretchyReportParamMap(String stretchyReportParamMap) {
HashMap<String,String> stretchyReportParamHashMap = new HashMap<>();
if (!StringUtils.isEmpty(stretchyReportParamMap)) {
try {
stretchyReportParamHashMap = new ObjectMapper().readValue(stretchyReportParamMap, new TypeReference<HashMap<String,String>>(){});
}
catch(Exception e) {
stretchyReportParamHashMap = null;
}
}
return stretchyReportParamHashMap;
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -0,0 +1,53 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import java.io.File;
import java.util.List;
import java.util.Set;
public class EmailMessageWithAttachmentData {
private final String to;
private final String text;
private final String subject;
private final List<File> attachments;
private EmailMessageWithAttachmentData(final String to, final String text, final String subject, final List<File> attachments) {
this.to = to;
this.text = text;
this.subject = subject;
this.attachments = attachments;
}
public static EmailMessageWithAttachmentData createNew (final String to, final String text, final String subject, final List<File> attachments){
return new EmailMessageWithAttachmentData(to,text,subject,attachments);
}
public String getTo() {return this.to;}
public String getText() {return this.text;}
public String getSubject() {return this.subject;}
public List<File> getAttachments() {
return this.attachments;
}
}
@@ -0,0 +1,40 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
public class PreviewCampaignMessage {
@SuppressWarnings("unused")
private final String campaignMessage;
private final Integer totalNumberOfMessages;
public PreviewCampaignMessage(String campaignMessage, Integer totalNumberOfMessages) {
this.campaignMessage = campaignMessage;
this.totalNumberOfMessages = totalNumberOfMessages;
}
public String getCampaignMessage() {
return campaignMessage;
}
public Integer getTotalNumberOfMessages() {
return totalNumberOfMessages;
}
}
@@ -0,0 +1,56 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.data;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.campaigns.email.domain.ScheduledEmailAttachmentFileFormat;
import org.apache.fineract.infrastructure.campaigns.email.domain.ScheduledEmailStretchyReportParamDateOption;
public class ScheduledEmailEnumerations {
public static EnumOptionData emailAttachementFileFormat(final Integer emailAttachementFileFormatId) {
return emailAttachementFileFormat(ScheduledEmailAttachmentFileFormat.instance(emailAttachementFileFormatId));
}
public static EnumOptionData emailAttachementFileFormat(final String emailAttachementFileFormatString) {
return emailAttachementFileFormat(ScheduledEmailAttachmentFileFormat.instance(emailAttachementFileFormatString));
}
public static EnumOptionData emailAttachementFileFormat(final ScheduledEmailAttachmentFileFormat emailAttachementFileFormat) {
EnumOptionData enumOptionData = null;
if (emailAttachementFileFormat != null) {
enumOptionData = new EnumOptionData(emailAttachementFileFormat.getId().longValue(), emailAttachementFileFormat.getCode(),
emailAttachementFileFormat.getValue());
}
return enumOptionData;
}
public static EnumOptionData stretchyReportDateOption(final ScheduledEmailStretchyReportParamDateOption
reportMailingJobStretchyReportParamDateOption) {
EnumOptionData enumOptionData = null;
if (reportMailingJobStretchyReportParamDateOption != null) {
enumOptionData = new EnumOptionData(reportMailingJobStretchyReportParamDateOption.getId().longValue(),
reportMailingJobStretchyReportParamDateOption.getCode(), reportMailingJobStretchyReportParamDateOption.getValue());
}
return enumOptionData;
}
}
@@ -0,0 +1,538 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.dataqueries.domain.Report;
import org.apache.fineract.infrastructure.campaigns.email.ScheduledEmailConstants;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignValidator;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.*;
import java.security.InvalidParameterException;
import java.util.*;
@Entity
@Table(name = "scheduled_email_campaign")
public class EmailCampaign extends AbstractPersistableCustom<Long> {
@Column(name = "campaign_name", nullable = false)
private String campaignName;
@Column(name = "campaign_type", nullable = false)
private Integer campaignType;
@ManyToOne
@JoinColumn(name = "businessRule_id", nullable = false)
private Report businessRuleId ;
@Column(name = "param_value")
private String paramValue;
@Column(name = "status_enum", nullable = false)
private Integer status;
@Column(name = "email_subject", nullable = false)
private String emailSubject;
@Column(name = "email_message", nullable = false)
private String emailMessage;
@Column(name = "email_attachment_file_format", nullable = false)
private String emailAttachmentFileFormat;
@ManyToOne
@JoinColumn(name = "stretchy_report_id", nullable = false)
private Report stretchyReport;
@Column(name = "stretchy_report_param_map", nullable = true)
private String stretchyReportParamMap;
@Column(name = "closedon_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date closureDate;
@ManyToOne(optional = true)
@JoinColumn(name = "closedon_userid", nullable = true)
private AppUser closedBy;
@Column(name = "submittedon_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date submittedOnDate;
@ManyToOne(optional = true)
@JoinColumn(name = "submittedon_userid", nullable = true)
private AppUser submittedBy;
@Column(name = "approvedon_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date approvedOnDate;
@ManyToOne(optional = true)
@JoinColumn(name = "approvedon_userid", nullable = true)
private AppUser approvedBy;
@Column(name = "recurrence", nullable = false)
private String recurrence;
@Column(name = "next_trigger_date", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date nextTriggerDate;
@Column(name = "last_trigger_date", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTriggerDate;
@Column(name = "recurrence_start_date", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date recurrenceStartDate;
@Column(name="is_visible",nullable = true)
private boolean isVisible;
@Column(name = "previous_run_status", nullable = true)
private String previousRunStatus;
@Column(name = "previous_run_error_log", nullable = true)
private String previousRunErrorLog;
@Column(name = "previous_run_error_message", nullable = true)
private String previousRunErrorMessage;
public EmailCampaign() {
}
private EmailCampaign(final String campaignName, final Integer campaignType, final Report businessRuleId, final String paramValue,
final String emailSubject, final String emailMessage,final LocalDate submittedOnDate, final AppUser submittedBy,
final Report stretchyReport, final String stretchyReportParamMap, final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat,
final String recurrence, final LocalDateTime localDateTime) {
this.campaignName = campaignName;
this.campaignType = EmailCampaignType.fromInt(campaignType).getValue();
this.businessRuleId = businessRuleId;
this.paramValue = paramValue;
this.status = EmailCampaignStatus.PENDING.getValue();
this.emailSubject = emailSubject;
this.emailMessage = emailMessage;
this.emailAttachmentFileFormat = emailAttachmentFileFormat.getValue();
this.stretchyReport = stretchyReport;
this.stretchyReportParamMap = stretchyReportParamMap;
this.submittedOnDate = submittedOnDate.toDate();
this.submittedBy = submittedBy;
this.recurrence = recurrence;
LocalDateTime recurrenceStartDate = new LocalDateTime();
this.isVisible = true;
if(localDateTime != null){
this.recurrenceStartDate = localDateTime.toDate();
}else{
this.recurrenceStartDate = recurrenceStartDate.toDate();
}
}
public static EmailCampaign instance(final AppUser submittedBy, final Report businessRuleId, final Report stretchyReport, final JsonCommand command){
final String campaignName = command.stringValueOfParameterNamed(EmailCampaignValidator.campaignName);
final Long campaignType = command.longValueOfParameterNamed(EmailCampaignValidator.campaignType);
final String paramValue = command.stringValueOfParameterNamed(EmailCampaignValidator.paramValue);
final String emailSubject = command.stringValueOfParameterNamed(EmailCampaignValidator.emailSubject);
final String emailMessage = command.stringValueOfParameterNamed(EmailCampaignValidator.emailMessage);
final String stretchyReportParamMap = command.stringValueOfParameterNamed(ScheduledEmailConstants.STRETCHY_REPORT_PARAM_MAP_PARAM_NAME);
final Integer emailAttachmentFileFormatId = command.integerValueOfParameterNamed(ScheduledEmailConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME);
final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat;
if (emailAttachmentFileFormatId!=null) {
emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat.instance(emailAttachmentFileFormatId);
}else{emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat.instance(2);}
LocalDate submittedOnDate = new LocalDate();
if (command.hasParameter(EmailCampaignValidator.submittedOnDateParamName)) {
submittedOnDate = command.localDateValueOfParameterNamed(EmailCampaignValidator.submittedOnDateParamName);
}
final String recurrence = command.stringValueOfParameterNamed(EmailCampaignValidator.recurrenceParamName);
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
LocalDateTime recurrenceStartDate = new LocalDateTime();
if(EmailCampaignType.fromInt(campaignType.intValue()).isSchedule()) {
if(command.hasParameter(EmailCampaignValidator.recurrenceStartDate)){
recurrenceStartDate = LocalDateTime.parse(command.stringValueOfParameterNamed(EmailCampaignValidator.recurrenceStartDate),fmt);
}
} else{recurrenceStartDate = null;}
return new EmailCampaign(campaignName,campaignType.intValue(),businessRuleId,paramValue,emailSubject,emailMessage,
submittedOnDate,submittedBy,stretchyReport,stretchyReportParamMap,emailAttachmentFileFormat,recurrence,recurrenceStartDate);
}
public Map<String,Object> update(JsonCommand command){
final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
if (command.isChangeInStringParameterNamed(EmailCampaignValidator.campaignName, this.campaignName)) {
final String newValue = command.stringValueOfParameterNamed(EmailCampaignValidator.campaignName);
actualChanges.put(EmailCampaignValidator.campaignName, newValue);
this.campaignName = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(EmailCampaignValidator.emailMessage, this.emailMessage)) {
final String newValue = command.stringValueOfParameterNamed(EmailCampaignValidator.emailMessage);
actualChanges.put(EmailCampaignValidator.emailMessage, newValue);
this.emailMessage = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(EmailCampaignValidator.paramValue, this.paramValue)) {
final String newValue = command.stringValueOfParameterNamed(EmailCampaignValidator.paramValue);
actualChanges.put(EmailCampaignValidator.paramValue, newValue);
this.paramValue = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInIntegerParameterNamed(EmailCampaignValidator.campaignType, this.campaignType)) {
final Integer newValue = command.integerValueOfParameterNamed(EmailCampaignValidator.campaignType);
actualChanges.put(EmailCampaignValidator.campaignType, EmailCampaignType.fromInt(newValue));
this.campaignType = EmailCampaignType.fromInt(newValue).getValue();
}
if (command.isChangeInLongParameterNamed(EmailCampaignValidator.businessRuleId, (this.businessRuleId != null) ? this.businessRuleId.getId() : null)) {
final String newValue = command.stringValueOfParameterNamed(EmailCampaignValidator.businessRuleId);
actualChanges.put(EmailCampaignValidator.businessRuleId, newValue);
}
if (command.isChangeInStringParameterNamed(EmailCampaignValidator.recurrenceParamName, this.recurrence)) {
final String newValue = command.stringValueOfParameterNamed(EmailCampaignValidator.recurrenceParamName);
actualChanges.put(EmailCampaignValidator.recurrenceParamName, newValue);
this.recurrence = StringUtils.defaultIfEmpty(newValue, null);
}
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
if (command.isChangeInLocalDateParameterNamed(EmailCampaignValidator.recurrenceStartDate, getRecurrenceStartDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(EmailCampaignValidator.recurrenceStartDate);
actualChanges.put(EmailCampaignValidator.recurrenceStartDate, valueAsInput);
actualChanges.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput);
actualChanges.put(ClientApiConstants.localeParamName, localeAsInput);
final LocalDateTime newValue = LocalDateTime.parse(valueAsInput, fmt);
this.recurrenceStartDate = newValue.toDate();
}
return actualChanges;
}
public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate){
if(isActive()){
//handle errors if already activated
final String defaultUserMessage = "Cannot activate campaign. Campaign is already active.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.already.active", defaultUserMessage,
EmailCampaignValidator.activationDateParamName, activationLocalDate.toString(formatter));
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
this.approvedOnDate = activationLocalDate.toDate();
this.approvedBy = currentUser;
this.status = EmailCampaignStatus.ACTIVE.getValue();
validate();
}
public void close(final AppUser currentUser,final DateTimeFormatter dateTimeFormatter, final LocalDate closureLocalDate){
if(isClosed()){
//handle errors if already activated
final String defaultUserMessage = "Cannot close campaign. Campaign already in closed state.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.already.closed", defaultUserMessage,
EmailCampaignValidator.statusParamName, EmailCampaignStatus.fromInt(this.status).getCode());
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
if(this.campaignType.intValue() == EmailCampaignType.SCHEDULE.getValue()){
this.nextTriggerDate = null;
this.lastTriggerDate = null;
}
this.closedBy = currentUser;
this.closureDate = closureLocalDate.toDate();
this.status = EmailCampaignStatus.CLOSED.getValue();
validateClosureDate();
}
public void reactivate(final AppUser currentUser, final DateTimeFormatter dateTimeFormat,final LocalDate reactivateLocalDate){
if(!isClosed()){
//handle errors if already activated
final String defaultUserMessage = "Cannot reactivate campaign. Campaign must be in closed state.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.must.be.closed", defaultUserMessage,
EmailCampaignValidator.statusParamName, EmailCampaignStatus.fromInt(this.status).getCode());
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
this.approvedOnDate = reactivateLocalDate.toDate();
this.status = EmailCampaignStatus.ACTIVE.getValue();
this.approvedBy =currentUser;
this.closureDate = null;
this.isVisible = true;
this.closedBy = null;
validateReactivate();
}
public void delete(){
if(!isClosed()){
//handle errors if already activated
final String defaultUserMessage = "Cannot delete campaign. Campaign must be in closed state.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.must.be.closed", defaultUserMessage,
EmailCampaignValidator.statusParamName, EmailCampaignStatus.fromInt(this.status).getCode());
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
this.isVisible = false;
}
public boolean isActive(){
return EmailCampaignStatus.fromInt(this.status).isActive();
}
public boolean isPending(){
return EmailCampaignStatus.fromInt(this.status).isPending();
}
public boolean isClosed(){
return EmailCampaignStatus.fromInt(this.status).isClosed();
}
public boolean isDirect(){
return EmailCampaignType.fromInt(this.campaignType).isDirect();
}
public boolean isSchedule(){
return EmailCampaignType.fromInt(this.campaignType).isSchedule();
}
private void validate() {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
validateActivationDate(dataValidationErrors);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
private void validateReactivate(){
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
validateReactivationDate(dataValidationErrors);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
private void validateClosureDate(){
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
validateClosureDate(dataValidationErrors);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.activationDateParamName, getActivationLocalDate());
dataValidationErrors.add(error);
}
}
private void validateReactivationDate(final List<ApiParameterError> dataValidationErrors){
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.activationDateParamName, getActivationLocalDate());
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
}
private void validateClosureDate(final List<ApiParameterError> dataValidationErrors){
if (getClosureDate() != null && isDateInTheFuture(getClosureDate())) {
final String defaultUserMessage = "closure date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.closureDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.closureDateParamName, this.closureDate);
dataValidationErrors.add(error);
}
}
public LocalDate getSubmittedOnDate() {
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null);
}
public LocalDate getClosureDate() {
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.closureDate), null);
}
public LocalDate getActivationLocalDate() {
LocalDate activationLocalDate = null;
if (this.approvedOnDate != null) {
activationLocalDate = LocalDate.fromDateFields(this.approvedOnDate);
}
return activationLocalDate;
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
}
public Report getBusinessRuleId() {
return this.businessRuleId;
}
public String getCampaignName() {
return this.campaignName;
}
public String getEmailSubject() { return this.emailSubject; }
public String getEmailMessage() {
return this.emailMessage;
}
public String getParamValue() {
return this.paramValue;
}
public String getRecurrence() {
return this.recurrence;
}
public LocalDate getRecurrenceStartDate() {
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.recurrenceStartDate), null);
}
public LocalDateTime getRecurrenceStartDateTime() {
return (LocalDateTime) ObjectUtils.defaultIfNull(new LocalDateTime(this.recurrenceStartDate), null);
}
public void setLastTriggerDate(Date lastTriggerDate) {
this.lastTriggerDate = lastTriggerDate;
}
public void setNextTriggerDate(Date nextTriggerDate) {
this.nextTriggerDate = nextTriggerDate;
}
public LocalDateTime getNextTriggerDate() {
return (LocalDateTime) ObjectUtils.defaultIfNull(new LocalDateTime(this.nextTriggerDate), null);
}
public Date getNextTriggerDateInDate(){
return this.nextTriggerDate;
}
public LocalDate getLastTriggerDate() {
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.lastTriggerDate), null);
}
public void updateIsVisible(boolean isVisible) {
this.isVisible = isVisible;
}
public void updateBusinessRuleId(final Report report){
this.businessRuleId = report;
}
public String getEmailAttachmentFileFormat() {
return this.emailAttachmentFileFormat;
}
public Report getStretchyReport() {
return this.stretchyReport;
}
public String getStretchyReportParamMap() {
return this.stretchyReportParamMap;
}
public void setStretchyReportParamMap(String stretchyReportParamMap) {
this.stretchyReportParamMap = stretchyReportParamMap;
}
public AppUser getApprovedBy() {return this.approvedBy;}
public AppUser getClosedBy() {
return this.closedBy;
}
}
@@ -0,0 +1,25 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface EmailCampaignRepository extends JpaRepository<EmailCampaign, Long>, JpaSpecificationExecutor<EmailCampaign> {
}
@@ -0,0 +1,71 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
public enum EmailCampaignStatus {
INVALID(0, "emailCampaignStatus.invalid"), //
PENDING(100, "emailCampaignStatus.pending"), //
ACTIVE(300, "emailCampaignStatus.active"), //
CLOSED(600, "emailCampaignStatus.closed");
private final Integer value;
private final String code;
EmailCampaignStatus(Integer value, String code) {
this.value = value;
this.code = code;
}
public static EmailCampaignStatus fromInt(final Integer statusValue) {
EmailCampaignStatus enumeration = EmailCampaignStatus.INVALID;
switch (statusValue) {
case 100:
enumeration = EmailCampaignStatus.PENDING;
break;
case 300:
enumeration = EmailCampaignStatus.ACTIVE;
break;
case 600:
enumeration = EmailCampaignStatus.CLOSED;
break;
}
return enumeration;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public boolean isActive(){
return this.value.equals(EmailCampaignStatus.ACTIVE.getValue());
}
public boolean isPending(){
return this.value.equals(EmailCampaignStatus.PENDING.getValue());
}
public boolean isClosed(){
return this.value.equals(EmailCampaignStatus.CLOSED.getValue());
}
}
@@ -0,0 +1,53 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public class EmailCampaignStatusEnumerations {
public static EnumOptionData status(final Integer statusId) {
return status(EmailCampaignStatus.fromInt(statusId));
}
public static EnumOptionData status(final EmailCampaignStatus status) {
EnumOptionData optionData = new EnumOptionData(EmailCampaignStatus.INVALID.getValue().longValue(),
EmailCampaignStatus.INVALID.getCode(), "Invalid");
switch (status) {
case INVALID:
optionData = new EnumOptionData(EmailCampaignStatus.INVALID.getValue().longValue(),
EmailCampaignStatus.INVALID.getCode(), "Invalid");
break;
case PENDING:
optionData = new EnumOptionData(EmailCampaignStatus.PENDING.getValue().longValue(),
EmailCampaignStatus.PENDING.getCode(), "Pending");
break;
case ACTIVE:
optionData = new EnumOptionData(EmailCampaignStatus.ACTIVE.getValue().longValue(), EmailCampaignStatus.ACTIVE.getCode(),
"active");
break;
case CLOSED:
optionData = new EnumOptionData(EmailCampaignStatus.CLOSED.getValue().longValue(),
EmailCampaignStatus.CLOSED.getCode(), "closed");
break;
}
return optionData;
}
}
@@ -0,0 +1,61 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
public enum EmailCampaignType {
DIRECT(1,"emailCampaignStatusType.direct"),
SCHEDULE(2,"emailCampaignStatusType.schedule");
private Integer value;
private String code;
EmailCampaignType(Integer value, String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static EmailCampaignType fromInt(final Integer typeValue) {
EmailCampaignType type = null;
switch (typeValue) {
case 1:
type = DIRECT;
break;
case 2:
type = SCHEDULE;
break;
}
return type;
}
public boolean isDirect(){
return this.value.equals(EmailCampaignType.DIRECT.getValue());
}
public boolean isSchedule(){
return this.value.equals(EmailCampaignType.SCHEDULE.getValue());
}
}
@@ -0,0 +1,60 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "scheduled_email_configuration")
public class EmailConfiguration extends AbstractPersistableCustom<Long> {
@Column(name = "name", nullable = false)
private String name;
@Column(name = "value", nullable = false)
private String value;
/**
* EmailConfiguration constructor
**/
protected EmailConfiguration() {}
/**
* EmailConfiguration constructor
**/
public EmailConfiguration(String name, String value) {
this.name = name;
this.value = value;
}
public void setValue(String value) {
this.value = value;
}
public String getName() {
return this.name;
}
public String getValue() {
return this.value;
}
}
@@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface EmailConfigurationRepository extends JpaRepository<EmailConfiguration, Long>, JpaSpecificationExecutor<EmailConfiguration> {
EmailConfiguration findByName(String name);
}
@@ -0,0 +1,164 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@Entity
@Table(name = "scheduled_email_messages_outbound")
public class EmailMessage extends AbstractPersistableCustom<Long> {
@ManyToOne
@JoinColumn(name = "group_id", nullable = true)
private Group group;
@ManyToOne
@JoinColumn(name = "client_id", nullable = true)
private Client client;
@ManyToOne
@JoinColumn(name = "staff_id", nullable = true)
private Staff staff;
@ManyToOne
@JoinColumn(name = "email_campaign_id", nullable = true)
private EmailCampaign emailCampaign;
@Column(name = "status_enum", nullable = false)
private Integer statusType;
@Column(name = "email_address", nullable = false, length = 50)
private String emailAddress;
@Column(name = "email_subject", nullable = false, length = 50)
private String emailSubject;
@Column(name = "message", nullable = false)
private String message;
@Column(name = "campaign_name", nullable = true)
private String campaignName;
@Column(name = "submittedon_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date submittedOnDate;
@Column(name = "error_message")
private String errorMessage;
public static EmailMessage pendingEmail(final Group group, final Client client, final Staff staff,final EmailCampaign emailCampaign, final String emailSubject, final String message,
final String emailAddress, final String campaignName) {
return new EmailMessage(group, client, staff,emailCampaign,EmailMessageStatusType.PENDING, emailSubject, message, emailAddress,campaignName);
}
public static EmailMessage instance(final Group group, final Client client, final Staff staff, final EmailCampaign emailCampaign, final EmailMessageStatusType statusType,
final String emailSubject, final String message, final String sourceAddress, final String emailAddress, final String campaignName) {
return new EmailMessage(group, client, staff,emailCampaign, statusType, emailSubject, message, emailAddress, campaignName);
}
protected EmailMessage() {
//
}
private EmailMessage(final Group group, final Client client, final Staff staff, final EmailCampaign emailCampaign, final EmailMessageStatusType statusType,
final String emailSubject, final String message, final String emailAddress, final String campaignName) {
this.group = group;
this.client = client;
this.staff = staff;
this.emailCampaign = emailCampaign;
this.statusType = statusType.getValue();
this.emailAddress = emailAddress;
this.emailSubject = emailSubject;
this.message = message;
this.campaignName = campaignName;
this.submittedOnDate = LocalDate.now().toDate();
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(1);
if (command.isChangeInStringParameterNamed(EmailApiConstants.messageParamName, this.message)) {
final String newValue = command.stringValueOfParameterNamed(EmailApiConstants.messageParamName);
actualChanges.put(EmailApiConstants.messageParamName, newValue);
this.message = StringUtils.defaultIfEmpty(newValue, null);
}
return actualChanges;
}
public Group getGroup() {
return group;
}
public Client getClient() {
return client;
}
public Staff getStaff() {
return staff;
}
public Integer getStatusType() {
return statusType;
}
public String getEmailAddress() {return this.emailAddress;}
public String getEmailSubject() {return emailSubject; }
public String getMessage() {
return message;
}
public void setStatusType(final Integer statusType) {
this.statusType = statusType;
}
public String getCampaignName() {
return this.campaignName;
}
public Date getSubmittedOnDate() {
return this.submittedOnDate;
}
public EmailCampaign getEmailCampaign() {return this.emailCampaign;}
public void updateErrorMessage(final String errorMessage) {this.errorMessage = errorMessage;}
public boolean isPending(){ return EmailMessageStatusType.fromInt(this.statusType).isPending();}
public boolean isSent(){ return EmailMessageStatusType.fromInt(this.statusType).isSent();}
}
@@ -0,0 +1,92 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import com.google.gson.JsonElement;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailNotFoundException;
import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EmailMessageAssembler {
private final EmailMessageRepository emailMessageRepository;
private final GroupRepositoryWrapper groupRepository;
private final ClientRepositoryWrapper clientRepository;
private final StaffRepositoryWrapper staffRepository;
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public EmailMessageAssembler(final EmailMessageRepository emailMessageRepository, final GroupRepositoryWrapper groupRepositoryWrapper,
final ClientRepositoryWrapper clientRepository, final StaffRepositoryWrapper staffRepository,
final FromJsonHelper fromApiJsonHelper) {
this.emailMessageRepository = emailMessageRepository;
this.groupRepository = groupRepositoryWrapper;
this.clientRepository = clientRepository;
this.staffRepository = staffRepository;
this.fromApiJsonHelper = fromApiJsonHelper;
}
public EmailMessage assembleFromJson(final JsonCommand command) {
final JsonElement element = command.parsedJson();
String emailAddress = null;
Group group = null;
if (this.fromApiJsonHelper.parameterExists(EmailApiConstants.groupIdParamName, element)) {
final Long groupId = this.fromApiJsonHelper.extractLongNamed(EmailApiConstants.groupIdParamName, element);
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
}
Client client = null;
if (this.fromApiJsonHelper.parameterExists(EmailApiConstants.clientIdParamName, element)) {
final Long clientId = this.fromApiJsonHelper.extractLongNamed(EmailApiConstants.clientIdParamName, element);
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
emailAddress = client.emailAddress();
}
Staff staff = null;
if (this.fromApiJsonHelper.parameterExists(EmailApiConstants.staffIdParamName, element)) {
final Long staffId = this.fromApiJsonHelper.extractLongNamed(EmailApiConstants.staffIdParamName, element);
staff = this.staffRepository.findOneWithNotFoundDetection(staffId);
emailAddress = staff.emailAddress();
}
final String message = this.fromApiJsonHelper.extractStringNamed(EmailApiConstants.messageParamName, element);
final String emailSubject = this.fromApiJsonHelper.extractStringNamed(EmailApiConstants.subjectParamName, element);
return EmailMessage.pendingEmail(group, client, staff,null,emailSubject, message,emailAddress,null);
}
public EmailMessage assembleFromResourceId(final Long resourceId) {
final EmailMessage email = this.emailMessageRepository.findOne(resourceId);
if (email == null) { throw new EmailNotFoundException(resourceId); }
return email;
}
}
@@ -0,0 +1,58 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public class EmailMessageEnumerations {
public static EnumOptionData status(final Integer statusId) {
return status(EmailMessageStatusType.fromInt(statusId));
}
public static EnumOptionData status(final EmailMessageStatusType status) {
EnumOptionData optionData = new EnumOptionData(EmailMessageStatusType.INVALID.getValue().longValue(),
EmailMessageStatusType.INVALID.getCode(), "Invalid");
switch (status) {
case INVALID:
optionData = new EnumOptionData(EmailMessageStatusType.INVALID.getValue().longValue(),
EmailMessageStatusType.INVALID.getCode(), "Invalid");
break;
case PENDING:
optionData = new EnumOptionData(EmailMessageStatusType.PENDING.getValue().longValue(),
EmailMessageStatusType.PENDING.getCode(), "Pending");
break;
case SENT:
optionData = new EnumOptionData(EmailMessageStatusType.SENT.getValue().longValue(), EmailMessageStatusType.SENT.getCode(),
"Sent");
break;
case DELIVERED:
optionData = new EnumOptionData(EmailMessageStatusType.DELIVERED.getValue().longValue(),
EmailMessageStatusType.DELIVERED.getCode(), "Delivered");
break;
case FAILED:
optionData = new EnumOptionData(EmailMessageStatusType.FAILED.getValue().longValue(), EmailMessageStatusType.FAILED.getCode(),
"Failed");
break;
}
return optionData;
}
}
@@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
public interface EmailMessageRepository extends JpaRepository<EmailMessage, Long>, JpaSpecificationExecutor<EmailMessage> {
// no extra behaviour
List<EmailMessage> findByStatusType(Integer emailMessageStatus);
}
@@ -0,0 +1,72 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
public enum EmailMessageStatusType {
INVALID(0, "emailMessageStatusType.invalid"), //
PENDING(100, "emailMessageStatusType.pending"), //
SENT(200, "emailMessageStatusType.sent"), //
DELIVERED(300, "emailMessageStatusType.delivered"), //
FAILED(400, "emailMessageStatusType.failed");
private final Integer value;
private final String code;
public static EmailMessageStatusType fromInt(final Integer statusValue) {
EmailMessageStatusType enumeration = EmailMessageStatusType.INVALID;
switch (statusValue) {
case 100:
enumeration = EmailMessageStatusType.PENDING;
break;
case 200:
enumeration = EmailMessageStatusType.SENT;
break;
case 300:
enumeration = EmailMessageStatusType.DELIVERED;
break;
case 400:
enumeration = EmailMessageStatusType.FAILED;
break;
}
return enumeration;
}
EmailMessageStatusType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
public boolean isPending(){
return this.value.equals(EmailMessageStatusType.PENDING.getValue());
}
public boolean isSent(){
return this.value.equals(EmailMessageStatusType.SENT.getValue());
}
}
@@ -0,0 +1,110 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
public enum ScheduledEmailAttachmentFileFormat {
INVALID(0, "EmailAttachmentFileFormat.invalid", "invalid"),
XLS(1, "EmailAttachmentFileFormat.xls", "xls"),
PDF(2, "EmailAttachmentFileFormat.pdf", "pdf"),
CSV(3, "EmailAttachmentFileFormat.csv", "csv");
private String code;
private String value;
private Integer id;
ScheduledEmailAttachmentFileFormat(final Integer id, final String code, final String value) {
this.value = value;
this.code = code;
this.id = id;
}
public static ScheduledEmailAttachmentFileFormat instance(final String value) {
ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat = INVALID;
switch (value) {
case "xls":
emailAttachmentFileFormat = XLS;
break;
case "pdf":
emailAttachmentFileFormat = PDF;
break;
case "csv":
emailAttachmentFileFormat = CSV;
break;
default:
break;
}
return emailAttachmentFileFormat;
}
public static ScheduledEmailAttachmentFileFormat instance(final Integer id) {
ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat = INVALID;
switch (id) {
case 1:
emailAttachmentFileFormat = XLS;
break;
case 2:
emailAttachmentFileFormat = PDF;
break;
case 3:
emailAttachmentFileFormat = CSV;
break;
default:
break;
}
return emailAttachmentFileFormat;
}
/**
* @return the code
*/
public String getCode() {
return code;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @return list of valid ScheduledEmailAttachmentFileFormat ids
**/
public static Object[] validValues() {
return new Object[] { XLS.getId(), PDF.getId(), CSV.getId() };
}
}
@@ -0,0 +1,117 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.domain;
public enum ScheduledEmailStretchyReportParamDateOption {
INVALID(0, "scheduledEmailStretchyReportParamDateOption.invalid", "invalid"),
TODAY(1, "scheduledEmailStretchyReportParamDateOption.today", "today"),
// YESTERDAY(2, "scheduledEmailStretchyReportParamDateOption.yesterday", "yesterday"),
TOMORROW(3, "scheduledEmailStretchyReportParamDateOption.tomorrow", "tomorrow");
private String code;
private String value;
private Integer id;
/**
* @param id
* @param code
* @param value
*/
private ScheduledEmailStretchyReportParamDateOption(final Integer id, final String code, final String value) {
this.value = value;
this.code = code;
this.id = id;
}
/**
* @param value
* @return
*/
public static ScheduledEmailStretchyReportParamDateOption instance(final String value) {
ScheduledEmailStretchyReportParamDateOption scheduledEmailStretchyReportParamDateOption = INVALID;
switch (value) {
case "today":
scheduledEmailStretchyReportParamDateOption = TODAY;
break;
// case "yesterday":
// scheduledEmailStretchyReportParamDateOption = YESTERDAY;
// break;
case "tomorrow":
scheduledEmailStretchyReportParamDateOption = TOMORROW;
break;
}
return scheduledEmailStretchyReportParamDateOption;
}
/**
* @param id
* @return
*/
public static ScheduledEmailStretchyReportParamDateOption instance(final Integer id) {
ScheduledEmailStretchyReportParamDateOption scheduledEmailStretchyReportParamDateOption = INVALID;
switch (id) {
case 1:
scheduledEmailStretchyReportParamDateOption = TODAY;
break;
// case 2:
// scheduledEmailStretchyReportParamDateOption = YESTERDAY;
// break;
case 3:
scheduledEmailStretchyReportParamDateOption = TOMORROW;
break;
}
return scheduledEmailStretchyReportParamDateOption;
}
/**
* @return the code
*/
public String getCode() {
return code;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @return list of valid ScheduledEmailAttachmentFileFormat values
**/
public static Object[] validValues() {
return new Object[] { TODAY.value, TOMORROW.value };
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class EmailBusinessRuleNotFound extends AbstractPlatformResourceNotFoundException {
public EmailBusinessRuleNotFound(final Long resourceId) {
super("error.msg.email.business.rule.not.found", "Email business rule with identifier `" + resourceId + "` does not exist", resourceId);
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class EmailCampaignMustBeClosedToBeDeletedException extends AbstractPlatformDomainRuleException {
public EmailCampaignMustBeClosedToBeDeletedException(final Long resourceId) {
super("error.msg.email.campaign.cannot.be.deleted",
"Campaign with identifier " + resourceId + " cannot be deleted as it is not in `Closed` state.", resourceId); }
}
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class EmailCampaignMustBeClosedToEditException extends AbstractPlatformDomainRuleException {
public EmailCampaignMustBeClosedToEditException(final Long resourceId) {
super("error.msg.email.campaign.cannot.be.updated",
"Campaign with identifier " + resourceId + " cannot be updated as it is not in `Closed` state.", resourceId);
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class EmailCampaignNotFound extends AbstractPlatformResourceNotFoundException{
public EmailCampaignNotFound(final Long resourceId) {
super("error.msg.email.campaign.identifier.not.found", "EMAIL_CAMPAIGN with identifier `" + resourceId + "` does not exist", resourceId);
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* A {@link RuntimeException} thrown when a code is not found.
*/
public class EmailConfigurationNotFoundException extends AbstractPlatformResourceNotFoundException {
public EmailConfigurationNotFoundException(final String name) {
super("error.msg.email.configuration.name.not.found", "Email configuration with name " + name + " does not exist", name);
}
}
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class EmailConfigurationSMTPUsernameNotValid extends AbstractPlatformDomainRuleException {
public EmailConfigurationSMTPUsernameNotValid(final String smtpUsername) {
super("error.msg.email.configuration.smtpusername.not.valid",
"SMTP username configuration with email " + "'"+smtpUsername+"'" + " is not a valid email address ");
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* A {@link RuntimeException} thrown when a code is not found.
*/
public class EmailNotFoundException extends AbstractPlatformResourceNotFoundException {
public EmailNotFoundException(final Long resourceId) {
super("error.msg.email.identifier.not.found", "Email with identifier `" + resourceId + "` does not exist", resourceId);
}
}
@@ -0,0 +1,45 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "ACTIVATE")
public class ActivateEmailCampaignCommandHandler implements NewCommandSourceHandler {
private EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public ActivateEmailCampaignCommandHandler(final EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.activateEmailCampaign(command.entityId(), command);
}
}
@@ -0,0 +1,43 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "CLOSE")
public class CloseEmailCampaignCommandHandler implements NewCommandSourceHandler {
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public CloseEmailCampaignCommandHandler(final EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.closeEmailCampaign(command.entityId(), command);
}
}
@@ -0,0 +1,46 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "CREATE")
public class CreateEmailCampaignCommandHandler implements NewCommandSourceHandler {
private EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public CreateEmailCampaignCommandHandler(final EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.create(command);
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL", action = "CREATE")
public class CreateEmailCommandHandler implements NewCommandSourceHandler {
private final EmailWritePlatformService writePlatformService;
@Autowired
public CreateEmailCommandHandler(final EmailWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.create(command);
}
}
@@ -0,0 +1,45 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "DELETE")
public class DeleteEmailCampaignCommandHandler implements NewCommandSourceHandler {
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public DeleteEmailCampaignCommandHandler(EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.delete(command.entityId());
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL", action = "DELETE")
public class DeleteEmailCommandHandler implements NewCommandSourceHandler {
private final EmailWritePlatformService writePlatformService;
@Autowired
public DeleteEmailCommandHandler(final EmailWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.delete(command.entityId());
}
}
@@ -0,0 +1,45 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "REACTIVATE")
public class ReactivateEmailCampaignCommandHandler implements NewCommandSourceHandler {
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public ReactivateEmailCampaignCommandHandler(EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.reactivateEmailCampaign(command.entityId(),command);
}
}
@@ -0,0 +1,44 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CAMPAIGN", action = "UPDATE")
public class UpdateEmailCampaignCommandHandler implements NewCommandSourceHandler {
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
@Autowired
public UpdateEmailCampaignCommandHandler(EmailCampaignWritePlatformService emailCampaignWritePlatformService) {
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.emailCampaignWritePlatformService.update(command.entityId(),command);
}
}
@@ -0,0 +1,48 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailConfigurationWritePlatformService;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "EMAIL_CONFIGURATION", action = "UPDATE")
public class UpdateEmailConfigurationCommandHandler implements NewCommandSourceHandler {
private final EmailConfigurationWritePlatformService writePlatformService;
@Autowired
public UpdateEmailConfigurationCommandHandler(final EmailConfigurationWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.update(command);
}
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailBusinessRulesData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignData;
import java.util.Collection;
public interface EmailCampaignReadPlatformService {
Collection<EmailBusinessRulesData> retrieveAll();
EmailBusinessRulesData retrieveOneTemplate(Long resourceId);
EmailCampaignData retrieveOne(Long resourceId);
Collection<EmailCampaignData> retrieveAllCampaign();
Collection<EmailCampaignData> retrieveAllScheduleActiveCampaign();
}
@@ -0,0 +1,285 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.dataqueries.data.ReportData;
import org.apache.fineract.infrastructure.campaigns.email.data.ScheduledEmailEnumerations;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailBusinessRuleNotFound;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailCampaignNotFound;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailBusinessRulesData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignTimeLine;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignStatus;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignStatusEnumerations;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
@Service
public class EmailCampaignReadPlatformServiceImpl implements EmailCampaignReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final BusinessRuleMapper businessRuleMapper;
private final EmailCampaignMapper emailCampaignMapper;
@Autowired
public EmailCampaignReadPlatformServiceImpl(final RoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.businessRuleMapper = new BusinessRuleMapper();
this.emailCampaignMapper = new EmailCampaignMapper();
}
private static final class EmailCampaignMapper implements RowMapper<EmailCampaignData>{
final String schema;
private EmailCampaignMapper() {
final StringBuilder sql = new StringBuilder(400);
sql.append("ec.id as id, ");
sql.append("ec.campaign_name as campaignName, ");
sql.append("ec.campaign_type as campaignType, ");
sql.append("ec.businessRule_id as businessRuleId, ");
sql.append("ec.email_subject as emailSubject, ");
sql.append("ec.email_message as emailMessage, ");
sql.append("ec.email_attachment_file_format as emailAttachmentFileFormat, ");
sql.append("sr.id as stretchyReportId, ");
sql.append("sr.report_name as reportName, sr.report_type as reportType, sr.report_subtype as reportSubType, ");
sql.append("sr.report_category as reportCategory, sr.report_sql as reportSql, sr.description as reportDescription, ");
sql.append("sr.core_report as coreReport, sr.use_report as useReport, ");
sql.append("ec.stretchy_report_param_map as stretchyReportParamMap, ");
sql.append("ec.param_value as paramValue, ");
sql.append("ec.status_enum as statusEnum, ");
sql.append("ec.recurrence as recurrence, ");
sql.append("ec.recurrence_start_date as recurrenceStartDate, ");
sql.append("ec.next_trigger_date as nextTriggerDate, ");
sql.append("ec.last_trigger_date as lastTriggerDate, ");
sql.append("ec.submittedon_date as submittedOnDate, ");
sql.append("sbu.username as submittedByUsername, ");
sql.append("ec.closedon_date as closedOnDate, ");
sql.append("clu.username as closedByUsername, ");
sql.append("acu.username as activatedByUsername, ");
sql.append("ec.approvedon_date as activatedOnDate ");
sql.append("from scheduled_email_campaign ec ");
sql.append("left join m_appuser sbu on sbu.id = ec.submittedon_userid ");
sql.append("left join m_appuser acu on acu.id = ec.approvedon_userid ");
sql.append("left join m_appuser clu on clu.id = ec.closedon_userid ");
sql.append("left join stretchy_report sr on ec.stretchy_report_id = sr.id");
this.schema = sql.toString();
}
public String schema() {
return this.schema;
}
@Override
public EmailCampaignData mapRow(ResultSet rs, int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final String campaignName = rs.getString("campaignName");
final Integer campaignType = JdbcSupport.getInteger(rs, "campaignType");
final Long businessRuleId = JdbcSupport.getLong(rs, "businessRuleId");
final String paramValue = rs.getString("paramValue");
final String emailSubject = rs.getString("emailSubject");
final String emailMessage = rs.getString("emailMessage");
final String emailAttachmentFileFormatString = rs.getString("emailAttachmentFileFormat");
final String stretchyReportParamMap = rs.getString("stretchyReportParamMap");
EnumOptionData emailAttachmentFileFormat = null;
if (emailAttachmentFileFormatString != null) {
emailAttachmentFileFormat = ScheduledEmailEnumerations.emailAttachementFileFormat(emailAttachmentFileFormatString);
}
final Long reportId = JdbcSupport.getLong(rs, "stretchyReportId");
final String reportName = rs.getString("reportName");
final String reportType = rs.getString("reportType");
final String reportSubType = rs.getString("reportSubType");
final String reportCategory = rs.getString("reportCategory");
final String reportSql = rs.getString("reportSql");
final String reportDescription = rs.getString("reportDescription");
final boolean coreReport = rs.getBoolean("coreReport");
final boolean useReport = rs.getBoolean("useReport");
final ReportData stretchyReport = new ReportData(reportId, reportName, reportType, reportSubType, reportCategory,
reportDescription, reportSql, coreReport, useReport, null);
final Integer statusId = JdbcSupport.getInteger(rs, "statusEnum");
final EnumOptionData status = EmailCampaignStatusEnumerations.status(statusId);
final DateTime nextTriggerDate = JdbcSupport.getDateTime(rs, "nextTriggerDate");
final LocalDate lastTriggerDate = JdbcSupport.getLocalDate(rs, "lastTriggerDate");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final String submittedByUsername = rs.getString("submittedByUsername");
final LocalDate activatedOnDate = JdbcSupport.getLocalDate(rs, "activatedOnDate");
final String activatedByUsername = rs.getString("activatedByUsername");
final String recurrence =rs.getString("recurrence");
final DateTime recurrenceStartDate = JdbcSupport.getDateTime(rs, "recurrenceStartDate");
final EmailCampaignTimeLine emailCampaignTimeLine = new EmailCampaignTimeLine(submittedOnDate,submittedByUsername,
activatedOnDate,activatedByUsername,closedOnDate,closedByUsername);
return EmailCampaignData.instance(id,campaignName,campaignType,businessRuleId,paramValue,status,emailSubject,emailMessage,
emailAttachmentFileFormatString,reportId,stretchyReportParamMap,nextTriggerDate,lastTriggerDate,emailCampaignTimeLine,
recurrenceStartDate,recurrence);
}
}
private static final class BusinessRuleMapper implements ResultSetExtractor<List<EmailBusinessRulesData>>{
final String schema;
private BusinessRuleMapper() {
final StringBuilder sql = new StringBuilder(300);
sql.append("sr.id as id, ");
sql.append("sr.report_name as reportName, ");
sql.append("sr.report_type as reportType, ");
sql.append("sr.report_subtype as reportSubType, ");
sql.append("sr.description as description, ");
sql.append("sp.parameter_variable as params, ");
sql.append("sp.parameter_FormatType as paramType, ");
sql.append("sp.parameter_label as paramLabel, ");
sql.append("sp.parameter_name as paramName ");
sql.append("from stretchy_report sr ");
sql.append("left join stretchy_report_parameter as srp on srp.report_id = sr.id ");
sql.append("left join stretchy_parameter as sp on sp.id = srp.parameter_id ");
this.schema = sql.toString();
}
public String schema(){
return this.schema;
}
@Override
public List<EmailBusinessRulesData> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<EmailBusinessRulesData> emailBusinessRulesDataList = new ArrayList<EmailBusinessRulesData>();
EmailBusinessRulesData emailBusinessRulesData = null;
Map<Long,EmailBusinessRulesData> mapOfSameObjects = new HashMap<Long, EmailBusinessRulesData>();
while(rs.next()){
final Long id = rs.getLong("id");
emailBusinessRulesData = mapOfSameObjects.get(id);
if(emailBusinessRulesData == null){
final String reportName = rs.getString("reportName") ;
final String reportType = rs.getString("reportType");
final String reportSubType = rs.getString("reportSubType");
final String paramName = rs.getString("paramName");
final String paramLabel = rs.getString("paramLabel");
final String description = rs.getString("description");
Map<String,Object> hashMap = new HashMap<String, Object>();
hashMap.put(paramLabel,paramName);
emailBusinessRulesData = EmailBusinessRulesData.instance(id,reportName,reportType,hashMap,reportSubType,description);
mapOfSameObjects.put(id,emailBusinessRulesData);
//add to the list
emailBusinessRulesDataList.add(emailBusinessRulesData);
}
//add new paramType to the existing object
Map<String,Object> hashMap = new HashMap<String, Object>();
final String paramName = rs.getString("paramName");
final String paramLabel = rs.getString("paramLabel");
hashMap.put(paramLabel,paramName);
//get existing map and add new items to it
emailBusinessRulesData.getReportParamName().putAll(hashMap);
}
return emailBusinessRulesDataList;
}
}
@Override
public Collection<EmailBusinessRulesData> retrieveAll() {
final String searchType = "Email";
final String sql = "select " + this.businessRuleMapper.schema() + " where sr.report_type = ?";
return this.jdbcTemplate.query(sql, this.businessRuleMapper, searchType);
}
@Override
public EmailBusinessRulesData retrieveOneTemplate(Long resourceId) {
final String searchType = "Email";
final String sql = "select " + this.businessRuleMapper.schema() + " where sr.report_type = ? and sr.id = ?";
List<EmailBusinessRulesData> retrieveOne = this.jdbcTemplate.query(sql, this.businessRuleMapper, searchType,resourceId);
try{
EmailBusinessRulesData emailBusinessRulesData = retrieveOne.get(0);
return emailBusinessRulesData;
}
catch (final IndexOutOfBoundsException e){
throw new EmailBusinessRuleNotFound(resourceId);
}
}
@Override
public EmailCampaignData retrieveOne(Long resourceId) {
final Integer isVisible =1;
try{
final String sql = "select " + this.emailCampaignMapper.schema + " where ec.id = ? and ec.is_visible = ?";
return this.jdbcTemplate.queryForObject(sql, this.emailCampaignMapper, resourceId,isVisible);
} catch (final EmptyResultDataAccessException e) {
throw new EmailCampaignNotFound(resourceId);
}
}
@Override
public Collection<EmailCampaignData> retrieveAllCampaign() {
final Integer visible = 1;
final String sql = "select " + this.emailCampaignMapper.schema() + " where ec.is_visible = ?";
return this.jdbcTemplate.query(sql, this.emailCampaignMapper, visible);
}
@Override
public Collection<EmailCampaignData> retrieveAllScheduleActiveCampaign() {
final Integer scheduleCampaignType = EmailCampaignType.SCHEDULE.getValue();
final Integer statusEnum = EmailCampaignStatus.ACTIVE.getValue();
final Integer visible = 1;
final String sql = "select " + this.emailCampaignMapper.schema() + " where ec.status_enum = ? and ec.campaign_type = ? and ec.is_visible = ?";
return this.jdbcTemplate.query(sql,this.emailCampaignMapper, statusEnum,scheduleCampaignType,visible);
}
}
@@ -0,0 +1,801 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.domain.*;
import org.apache.fineract.infrastructure.dataqueries.exception.ReportNotFoundException;
import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
import org.apache.fineract.infrastructure.dataqueries.service.ReadReportingService;
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.FileSystemContentRepository;
import org.apache.fineract.infrastructure.reportmailingjob.helper.IPv4Helper;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailMessageWithAttachmentData;
import org.apache.fineract.infrastructure.campaigns.email.domain.*;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailCampaignMustBeClosedToBeDeletedException;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailCampaignMustBeClosedToEditException;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailCampaignNotFound;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.campaigns.email.data.PreviewCampaignMessage;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignValidator;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
import org.apache.fineract.useradministration.domain.AppUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import java.io.*;
import java.util.*;
@Service
public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampaignWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(EmailCampaignWritePlatformCommandHandlerImpl.class);
private final PlatformSecurityContext context;
private final EmailCampaignRepository emailCampaignRepository;
private final EmailCampaignValidator emailCampaignValidator;
private final EmailCampaignReadPlatformService emailCampaignReadPlatformService;
private final ReportRepository reportRepository;
private final EmailMessageRepository emailMessageRepository;
private final ClientRepositoryWrapper clientRepositoryWrapper;
private final ReadReportingService readReportingService;
private final GenericDataService genericDataService;
private final FromJsonHelper fromJsonHelper;
private final LoanRepository loanRepository;
private final SavingsAccountRepository savingsAccountRepository;
private final EmailMessageJobEmailService emailMessageJobEmailService;
@Autowired
public EmailCampaignWritePlatformCommandHandlerImpl(final PlatformSecurityContext context,
final EmailCampaignRepository emailCampaignRepository, final EmailCampaignValidator emailCampaignValidator,
final EmailCampaignReadPlatformService emailCampaignReadPlatformService, final ReportRepository reportRepository,
final EmailMessageRepository emailMessageRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
final ReadReportingService readReportingService, final GenericDataService genericDataService,
final FromJsonHelper fromJsonHelper, final LoanRepository loanRepository,
final SavingsAccountRepository savingsAccountRepository, final EmailMessageJobEmailService emailMessageJobEmailService) {
this.context = context;
this.emailCampaignRepository = emailCampaignRepository;
this.emailCampaignValidator = emailCampaignValidator;
this.emailCampaignReadPlatformService = emailCampaignReadPlatformService;
this.reportRepository = reportRepository;
this.emailMessageRepository = emailMessageRepository;
this.clientRepositoryWrapper = clientRepositoryWrapper;
this.readReportingService = readReportingService;
this.genericDataService = genericDataService;
this.fromJsonHelper = fromJsonHelper;
this.loanRepository = loanRepository;
this.savingsAccountRepository = savingsAccountRepository;
this.emailMessageJobEmailService = emailMessageJobEmailService;
}
@Transactional
@Override
public CommandProcessingResult create(JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.emailCampaignValidator.validateCreate(command.json());
final Long businessRuleId = command.longValueOfParameterNamed(EmailCampaignValidator.businessRuleId);
final Report businessRule = this.reportRepository.findOne(businessRuleId);
if (businessRule == null) { throw new ReportNotFoundException(businessRuleId); }
final Long reportId = command.longValueOfParameterNamed(EmailCampaignValidator.stretchyReportId);
final Report report = this.reportRepository.findOne(reportId);
if (report == null) { throw new ReportNotFoundException(reportId); }
// find all report parameters and store them as json string
final Set<ReportParameterUsage> reportParameterUsages = report.getReportParameterUsages();
final Map<String, String> stretchyReportParams = new HashMap<>();
if (reportParameterUsages != null && !reportParameterUsages.isEmpty()) {
for (final ReportParameterUsage reportParameterUsage : reportParameterUsages) {
stretchyReportParams.put(reportParameterUsage.getReportParameterName(), "");
}
}
EmailCampaign emailCampaign = EmailCampaign.instance(currentUser, businessRule, report, command);
emailCampaign.setStretchyReportParamMap(new Gson().toJson(stretchyReportParams));
this.emailCampaignRepository.save(emailCampaign);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(emailCampaign.getId()) //
.build();
}
@Transactional
@Override
public CommandProcessingResult update(final Long resourceId, final JsonCommand command) {
try {
this.context.authenticatedUser();
this.emailCampaignValidator.validateForUpdate(command.json());
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(resourceId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(resourceId); }
if (emailCampaign.isActive()) { throw new EmailCampaignMustBeClosedToEditException(emailCampaign.getId()); }
final Map<String, Object> changes = emailCampaign.update(command);
if (changes.containsKey(EmailCampaignValidator.businessRuleId)) {
final Long newValue = command.longValueOfParameterNamed(EmailCampaignValidator.businessRuleId);
final Report reportId = this.reportRepository.findOne(newValue);
if (reportId == null) { throw new ReportNotFoundException(newValue); }
emailCampaign.updateBusinessRuleId(reportId);
}
if (!changes.isEmpty()) {
this.emailCampaignRepository.saveAndFlush(emailCampaign);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(resourceId) //
.with(changes) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult delete(final Long resourceId) {
this.context.authenticatedUser();
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(resourceId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(resourceId); }
if (emailCampaign.isActive()) { throw new EmailCampaignMustBeClosedToBeDeletedException(emailCampaign.getId()); }
/*
* Do not delete but set a boolean is_visible to zero
*/
emailCampaign.delete();
this.emailCampaignRepository.saveAndFlush(emailCampaign);
return new CommandProcessingResultBuilder() //
.withEntityId(emailCampaign.getId()) //
.build();
}
private void insertDirectCampaignIntoEmailOutboundTable(final String emailParams, final String emailSubject,
final String messageTemplate, final String campaignName, final Long campaignId) {
try {
HashMap<String, String> campaignParams = new ObjectMapper().readValue(emailParams,
new TypeReference<HashMap<String, String>>() {});
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(emailParams,
new TypeReference<HashMap<String, String>>() {});
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
queryParamForRunReport);
if (runReportObject != null) {
for (HashMap<String, Object> entry : runReportObject) {
String message = this.compileEmailTemplate(messageTemplate, campaignName, entry);
Integer clientId = (Integer) entry.get("id");
EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(campaignId);
Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId.longValue());
String emailAddress = client.emailAddress();
if (emailAddress != null && isValidEmail(emailAddress)) {
EmailMessage emailMessage = EmailMessage.pendingEmail(null, client, null, emailCampaign, emailSubject, message,
emailAddress, campaignName);
this.emailMessageRepository.save(emailMessage);
}
}
}
} catch (final IOException e) {
// TODO throw something here
}
}
public static boolean isValidEmail(String email) {
boolean isValid = true;
try {
InternetAddress emailO = new InternetAddress(email);
emailO.validate();
} catch (AddressException ex) {
isValid = false;
}
return isValid;
}
@Override
@CronTarget(jobName = JobName.UPDATE_EMAIL_OUTBOUND_WITH_CAMPAIGN_MESSAGE)
public void storeTemplateMessageIntoEmailOutBoundTable() throws JobExecutionException {
final Collection<EmailCampaignData> emailCampaignDataCollection = this.emailCampaignReadPlatformService
.retrieveAllScheduleActiveCampaign();
if (emailCampaignDataCollection != null) {
for (EmailCampaignData emailCampaignData : emailCampaignDataCollection) {
LocalDateTime tenantDateNow = tenantDateTime();
LocalDateTime nextTriggerDate = emailCampaignData.getNextTriggerDate().toLocalDateTime();
logger.info("tenant time " + tenantDateNow.toString() + " trigger time " + nextTriggerDate.toString());
if (nextTriggerDate.isBefore(tenantDateNow)) {
insertDirectCampaignIntoEmailOutboundTable(emailCampaignData.getParamValue(), emailCampaignData.getEmailSubject(),
emailCampaignData.getMessage(), emailCampaignData.getCampaignName(), emailCampaignData.getId());
this.updateTriggerDates(emailCampaignData.getId());
}
}
}
}
private void updateTriggerDates(Long campaignId) {
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(campaignId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(campaignId); }
LocalDateTime nextTriggerDate = emailCampaign.getNextTriggerDate();
emailCampaign.setLastTriggerDate(nextTriggerDate.toDate());
// calculate new trigger date and insert into next trigger date
/**
* next run time has to be in the future if not calculate a new future
* date
*/
LocalDate nextRuntime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(),
emailCampaign.getNextTriggerDate().toLocalDate(), nextTriggerDate.toLocalDate());
if (nextRuntime.isBefore(DateUtils.getLocalDateOfTenant())) { // means
// next
// run
// time is
// in the
// past
// calculate
// a new
// future
// date
nextRuntime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(),
emailCampaign.getNextTriggerDate().toLocalDate(), DateUtils.getLocalDateOfTenant());
}
final LocalDateTime getTime = emailCampaign.getRecurrenceStartDateTime();
final String dateString = nextRuntime.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
+ getTime.getSecondOfMinute();
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
final LocalDateTime newTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
emailCampaign.setNextTriggerDate(newTriggerDateWithTime.toDate());
this.emailCampaignRepository.saveAndFlush(emailCampaign);
}
@Transactional
@Override
public CommandProcessingResult activateEmailCampaign(Long campaignId, JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.emailCampaignValidator.validateActivation(command.json());
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(campaignId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(campaignId); }
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
emailCampaign.activate(currentUser, fmt, activationDate);
this.emailCampaignRepository.saveAndFlush(emailCampaign);
if (emailCampaign.isDirect()) {
insertDirectCampaignIntoEmailOutboundTable(emailCampaign.getParamValue(), emailCampaign.getEmailSubject(),
emailCampaign.getEmailMessage(), emailCampaign.getCampaignName(), emailCampaign.getId());
} else {
if (emailCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next
* trigger date if not use recurrence start date us next trigger
* date when activating
*/
LocalDate nextTriggerDate = null;
if (emailCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(),
emailCampaign.getRecurrenceStartDate(), DateUtils.getLocalDateOfTenant());
} else {
nextTriggerDate = emailCampaign.getRecurrenceStartDate();
}
// to get time of tenant
final LocalDateTime getTime = emailCampaign.getRecurrenceStartDateTime();
final String dateString = nextTriggerDate.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
+ getTime.getSecondOfMinute();
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
final LocalDateTime nextTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
emailCampaign.setNextTriggerDate(nextTriggerDateWithTime.toDate());
this.emailCampaignRepository.saveAndFlush(emailCampaign);
}
}
/*
* if campaign is direct insert campaign message into email outbound
* table else if its a schedule create a job process for it
*/
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(emailCampaign.getId()) //
.build();
}
@Transactional
@Override
public CommandProcessingResult closeEmailCampaign(Long campaignId, JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.emailCampaignValidator.validateClosedDate(command.json());
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(campaignId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(campaignId); }
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate closureDate = command.localDateValueOfParameterNamed("closureDate");
emailCampaign.close(currentUser, fmt, closureDate);
this.emailCampaignRepository.saveAndFlush(emailCampaign);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(emailCampaign.getId()) //
.build();
}
private String compileEmailTemplate(final String textMessageTemplate, final String campaignName,
final Map<String, Object> emailParams) {
final MustacheFactory mf = new DefaultMustacheFactory();
final Mustache mustache = mf.compile(new StringReader(textMessageTemplate), campaignName);
final StringWriter stringWriter = new StringWriter();
mustache.execute(stringWriter, emailParams);
return stringWriter.toString();
}
@SuppressWarnings({ "unused", "rawtypes" })
private List<HashMap<String, Object>> getRunReportByServiceImpl(final String reportName, final Map<String, String> queryParams)
throws IOException {
final String reportType = "report";
List<HashMap<String, Object>> resultList = new ArrayList<HashMap<String, Object>>();
final GenericResultsetData results = this.readReportingService.retrieveGenericResultSetForSmsEmailCampaign(reportName, reportType,
queryParams);
final String response = this.genericDataService.generateJsonFromGenericResultsetData(results);
resultList = new ObjectMapper().readValue(response, new TypeReference<List<HashMap<String, Object>>>() {});
// loop changes array date to string date
for (HashMap<String, Object> entry : resultList) {
for (Map.Entry<String, Object> map : entry.entrySet()) {
String key = map.getKey();
Object ob = map.getValue();
if (ob instanceof ArrayList && ((ArrayList) ob).size() == 3) {
String changeArrayDateToStringDate = ((ArrayList) ob).get(2).toString() + "-" + ((ArrayList) ob).get(1).toString() + "-"
+ ((ArrayList) ob).get(0).toString();
entry.put(key, changeArrayDateToStringDate);
}
}
}
return resultList;
}
@Override
public PreviewCampaignMessage previewMessage(final JsonQuery query) {
PreviewCampaignMessage campaignMessage = null;
this.context.authenticatedUser();
this.emailCampaignValidator.validatePreviewMessage(query.json());
final String emailParams = this.fromJsonHelper.extractStringNamed("paramValue", query.parsedJson());
final String textMessageTemplate = this.fromJsonHelper.extractStringNamed("emailMessage", query.parsedJson());
try {
HashMap<String, String> campaignParams = new ObjectMapper().readValue(emailParams,
new TypeReference<HashMap<String, String>>() {});
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(emailParams,
new TypeReference<HashMap<String, String>>() {});
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
queryParamForRunReport);
if (runReportObject != null) {
for (HashMap<String, Object> entry : runReportObject) {
// add string object to campaignParam object
String textMessage = this.compileEmailTemplate(textMessageTemplate, "EmailCampaign", entry);
if (!textMessage.isEmpty()) {
final Integer totalMessage = runReportObject.size();
campaignMessage = new PreviewCampaignMessage(textMessage, totalMessage);
break;
}
}
}
} catch (final IOException e) {
// TODO throw something here
}
return campaignMessage;
}
@Transactional
@Override
public CommandProcessingResult reactivateEmailCampaign(final Long campaignId, JsonCommand command) {
this.emailCampaignValidator.validateActivation(command.json());
final AppUser currentUser = this.context.authenticatedUser();
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(campaignId);
if (emailCampaign == null) { throw new EmailCampaignNotFound(campaignId); }
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate reactivationDate = command.localDateValueOfParameterNamed("activationDate");
emailCampaign.reactivate(currentUser, fmt, reactivationDate);
if (emailCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next trigger
* date if not use recurrence start date us next trigger date when
* activating
*/
LocalDate nextTriggerDate = null;
if (emailCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), emailCampaign.getRecurrenceStartDate(),
DateUtils.getLocalDateOfTenant());
} else {
nextTriggerDate = emailCampaign.getRecurrenceStartDate();
}
// to get time of tenant
final LocalDateTime getTime = emailCampaign.getRecurrenceStartDateTime();
final String dateString = nextTriggerDate.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
+ getTime.getSecondOfMinute();
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
final LocalDateTime nextTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
emailCampaign.setNextTriggerDate(nextTriggerDateWithTime.toDate());
this.emailCampaignRepository.saveAndFlush(emailCampaign);
}
return new CommandProcessingResultBuilder() //
.withEntityId(emailCampaign.getId()) //
.build();
}
private void handleDataIntegrityIssues(@SuppressWarnings("unused") final JsonCommand command,
final DataIntegrityViolationException dve) {
final Throwable realCause = dve.getMostSpecificCause();
throw new PlatformDataIntegrityException("error.msg.email.campaign.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
private LocalDateTime tenantDateTime() {
LocalDateTime today = new LocalDateTime();
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final DateTimeZone zone = DateTimeZone.forID(tenant.getTimezoneId());
if (zone != null) {
today = new LocalDateTime(zone);
}
}
return today;
}
@Override
@CronTarget(jobName = JobName.EXECUTE_EMAIL)
public void sendEmailMessage() throws JobExecutionException {
if (IPv4Helper.applicationIsNotRunningOnLocalMachine()) { // remove when
// testing
// locally
final List<EmailMessage> emailMessages = this.emailMessageRepository
.findByStatusType(EmailMessageStatusType.PENDING.getValue()); // retrieve
// all
// pending
// message
for (final EmailMessage emailMessage : emailMessages) {
if (isValidEmail(emailMessage.getEmailAddress())) {
final EmailCampaign emailCampaign = this.emailCampaignRepository.findOne(emailMessage.getEmailCampaign().getId()); //
final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat
.instance(emailCampaign.getEmailAttachmentFileFormat());
final List<File> attachmentList = new ArrayList<>();
final StringBuilder errorLog = new StringBuilder();
// check if email attachment format exist
if (emailAttachmentFileFormat != null && Arrays.asList(ScheduledEmailAttachmentFileFormat.validValues())
.contains(emailAttachmentFileFormat.getId())) {
final Report stretchyReport = emailCampaign.getStretchyReport();
final String reportName = (stretchyReport != null) ? stretchyReport.getReportName() : null;
final HashMap<String, String> reportStretchyParams = this
.validateStretchyReportParamMap(emailCampaign.getStretchyReportParamMap());
// there is a probability that a client has one or more
// loans or savings therefore we need to send two or
// more attachments
if (reportStretchyParams.containsKey("selectLoan") || reportStretchyParams.containsKey("loanId")) {
// get all ids of the client loans
if (emailMessage.getClient() != null) {
final List<Loan> loans = this.loanRepository.findLoanByClientId(emailMessage.getClient().getId());
HashMap<String, String> reportParams = this
.replaceStretchyParamsWithActualClientParams(reportStretchyParams, emailMessage.getClient());
for (final Loan loan : loans) {
if (loan.isOpen()) { // only send attachment
// for active loan
if (reportStretchyParams.containsKey("selectLoan")) {
reportParams.put("SelectLoan", loan.getId().toString());
} else if (reportStretchyParams.containsKey("loanId")) {
reportParams.put("loanId", loan.getId().toString());
}
File file = this.generateAttachments(emailCampaign, emailAttachmentFileFormat, reportParams,
reportName, errorLog);
if (file != null) {
attachmentList.add(file);
} else {
errorLog.append(reportParams.toString());
}
}
}
}
} else if (reportStretchyParams.containsKey("savingId")) {
if (emailMessage.getClient() != null) {
final List<SavingsAccount> savingsAccounts = this.savingsAccountRepository
.findSavingAccountByClientId(emailMessage.getClient().getId());
HashMap<String, String> reportParams = this
.replaceStretchyParamsWithActualClientParams(reportStretchyParams, emailMessage.getClient());
for (final SavingsAccount savingsAccount : savingsAccounts) {
if (savingsAccount.isActive()) {
reportParams.put("savingId", savingsAccount.getId().toString());
File file = this.generateAttachments(emailCampaign, emailAttachmentFileFormat, reportParams,
reportName, errorLog);
if (file != null) {
attachmentList.add(file);
} else {
errorLog.append(reportParams.toString());
}
}
}
}
} else {
if (emailMessage.getClient() != null) {
HashMap<String, String> reportParams = this
.replaceStretchyParamsWithActualClientParams(reportStretchyParams, emailMessage.getClient());
File file = this.generateAttachments(emailCampaign, emailAttachmentFileFormat, reportParams, reportName,
errorLog);
if (file != null) {
attachmentList.add(file);
} else {
errorLog.append(reportParams.toString());
}
}
}
}
final EmailMessageWithAttachmentData emailMessageWithAttachmentData = EmailMessageWithAttachmentData.createNew(
emailMessage.getEmailAddress(), emailMessage.getMessage(), emailMessage.getEmailSubject(), attachmentList);
if (!attachmentList.isEmpty() && attachmentList.size() > 0) { // only
// send
// email
// message
// if
// there
// is
// an
// attachment
// to
// it
this.emailMessageJobEmailService.sendEmailWithAttachment(emailMessageWithAttachmentData);
emailMessage.setStatusType(EmailMessageStatusType.SENT.getValue());
this.emailMessageRepository.save(emailMessage);
} else {
emailMessage.updateErrorMessage(errorLog.toString());
emailMessage.setStatusType(EmailMessageStatusType.FAILED.getValue());
this.emailMessageRepository.save(emailMessage);
}
}
}
}
}
/**
* This generates the the report and converts it to a file by passing the
* parameters below
*
* @param emailCampaign
* @param emailAttachmentFileFormat
* @param reportParams
* @param reportName
* @param errorLog
* @return
*/
private File generateAttachments(final EmailCampaign emailCampaign, final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat,
final Map<String, String> reportParams, final String reportName, final StringBuilder errorLog) {
try {
final ByteArrayOutputStream byteArrayOutputStream = this.readReportingService.generatePentahoReportAsOutputStream(reportName,
emailAttachmentFileFormat.getValue(), reportParams, null, emailCampaign.getApprovedBy(), errorLog);
final String fileLocation = FileSystemContentRepository.FINERACT_BASE_DIR + File.separator + "";
final String fileNameWithoutExtension = fileLocation + File.separator + reportName;
// check if file directory exists, if not create directory
if (!new File(fileLocation).isDirectory()) {
new File(fileLocation).mkdirs();
}
if (byteArrayOutputStream.size() == 0) {
errorLog.append("Pentaho report processing failed, empty output stream created");
} else if (errorLog.length() == 0 && (byteArrayOutputStream.size() > 0)) {
final String fileName = fileNameWithoutExtension + "." + emailAttachmentFileFormat.getValue();
final File file = new File(fileName);
final FileOutputStream outputStream = new FileOutputStream(file);
byteArrayOutputStream.writeTo(outputStream);
return file;
}
} catch (IOException | PlatformDataIntegrityException e) {
errorLog.append("The ReportMailingJobWritePlatformServiceImpl.executeReportMailingJobs threw an IOException " + "exception: "
+ e.getMessage() + " ---------- ");
}
return null;
}
/**
* This matches the the actual values to the key in the report stretchy
* parameters map
*
* @param stretchyParams
* @param client
* @return
*/
private HashMap<String, String> replaceStretchyParamsWithActualClientParams(final HashMap<String, String> stretchyParams,
final Client client) {
HashMap<String, String> actualParams = new HashMap<>();
for (Map.Entry<String, String> entry : stretchyParams.entrySet()) {
if (entry.getKey().equals("selectOffice")) {
// most at times the reports are run by picking the office of
// the staff Id
if (client.getStaff() != null) {
actualParams.put(entry.getKey(), client.getStaff().officeId().toString());
} else {
actualParams.put(entry.getKey(), client.getOffice().getId().toString());
}
} else if (entry.getKey().equals("selectClient")) {
actualParams.put(entry.getKey(), client.getId().toString());
} else if (entry.getKey().equals("selectLoanofficer")) {
actualParams.put(entry.getKey(), client.getStaff().getId().toString());
} else if (entry.getKey().equals("environementUrl")) {
actualParams.put(entry.getKey(), entry.getKey());
}
}
return actualParams;
}
private HashMap<String, String> validateStretchyReportParamMap(final String stretchyParams) {
HashMap<String, String> stretchyReportParamHashMap = new HashMap<>();
if (!StringUtils.isEmpty(stretchyParams)) {
try {
stretchyReportParamHashMap = new ObjectMapper().readValue(stretchyParams, new TypeReference<HashMap<String, String>>() {});
}
catch (Exception e) {
stretchyReportParamHashMap = null;
}
}
return stretchyReportParamHashMap;
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.campaigns.email.data.PreviewCampaignMessage;
public interface EmailCampaignWritePlatformService {
CommandProcessingResult create(JsonCommand command);
CommandProcessingResult update(Long resourceId, JsonCommand command);
CommandProcessingResult delete(Long resourceId);
CommandProcessingResult activateEmailCampaign(Long campaignId, JsonCommand command);
CommandProcessingResult closeEmailCampaign(Long campaignId, JsonCommand command);
CommandProcessingResult reactivateEmailCampaign(Long campaignId, JsonCommand command);
void storeTemplateMessageIntoEmailOutBoundTable() throws JobExecutionException;
PreviewCampaignMessage previewMessage(JsonQuery query);
void sendEmailMessage() throws JobExecutionException;
}
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailConfigurationData;
import java.util.Collection;
public interface EmailConfigurationReadPlatformService {
Collection<EmailConfigurationData> retrieveAll();
EmailConfigurationData retrieveOne(String name);
}
@@ -0,0 +1,99 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailConfigurationNotFoundException;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailConfigurationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
@Service
public class EmailConfigurationReadPlatformServiceImpl implements EmailConfigurationReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final EmailConfigurationRowMapper emailConfigurationRowMapper;
@Autowired
public EmailConfigurationReadPlatformServiceImpl(final RoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.emailConfigurationRowMapper = new EmailConfigurationRowMapper();
}
private static final class EmailConfigurationRowMapper implements RowMapper<EmailConfigurationData> {
final String schema;
public EmailConfigurationRowMapper() {
final StringBuilder sql = new StringBuilder(300);
sql.append("cnf.id as id, ");
sql.append("cnf.name as name, ");
sql.append("cnf.value as value ");
sql.append("from scheduled_email_configuration cnf");
this.schema = sql.toString();
}
public String schema() {
return this.schema;
}
@Override
public EmailConfigurationData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final String name = rs.getString("name");
final String value = rs.getString("value");
return EmailConfigurationData.instance(id, name, value);
}
}
@Override
public Collection<EmailConfigurationData> retrieveAll() {
final String sql = "select " + this.emailConfigurationRowMapper.schema();
return this.jdbcTemplate.query(sql, this.emailConfigurationRowMapper, new Object[] {});
}
@Override
public EmailConfigurationData retrieveOne(String name) {
try {
final String sql = "select " + this.emailConfigurationRowMapper.schema() + " where cnf.name = ?";
return this.jdbcTemplate.queryForObject(sql, this.emailConfigurationRowMapper, name);
}
catch(final EmptyResultDataAccessException e) {
throw new EmailConfigurationNotFoundException(name);
}
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
public interface EmailConfigurationWritePlatformService {
CommandProcessingResult update(JsonCommand command);
}
@@ -0,0 +1,89 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import com.google.gson.JsonElement;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailConfigurationData;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailConfigurationValidator;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfiguration;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfigurationRepository;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailConfigurationSMTPUsernameNotValid;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Service
public class EmailConfigurationWritePlatformServiceImpl implements EmailConfigurationWritePlatformService {
private final PlatformSecurityContext context;
private final EmailConfigurationRepository repository;
private final EmailConfigurationValidator emailConfigurationValidator;
@Autowired
public EmailConfigurationWritePlatformServiceImpl(final PlatformSecurityContext context, final EmailConfigurationRepository repository,
final EmailConfigurationValidator emailConfigurationValidator) {
this.context = context;
this.repository = repository;
this.emailConfigurationValidator = emailConfigurationValidator;
}
@Override
public CommandProcessingResult update(final JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.emailConfigurationValidator.validateUpdateConfiguration(command.json());
final String smtpUsername = command.stringValueOfParameterNamed("SMTP_USERNAME");
if(!this.emailConfigurationValidator.isValidEmail(smtpUsername)){
throw new EmailConfigurationSMTPUsernameNotValid(smtpUsername);
}
final Map<String,Object> changes = new HashMap<>(4);
Collection<EmailConfiguration> configurations = this.repository.findAll();
/**
*Default SMTP configuration added to flyway
*/
for (EmailConfiguration config : configurations) {
if(config.getName() !=null){
String value = command.stringValueOfParameterNamed(config.getName());
config.setValue(value); changes.put(config.getName(),value);
this.repository.saveAndFlush(config);
}
}
return new CommandProcessingResultBuilder() //
.with(changes)
.build();
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailMessageWithAttachmentData;
public interface EmailMessageJobEmailService {
void sendEmailWithAttachment(EmailMessageWithAttachmentData emailMessageWithAttachmentData);
}
@@ -0,0 +1,110 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailMessageWithAttachmentData;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfiguration;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfigurationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.List;
import java.util.Properties;
import java.util.Set;
@Service
public class EmailMessageJobEmailServiceImpl implements EmailMessageJobEmailService {
private EmailConfigurationRepository emailConfigurationRepository;
@Autowired
private EmailMessageJobEmailServiceImpl(final EmailConfigurationRepository emailConfigurationRepository) {
this.emailConfigurationRepository = emailConfigurationRepository;
}
@Override
public void sendEmailWithAttachment(EmailMessageWithAttachmentData emailMessageWithAttachmentData) {
try{
JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl();
javaMailSenderImpl.setHost(this.getGmailSmtpServer());
javaMailSenderImpl.setPort(this.getGmailSmtpPort());
javaMailSenderImpl.setUsername(this.getGmailSmtpUsername());
javaMailSenderImpl.setPassword(this.getGmailSmtpPassword());
javaMailSenderImpl.setJavaMailProperties(this.getJavaMailProperties());
MimeMessage mimeMessage = javaMailSenderImpl.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setTo(emailMessageWithAttachmentData.getTo());
mimeMessageHelper.setText(emailMessageWithAttachmentData.getText());
mimeMessageHelper.setSubject(emailMessageWithAttachmentData.getSubject());
final List<File> attachments = emailMessageWithAttachmentData.getAttachments();
if(attachments !=null && attachments.size() > 0){
for(final File attachment : attachments){
if(attachment !=null){
mimeMessageHelper.addAttachment(attachment.getName(),attachment);
}
}
}
javaMailSenderImpl.send(mimeMessage);
}catch(MessagingException e){
}
}
private String getGmailSmtpServer(){
final EmailConfiguration gmailSmtpServer = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_SERVER);
return (gmailSmtpServer !=null) ? gmailSmtpServer.getValue() : null;
}
private Integer getGmailSmtpPort(){
final EmailConfiguration gmailSmtpPort = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_PORT);
return (gmailSmtpPort !=null) ? Integer.parseInt(gmailSmtpPort.getValue()) : null;
}
private String getGmailSmtpUsername(){
final EmailConfiguration gmailSmtpUsername = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_USERNAME);
return (gmailSmtpUsername !=null) ? gmailSmtpUsername.getValue() : null;
}
private String getGmailSmtpPassword(){
final EmailConfiguration gmailSmtpPassword = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_PASSWORD);
return (gmailSmtpPassword !=null) ? gmailSmtpPassword.getValue() : null;
}
private Properties getJavaMailProperties() {
Properties properties = new Properties();
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.smtp.auth", "true");
properties.setProperty("mail.smtp.ssl.trust", this.getGmailSmtpServer());
return properties;
}
}
@@ -0,0 +1,46 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailData;
import java.util.Collection;
import java.util.Date;
import java.util.List;
public interface EmailReadPlatformService {
Collection<EmailData> retrieveAll();
EmailData retrieveOne(Long resourceId);
Collection<EmailData> retrieveAllPending(final SearchParameters searchParameters);
Collection<EmailData> retrieveAllSent(final SearchParameters searchParameters);
Collection<EmailData> retrieveAllDelivered(Integer limit);
Collection<EmailData> retrieveAllFailed(final SearchParameters searchParameters);
Page<EmailData> retrieveEmailByStatus(Integer limit, Integer status, Date dateFrom, Date dateTo);
List<Long> retrieveExternalIdsOfAllSent(Integer limit);
}
@@ -0,0 +1,200 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.joda.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailNotFoundException;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailData;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessageEnumerations;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessageStatusType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@Service
public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final EmailMapper emailRowMapper = new EmailMapper();
private final PaginationHelper<EmailData> paginationHelper = new PaginationHelper<>();
@Autowired
public EmailReadPlatformServiceImpl(final RoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private static final class EmailMapper implements RowMapper<EmailData> {
final String schema;
public EmailMapper() {
final StringBuilder sql = new StringBuilder(300);
sql.append(" emo.id as id, ");
sql.append("emo.group_id as groupId, ");
sql.append("emo.client_id as clientId, ");
sql.append("emo.staff_id as staffId, ");
sql.append("emo.campaign_name as campaignName, ");
sql.append("emo.status_enum as statusId, ");
sql.append("emo.email_address as emailAddress, ");
sql.append("emo.submittedon_date as sentDate, ");
sql.append("emo.email_subject as emailSubject, ");
sql.append("emo.message as message, ");
sql.append("emo.error_message as errorMessage ");
sql.append("from " + tableName() + " emo");
this.schema = sql.toString();
}
public String schema() {
return this.schema;
}
public String tableName() {
return "scheduled_email_messages_outbound";
}
@Override
public EmailData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final Long groupId = JdbcSupport.getLong(rs, "groupId");
final Long clientId = JdbcSupport.getLong(rs, "clientId");
final Long staffId = JdbcSupport.getLong(rs, "staffId");
final String emailAddress = rs.getString("emailAddress");
final String emailSubject = rs.getString("emailSubject");
final String message = rs.getString("message");
final String campaignName = rs.getString("campaignName");
final Integer statusId = JdbcSupport.getInteger(rs, "statusId");
final LocalDate sentDate = JdbcSupport.getLocalDate(rs, "sentDate");
final String errorMessage = rs.getString("errorMessage");
final EnumOptionData status = EmailMessageEnumerations.status(statusId);
return EmailData.instance(id,groupId, clientId, staffId, status, emailAddress, emailSubject,
message,null,null,null,null,null,campaignName,sentDate,errorMessage);
}
}
@Override
public Collection<EmailData> retrieveAll() {
final String sql = "select " + this.emailRowMapper.schema();
return this.jdbcTemplate.query(sql, this.emailRowMapper, new Object[] {});
}
@Override
public EmailData retrieveOne(final Long resourceId) {
try {
final String sql = "select " + this.emailRowMapper.schema() + " where emo.id = ?";
return this.jdbcTemplate.queryForObject(sql, this.emailRowMapper, resourceId);
} catch (final EmptyResultDataAccessException e) {
throw new EmailNotFoundException(resourceId);
}
}
@Override
public Collection<EmailData> retrieveAllPending(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = "
+ EmailMessageStatusType.PENDING.getValue() + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, new Object[] {});
}
@Override
public Collection<EmailData> retrieveAllSent(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = "
+ EmailMessageStatusType.SENT.getValue() + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, new Object[] {});
}
@Override
public List<Long> retrieveExternalIdsOfAllSent(final Integer limit) {
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
final String sql = "select external_id from " + this.emailRowMapper.tableName() + " where status_enum = "
+ EmailMessageStatusType.SENT.getValue() + sqlPlusLimit;
return this.jdbcTemplate.queryForList(sql, Long.class);
}
@Override
public Collection<EmailData> retrieveAllDelivered(final Integer limit) {
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = "
+ EmailMessageStatusType.DELIVERED.getValue() + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, new Object[] {});
}
@Override
public Collection<EmailData> retrieveAllFailed(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = "
+ EmailMessageStatusType.FAILED.getValue() + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, new Object[] {});
}
@Override
public Page<EmailData> retrieveEmailByStatus(final Integer limit, final Integer status,final Date dateFrom, final Date dateTo) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.emailRowMapper.schema());
if(status !=null){
sqlBuilder.append(" where emo.status_enum= ? ");
}
String fromDateString = null;
String toDateString = null;
if(dateFrom !=null && dateTo !=null){
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
fromDateString = df.format(dateFrom);
toDateString = df.format(dateTo);
sqlBuilder.append(" and emo.submittedon_date >= ? and emo.submittedon_date <= ? ");
}
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
if(!sqlPlusLimit.isEmpty()){
sqlBuilder.append(sqlPlusLimit);
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate,sqlCountRows,sqlBuilder.toString(),new Object[]{status,fromDateString,toDateString},this.emailRowMapper);
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
public interface EmailWritePlatformService {
CommandProcessingResult create(JsonCommand command);
CommandProcessingResult update(Long resourceId, JsonCommand command);
CommandProcessingResult delete(Long resourceId);
}
@@ -0,0 +1,134 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.campaigns.email.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailDataValidator;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessage;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessageAssembler;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessageRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
@Service
public class EmailWritePlatformServiceJpaRepositoryImpl implements EmailWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(EmailWritePlatformServiceJpaRepositoryImpl.class);
private final EmailMessageAssembler assembler;
private final EmailMessageRepository repository;
private final EmailDataValidator validator;
@Autowired
public EmailWritePlatformServiceJpaRepositoryImpl(final EmailMessageAssembler assembler, final EmailMessageRepository repository,
final EmailDataValidator validator) {
this.assembler = assembler;
this.repository = repository;
this.validator = validator;
}
@Transactional
@Override
public CommandProcessingResult create(final JsonCommand command) {
try {
this.validator.validateCreateRequest(command);
final EmailMessage message = this.assembler.assembleFromJson(command);
// TODO: at this point we also want to fire off request using third
// party service to send Email.
// TODO: decision to be made on wheter we 'wait' for response or use
// 'future/promise' to capture response and update the EmailMessage
// table
this.repository.save(message);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(message.getId()) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult update(final Long resourceId, final JsonCommand command) {
try {
this.validator.validateUpdateRequest(command);
final EmailMessage message = this.assembler.assembleFromResourceId(resourceId);
final Map<String, Object> changes = message.update(command);
if (!changes.isEmpty()) {
this.repository.save(message);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(resourceId) //
.with(changes) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult delete(final Long resourceId) {
try {
final EmailMessage message = this.assembler.assembleFromResourceId(resourceId);
this.repository.delete(message);
this.repository.flush();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(null, dve);
return CommandProcessingResult.empty();
}
return new CommandProcessingResultBuilder().withEntityId(resourceId).build();
}
/*
* Guaranteed to throw an exception no matter what the data integrity issue
* is.
*/
private void handleDataIntegrityIssues(@SuppressWarnings("unused") final JsonCommand command, final DataIntegrityViolationException dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("email_address")) { throw new PlatformDataIntegrityException("error.msg.email.no.email.address.exists",
"The group, client or staff provided has no email address.", "id"); }
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.email.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
}
@@ -137,7 +137,7 @@ public class SmsCampaignApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@ApiOperation(value = "List SMS Campaigns", notes = "Example Requests:\n" + "\n" + "smscampaigns")
@ApiResponse(code = 200, message = "", response = SmsCampaignData.class)
public String retrieveAllCampaigns(@QueryParam("sqlSearch") final String sqlSearch,
public String retrieveAllEmails(@QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
this.platformSecurityContext.authenticatedUser().validateHasReadPermission(SmsCampaignConstants.RESOURCE_NAME);
@@ -61,6 +61,9 @@ public class SmsCampaignEnumerations {
case SMS:
optionData = new EnumOptionData(CampaignType.SMS.getValue().longValue(), CampaignType.SMS.getCode(), "SMS");
break;
case NOTIFICATION:
optionData = new EnumOptionData(CampaignType.NOTIFICATION.getValue().longValue(), CampaignType.NOTIFICATION.getCode(), "NOTIFICATION");
break;
}
return optionData;
}
@@ -44,6 +44,8 @@ public class SmsCampaignData {
private final DateTime recurrenceStartDate;
private final String recurrence;
private final Long providerId;
private final boolean isNotification;
private final Collection<SmsProviderData> smsProviderOptions;
@@ -70,7 +72,7 @@ public class SmsCampaignData {
final Collection<SmsProviderData> smsProviderOptions, final Collection<EnumOptionData> campaignTypeOptions,
final Collection<EnumOptionData> triggerTypeOptions, final Collection<EnumOptionData> months,
final Collection<EnumOptionData> weekDays, final Collection<EnumOptionData> frequencyTypeOptions,
final Collection<EnumOptionData> periodFrequencyOptions) {
final Collection<EnumOptionData> periodFrequencyOptions, final boolean isNotification) {
this.id = id;
this.campaignName = campaignName;
this.campaignType = campaignType;
@@ -90,6 +92,7 @@ public class SmsCampaignData {
} else {
this.lastTriggerDate = null;
}
this.isNotification = isNotification;
this.smsCampaignTimeLine = smsCampaignTimeLine;
this.recurrenceStartDate = recurrenceStartDate;
this.recurrence = recurrence;
@@ -109,7 +112,7 @@ public class SmsCampaignData {
final Long runReportId, final String reportName, final String paramValue, final EnumOptionData campaignStatus,
final String message, final DateTime nextTriggerDate, final LocalDate lastTriggerDate,
final SmsCampaignTimeLine smsCampaignTimeLine, final DateTime recurrenceStartDate, final String recurrence,
final Long providerId) {
final Long providerId, final boolean isNotification) {
final Collection<SmsBusinessRulesData> businessRulesOptions = null;
final Collection<SmsProviderData> smsProviderOptions = null;
final Collection<EnumOptionData> campaignTypeOptions = null;
@@ -122,7 +125,7 @@ public class SmsCampaignData {
return new SmsCampaignData(id, campaignName, campaignType, triggerType, runReportId,
reportName, paramValue, campaignStatus, message, nextTriggerDate, lastTriggerDate, smsCampaignTimeLine,
recurrenceStartDate, recurrence, providerId, businessRulesOptions, smsProviderOptions, campaignTypeOptions,
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions);
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions, isNotification);
}
public static SmsCampaignData template(final Collection<SmsProviderData> smsProviderOptions,
@@ -145,10 +148,11 @@ public class SmsCampaignData {
final EnumOptionData triggerType = null;
final String reportName = null;
final Long providerId = null;
final boolean isNotification = false;
return new SmsCampaignData(id, campaignName, campaignType, triggerType, runReportId,
reportName, paramValue, campaignStatus, message, nextTriggerDate, lastTriggerDate, smsCampaignTimeLine,
recurrenceStartDate, recurrence, providerId, businessRulesOptions, smsProviderOptions, campaignTypeOptions,
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions);
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions, isNotification);
}
public Long getId() {
@@ -203,4 +207,8 @@ public class SmsCampaignData {
return this.providerId;
}
public boolean isNotification() {
return this.isNotification;
}
}
@@ -67,7 +67,7 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
@Column(name = "campaign_trigger_type", nullable = false)
private Integer triggerType; //defines direct, scheduled, transaction
@Column(name = "provider_id", nullable = false)
@Column(name = "provider_id", nullable = true)//null for notifications
private Long providerId; // defined provider details
@ManyToOne
@@ -124,13 +124,16 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
@Column(name = "is_visible", nullable = true)
private boolean isVisible;
@Column(name = "is_notification", nullable = true)
private boolean isNotification;
public SmsCampaign() {}
private SmsCampaign(final String campaignName, final Integer campaignType,
final Integer triggerType, final Report businessRuleId, final Long providerId, final String paramValue,
final String message, final LocalDate submittedOnDate, final AppUser submittedBy, final String recurrence,
final LocalDateTime localDateTime) {
final LocalDateTime localDateTime, final boolean isNotification) {
this.campaignName = campaignName;
this.campaignType = campaignType;
this.triggerType = SmsCampaignTriggerType.fromInt(triggerType).getValue();
@@ -149,6 +152,7 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
} else {
this.recurrenceStartDate = recurrenceStartDate.toDate();
}
this.isNotification = isNotification;
}
public static SmsCampaign instance(final AppUser submittedBy, final Report report, final JsonCommand command) {
@@ -156,7 +160,15 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
final String campaignName = command.stringValueOfParameterNamed(SmsCampaignValidator.campaignName);
final Long campaignType = command.longValueOfParameterNamed(SmsCampaignValidator.campaignType);
final Long triggerType = command.longValueOfParameterNamed(SmsCampaignValidator.triggerType);
final Long providerId = command.longValueOfParameterNamed(SmsCampaignValidator.providerId);
boolean isNotification = false;
if(command.parameterExists(SmsCampaignValidator.isNotificationParamName)){
isNotification = command.booleanPrimitiveValueOfParameterNamed(SmsCampaignValidator.isNotificationParamName);
}
Long providerId = null;
if(!isNotification){
providerId = command.longValueOfParameterNamed(SmsCampaignValidator.providerId);
}
final String paramValue = command.jsonFragment(SmsCampaignValidator.paramValue);
final String message = command.stringValueOfParameterNamed(SmsCampaignValidator.message);
@@ -165,6 +177,7 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
submittedOnDate = command.localDateValueOfParameterNamed(SmsCampaignValidator.submittedOnDateParamName);
}
String recurrence = null;
LocalDateTime recurrenceStartDate = new LocalDateTime();
if (SmsCampaignTriggerType.fromInt(triggerType.intValue()).isSchedule()) {
@@ -184,7 +197,7 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
}
return new SmsCampaign(campaignName, campaignType.intValue(), triggerType.intValue(), report,
providerId, paramValue, message, submittedOnDate, submittedBy, recurrence, recurrenceStartDate);
providerId, paramValue, message, submittedOnDate, submittedBy, recurrence, recurrenceStartDate, isNotification);
}
public Map<String, Object> update(JsonCommand command) {
@@ -232,6 +245,11 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
final Long newValue = command.longValueOfParameterNamed(SmsCampaignValidator.providerId);
actualChanges.put(SmsCampaignValidator.providerId, newValue);
}
if (command.isChangeInBooleanParameterNamed(SmsCampaignValidator.isNotificationParamName, this.isNotification)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(SmsCampaignValidator.isNotificationParamName);
this.isNotification = newValue;
actualChanges.put(SmsCampaignValidator.isNotificationParamName, newValue);
}
if (SmsCampaignTriggerType.fromInt(this.triggerType).isSchedule()) {
final String dateFormatAsInput = command.dateFormat();
@@ -558,4 +576,14 @@ public class SmsCampaign extends AbstractPersistableCustom<Long> {
}
return recurrenceBuilder.toString();
}
public boolean isNotification() {
return this.isNotification;
}
public void setNotification(boolean isNotification) {
this.isNotification = isNotification;
}
}
@@ -32,6 +32,8 @@ public interface SmsCampaignRepository extends JpaRepository<SmsCampaign, Long>,
Collection<SmsCampaign> findByCampaignTypeAndTriggerTypeAndStatus(final Integer campaignType, final Integer triggerType,
final Integer status);
Collection<SmsCampaign> findByTriggerTypeAndStatus(final Integer triggerType, final Integer status);
Collection<SmsCampaign> findByTriggerType(final Integer triggerType) ;
@@ -28,12 +28,16 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositoryWrapper;
import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
import org.apache.fineract.portfolio.client.domain.Client;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -67,19 +71,21 @@ public class SmsCampaignValidator {
public static final String frequencyParamName = "frequency";
public static final String intervalParamName = "interval";
public static final String repeatsOnDayParamName = "repeatsOnDay";
public static final String isNotificationParamName = "isNotification";
private final FromJsonHelper fromApiJsonHelper;
private final DeviceRegistrationRepositoryWrapper deviceRegistrationRepository;
protected static final Set<String> supportedParams = new HashSet<>(Arrays.asList(campaignName, campaignType,
localeParamName,
dateFormatParamName, runReportId, paramValue, message, recurrenceStartDate, activationDateParamName, submittedOnDateParamName,
closureDateParamName, recurrenceParamName, providerId, triggerType, frequencyParamName, intervalParamName,
repeatsOnDayParamName, triggerEntityType, triggerActionType, dateTimeFormat));
repeatsOnDayParamName, triggerEntityType, triggerActionType, dateTimeFormat, isNotificationParamName));
protected static final Set<String> supportedParamsForUpdate = new HashSet<>(Arrays.asList(campaignName, campaignType,
localeParamName,
dateFormatParamName, runReportId, paramValue, message, recurrenceStartDate, activationDateParamName, recurrenceParamName,
providerId, triggerType, triggerEntityType, triggerActionType, dateTimeFormat));
providerId, triggerType, triggerEntityType, triggerActionType, dateTimeFormat, isNotificationParamName));
protected static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName,
@@ -92,8 +98,9 @@ public class SmsCampaignValidator {
protected static final Set<String> PREVIEW_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(paramValue, message));
@Autowired
public SmsCampaignValidator(FromJsonHelper fromApiJsonHelper) {
public SmsCampaignValidator(FromJsonHelper fromApiJsonHelper, final DeviceRegistrationRepositoryWrapper deviceRegistrationRepository) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.deviceRegistrationRepository = deviceRegistrationRepository;
}
public void validateCreate(String json) {
@@ -159,6 +166,12 @@ public class SmsCampaignValidator {
element);
baseDataValidator.reset().parameter(SmsCampaignValidator.submittedOnDateParamName).value(submittedOnDate).notNull();
}
if (this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.isNotificationParamName, element)) {
final Boolean isNotification = this.fromApiJsonHelper.extractBooleanNamed(SmsCampaignValidator.isNotificationParamName,
element);
baseDataValidator.reset().parameter(SmsCampaignValidator.submittedOnDateParamName).trueOrFalseRequired(isNotification);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -214,7 +227,11 @@ public class SmsCampaignValidator {
}
}
}
if (this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.isNotificationParamName, element)) {
final Boolean isNotification = this.fromApiJsonHelper.extractBooleanNamed(SmsCampaignValidator.isNotificationParamName,
element);
baseDataValidator.reset().parameter(SmsCampaignValidator.submittedOnDateParamName).trueOrFalseRequired(isNotification);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -303,4 +320,17 @@ public class SmsCampaignValidator {
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public boolean isValidNotificationOrSms(Client client, SmsCampaign smsCampaign, Object mobileNo) {
if (smsCampaign.isNotification()) {
if (client != null) {
DeviceRegistration deviceRegistration = this.deviceRegistrationRepository
.findDeviceRegistrationByClientId(client.getId());
return (deviceRegistration != null);
}
return false;
}
return (mobileNo != null);
}
}
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTri
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignRepository;
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsRuntimeException;
import org.apache.fineract.infrastructure.campaigns.sms.serialization.SmsCampaignValidator;
import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService;
@@ -77,13 +78,15 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
private final GroupRepository groupRepository;
private final SmsMessageScheduledJobService smsMessageScheduledJobService;
private final SmsCampaignValidator smsCampaignValidator;
@Autowired
public SmsCampaignDomainServiceImpl(final SmsCampaignRepository smsCampaignRepository, final SmsMessageRepository smsMessageRepository,
final BusinessEventNotifierService businessEventNotifierService, final OfficeRepository officeRepository,
final SmsCampaignWritePlatformService smsCampaignWritePlatformCommandHandler,
final GroupRepository groupRepository,
final SmsMessageScheduledJobService smsMessageScheduledJobService){
final SmsMessageScheduledJobService smsMessageScheduledJobService,
final SmsCampaignValidator smsCampaignValidator){
this.smsCampaignRepository = smsCampaignRepository;
this.smsMessageRepository = smsMessageRepository;
this.businessEventNotifierService = businessEventNotifierService;
@@ -91,6 +94,7 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
this.smsCampaignWritePlatformCommandHandler = smsCampaignWritePlatformCommandHandler;
this.groupRepository = groupRepository;
this.smsMessageScheduledJobService = smsMessageScheduledJobService ;
this.smsCampaignValidator = smsCampaignValidator;
}
@PostConstruct
@@ -217,10 +221,13 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
String message = this.smsCampaignWritePlatformCommandHandler.compileSmsTemplate(
smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams);
Object mobileNo = smsParams.get("mobileNo");
if (mobileNo != null) {
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message,
mobileNo.toString(), smsCampaign);
this.smsMessageRepository.save(smsMessage);
mobileNumber, smsCampaign, smsCampaign.isNotification());
Collection<SmsMessage> messages = new ArrayList<>();
messages.add(smsMessage);
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
@@ -273,9 +280,13 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
String message = this.smsCampaignWritePlatformCommandHandler
.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams);
Object mobileNo = smsParams.get("mobileNo");
if (mobileNo != null) {
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message,
mobileNo.toString(), smsCampaign);
mobileNumber, smsCampaign, smsCampaign.isNotification());
this.smsMessageRepository.save(smsMessage);
Collection<SmsMessage> messages = new ArrayList<>();
messages.add(smsMessage);
@@ -30,7 +30,6 @@ import org.apache.fineract.infrastructure.campaigns.helper.SmsConfigUtils;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignEnumerations;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsProviderData;
import org.apache.fineract.infrastructure.campaigns.sms.exception.ConnectionFailureException;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
@@ -81,10 +80,8 @@ public class SmsCampaignDropdownReadPlatformServiceImpl implements SmsCampaignDr
new ParameterizedTypeReference<Collection<SmsProviderData>>() {});
smsProviderOptions = responseOne.getBody();
if (!responseOne.getStatusCode().equals(HttpStatus.OK)) {
throw new ConnectionFailureException(hostName);
}
} catch (Exception e) {
throw new ConnectionFailureException(hostName);
}
return smsProviderOptions;
}
@@ -219,7 +219,8 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
sql.append("acu.username as activatedByUsername, ");
sql.append("sc.approvedon_date as activatedOnDate, ");
sql.append("sr.report_name as reportName, ");
sql.append("provider_id as providerId ");
sql.append("provider_id as providerId, ");
sql.append("sc.is_notification as isNotification ");
sql.append("from sms_campaign sc ");
sql.append("left join m_appuser sbu on sbu.id = sc.submittedon_userid ");
sql.append("left join m_appuser acu on acu.id = sc.approvedon_userid ");
@@ -265,9 +266,9 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
activatedByUsername, closedOnDate, closedByUsername);
final String reportName = rs.getString("reportName");
final Long providerId = rs.getLong("providerId");
final Boolean isNotification = rs.getBoolean("isNotification");
return SmsCampaignData.instance(id, campaignName, campaignTypeEnum, triggerTypeEnum, runReportId, reportName, paramValue, status, message, nextTriggerDate, lastTriggerDate,
smsCampaignTimeLine, recurrenceStartDate, recurrence, providerId);
smsCampaignTimeLine, recurrenceStartDate, recurrence, providerId, isNotification);
}
}
@@ -30,7 +30,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignStatus;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
import org.apache.fineract.infrastructure.campaigns.sms.data.CampaignPreviewData;
@@ -56,6 +55,8 @@ import org.apache.fineract.infrastructure.dataqueries.domain.ReportRepository;
import org.apache.fineract.infrastructure.dataqueries.exception.ReportNotFoundException;
import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
import org.apache.fineract.infrastructure.dataqueries.service.ReadReportingService;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositoryWrapper;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.jobs.service.JobName;
@@ -109,6 +110,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
private final ReadReportingService readReportingService;
private final GenericDataService genericDataService;
private final FromJsonHelper fromJsonHelper;
private final DeviceRegistrationRepositoryWrapper deviceRegistrationRepository;
private final SmsMessageScheduledJobService smsMessageScheduledJobService;
@@ -118,7 +120,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
final SmsMessageRepository smsMessageRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
final ReadReportingService readReportingService, final GenericDataService genericDataService,
final FromJsonHelper fromJsonHelper, final GroupRepository groupRepository,
final SmsMessageScheduledJobService smsMessageScheduledJobService) {
final SmsMessageScheduledJobService smsMessageScheduledJobService, final DeviceRegistrationRepositoryWrapper deviceRegistrationRepository) {
this.context = context;
this.smsCampaignRepository = smsCampaignRepository;
this.smsCampaignValidator = smsCampaignValidator;
@@ -130,6 +132,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
this.fromJsonHelper = fromJsonHelper;
this.groupRepository = groupRepository;
this.smsMessageScheduledJobService = smsMessageScheduledJobService ;
this.deviceRegistrationRepository = deviceRegistrationRepository;
}
@Transactional
@@ -228,10 +231,14 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
Object mobileNo = entry.get("mobileNo");
Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId.longValue());
if (mobileNo != null) {
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
// String countryCode = this.smsReadPlatformService.retrieveCountryCode(client.getOffice().getId()).getCountryCode();
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNo.toString(),
smsCampaign);
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNumber,
smsCampaign, smsCampaign.isNotification());
this.smsMessageRepository.save(smsMessage);
}
}
@@ -242,6 +249,8 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
}
@Override
public void insertDirectCampaignIntoSmsOutboundTable(final Loan loan, final SmsCampaign smsCampaign) {
try {
@@ -278,9 +287,13 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
String textMessage = this.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), entry);
Object mobileNo = entry.get("mobileNo");
if (mobileNo != null) {
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNo.toString(),
smsCampaign);
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNumber,
smsCampaign, smsCampaign.isNotification());
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
this.smsMessageRepository.save(smsMessage);
Collection<SmsMessage> messages = new ArrayList<>() ;
@@ -320,9 +333,13 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
smsCampaign.getCampaignName(), entry);
Object mobileNo = entry.get("mobileNo");
if (mobileNo != null) {
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage,
mobileNo.toString(), smsCampaign);
mobileNumber, smsCampaign, smsCampaign.isNotification());
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
this.smsMessageRepository.save(smsMessage);
Collection<SmsMessage> messages = new ArrayList<>();
@@ -360,9 +377,13 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
smsCampaign.getCampaignName(), entry);
Object mobileNo = entry.get("mobileNo");
if (mobileNo != null) {
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if(mobileNo != null){
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage,
mobileNo.toString(), smsCampaign);
mobileNumber, smsCampaign, smsCampaign.isNotification());
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
this.smsMessageRepository.save(smsMessage);
Collection<SmsMessage> messages = new ArrayList<>();
@@ -514,7 +535,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
final String reportType = "report";
List<HashMap<String, Object>> resultList = new ArrayList<>();
final GenericResultsetData results = this.readReportingService.retrieveGenericResultSetForSmsCampaign(reportName, reportType,
final GenericResultsetData results = this.readReportingService.retrieveGenericResultSetForSmsEmailCampaign(reportName, reportType,
queryParams);
try {
@@ -634,8 +655,8 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
@Override
@CronTarget(jobName = JobName.UPDATE_SMS_OUTBOUND_WITH_CAMPAIGN_MESSAGE)
public void storeTemplateMessageIntoSmsOutBoundTable() throws JobExecutionException {
final Collection<SmsCampaign> smsCampaignDataCollection = this.smsCampaignRepository.findByCampaignTypeAndTriggerTypeAndStatus(
CampaignType.SMS.getValue(), SmsCampaignTriggerType.SCHEDULE.getValue(), SmsCampaignStatus.ACTIVE.getValue());
final Collection<SmsCampaign> smsCampaignDataCollection = this.smsCampaignRepository.findByTriggerTypeAndStatus(
SmsCampaignTriggerType.SCHEDULE.getValue(), SmsCampaignStatus.ACTIVE.getValue());
if (smsCampaignDataCollection != null) {
for (SmsCampaign smsCampaign : smsCampaignDataCollection) {
LocalDateTime tenantDateNow = tenantDateTime();
@@ -85,5 +85,12 @@ public interface ConfigurationDomainService {
Long getDailyTPTLimit();
void removeGlobalConfigurationPropertyDataFromCache(String propertyName);
boolean isSMSOTPDeliveryEnabled();
boolean isEmailOTPDeliveryEnabled();
Integer retrieveOTPCharacterLength();
Integer retrieveOTPLiveTime();
}
@@ -287,6 +287,43 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
configurations.remove(key);
}
@Override
public boolean isSMSOTPDeliveryEnabled() {
final String propertyName = "use-sms-for-2fa";
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled();
}
@Override
public boolean isEmailOTPDeliveryEnabled() {
final String propertyName = "use-email-for-2fa";
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled();
}
@Override
public Integer retrieveOTPCharacterLength() {
final String propertyName = "otp-character-length";
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
int defaultValue = 6;
int value = property.getValue().intValue();
if(value < 1)
return defaultValue;
return value;
}
@Override
public Integer retrieveOTPLiveTime() {
final String propertyName = "otp-validity-period";
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
int defaultValue = 300;
int value = property.getValue().intValue();
if(value < 1) {
return defaultValue;
}
return value;
}
private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) {
String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
String key = identifier + "_" + propertyName;
@@ -24,6 +24,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.configuration.exception.ExternalServiceConfigurationNotFoundException;
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.NOTIFICATION_JSON_INPUT_PARAMS;
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.S3_JSON_INPUT_PARAMS;
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.SMS_JSON_INPUT_PARAMS;
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.SMTP_JSON_INPUT_PARAMS;
@@ -40,6 +41,7 @@ public class ExternalServicesPropertiesCommandFromApiJsonDeserializer {
private final Set<String> S3SupportedParameters = S3_JSON_INPUT_PARAMS.getAllValues();
private final Set<String> SMTPSupportedParameters = SMTP_JSON_INPUT_PARAMS.getAllValues();
private final Set<String> SMSSupportedParameters = SMS_JSON_INPUT_PARAMS.getAllValues();
private final Set<String> NotificationSupportedParameters = NOTIFICATION_JSON_INPUT_PARAMS.getAllValues();
private final FromJsonHelper fromApiJsonHelper;
@Autowired
@@ -64,6 +66,10 @@ public class ExternalServicesPropertiesCommandFromApiJsonDeserializer {
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.SMSSupportedParameters);
break;
case "NOTIFICATION":
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.NotificationSupportedParameters);
break;
default:
throw new ExternalServiceConfigurationNotFoundException(externalServiceName);
}
@@ -41,6 +41,11 @@ public class ExternalServicesConstants {
public static final String SMS_END_POINT = "end_point";
public static final String SMS_TENANT_APP_KEY = "tenant_app_key";
public static final String NOTIFICATION_SERVICE_NAME = "NOTIFICATION";
public static final String NOTIFICATION_SERVER_KEY = "server_key";
public static final String NOTIFICATION_GCM_END_POINT = "gcm_end_point";
public static final String NOTIFICATION_FCM_END_POINT = "fcm_end_point";
public static enum EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS {
EXTERNAL_SERVICE_ID("external_service_id"), NAME("name"), VALUE("value");
@@ -164,5 +169,36 @@ public class ExternalServicesConstants {
return this.value;
}
}
public static enum NOTIFICATION_JSON_INPUT_PARAMS {
SERVER_KEY("server_key"), GCM_END_POINT("gcm_end_point"), FCM_END_POINT("fcm_end_point");
private final String value;
private NOTIFICATION_JSON_INPUT_PARAMS(final String value) {
this.value = value;
}
private static final Set<String> values = new HashSet<>();
static {
for (final NOTIFICATION_JSON_INPUT_PARAMS type : NOTIFICATION_JSON_INPUT_PARAMS.values()) {
values.add(type.value);
}
}
public static Set<String> getAllValues() {
return values;
}
@Override
public String toString() {
return name().toString().replaceAll("_", " ");
}
public String getValue() {
return this.value;
}
}
}
@@ -24,6 +24,7 @@ import org.apache.fineract.infrastructure.campaigns.sms.data.MessageGatewayConfi
import org.apache.fineract.infrastructure.configuration.data.ExternalServicesPropertiesData;
import org.apache.fineract.infrastructure.configuration.data.S3CredentialsData;
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
import org.apache.fineract.infrastructure.gcm.domain.NotificationConfigurationData;
public interface ExternalServicesPropertiesReadPlatformService {
@@ -34,5 +35,7 @@ public interface ExternalServicesPropertiesReadPlatformService {
MessageGatewayConfigurationData getSMSGateway();
Collection<ExternalServicesPropertiesData> retrieveOne(String serviceName);
NotificationConfigurationData getNotificationConfiguration();
}
@@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.configuration.data.S3CredentialsData;
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
import org.apache.fineract.infrastructure.configuration.exception.ExternalServiceConfigurationNotFoundException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.gcm.domain.NotificationConfigurationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -176,6 +177,10 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
serviceNameToUse = ExternalServicesConstants.SMS_SERVICE_NAME;
break;
case "NOTIFICATION":
serviceNameToUse = ExternalServicesConstants.NOTIFICATION_SERVICE_NAME;
break;
default:
throw new ExternalServiceConfigurationNotFoundException(serviceName);
}
@@ -185,5 +190,35 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
}
private static final class NotificationDataExtractor implements ResultSetExtractor<NotificationConfigurationData> {
@Override
public NotificationConfigurationData extractData(final ResultSet rs) throws SQLException, DataAccessException {
String serverKey = null;
String gcmEndPoint = null;
String fcmEndPoint = null;
while (rs.next()) {
if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.NOTIFICATION_SERVER_KEY )) {
serverKey = rs.getString("value");
} else if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.NOTIFICATION_GCM_END_POINT )) {
gcmEndPoint = rs.getString("value");
} else if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.NOTIFICATION_FCM_END_POINT )) {
fcmEndPoint = rs.getString("value");
}
}
return new NotificationConfigurationData(null, serverKey, gcmEndPoint, fcmEndPoint);
}
}
@Override
public NotificationConfigurationData getNotificationConfiguration() {
final ResultSetExtractor<NotificationConfigurationData> resultSetExtractor = new NotificationDataExtractor();
final String sql = "SELECT esp.name, esp.value FROM c_external_service_properties esp inner join c_external_service es on esp.external_service_id = es.id where es.name = '"
+ ExternalServicesConstants.NOTIFICATION_SERVICE_NAME + "'";
final NotificationConfigurationData notificationConfigurationData = this.jdbcTemplate.query(sql, resultSetExtractor, new Object[] {});
return notificationConfigurationData;
}
}
@@ -58,6 +58,10 @@ public class ExternalServicesReadPlatformServiceImpl implements ExternalServices
serviceNameToUse = ExternalServicesConstants.SMS_SERVICE_NAME;
break;
case "NOTIFICATION":
serviceNameToUse = ExternalServicesConstants.NOTIFICATION_SERVICE_NAME;
break;
default:
throw new ExternalServiceConfigurationNotFoundException(serviceName);
}
@@ -40,7 +40,8 @@ import org.springframework.context.annotation.PropertySource;
* and MariaDB4j (because those differ in the subclasses).
*/
@Configuration
@Import({ WebXmlConfiguration.class, WebXmlOauthConfiguration.class, WebFrontEndConfiguration.class })
@Import({ WebXmlConfiguration.class, WebXmlOauthConfiguration.class, WebFrontEndConfiguration.class,
WebTwoFactorXmlConfiguration.class })
@ImportResource({ "classpath*:META-INF/spring/appContext.xml" })
@PropertySource(value="classpath:META-INF/spring/jdbc.properties")
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
@@ -0,0 +1,36 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.core.boot;
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebTwoFactorXmlConfiguration {
@Bean
public FilterRegistrationBean twoFactorFilterBean(TwoFactorAuthenticationFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
}
@@ -225,6 +225,21 @@ public final class SearchParameters {
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
}
public static SearchParameters forEmailCampaign(final String sqlSearch, final Integer offset, final Integer limit, final String orderBy, final String sortOrder) {
final String externalId = null;
final Integer maxLimitAllowed = getCheckedLimit(limit);
final Long staffId = null;
final String accountNo = null;
final Long loanId = null;
final Long savingsId = null;
final Boolean orphansOnly = false;
final boolean isSelfUser = false;
return new SearchParameters(sqlSearch, null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder,
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
}
private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name,
final String hierarchy, final String firstname, final String lastname, final Integer offset, final Integer limit,
final String orderBy, final String sortOrder, final Long staffId, final String accountNo, final Long loanId,
@@ -42,7 +42,7 @@ import com.google.gson.reflect.TypeToken;
@Component
public class CreditBureauCommandFromApiJsonDeserializer {
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("alias", "is_active"));
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("alias", "is_active","creditBureauId"));
private final FromJsonHelper fromApiJsonHelper;
@@ -79,6 +79,42 @@ public class CreditBureauCommandFromApiJsonDeserializer {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json)
{
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource("CreditBureau");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final String creditBureauIdParameter = "creditBureauId";
if (this.fromApiJsonHelper.parameterExists(creditBureauIdParameter, element)) {
final Long creditBureauId = this.fromApiJsonHelper.extractLongNamed("creditBureauId", element);
baseDataValidator.reset().parameter("creditBureauId").value(creditBureauId).notNull().notBlank().longGreaterThanZero();
}
final String is_activeParameter = "is_active";
if (this.fromApiJsonHelper.parameterExists(is_activeParameter, element)) {
final boolean is_active = this.fromApiJsonHelper.extractBooleanNamed("is_active", element);
baseDataValidator.reset().parameter("is_active").value(is_active).notNull().notBlank().trueOrFalseRequired(is_active);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
@@ -40,8 +40,8 @@ import com.google.gson.reflect.TypeToken;
@Component
public class CreditBureauLoanProductCommandFromApiJsonDeserializer {
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("loan_product_id",
"is_creditcheck_mandatory", "skip_creditcheck_in_failure", "stale_period", "is_active", "locale"));
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("loanProductId",
"isCreditcheckMandatory", "skipCreditcheckInFailure", "stalePeriod", "is_active", "locale","creditbureauLoanProductMappingId"));
private final FromJsonHelper fromApiJsonHelper;
@@ -67,47 +67,47 @@ public class CreditBureauLoanProductCommandFromApiJsonDeserializer {
baseDataValidator.reset().value(cb_id).notBlank().integerGreaterThanZero();
final long loan_product_id = this.fromApiJsonHelper.extractLongNamed("loan_product_id", element);
baseDataValidator.reset().parameter("loan_product_id").value(loan_product_id).notBlank()
final long loanProductId = this.fromApiJsonHelper.extractLongNamed("loanProductId", element);
baseDataValidator.reset().parameter("loanProductId").value(loanProductId).notBlank()
.integerGreaterThanZero();
System.out.println("loan product id " + loan_product_id);
if(this.fromApiJsonHelper.extractBooleanNamed("is_creditcheck_mandatory",element)!= null)
if(this.fromApiJsonHelper.extractBooleanNamed("isCreditcheckMandatory",element)!= null)
{
final boolean is_creditcheck_mandatory = this.fromApiJsonHelper.extractBooleanNamed("is_creditcheck_mandatory",
final boolean isCreditcheckMandatory = this.fromApiJsonHelper.extractBooleanNamed("isCreditcheckMandatory",
element);
baseDataValidator.reset().parameter("is_creditcheck_mandatory").value(is_creditcheck_mandatory).notBlank()
.trueOrFalseRequired(is_creditcheck_mandatory);
baseDataValidator.reset().parameter("isCreditcheckMandatory").value(isCreditcheckMandatory).notBlank()
.trueOrFalseRequired(isCreditcheckMandatory);
}
else
{
baseDataValidator.reset().parameter("is_creditcheck_mandatory").value(this.fromApiJsonHelper.extractBooleanNamed("is_creditcheck_mandatory",
baseDataValidator.reset().parameter("isCreditcheckMandatory").value(this.fromApiJsonHelper.extractBooleanNamed("isCreditcheckMandatory",
element)).notBlank()
.trueOrFalseRequired(this.fromApiJsonHelper.extractBooleanNamed("is_creditcheck_mandatory",
.trueOrFalseRequired(this.fromApiJsonHelper.extractBooleanNamed("isCreditcheckMandatory",
element));
}
if( this.fromApiJsonHelper.extractBooleanNamed("skip_creditcheck_in_failure", element)!=null)
if( this.fromApiJsonHelper.extractBooleanNamed("skipCreditcheckInFailure", element)!=null)
{
final boolean skip_creditcheck_in_failure = this.fromApiJsonHelper.extractBooleanNamed("skip_creditcheck_in_failure", element);
baseDataValidator.reset().parameter("skip_creditcheck_in_failure").value(skip_creditcheck_in_failure).notBlank().trueOrFalseRequired(skip_creditcheck_in_failure);
final boolean skipCreditcheckInFailure = this.fromApiJsonHelper.extractBooleanNamed("skipCreditcheckInFailure", element);
baseDataValidator.reset().parameter("skipCreditcheckInFailure").value(skipCreditcheckInFailure).notBlank().trueOrFalseRequired(skipCreditcheckInFailure);
}
else
{
baseDataValidator.reset().parameter("skip_creditcheck_in_failure").value(this.fromApiJsonHelper.extractBooleanNamed("skip_creditcheck_in_failure", element)).notBlank().trueOrFalseRequired(this.fromApiJsonHelper.extractBooleanNamed("skip_creditcheck_in_failure", element));
baseDataValidator.reset().parameter("skipCreditcheckInFailure").value(this.fromApiJsonHelper.extractBooleanNamed("skipCreditcheckInFailure", element)).notBlank().trueOrFalseRequired(this.fromApiJsonHelper.extractBooleanNamed("skipCreditcheckInFailure", element));
}
if(this.fromApiJsonHelper.extractLongNamed("stale_period", element)!=null)
if(this.fromApiJsonHelper.extractLongNamed("stalePeriod", element)!=null)
{
final long stale_period = this.fromApiJsonHelper.extractLongNamed("stale_period", element);
baseDataValidator.reset().parameter("stale_period").value(stale_period).notBlank().integerGreaterThanZero();
final long stalePeriod = this.fromApiJsonHelper.extractLongNamed("stalePeriod", element);
baseDataValidator.reset().parameter("stalePeriod").value(stalePeriod).notBlank().integerGreaterThanZero();
}
else
{
baseDataValidator.reset().parameter("stale_period").value(this.fromApiJsonHelper.extractLongNamed("stale_period", element)).notBlank().integerGreaterThanZero();
baseDataValidator.reset().parameter("stalePeriod").value(this.fromApiJsonHelper.extractLongNamed("stalePeriod", element)).notBlank().integerGreaterThanZero();
}
@@ -127,6 +127,42 @@ public class CreditBureauLoanProductCommandFromApiJsonDeserializer {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json)
{
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource("CREDITBUREAU_LOANPRODUCT_MAPPING");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final String creditbureauLoanProductMappingIdParameter = "creditbureauLoanProductMappingId";
if (this.fromApiJsonHelper.parameterExists(creditbureauLoanProductMappingIdParameter, element)) {
final Long creditbureauLoanProductMappingId = this.fromApiJsonHelper.extractLongNamed("creditbureauLoanProductMappingId", element);
baseDataValidator.reset().parameter("creditbureauLoanProductMappingId").value(creditbureauLoanProductMappingId).notNull().notBlank().longGreaterThanZero();
}
final String is_activeParameter = "is_active";
if (this.fromApiJsonHelper.parameterExists(is_activeParameter, element)) {
final boolean is_active = this.fromApiJsonHelper.extractBooleanNamed("is_active", element);
baseDataValidator.reset().parameter("is_active").value(is_active).notNull().notBlank().trueOrFalseRequired(is_active);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
@@ -64,10 +64,9 @@ public class CreditBureauLoanProductMappingWritePlatformServiceImpl implements C
public CommandProcessingResult addCreditBureauLoanProductMapping(Long creditBureau_id, JsonCommand command) {
this.context.authenticatedUser();
System.out.println("mapping called for creditBureau_id "+creditBureau_id);
this.fromApiJsonDeserializer.validateForCreate(command.json(), creditBureau_id);
final long lpid = command.longValueOfParameterNamed("loan_product_id");
final long lpid = command.longValueOfParameterNamed("loanProductId");
final OrganisationCreditBureau orgcb = this.organisationCreditBureauRepository.getOne(creditBureau_id);
@@ -84,6 +83,9 @@ public class CreditBureauLoanProductMappingWritePlatformServiceImpl implements C
@Override
public CommandProcessingResult updateCreditBureauLoanProductMapping(JsonCommand command) {
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final Long mappingid = command.longValueOfParameterNamed("creditbureauLoanProductMappingId");
final boolean is_active = command.booleanPrimitiveValueOfParameterNamed("is_active");
@@ -72,12 +72,11 @@ public class OrganisationCreditBureauWritePlatflormServiceImpl
@Transactional
@Override
public CommandProcessingResult updateCreditBureau(JsonCommand command) {
// this.context.authenticatedUser();
// this.fromApiJsonDeserializer.validateForCreate(command.json());
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final long creditbureauID = command.longValueOfParameterNamed("creditBureauId");
//System.out.println("creditbureauID is " + creditbureauID);
final boolean is_active = command.booleanPrimitiveValueOfParameterNamed("is_active");
final OrganisationCreditBureau orgcb = organisationCreditBureauRepository.getOne(creditbureauID);
@@ -276,4 +276,8 @@ public final class Report extends AbstractPersistableCustom<Long> {
return false;
}
public Set<ReportParameterUsage> getReportParameterUsages() {
return this.reportParameterUsages;
}
}
@@ -86,4 +86,8 @@ public final class ReportParameterUsage extends AbstractPersistableCustom<Long>
public void updateParameterName(final String parameterName) {
this.reportParameterName = parameterName;
}
public String getReportParameterName() {
return this.reportParameterName;
}
}
@@ -18,10 +18,14 @@
*/
package org.apache.fineract.infrastructure.dataqueries.domain;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface ReportParameterUsageRepository extends JpaRepository<ReportParameterUsage, Long>,
JpaSpecificationExecutor<ReportParameterUsage> {
// no added behaviour
List<ReportParameterUsage> findByReport(Report report);
}
@@ -18,7 +18,9 @@
*/
package org.apache.fineract.infrastructure.dataqueries.service;
import java.io.ByteArrayOutputStream;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import javax.ws.rs.core.StreamingOutput;
@@ -26,6 +28,7 @@ import javax.ws.rs.core.StreamingOutput;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.data.ReportData;
import org.apache.fineract.infrastructure.dataqueries.data.ReportParameterData;
import org.apache.fineract.useradministration.domain.AppUser;
public interface ReadReportingService {
@@ -45,8 +48,11 @@ public interface ReadReportingService {
Collection<String> getAllowedReportTypes();
//needed for smsCampaign jobs where securityContext is null
GenericResultsetData retrieveGenericResultSetForSmsCampaign(String name, String type, Map<String, String> extractedQueryParams);
String sqlToRunForSmsCampaign(String name, String type, Map<String, String> queryParams);
//needed for smsCampaign and emailCampaign jobs where securityContext is null
GenericResultsetData retrieveGenericResultSetForSmsEmailCampaign(String name, String type, Map<String, String> extractedQueryParams);
String sqlToRunForSmsEmailCampaign(String name, String type, Map<String, String> queryParams);
ByteArrayOutputStream generatePentahoReportAsOutputStream(String reportName, String outputTypeParam,
Map<String, String> queryParams, Locale locale, AppUser runReportAsUser, StringBuilder errorLog);
}
@@ -19,6 +19,7 @@
package org.apache.fineract.infrastructure.dataqueries.service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
@@ -28,6 +29,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -486,11 +488,11 @@ public class ReadReportingServiceImpl implements ReadReportingService {
}
@Override
public GenericResultsetData retrieveGenericResultSetForSmsCampaign(String name, String type, Map<String, String> queryParams) {
public GenericResultsetData retrieveGenericResultSetForSmsEmailCampaign(String name, String type, Map<String, String> queryParams) {
final long startTime = System.currentTimeMillis();
logger.info("STARTING REPORT: " + name + " Type: " + type);
final String sql = sqlToRunForSmsCampaign(name, type, queryParams);
final String sql = sqlToRunForSmsEmailCampaign(name, type, queryParams);
final GenericResultsetData result = this.genericDataService.fillGenericResultSet(sql);
@@ -500,7 +502,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
}
@Override
public String sqlToRunForSmsCampaign(final String name, final String type, final Map<String, String> queryParams) {
public String sqlToRunForSmsEmailCampaign(final String name, final String type, final Map<String, String> queryParams) {
String sql = getSql(name, type);
final Set<String> keys = queryParams.keySet();
@@ -515,4 +517,86 @@ public class ReadReportingServiceImpl implements ReadReportingService {
return sql;
}
@Override
public ByteArrayOutputStream generatePentahoReportAsOutputStream(final String reportName, final String outputTypeParam, final Map<String, String> queryParams,
final Locale locale, final AppUser runReportAsUser, final StringBuilder errorLog) {
//This complete implementation should be moved to Pentaho Report Service
/*
String outputType = "HTML";
if (StringUtils.isNotBlank(outputTypeParam)) {
outputType = outputTypeParam;
}
if (!(outputType.equalsIgnoreCase("HTML") || outputType.equalsIgnoreCase("PDF") || outputType.equalsIgnoreCase("XLS") || outputType
.equalsIgnoreCase("CSV"))) { throw new PlatformDataIntegrityException("error.msg.invalid.outputType",
"No matching Output Type: " + outputType); }
if (this.noPentaho) { throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled",
"Pentaho is not enabled"); }
final String reportPath = FileSystemContentRepository.FINERACT_BASE_DIR + File.separator + "pentahoReports" + File.separator
+ reportName + ".prpt";
logger.info("Report path: " + reportPath);
// load report definition
final ResourceManager manager = new ResourceManager();
manager.registerDefaults();
Resource res;
try {
res = manager.createDirectly(reportPath, MasterReport.class);
final MasterReport masterReport = (MasterReport) res.getResource();
final DefaultReportEnvironment reportEnvironment = (DefaultReportEnvironment) masterReport.getReportEnvironment();
if (locale != null) {
reportEnvironment.setLocale(locale);
}
addParametersToReport(masterReport, queryParams, runReportAsUser, errorLog);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
if ("PDF".equalsIgnoreCase(outputType)) {
PdfReportUtil.createPDF(masterReport, baos);
return baos;
}
if ("XLS".equalsIgnoreCase(outputType)) {
ExcelReportUtil.createXLS(masterReport, baos);
return baos;
}
if ("CSV".equalsIgnoreCase(outputType)) {
CSVReportUtil.createCSV(masterReport, baos, "UTF-8");
return baos;
}
if ("HTML".equalsIgnoreCase(outputType)) {
HtmlReportUtil.createStreamHTML(masterReport, baos);
return baos;
}
} catch (final ResourceException e) {
errorLog.append("ReadReportingServiceImpl.generatePentahoReportAsOutputStream method threw a Pentaho ResourceException "
+ "exception: " + e.getMessage() + " ---------- ");
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
} catch (final ReportProcessingException e) {
errorLog.append("ReadReportingServiceImpl.generatePentahoReportAsOutputStream method threw a Pentaho ReportProcessingException "
+ "exception: " + e.getMessage() + " ---------- ");
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
} catch (final IOException e) {
errorLog.append("ReadReportingServiceImpl.generatePentahoReportAsOutputStream method threw an IOException "
+ "exception: " + e.getMessage() + " ---------- ");
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
}
errorLog.append("ReadReportingServiceImpl.generatePentahoReportAsOutputStream method threw a PlatformDataIntegrityException "
+ "exception: No matching Output Type: " + outputType + " ---------- ");
throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
*/
return null ;
}
}
@@ -0,0 +1,242 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.gcm;
/**
* Constants used on GCM service communication.
*/
public final class GcmConstants {
/**
* Title for notification
*/
public static final String title = "Hello !";
/**
* icon for notification.
*/
public static final String defaultIcon = "default";
/**
* Parameter for to field.
*/
public static final String PARAM_TO = "to";
/**
* Prefix of the topic.
*/
public static final String TOPIC_PREFIX = "/topics/";
/**
* HTTP parameter for registration id.
*/
//public static final String PARAM_REGISTRATION_ID = "registration_id";
/**
* HTTP parameter for collapse key.
*/
public static final String PARAM_COLLAPSE_KEY = "collapse_key";
/**
* HTTP parameter for delaying the message delivery if the device is idle.
*/
public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
/**
* HTTP parameter for telling gcm to validate the message without actually
* sending it.
*/
public static final String PARAM_DRY_RUN = "dry_run";
/**
* HTTP parameter for package name that can be used to restrict message
* delivery by matching against the package name used to generate the
* registration id.
*/
public static final String PARAM_RESTRICTED_PACKAGE_NAME = "restricted_package_name";
/**
* Parameter used to set the message time-to-live.
*/
public static final String PARAM_TIME_TO_LIVE = "time_to_live";
/**
* Parameter used to set the message priority.
*/
public static final String PARAM_PRIORITY = "priority";
/**
* Parameter used to set the content available (iOS only)
*/
public static final String PARAM_CONTENT_AVAILABLE = "content_available";
/**
* Value used to set message priority to normal.
*/
public static final String MESSAGE_PRIORITY_NORMAL = "normal";
/**
* Value used to set message priority to high.
*/
public static final String MESSAGE_PRIORITY_HIGH = "high";
/**
* A particular message could not be sent because the GCM servers were not
* available. Used only on JSON requests, as in plain text requests
* unavailability is indicated by a 503 response.
*/
public static final String ERROR_UNAVAILABLE = "Unavailable";
/**
* A particular message could not be sent because the GCM servers
* encountered an error. Used only on JSON requests, as in plain text
* requests internal errors are indicated by a 500 response.
*/
public static final String ERROR_INTERNAL_SERVER_ERROR = "InternalServerError";
/**
* Token returned by GCM when the requested registration id has a canonical
* value.
*/
public static final String TOKEN_CANONICAL_REG_ID = "registration_id";
/**
* JSON-only field representing the registration ids.
*/
public static final String JSON_REGISTRATION_IDS = "registration_ids";
/**
* JSON-only field representing the to recipient.
*/
public static final String JSON_TO = "to";
/**
* JSON-only field representing the payload data.
*/
public static final String JSON_PAYLOAD = "data";
/**
* JSON-only field representing the notification payload.
*/
public static final String JSON_NOTIFICATION = "notification";
/**
* JSON-only field representing the notification title.
*/
public static final String JSON_NOTIFICATION_TITLE = "title";
/**
* JSON-only field representing the notification body.
*/
public static final String JSON_NOTIFICATION_BODY = "body";
/**
* JSON-only field representing the notification icon.
*/
public static final String JSON_NOTIFICATION_ICON = "icon";
/**
* JSON-only field representing the notification sound.
*/
public static final String JSON_NOTIFICATION_SOUND = "sound";
/**
* JSON-only field representing the notification badge.
*/
public static final String JSON_NOTIFICATION_BADGE = "badge";
/**
* JSON-only field representing the notification tag.
*/
public static final String JSON_NOTIFICATION_TAG = "tag";
/**
* JSON-only field representing the notification color.
*/
public static final String JSON_NOTIFICATION_COLOR = "color";
/**
* JSON-only field representing the notification click action.
*/
public static final String JSON_NOTIFICATION_CLICK_ACTION = "click_action";
/**
* JSON-only field representing the notification body localization key.
*/
public static final String JSON_NOTIFICATION_BODY_LOC_KEY = "body_loc_key";
/**
* JSON-only field representing the notification body localization values.
*/
public static final String JSON_NOTIFICATION_BODY_LOC_ARGS = "body_loc_args";
/**
* JSON-only field representing the notification title localization key.
*/
public static final String JSON_NOTIFICATION_TITLE_LOC_KEY = "title_loc_key";
/**
* JSON-only field representing the notification title localization values.
*/
public static final String JSON_NOTIFICATION_TITLE_LOC_ARGS = "title_loc_args";
/**
* JSON-only field representing the number of successful messages.
*/
public static final String JSON_SUCCESS = "success";
/**
* JSON-only field representing the number of failed messages.
*/
public static final String JSON_FAILURE = "failure";
/**
* JSON-only field representing the number of messages with a canonical
* registration id.
*/
public static final String JSON_CANONICAL_IDS = "canonical_ids";
/**
* JSON-only field representing the id of the multicast request.
*/
public static final String JSON_MULTICAST_ID = "multicast_id";
/**
* JSON-only field representing the result of each individual request.
*/
public static final String JSON_RESULTS = "results";
/**
* JSON-only field representing the error field of an individual request.
*/
public static final String JSON_ERROR = "error";
/**
* JSON-only field sent by GCM when a message was successfully sent.
*/
public static final String JSON_MESSAGE_ID = "message_id";
private GcmConstants() {
throw new UnsupportedOperationException();
}
public static final Integer TIME_TO_LIVE = 30;
}
@@ -0,0 +1,25 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.gcm.api;
public class DeviceRegistrationApiConstants {
public static final String clientIdParamName = "clientId";
public static final String registrationIdParamName = "registrationId";
}
@@ -0,0 +1,160 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.fineract.infrastructure.gcm.api;
import java.util.Collection;
import java.util.HashMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationData;
import org.apache.fineract.infrastructure.gcm.service.DeviceRegistrationReadPlatformService;
import org.apache.fineract.infrastructure.gcm.service.DeviceRegistrationWritePlatformService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
@Path("/device/registration")
@Component
@Scope("singleton")
public class DeviceRegistrationApiResource {
private final PlatformSecurityContext context;
private final DeviceRegistrationWritePlatformService deviceRegistrationWritePlatformService;
private final DefaultToApiJsonSerializer<DeviceRegistrationData> toApiJsonSerializer;
private final DeviceRegistrationReadPlatformService deviceRegistrationReadPlatformService;
@Autowired
public DeviceRegistrationApiResource(PlatformSecurityContext context,
final DefaultToApiJsonSerializer<DeviceRegistrationData> toApiJsonSerializer,
final DeviceRegistrationReadPlatformService deviceRegistrationReadPlatformService,
final DeviceRegistrationWritePlatformService deviceRegistrationWritePlatformService) {
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.deviceRegistrationReadPlatformService = deviceRegistrationReadPlatformService;
this.deviceRegistrationWritePlatformService = deviceRegistrationWritePlatformService;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String registerDevice(final String apiRequestBodyAsJson) {
this.context.authenticatedUser();
Gson gson = new Gson();
JsonObject json = new Gson().fromJson(apiRequestBodyAsJson, JsonObject.class);
Long clientId = json.get(DeviceRegistrationApiConstants.clientIdParamName).getAsLong();
String registrationId = json.get(DeviceRegistrationApiConstants.registrationIdParamName).getAsString();
DeviceRegistration deviceRegistration = this.deviceRegistrationWritePlatformService.registerDevice(clientId, registrationId);
String response = gson.toJson(deviceRegistration);
return response;
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllDeviceRegistrations(@Context final UriInfo uriInfo) {
this.context.authenticatedUser();
Collection<DeviceRegistrationData> deviceRegistrationDataList = this.deviceRegistrationReadPlatformService
.retrieveAllDeviceRegiistrations();
return this.toApiJsonSerializer.serialize(deviceRegistrationDataList);
}
@GET
@Path("client/{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveDeviceRegistrationByClientId(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
this.context.authenticatedUser();
DeviceRegistrationData deviceRegistrationData = this.deviceRegistrationReadPlatformService
.retrieveDeviceRegiistrationByClientId(clientId);
return this.toApiJsonSerializer.serialize(deviceRegistrationData);
}
@GET
@Path("{id}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveDeviceRegiistration(@PathParam("id") final Long id, @Context final UriInfo uriInfo) {
this.context.authenticatedUser();
DeviceRegistrationData deviceRegistrationData = this.deviceRegistrationReadPlatformService.retrieveDeviceRegiistration(id);
return this.toApiJsonSerializer.serialize(deviceRegistrationData);
}
@PUT
@Path("{id}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDeviceRegistration(@PathParam("id") final Long id, final String apiRequestBodyAsJson) {
this.context.authenticatedUser();
Gson gson = new Gson();
JsonObject json = new Gson().fromJson(apiRequestBodyAsJson, JsonObject.class);
Long clientId = json.get(DeviceRegistrationApiConstants.clientIdParamName).getAsLong();
String registrationId = json.get(DeviceRegistrationApiConstants.registrationIdParamName).getAsString();
DeviceRegistration deviceRegistration = this.deviceRegistrationWritePlatformService.updateDeviceRegistration(id, clientId,
registrationId);
String response = gson.toJson(deviceRegistration);
return response;
}
@DELETE
@Path("{id}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String delete(@PathParam("id") final Long id) {
this.context.authenticatedUser();
this.deviceRegistrationWritePlatformService.deleteDeviceRegistration(id);
return responseMap(id);
}
public String responseMap(Long id){
HashMap<String, Object> responseMap = new HashMap<>();
responseMap.put("resource", id);
return new Gson().toJson(responseMap);
}
}

Some files were not shown because too many files have changed in this diff Show More