Skip to content

Commit

Permalink
ditch brevo for onboarding
Browse files Browse the repository at this point in the history
  • Loading branch information
lexoyo committed Nov 14, 2024
1 parent 470753a commit 1ed132e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 63 deletions.
3 changes: 3 additions & 0 deletions .silex.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const node_modules = require('node_modules-path')
const onboarding = require(__dirname + '/server-plugins/onboarding.js')
const { join } = require('path')

// Load .env file
require('dotenv').config()

module.exports = async function (config) {
await config.addPlugin(dash)
await config.addPlugin(onboarding)
Expand Down
1 change: 1 addition & 0 deletions client-plugins/onboarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ async function hook(type, lang) {
},
body: JSON.stringify({
type,
lang,
})
})
if(response.status < 400) {
Expand Down
4 changes: 4 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ GITLAB2_DISPLAY_NAME=
GITLAB2_DOMAIN=
GITLAB2_CLIENT_ID=
GITLAB2_CLIENT_SECRET=

NOCO_URL=
NOCO_API_KEY=
NOCO_TABLE=
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"dependencies": {
"@silexlabs/silex": "^3.0.0-alpha.179",
"@silexlabs/silex-cms": "^0.0.157",
"@silexlabs/silex-dashboard": "^1.0.73"
"@silexlabs/silex-dashboard": "^1.0.73",
"dotenv": "^16.4.5"
},
"repository": {
"type": "git",
Expand Down
171 changes: 109 additions & 62 deletions server-plugins/onboarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const ONBOADRDING_STEPS = require('../onboarding.json')

/**
* @fileoverview
* This plugin is used to store user information in brevo
* This plugin is used to store user information in db
* It will start an onboarding process the first time the user logs in
* and the first time the user publishes a website.
*/
Expand All @@ -20,12 +20,12 @@ function getOnboarding(type, oldUser, lang) {
}
switch(type) {
case 'STORAGE':
// User already in brevo
// User already in db
if(oldUser) return null
// First time no see
return steps.STORAGE
case 'HOSTING':
// Something went wrong, no user found in brevo
// Something went wrong, no user found in db
if(!oldUser?.attributes) return null
// User already published
if(oldUser.attributes.HAS_PUBLISHED) return null
Expand All @@ -46,104 +46,151 @@ async function getUserFromConnector(connectors, session) {
return null
}

async function getUserFromBrevo(email) {
const response = await fetch(`https://api.brevo.com/v3/contacts/${email}`, {
headers: {
'accept': 'application/json',
'api-key': process.env.BREVO_API_KEY,
const nocoUrl = process.env.NOCO_URL
const nocoTableName = process.env.NOCO_TABLE
const nocoApiKey = process.env.NOCO_API_KEY

async function loadUserFromDatabase(email) {
try {
const limit = 1
const url = `${ nocoUrl }/api/v2/tables/${ nocoTableName }/records?where=${ encodeURI(`where=(email,eq,${ email })`) }&limit=${ limit }`
const response = await fetch(url, {
"headers": {
"xc-token": `${ nocoApiKey }`,
"Accept": "application/json",
"Cache-Control": "no-cache"
},
"method": "GET",
})

if (response.status < 400) {
const responseData = await response.json();
if (responseData.list && responseData.list.length > 0) {
return responseData.list[0]; // Return the first user if found
} else {
return null; // Return null if no user is found
}
} else {
const errorText = await response.text();
console.error('Error while fetching user from NocoDB', response.status, response.statusText, errorText);
throw new Error(`Error while fetching user from NocoDB: ${ response.statusText } - ${ errorText }`);
}
})
if(response.status < 400) {
const responseData = await response.json()
return responseData
} else if(response.status === 404) {
return null
} else {
console.error('Error while fetching user from brevo', response.statusText, await response.text())
throw new Error('Error while fetching user from brevo: ' + response.statusText, await response.text())
} catch (error) {
console.error('Error in loadUserFromDatabase:', error);
throw error;
}
}

function getCurrentDateForMySQL() {
const today = new Date();
const day = String(today.getDate()).padStart(2, '0');
const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-based
const year = today.getFullYear();
return `${year}-${month}-${day}`;
}

/**
* @returns true if the user was updated, false if the user was created
*/
async function storeUser(user, type) {
async function saveUserToDatabase(user, type, lang) {
const headers = {
'accept': 'application/json',
'api-key': process.env.BREVO_API_KEY,
'content-type': 'application/json'
}
const data = {
updateEnabled: true,
email: user.email,
attributes: {
FIRSTNAME: user.name.split(' ')[0],
LASTNAME: user.name.split(' ')[1],
},
listIds: process.env.BREVO_LIST_ID.split(',').map(id => parseInt(id)),
}
if(type === 'HOSTING') {
data.attributes.HAS_PUBLISHED = true
}
'xc-token': process.env.NOCO_API_KEY,
'content-type': 'application/json',
};

const response = await fetch(process.env.BREVO_API_URL, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
})
// Check if the user already exists
const existingUser = await loadUserFromDatabase(user.email);
const [first_name, last_name] = user.name.split(' ');

if (existingUser) {
const updated = getCurrentDateForMySQL()
console.log('date_first_published', created);
// Update the existing user
const updateData = {
Id: existingUser.Id,
name: user.name,
last_name,
first_name,
updated,
lang,
};

if(response.status < 400) {
// If response is empty
if(response.status === 204) {
return true
const response = await fetch(`${process.env.NOCO_URL}/api/v2/tables/${process.env.NOCO_TABLE}/records/`, {
method: 'PATCH',
headers: headers,
body: JSON.stringify({
...updateData,
}),
});

if (response.status < 400) {
return true;
} else {
const responseData = await response.json()
return false
console.error('Error while updating user in NocoDB', response.statusText, await response.text());
throw new Error('Error while updating user in NocoDB: ' + response.statusText);
}
} else {
console.error('Error while storing user in brevo', response.statusText, await response.text())
throw new Error('Error while storing user in brevo: ' + response.statusText, await response.text())
const updated = getCurrentDateForMySQL()
console.log('date_first_published', updated);
// Create a new user
const createData = {
email: user.email,
name: user.name,
last_name,
first_name,
updated,
...(type === 'HOSTING' && { date_first_published: updated }), // Conditional attribute
lang,
};

const response = await fetch(`${process.env.NOCO_URL}/api/v2/tables/${process.env.NOCO_TABLE}/records`, {
method: 'POST',
headers: headers,
body: JSON.stringify(createData),
});

if (response.status < 400) {
return false;
} else {
console.error('Error while creating user in NocoDB', response.statusText, await response.text());
throw new Error('Error while creating user in NocoDB: ' + response.statusText);
}
}
}


module.exports = async function(config, options) {
console.info('> Silex brevo plugin starting', {options})
console.info('> Silex onboarding plugin starting', {options})

// Check the environment variables
if(!process.env.BREVO_API_KEY) {
console.warn('No BREVO_API_KEY env variable => skipping brevo')
if(!['NOCO_URL', 'NOCO_API_KEY', 'NOCO_TABLE'].every(env => process.env[env])) {
console.warn('Missing NOCODB env variables => NOCODB off')
return
}
if(!process.env.BREVO_API_URL) {
throw new Error('No BREVO_API_URL env variable')
}
if(!process.env.BREVO_LIST_ID) {
throw new Error('No BREVO_LIST_ID env variable')
}

// Serve the dashboard and the editor
config.on(ServerEvent.STARTUP_START, ({app}) => {
const editorRouter = express.Router()
editorRouter.post(apiUrl, express.json(), async (request, response) => {
try {
const lang = request.headers['accept-language']
// Get all the connectors
const connectors = config.getConnectors()
// Find the first connected storage connector
const user = await getUserFromConnector(connectors, request.session)
if(user) {
// Get the user from brevo
const oldUser = await getUserFromBrevo(user.email)
// Store the user in brevo
await storeUser(user, request.body.type)
// Get the user from db
const oldUser = await loadUserFromDatabase(user.email)
// Store the user in db
await saveUserToDatabase(user, request.body.type, request.body.lang)
// Return the connector info
response.json({
success: true,
onboarding: getOnboarding(request.body.type, oldUser, lang),
onboarding: getOnboarding(request.body.type, oldUser, request.body.lang),
})
}
} catch (error) {
console.error('Error while storing user in brevo', error)
console.error('Error while storing user in db', error)
// Ignore any error as onboarding is not critical
response.json({success: false})
}
Expand Down

0 comments on commit 1ed132e

Please sign in to comment.