Compare commits

..

13 Commits

Author SHA1 Message Date
212cd48249 debug: postgres conn string
Some checks failed
release / docker (push) Has been cancelled
2024-11-19 17:53:06 +03:00
7adc0c9c08 fix: Dockerfile to include .env
Some checks failed
release / docker (push) Has been cancelled
2024-11-19 17:25:20 +03:00
0a19a6c48b fix: github ci spec
Some checks failed
release / docker (push) Has been cancelled
2024-11-19 17:18:13 +03:00
66b5843b0d feat: dockerfile and github based CI build for Africastalking variant (#174)
## Summary

* fixed missing error handler in main
* add injectable build string in main
* add (dynamically linked) docker build
* add github CI workflow
* add extra but useful dev files in dev folder

* closes #93

## Notes

* We'll move to a self-hosted CI runner once it is installed on Gitea.

Reviewed-on: #174
Co-authored-by: Mohammed Sohail <sohailsameja@gmail.com>
Co-committed-by: Mohammed Sohail <sohailsameja@gmail.com>
2024-11-19 15:15:24 +01:00
carlos
109a2a2020 Merge pull request 'menu-balances' (#173) from menu-balances into master
Reviewed-on: #173
Reviewed-by: Alfred Kamanda <alfredkamandamw@gmail.com>
2024-11-19 08:18:43 +01:00
alfred-mk
bc6d8098f3 updated the failed test 2024-11-19 10:15:34 +03:00
Carlosokumu
01e75e9217 update test 2024-11-18 17:30:34 +03:00
Carlosokumu
f2b17880ba check community and my balance separately 2024-11-18 17:30:09 +03:00
Carlosokumu
1d4f116079 community balance str 2024-11-18 17:23:59 +03:00
Carlosokumu
44c52b6ed7 rename fetch_custodial_balances -> fetch_community_balance 2024-11-18 17:23:36 +03:00
Carlosokumu
454f67b317 show balance based on current voucher 2024-11-18 17:21:04 +03:00
Carlosokumu
e1506a3dcf show a placehlolder community balance 2024-11-18 17:20:12 +03:00
carlos
b22a4adec1 Merge pull request 'updated send node' (#172) from send-node into master
Reviewed-on: #172
2024-11-18 14:19:42 +01:00
18 changed files with 181 additions and 78 deletions

13
.dockerignore Normal file
View File

@@ -0,0 +1,13 @@
/**
!/cmd/africastalking
!/common
!/config
!/initializers
!/internal
!/models
!/remote
!/services
!/LICENSE
!/README.md
!/go.*
!/.env.example

56
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: release
on:
push:
tags:
- "v*"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Check out repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to GHCR Docker registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
run: |
echo "RELEASE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV \
&& echo "RELEASE_SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Build and push image
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
platforms: linux/amd64
push: true
build-args: |
BUILD=${{ env.RELEASE_SHORT_COMMIT }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
tags: |
ghcr.io/grassrootseconomics/urdt-ussd:latest
ghcr.io/grassrootseconomics/urdt-ussd:${{ env.RELEASE_TAG }}

41
Dockerfile Normal file
View File

@@ -0,0 +1,41 @@
FROM golang:1.23.0-bookworm AS build
ENV CGO_ENABLED=1
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG BUILD=dev
WORKDIR /build
COPY . .
RUN apt update && apt install libgdbm-dev
RUN git clone https://git.defalsify.org/vise.git go-vise
WORKDIR /build/services/registration
RUN echo "Compiling go-vise files"
RUN make VISE_PATH=/build/go-vise -B
WORKDIR /build
RUN echo "Building on $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN go mod download
RUN go build -tags logtrace -o ussd-africastalking -ldflags="-X main.build=${BUILD} -s -w" cmd/africastalking/main.go
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install libgdbm-dev ca-certificates -y
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /service
COPY --from=build /build/ussd-africastalking .
COPY --from=build /build/LICENSE .
COPY --from=build /build/README.md .
COPY --from=build /build/services ./services
COPY --from=build /build/.env.example .
RUN mv .env.example .env
EXPOSE 7123
CMD ["./ussd-africastalking"]

View File

@@ -29,8 +29,10 @@ import (
) )
var ( var (
logg = logging.NewVanilla() logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
build = "dev"
) )
func init() { func init() {
@@ -115,7 +117,7 @@ func main() {
flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port") flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port")
flag.Parse() flag.Parse()
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) logg.Infof("start command", "build", build, "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size)
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, "Database", database) ctx = context.WithValue(ctx, "Database", database)
@@ -157,6 +159,10 @@ func main() {
} }
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
if err != nil { if err != nil {

View File

@@ -0,0 +1,3 @@
url: http://localhost:7123
dial: "*384*96#"
phoneNumber: +254722123456

21
dev/docker-compose.yaml Normal file
View File

@@ -0,0 +1,21 @@
services:
ussd-pg-store:
image: postgres:17-alpine
restart: unless-stopped
user: postgres
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
volumes:
- ./init_db.sql:/docker-entrypoint-initdb.d/init_db.sql
- ussd-pg:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
ussd-pg:
driver: local

1
dev/init_db.sql Normal file
View File

@@ -0,0 +1 @@
CREATE DATABASE urdt_ussd;

View File

@@ -103,7 +103,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn
ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp)
ls.DbRs.AddLocalFunc("fetch_custodial_balances", ussdHandlers.FetchCustodialBalances) ls.DbRs.AddLocalFunc("fetch_community_balance", ussdHandlers.FetchCommunityBalance)
ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher) ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher)
ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers)
ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList)

View File

@@ -822,42 +822,14 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
return res, nil return res, nil
} }
func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) FetchCommunityBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
code := codeFromCtx(ctx)
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
sessionId, ok := ctx.Value("SessionId").(string) //TODO:
if !ok { //Check if the address is a community account,if then,get the actual balance
return res, fmt.Errorf("missing session") res.Content = l.Get("Community Balance: 0.00")
}
symbol, _ := h.st.Where()
balanceType := strings.Split(symbol, "_")[0]
store := h.userdataStore
publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err)
return res, err
}
balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey))
if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error)
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_api_error)
balance := balanceResponse.Balance
switch balanceType {
case "my":
res.Content = fmt.Sprintf("Your balance is %s", balance)
case "community":
res.Content = fmt.Sprintf("Your community balance is %s", balance)
default:
break
}
return res, nil return res, nil
} }

View File

@@ -2,7 +2,6 @@ package ussd
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"log" "log"
"path" "path"
@@ -1773,58 +1772,43 @@ func TestConfirmPin(t *testing.T) {
} }
} }
func TestFetchCustodialBalances(t *testing.T) { func TestFetchCommunityBalance(t *testing.T) {
fm, err := NewFlagManager(flagsPath)
if err != nil {
t.Logf(err.Error())
}
flag_api_error, _ := fm.GetFlag("flag_api_call_error")
// Define test data // Define test data
sessionId := "session123" sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
err = store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
tests := []struct { tests := []struct {
name string name string
balanceResponse *models.BalanceResult languageCode string
expectedResult resource.Result expectedResult resource.Result
}{ }{
{ {
name: "Test when fetch custodial balances is not a success", name: "Test community balance content when language is english",
balanceResponse: &models.BalanceResult{
Balance: "0.003 CELO",
Nonce: json.Number("0"),
},
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_api_error}, Content: "Community Balance: 0.00",
}, },
languageCode: "eng",
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
mockState := state.NewState(16) mockState := state.NewState(16)
h := &Handlers{ h := &Handlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser,
st: mockState, st: mockState,
accountService: mockAccountService, accountService: mockAccountService,
} }
ctx = context.WithValue(ctx, "SessionId", sessionId)
// Set up the expected behavior of the mock ctx = context.WithValue(ctx, "Language", lang.Language{
mockAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResponse, nil) Code: tt.languageCode,
})
// Call the method // Call the method
res, _ := h.FetchCustodialBalances(ctx, "fetch_custodial_balances", []byte("")) res, _ := h.FetchCommunityBalance(ctx, "fetch_community_balance", []byte(""))
//Assert that the result set to content is what was expected //Assert that the result set to content is what was expected
assert.Equal(t, res, tt.expectedResult, "Result should match expected result") assert.Equal(t, res, tt.expectedResult, "Result should match expected result")

View File

@@ -41,10 +41,13 @@ func buildConnStr() string {
dbName := initializers.GetEnv("DB_NAME", "") dbName := initializers.GetEnv("DB_NAME", "")
port := initializers.GetEnv("DB_PORT", "5432") port := initializers.GetEnv("DB_PORT", "5432")
return fmt.Sprintf( connString := fmt.Sprintf(
"postgres://%s:%s@%s:%s/%s", "postgres://%s:%s@%s:%s/%s",
user, password, host, port, dbName, user, password, host, port, dbName,
) )
logg.Debugf("pg conn string", "conn", connString)
return connString
} }
func NewMenuStorageService(dbDir string, resourceDir string) *MenuStorageService { func NewMenuStorageService(dbDir string, resourceDir string) *MenuStorageService {

View File

@@ -103,7 +103,7 @@
}, },
{ {
"input": "1234", "input": "1234",
"expectedContent": "Your balance is 0.003 CELO\n0:Back\n9:Quit" "expectedContent": "Balance: {balance}\n\n0:Back\n9:Quit"
}, },
{ {
"input": "0", "input": "0",
@@ -149,7 +149,7 @@
}, },
{ {
"input": "1234", "input": "1234",
"expectedContent": "Your community balance is 0.003 CELO\n0:Back\n9:Quit" "expectedContent": "{balance}\n0:Back\n9:Quit"
}, },
{ {
"input": "0", "input": "0",

View File

@@ -1 +1 @@
Salio la kikundi {{.fetch_community_balance}}

View File

@@ -1 +1 @@
{{.fetch_custodial_balances}} {{.fetch_community_balance}}

View File

@@ -1,7 +1,7 @@
LOAD reset_incorrect 6 LOAD reset_incorrect 6
LOAD fetch_custodial_balances 0 LOAD fetch_community_balance 0
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
MAP fetch_custodial_balances MAP fetch_community_balance
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0 CATCH pin_entry flag_account_authorized 0
MOUT back 0 MOUT back 0

View File

@@ -21,3 +21,6 @@ msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu limetumwa."
msgid "Your request failed. Please try again later." msgid "Your request failed. Please try again later."
msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye." msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye."
msgid "Community Balance: 0.00"
msgid "Salio la Kikundi: 0.00"

View File

@@ -1 +1 @@
{{.fetch_custodial_balances}} {{.check_balance}}

View File

@@ -1,7 +1,7 @@
LOAD reset_incorrect 6 LOAD reset_incorrect 6
LOAD fetch_custodial_balances 0 LOAD check_balance 0
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
MAP fetch_custodial_balances MAP check_balance
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0 CATCH pin_entry flag_account_authorized 0
MOUT back 0 MOUT back 0