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
28 changes: 28 additions & 0 deletions backend/localhost+1-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC95BucU1yG9ca1
DvJZm6qkDNg2SNZSQZIuB7b5KTk73cdjOJDnXfL8WXzzuxg3Toab22vvsAk+ZVvR
8mAUCg8/FJ1HoPUvf+7GofwByE1cup/sDnJbgkp6EbCCAOFgS2bAD8Pb2r0/1dzS
c03z8U3IRFTvhkDMZRMRXJIwU3r6/F0hfF0ouCY9tCqGLpsp/kIo8M9pgpkPVr3n
b+z1Jtoc5av75Y1DQU8KtRqjX9jZ8UrcRKtXe5dM/+p8R47v+vmW/1qSh0xAqJqn
ZNNKSnd0zIbslN8bv2xWQkkJBzc6TagWid61AxVrw5TVp8ReGrVDWb9tzo2II2Zr
cSYA5j+LAgMBAAECggEAKUNFIK4YoBcOK8/op8IkzWshHIKtV8h53Fi+0Nu9XR3v
Msda7XvDzkQf29KfC32b0IhYpwfoqk9aKX/yksgw0fNHzgXS4ZR6LV2LplOBRBIl
qCTngq0IRAhOA6HvV35rAHcshzy7/QAa8PwvRz/7N/ZpQnc443FfOFmWRrwNMDaA
lziW8am8bX5KkAGtoqLSL2AK0unMUuJA5sQYUeR+gFTQ6fsbMp+4tzjmqopuKGlz
uQoj6YuuwTzaPMk2SyebOQTv+CMtw8ISS7i89wusqL9bz/NdpEv6xozhPE5GpmWS
Ql+tzbc4rjo75Lo6WFdHUG+CUreBsKWiZx/ZgFTmQQKBgQDSzC7fRp7LhdQOkSwZ
vKunmNw83d8I7DU8OpZFHpQz6z1mIXE4el+fBeo6ys9tNXDc0jmFMTlgBtKomGTI
sfuTBhMwxyFqQ+EX4M6/TtZ9AdTU1ujpgWFDPFXYXMLg8dZ5qV/3JPBVVufOOCIA
yRgPrjGymKxGx6hRwfchXNUeqwKBgQDmnEB0uo6YDJWrIfbPOQDnpDpId1CGwmPl
kab2BGXPLtjph+gz9wKYlCRhVsqv3YeHLd9p48D2DsNVKs/l2xgTRVRV/y9YM1KA
mrSgF9gTUhax09JKx9YrNoMVyBXC5svo4JKKi+b9LLuGNQGegTmpDqSqevfPIpJJ
hD5FkWHioQKBgAPJ+8WzpUMPQsKIRXyo8YTvsHW/nzSv2j0c6HqRlCRixBXD4B8d
w/49wvoPjy7tWPv/I12LhvZ86Ohy5MzetiDsaQflbGpWkgM13UF/D0fr8oFo44Le
+nqU6Q4cjLwyXKKPMtRka5V9HGmOhL3y32XYwbfuGpqjGBlwHRsSahpFAoGAT6Iv
Y9+0M+9Mk77zwpU1qcf9VF7XUOG5q2HDnPrhyUytHN+QoLkwjU3CzlYxQc+m6Fg/
6Qn77Twl2bgh+IbS5nyvZc7sI3H9kGlb7FivheR378psuOQPIfb+BzyDvz0BtxYt
pGgxSMX0r6CIQZrwNV/YHwK9piqTB44CDvXoLmECgYEAvxOVma4GvLnyB5Zsiv4m
F4gz+aGX894S4tUHsFQRGwVGkr1RRmdEJZsj8vzZ+o3HSW8oGL7R12lQoOx4H0wM
k/d3FK4YPi5yOvvk38+wIAJvHpvaxUJNjLtLggUK4EEOFu6Rzxb76Yo28dcB/BKU
1N1iFgXyZlaszcVIFYuv22w=
-----END PRIVATE KEY-----
26 changes: 26 additions & 0 deletions backend/localhost+1.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEXDCCAsSgAwIBAgIRANe4eaXwDiKLNFI9rV3cK6gwDQYJKoZIhvcNAQELBQAw
gY8xHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEyMDAGA1UECwwpR01Y
XDBHNDAxMTY0OUBERVNLVE9QLTFWNDVLS0ggKDBHNDAxMTY0OSkxOTA3BgNVBAMM
MG1rY2VydCBHTVhcMEc0MDExNjQ5QERFU0tUT1AtMVY0NUtLSCAoMEc0MDExNjQ5
KTAeFw0yMjAzMjQwMjMzNDFaFw0yNDA2MjQwMjMzNDFaMF0xJzAlBgNVBAoTHm1r
Y2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEyMDAGA1UECwwpR01YXDBHNDAx
MTY0OUBERVNLVE9QLTFWNDVLS0ggKDBHNDAxMTY0OSkwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQC95BucU1yG9ca1DvJZm6qkDNg2SNZSQZIuB7b5KTk7
3cdjOJDnXfL8WXzzuxg3Toab22vvsAk+ZVvR8mAUCg8/FJ1HoPUvf+7GofwByE1c
up/sDnJbgkp6EbCCAOFgS2bAD8Pb2r0/1dzSc03z8U3IRFTvhkDMZRMRXJIwU3r6
/F0hfF0ouCY9tCqGLpsp/kIo8M9pgpkPVr3nb+z1Jtoc5av75Y1DQU8KtRqjX9jZ
8UrcRKtXe5dM/+p8R47v+vmW/1qSh0xAqJqnZNNKSnd0zIbslN8bv2xWQkkJBzc6
TagWid61AxVrw5TVp8ReGrVDWb9tzo2II2ZrcSYA5j+LAgMBAAGjZDBiMA4GA1Ud
DwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBQzjb7q
ctGevL4x7cEuwW5Og3galzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJ
KoZIhvcNAQELBQADggGBAIlAn6FoncPHykKJt7Cy3lbbQFLXtbO//FlzSD8KrkKm
G4dvEVG4u13D6NYHjwBnAWaZprZlvdelcL6REGyNN1YoJRy0nG8IC+DDTpqq3Ez2
ctMZoEQdzYuzqnAXOuA1UrPsBHtAECKF2bYRBkilYF489KYpG9wEKK192F2jy4yq
gYlYAV+2abtuvHjJNF5rF5/ACujvHHdt8deCONE3U8xMUAgT7YSrueuoI+60fdHR
881qggFfFK5SkJqlJ4JUbuD7Gm44s8qKbj5KGzSNoqJe7GX5Nzn80MHPVMWhRfg5
IqTMqvR5FeXEcF1TzSqhlTuw1kO2lZFwXjoDzlz/iq8wNJ3WxJruMkSwjuVICR8b
RvEBf6tMg3iMIDI4WAeG/UvowwyfC6r5KPft4hfv9a99RJXPAO86hDB+eWvAGO25
hBIZNKbX8yiG8cIwB0pq9RlJ+pZJwrYe9ywOD2ni8jcpEZ9cA1vP3wO7h6bkc7he
pwCZvEkuZI9QP3MajEBCUg==
-----END CERTIFICATE-----
Binary file added backend/mkcert.exe
Binary file not shown.
206 changes: 206 additions & 0 deletions backend/src/integrations/AfricaTalks/africaTalks.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { CoopManager } from "./../../db/entities/coopManager";
import Africastalking from "africastalking";
import { Farmer, FarmerModel } from "./../../db/entities/farmer";
import { MessageLog, MessageLogModel, Source, Status } from "./../../db/entities/messageLog";
import { MessagingInterface } from "./../../integrations/messagingInterface";



/**
* The Message we get from africastalks on our webhook
* Source: https://www.twilio.com/docs/messaging/guides/webhook-request
*/
export interface ATMessage {
Sessionid: string;
servicecode: string;
phoneNumber: string;
text: string;


// todo media items
}

/**
* This class handles interfacing with twilio.
* It provides one
*/
class AfricaTalksAPI extends MessagingInterface<ATMessage> {

SMSClient: any;
SMSShortCode: string;

constructor() {
super();
const apiKey = process.env.Africastalking_apiKey;
const username = process.env.Africastalking_username;
this.SMSShortCode = process.env.Africastalking_SMS_ShortCode!!;

if (apiKey === undefined) {
throw new Error("AfricasTalking API Key not defined! Enter the data in the env var: Africastalking_apiKey");
}
if (username === undefined) {
throw new Error("AfricasTalking username not defined! Enter the data in the env var: Africastalking_username");
}
if (this.SMSShortCode === undefined) {
throw new Error("AfricasTalking SMS short code not defined! Enter the data in the env var: Africastalking_SMS_ShortCode");
}

const africastalking = Africastalking({
apiKey,
username
});

this.SMSClient = africastalking.SMS;
}

async sendMessageToFarmer(farmer: Farmer, message: string): Promise<MessageLog> {
const number = farmer.mobile;

if (message === undefined || message === null || message === "") {
throw new Error("Message is empty!");
}

const messageRef = await this.sendMessage(number, message);

const messageLogEntry: MessageLog = {
farmer_id: farmer._id!!.toString(),
address: number,
message,
status: Status.Sent,
source: Source.OpenHarvest,
timestamp: new Date(),
messageRef
}

const messageLog = await MessageLogModel.create(messageLogEntry);

return messageLog;
}

async sendMessageToCoopManager(coopManager: CoopManager, message: string): Promise<MessageLog> {
throw new Error("Method not implemented.");
}


/**
* Send a message to a number
* @param number The number we're sending to
* @param message The string message to send
*/
async sendMessage(number: string, message: string): Promise<string> {
const response = await this.SMSClient.send({
to: number,
message,
from: this.SMSShortCode
});

console.log("[AfricasTalking] Response", response);

return "Unavailable";
}

async onReceivedMessage(message: ATMessage): Promise<MessageLog | null> {
const number = message.phoneNumber;

const farmer = await FarmerModel.findOne({mobile: number});

if (farmer === null) {
console.error("Unknown number!! Ignoring...", number);
return null;
}

const messageLogEntry: MessageLog = {
farmer_id: farmer._id!!.toString(),
address: message.phoneNumber,
message: message.text,
status: Status.Unread,
source: Source.Farmer,
timestamp: new Date(),
messageRef: message.Sessionid+message.text
}

const messageLog = await MessageLogModel.create(messageLogEntry);

this.emit("onMessage", messageLog);
this.notify(messageLog)

return messageLog;
}

async onReceivedUSSDMessage(message: ATMessage): Promise<string> {
const number = message.phoneNumber;

const farmer = await FarmerModel.findOne({mobile: number});

// if (farmer === null) {
// console.error("Unknown number!! Ignoring...", number);
// return null;
// }

const id = farmer ? farmer.id!!.toString() : "";

const messageLogEntry: MessageLog = {
farmer_id: id,
address: message.phoneNumber,
message: message.text,
status: Status.Unread,
source: Source.Farmer,
timestamp: new Date(),
messageRef: message.Sessionid+message.text
}

const messageLog = await MessageLogModel.create(messageLogEntry);

this.emit("onMessage", messageLog);
this.notify(messageLog);

const response = this.handleUSSDMessage(message);

const messageLogResponse: MessageLog = {
farmer_id: id,
address: message.phoneNumber,
message: message.text,
status: Status.Unread,
source: Source.OpenHarvest,
timestamp: new Date(),
messageRef: "OH"+message.Sessionid+message.text
}

const messageLogResponseDoc = await MessageLogModel.create(messageLogEntry);

this.emit("onMessage", messageLogResponseDoc);
this.notify(messageLogResponseDoc);

return response;
}



async handleUSSDMessage(message: ATMessage): Promise<string> {
if (message.text === ""){
return "CON Thank you for contacting OpenHarvest! Here are the menu items: \n 1.Reputation Value \n2.Weather Updates \n3.Send Task status"

}
else if (message.text === "1"){
return "END You are loved"
}
else if (message.text === "2"){
return "Weather Forecast for $date : \nCloudy \nPrecipitation: "
}
else if (message.text === "3"){
return "CON Please enter your task id:"
}
else if (message.text.match(/3\*(\d+)/i)){
return "CON Please enter your task status ( 1 = in-progress , 2 = completed ):"
}
else if (message.text.match(/3\*(\d+)\*(1|2)/i)){
return "END Thank you, your task status has been received."
}


return ""
}

}

export const AfricaTalksInstance = new AfricaTalksAPI();
52 changes: 52 additions & 0 deletions backend/src/integrations/ussdBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// if (message.text === ""){
// return "CON Thank you for contacting OpenHarvest! Here are the menu items: \n 1.Reputation Value \n2.Weather Updates \n3.Send Task status"

// }
// else if (message.text === "1"){
// return "END You are loved"
// }
// else if (message.text === "2"){
// return "Weather Forecast for $date : \nCloudy \nPrecipitation: "
// }
// else if (message.text === "3"){
// return "CON Please enter your task id:"
// }
// else if (message.text.match(/3\*(\d+)/i)){
// return "CON Please enter your task status ( 1 = in-progress , 2 = completed ):"
// }
// else if (message.text.match(/3\*(\d+)\*(1|2)/i)){
// return "END Thank you, your task status has been received."
// }

// export interface Menu {
// message: string;
// type: "menu" | "terminator",
// children: MenuItem[]
// }

// export interface MenuItem extends Menu {
// menuItemName: string;
// onSelect: (history: string) => {}
// }

// const USSDMessagePrompts: Menu = {
// message: "Thank you for contacting OpenHarvest! Here are the menu items",
// type: "menu",
// children: [{
// menuItemName: "Reputation Value",
// type: "terminator",
// onSelect: (history: string) => {return "You are loved"}
// }, {
// menuItemName: "Reputation Value",
// type: "terminator",
// onSelect: (history: string) => {return "You are loved"}
// }]
// }

/**
* This class handles taking in USSD prompts and responding according to a predefined tree
*/
class USSDBuilder {

}

36 changes: 36 additions & 0 deletions backend/src/integrations/weather-company-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,40 @@ export class WeatherCompanyAPI {

// return testForecastData;
}

async sixMonthHistory(geocode: GeoCode, commonOptions = this.defaultOptions) {
const paramOptions = {
geocode: this.GeoCodeToString(geocode),
apiKey: this.apiKey
}
const queryOptions = Object.assign({}, commonOptions, paramOptions);

this.apiHitCounter()

const response = await axios.get(this.baseAPI + "v3/wx/almanac/monthly/6month", {
params: queryOptions
});

return response.data;

// return testForecastData;
}

async twelveMonthHistory(geocode: GeoCode, commonOptions = this.defaultOptions) {
const paramOptions = {
geocode: this.GeoCodeToString(geocode),
apiKey: this.apiKey
}
const queryOptions = Object.assign({}, commonOptions, paramOptions);

this.apiHitCounter()

const response = await axios.get(this.baseAPI + "v3/wx/almanac/monthly/6month", {
params: queryOptions
});

return response.data;

// return testForecastData;
}
}
2 changes: 1 addition & 1 deletion backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const app = express();
app.use(cors());

// enable parsing of http request body
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Enable session for the sole reason of passport-ci-oidc. WE ARE NOT SUPPORTING SESSION BASED AUTH
Expand Down
15 changes: 15 additions & 0 deletions backend/src/routes/dashboard-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ var router = Router();
import LandAreasService from "../services/land-areas.service";
const lotAreas = new LandAreasService();


import { GeoCode } from "integrations/weather-company-api.types";
import { WeatherCompanyAPI } from "./../integrations/weather-company-api.service";



const api = new WeatherCompanyAPI();

const testMchinjiMalawiCoords: GeoCode = {
latitude: -13.7971726,
longitude: 32.8874963
}



//data table
const tableDataYHBC = [
{
Expand Down
Loading