Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.class
*.jar
!/keycloak-theme/*.jar
*.war
*.ear
.classpath
Expand Down
16 changes: 16 additions & 0 deletions config/apache/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM httpd:2.4

# Install the pre-packaged OpenID Connect module for Apache
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libapache2-mod-auth-openidc \
ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
ln -s /usr/lib/apache2/modules/mod_auth_openidc.so /usr/local/apache2/modules/mod_auth_openidc.so

# # The httpd.conf file is mounted via docker-compose, so no COPY is needed here.
# # The modules are enabled via LoadModule directives in the mounted httpd.conf.

# # The httpd.conf file is mounted via docker-compose, so no COPY is needed here.
# # The modules are enabled via LoadModule directives in the mounted httpd.conf.
120 changes: 120 additions & 0 deletions config/apache/httpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule auth_openidc_module modules/mod_auth_openidc.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule headers_module modules/mod_headers.so

ServerName localhost

User daemon
Group daemon

Listen 80

LogLevel debug

ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 common

<VirtualHost *:80>
ProxyPreserveHost On

SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

ProxyPass /fineract-provider/ https://fineract:8443/fineract-provider/
ProxyPassReverse /fineract-provider/ https://fineract:8443/fineract-provider/

RewriteEngine on

# --- Cashier App ---
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/cashier/(.*) "ws://172.20.0.1:5173/cashier/$1" [P,L]

ProxyPass /cashier/callback !
ProxyPass /cashier/ http://172.20.0.1:5173/cashier/
ProxyPassReverse /cashier/ http://172.20.0.1:5173/cashier/
ProxyPassReverseCookieDomain 172.20.0.1 localhost
ProxyPassReverseCookiePath / /cashier/

# ----------------------
# OIDC Configuration
# ----------------------
OIDCCryptoPassphrase a-very-secret-passphrase
OIDCProviderMetadataURL http://172.17.0.1:9000/realms/fineract/.well-known/openid-configuration
OIDCClientID web-client
OIDCClientSecret **********
OIDCRedirectURI http://localhost/cashier/callback

OIDCSessionType server-cache
OIDCCookiePath /
OIDCCookieSameSite On

# Prefix used for exported claims in environment vars
OIDCClaimPrefix "OIDC_CLAIM_"

<Location /cashier/>
AuthType openid-connect
Require valid-user

# Export JWT claim as header
RequestHeader set X-Staff-Id "%{OIDC_CLAIM_staffId}e"

# Create a cookie named "staffId" containing that claim value
Header set Set-Cookie "staffId=%{OIDC_CLAIM_staffId}e; Path=/; SameSite=Lax"

</Location>

# --- Fineract API Token Injection ---
<Location /fineract-provider/api/>
AuthType openid-connect
Require valid-user
RequestHeader set Authorization "Bearer %{OIDC_access_token}e"
RequestHeader set Fineract-Platform-TenantId "default"
</Location>

# --- Branch Manager App ---
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/branch/(.*) "ws://172.20.0.1:5174/branch/$1" [P,L]

ProxyPass /branch/callback !
ProxyPass /branch/ http://172.20.0.1:5174/branch/
ProxyPassReverse /branch/ http://172.20.0.1:5174/branch/
ProxyPassReverseCookiePath / /branch/

<Location /branch/>
AuthType openid-connect
Require valid-user
</Location>

# --- Account Manager App ---
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/account/(.*) "ws://172.20.0.1:5175/account/$1" [P,L]

ProxyPass /account/callback !
ProxyPass /account/ http://172.20.0.1:5175/account/
ProxyPassReverse /account/ http://172.20.0.1:5175/account/
ProxyPassReverseCookiePath / /account/

<Location /account/>
AuthType openid-connect
Require valid-user
</Location>

</VirtualHost>
1 change: 1 addition & 0 deletions config/docker/env/fineract.env
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
#

FINERACT_NODE_ID=1
my-org.teller.extended.enabled=true
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<insert tableName="job">
<column name="name" value="Acme Noop Job"/>
<column name="display_name" value="Acme Noop Job"/>
<column name="short_name" value="ACM_NOOP"/>
<column name="cron_expression" value="0 1 0 1/1 * ? *"/>
<column name="create_time" valueDate="${current_datetime}"/>
<column name="task_priority" valueNumeric="5"/>
Expand All @@ -42,10 +43,4 @@
<column name="is_mismatched_job" valueBoolean="true"/>
</insert>
</changeSet>
<changeSet author="acme" id="2">
<update tableName="job">
<column name="short_name" value="ACM_NOOP"/>
<where>name='Acme Noop Job'</where>
</update>
</changeSet>
</databaseChangeLog>
27 changes: 27 additions & 0 deletions custom/myorg/teller/service/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* 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.
*/
description = 'MyOrg Fineract Teller Service'

group = 'com.myorg.fineract'

base {
archivesName = 'myorg-fineract-teller-service'
}

apply from: 'dependencies.gradle'
8 changes: 8 additions & 0 deletions custom/myorg/teller/service/dependencies.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dependencies {
implementation(project(':fineract-core'))
implementation(project(':fineract-provider'))
implementation(project(':fineract-branch'))
implementation('org.springframework.boot:spring-boot-starter-jdbc')
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
compileOnly('org.springframework.boot:spring-boot-autoconfigure')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* 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 com.myorg.fineract.teller.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.service.SqlValidator;
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
import org.apache.fineract.organisation.teller.data.CashierData;
import org.apache.fineract.organisation.teller.service.TellerManagementReadPlatformServiceImpl;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

@Service
@Primary
public class CustomTellerManagementReadPlatformServiceImpl extends TellerManagementReadPlatformServiceImpl {

private static final Logger LOG = LoggerFactory.getLogger(CustomTellerManagementReadPlatformServiceImpl.class);
private final JdbcTemplate jdbcTemplate;

public CustomTellerManagementReadPlatformServiceImpl(final JdbcTemplate jdbcTemplate, final PlatformSecurityContext context,
final OfficeReadPlatformService officeReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService, final DatabaseSpecificSQLGenerator sqlGenerator,
final PaginationHelper paginationHelper, final SqlValidator sqlValidator) {
super(jdbcTemplate, context, officeReadPlatformService, staffReadPlatformService, currencyReadPlatformService, sqlGenerator,
paginationHelper, sqlValidator);
this.jdbcTemplate = jdbcTemplate;
LOG.info("Custom Teller Management Service has been initialized and is overriding the default implementation.");
}

@Override
public Collection<CashierData> getCashierData(Long officeId, Long tellerId, Long staffId, LocalDate date) {
LOG.info("Executing custom getCashierData method with officeId: {}, tellerId: {}, staffId: {}, date: {}", officeId, tellerId,
staffId, date);
final CashierMapper cm = new CashierMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select ").append(cm.schema()).append(" where 1=1 ");

final List<Object> params = new ArrayList<>();

if (officeId != null) {
sqlBuilder.append(" and t.office_id = ? ");
params.add(officeId);
}
if (tellerId != null) {
sqlBuilder.append(" and c.teller_id = ? ");
params.add(tellerId);
}
if (staffId != null) {
sqlBuilder.append(" and c.staff_id = ? ");
params.add(staffId);
}
if (date != null) {
sqlBuilder.append(" and ? between c.start_date and c.end_date ");
params.add(date);
}

return this.jdbcTemplate.query(sqlBuilder.toString(), cm, params.toArray());
}

private static final class CashierMapper implements RowMapper<CashierData> {

public String schema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("c.id as id,c.teller_id as teller_id, t.name as teller_name, c.description as description, ");
sqlBuilder.append("c.staff_id as staff_id, s.display_name as staff_name, ");
sqlBuilder.append("c.start_date as start_date, c.end_date as end_date, ");
sqlBuilder.append("c.full_day as full_day, c.start_time as start_time, c.end_time as end_time ");
sqlBuilder.append("from m_cashiers c ");
sqlBuilder.append("join m_tellers t on t.id = c.teller_id ");
sqlBuilder.append("join m_staff s on s.id = c.staff_id ");
return sqlBuilder.toString();
}

@Override
public CashierData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long tellerId = rs.getLong("teller_id");
final String tellerName = rs.getString("teller_name");
final Long staffId = rs.getLong("staff_id");
final String staffName = rs.getString("staff_name");
final String description = rs.getString("description");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date");
final Boolean fullDay = rs.getBoolean("full_day");
final String startTime = rs.getString("start_time");
final String endTime = rs.getString("end_time");
return CashierData.instance(id, null, null, staffId, staffName, tellerId, tellerName, description, startDate, endDate,
fullDay, startTime, endTime);
}
}
}
31 changes: 31 additions & 0 deletions custom/myorg/teller/starter/build.gradle
Original file line number Diff line number Diff line change
@@ -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.
*/
plugins {
id 'org.springframework.boot'
}

description = 'MyOrg Fineract Teller Starter'

group = 'com.myorg.fineract'

base {
archivesName = 'myorg-fineract-teller-starter'
}

apply from: 'dependencies.gradle'
6 changes: 6 additions & 0 deletions custom/myorg/teller/starter/dependencies.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies {
implementation project(':fineract-provider')
implementation project(':custom:myorg:teller:service')
implementation 'org.springframework.boot:spring-boot-starter'
compileOnly('org.springframework.boot:spring-boot-autoconfigure')
}
Loading
Loading