diff --git a/web/package.json b/web/package.json
index 927f91588..46564bd3c 100644
--- a/web/package.json
+++ b/web/package.json
@@ -42,7 +42,9 @@
"@sanity/client": "5.4.2",
"@sanity/image-url": "^1.0.2",
"@sanity/webhook": "^2.0.0",
+ "@types/axios": "^0.14.4",
"algoliasearch": "^4.16.0",
+ "axios": "^1.7.9",
"date-fns": "^2.29.3",
"date-fns-tz": "^2.0.0",
"easy-soap-request": "^5.4.0",
diff --git a/web/pages/api/news-letter-distribution.ts b/web/pages/api/news-letter-distribution.ts
index a13436265..3aa7980e0 100644
--- a/web/pages/api/news-letter-distribution.ts
+++ b/web/pages/api/news-letter-distribution.ts
@@ -1,6 +1,5 @@
import { distribute } from './subscription'
import { languages } from '../../languages'
-import { NewsDistributionParameters } from '../../types/index'
import { NextApiRequest, NextApiResponse } from 'next'
import { isValidSignature, SIGNATURE_HEADER_NAME } from '@sanity/webhook'
import getRawBody from 'raw-body'
@@ -17,6 +16,16 @@ export const config = {
},
}
+export type NewsDistributionParameters = {
+ segmentId?: number
+ timeStamp: string
+ title: string
+ ingress: string
+ link: string
+ newsType: string
+ languageCode: string
+}
+
const logRequest = (req: NextApiRequest, title: string) => {
console.log('\n')
console.log(title)
@@ -36,7 +45,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
logRequest(req, 'Unauthorized request: Newsletter Distribution Endpoint')
return res.status(401).json({ success: false, msg: 'Unauthorized!' })
}
-
+
const { publicRuntimeConfig } = getConfig()
const data = JSON.parse(body)
const locale = languages.find((lang) => lang.name == data.languageCode)?.locale || 'en'
@@ -83,7 +92,7 @@ async function distributeWithRetry(
const date = getDateWithMs()
try {
- const isSuccessful = await distribute(newsDistributionParameters)
+ const isSuccessful = await distribute()
if (!isSuccessful) throw new Error('Distribution was unsuccessful.')
res = {
success: true,
diff --git a/web/pages/api/rss/groq.global.ts b/web/pages/api/rss/groq.global.ts
index 7abad096c..bd168a61a 100644
--- a/web/pages/api/rss/groq.global.ts
+++ b/web/pages/api/rss/groq.global.ts
@@ -12,6 +12,7 @@ export type LatestNewsType = {
publishDateTime: string
hero: ImageWithCaptionData
ingress: PortableTextBlock
+ subscriptionType: string
}
export const latestNews = /* groq */ `
@@ -20,6 +21,7 @@ export const latestNews = /* groq */ `
"slug": slug.current,
title,
"hero": heroImage,
+ subscriptionType,
"publishDateTime": ${publishDateTimeQuery},
${ingressForNewsQuery},
}
diff --git a/web/pages/api/rss/index.global.ts b/web/pages/api/rss/index.global.ts
index 8fa5e3aee..a92c1b2b4 100644
--- a/web/pages/api/rss/index.global.ts
+++ b/web/pages/api/rss/index.global.ts
@@ -55,6 +55,7 @@ const generateRssFeed = async (lang: 'no' | 'en') => {
https://equinor.com${lang === 'no' ? '/no' : ''}${article.slug}
${new Date(article.publishDateTime).toUTCString()}
${descriptionHtml}]]>
+ ${article.subscriptionType ? `${article.subscriptionType}` : ''}
`
})
diff --git a/web/pages/api/subscription.ts b/web/pages/api/subscription.ts
index 3bbbf51f3..0ec3027f9 100644
--- a/web/pages/api/subscription.ts
+++ b/web/pages/api/subscription.ts
@@ -1,120 +1,105 @@
-import soapRequest from 'easy-soap-request'
-import * as xml2js from 'xml2js'
-import { LoginResult, SubscribeFormParameters, NewsDistributionParameters } from '../../types/index'
-//import { appInsights } from '../../common'
+import axios from 'axios'
-const subscriptionUrl = process.env.BRANDMASTER_EMAIL_SUBSCRIPTION_URL || ''
-export const authenticationUrl = process.env.BRANDMASTER_EMAIL_AUTHENTICATION_URL || ''
-const clientSecret = process.env.BRANDMASTER_EMAIL_CLIENT_SECRET
-const password = process.env.BRANDMASTER_EMAIL_PASSWORD
-const apnId = process.env.BRANDMASTER_EMAIL_APN_ID
-const otyId = process.env.BRANDMASTER_EMAIL_OTY_ID
-const ptlId = process.env.BRANDMASTER_EMAIL_PTL_ID
-
-const sampleHeaders = {
- 'Content-Type': 'text/xml;charset=UTF-8',
+export type SubscribeFormParameters = {
+ firstName: string
+ email: string
+ crudeOilAssays?: boolean
+ generalNews?: boolean
+ magazineStories?: boolean
+ stockMarketAnnouncements?: boolean
+ languageCode: string
}
-const xml = `${clientSecret}SUBSCRIPTIONAPI${password}34${ptlId}${otyId}1${apnId}`
-const authenticate = async () => {
- const { response } = await soapRequest({
- url: authenticationUrl,
- headers: sampleHeaders,
- xml: xml,
- timeout: 5000,
- })
- const { body } = response
- let apiSecret = ''
- let instId = ''
- xml2js.parseString(body, function (err, result) {
- if (err != null) console.error('Error while authenticating from Brandmaster : ----------------\n' + err)
- if (parsedError(result, 'could not get apiSecret and instId ') != undefined) return
- const soapBody = result['SOAP-ENV:Envelope']['SOAP-ENV:Body']['0']
- const loginResult = soapBody['v1:Authentication___LoginResponse']['0']['v1:Result']['0']
- apiSecret = loginResult['v1:apiSecret']['0']
- instId = loginResult['v1:instId']['0']
- })
- return { apiSecret, instId }
+const MAKE_SUBSCRIBER_API_BASE_URL = process.env.MAKE_SUBSCRIBER_API_BASE_URL
+const MAKE_NEWSLETTER_API_BASE_URL = process.env.MAKE_NEWSLETTER_API_BASE_URL
+const MAKE_API_KEY = process.env.MAKE_API_KEY || ''
+const SUBSCRIBER_LIST_ID = process.env.MAKE_SUBSCRIBER_LIST_ID
+const MAKE_API_USER = process.env.MAKE_API_USERID || ''
+const MAKE_NEWSLETTER_ID = process.env.MAKE_NEWSLETTER_ID
+
+export type NewsDistributionParameters = {
+ newsletterId: number
+ senderId: number
+ segmentId?: number
+ timeStamp: string
+ title: string
+ ingress: string
+ link: string
+ newsType: string
+ languageCode: string
}
-const createSignUpRequest = async (loginResult: LoginResult, formParameters: SubscribeFormParameters) => {
- const additionalParameters = `
- {
- "stock_market": "${formParameters.stockMarketAnnouncements ? 'Y' : 'N'}",
- "company_news": "${formParameters.generalNews ? 'Y' : 'N'}",
- "crude_oil_assays": "${formParameters.crudeOilAssays ? 'Y' : 'N'}",
- "magazine": "${formParameters.magazineStories ? 'Y' : 'N'}",
- "type": "Investor",
- "lang": "${formParameters.languageCode}"
- }`
+const subscriberApi = axios.create({
+ baseURL: MAKE_SUBSCRIBER_API_BASE_URL,
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${Buffer.from(`${MAKE_API_USER}:${MAKE_API_KEY}`).toString('base64')}`,
+ },
+})
- const envelope = `${clientSecret}${loginResult.apiSecret}${loginResult.instId}${formParameters.firstName}${formParameters.email}${additionalParameters}`
- const { response } = await soapRequest({
- url: subscriptionUrl,
- headers: sampleHeaders,
- xml: envelope,
- timeout: 5000,
- })
- xml2js.parseString(response.body, function (err, result) {
- if (err != null) {
- console.log('Error while creating signup request to Brandmaster : ----------------\n' + err)
- response.statusCode = 500
- }
- if (parsedError(result, 'could not create sign up request ') != undefined) {
- response.statusCode = 500
- return
- }
- })
- return response.statusCode == 200
-}
+/**
+ * Subscribe a user using subscriber_list_id and tags
+ */
+export const signUp = async (formParameters: SubscribeFormParameters) => {
+ try {
+ const requestedTags: string[] = []
+ if (formParameters.stockMarketAnnouncements) requestedTags.push('Stock')
+ if (formParameters.generalNews) requestedTags.push('Company')
+ if (formParameters.crudeOilAssays) requestedTags.push('Crude')
+ if (formParameters.magazineStories) requestedTags.push('Magazine')
-const createDistributeRequest = async (loginResult: LoginResult, parameters: NewsDistributionParameters) => {
- const envelope = `${clientSecret}${loginResult.apiSecret}${loginResult.instId}${parameters.timeStamp}`
- const { response } = await soapRequest({
- url: subscriptionUrl,
- headers: sampleHeaders,
- xml: envelope,
- timeout: 5000,
- })
- xml2js.parseString(response.body, function (err, result) {
- if (err != null) {
- console.error('Error while creating distribute request to Brandmaster : ----------------\n' + err)
- response.statusCode = 400
- }
- const error = parsedError(
- result,
- 'could not distribute newsletter ' + parameters.link + ' published at ' + parameters.timeStamp,
- )
- if (error != undefined) {
- // should trigger mail...
- console.log('Newsletter distribution failure', response.body.toString())
- // @TODO Move to Dynatrace
- // appInsights.trackEvent({name:"Newsletter distribution failure"},{message:error})
- response.statusCode = 400
+ const requestBody = {
+ email: formParameters.email,
+ tags: requestedTags,
}
- })
- return response.statusCode == 200
-}
+ console.log('📤 Sending subscription request:', {
+ url: `/subscribers?subscriber_list_id=${SUBSCRIBER_LIST_ID}`,
+ headers: subscriberApi.defaults.headers,
+ body: requestBody,
+ })
-export const signUp = async (formParameters: SubscribeFormParameters) => {
- const loginResult = await authenticate()
- if (loginResult.apiSecret != '' && loginResult.instId != '') return createSignUpRequest(loginResult, formParameters)
- else return false
-}
+ const response = await subscriberApi.post(`/subscribers?subscriber_list_id=${SUBSCRIBER_LIST_ID}`, requestBody)
-export const distribute = async (parameters: NewsDistributionParameters) => {
- const loginResult = await authenticate()
- if (loginResult.apiSecret != '' && loginResult.instId != '') {
- return createDistributeRequest(loginResult, parameters)
- } else return false
+ return response.status === 200
+ } catch (error: any) {
+ console.error('❌ Error in signUp:', {
+ message: error.message,
+ responseData: error.response?.data,
+ responseStatus: error.response?.status,
+ requestHeaders: error.config?.headers,
+ })
+ return false
+ }
}
-const parsedError = (result: any, prefix: string) => {
- const soapBody = result['SOAP-ENV:Envelope']['SOAP-ENV:Body']['0']
- if (soapBody['SOAP-ENV:Fault'] != undefined) {
- const error = soapBody['SOAP-ENV:Fault']['0']['faultstring']
- console.error(Date() + ' : Newsletter Failure Error: ' + prefix + '\n' + error)
- return error
+const newsletterApi = axios.create({
+ baseURL: MAKE_NEWSLETTER_API_BASE_URL,
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${Buffer.from(`${MAKE_API_USER}:${MAKE_API_KEY}`).toString('base64')}`,
+ },
+})
+
+/**
+ * Distribute a newsletter
+ */
+export const distribute = async () => {
+ try {
+ const url = `${MAKE_NEWSLETTER_API_BASE_URL}/recurring_actions/${MAKE_NEWSLETTER_ID}/trigger`
+ const requestBody = {
+ sender_id: MAKE_API_USER,
+ }
+ const response = await newsletterApi.post(url, requestBody)
+ return response.status === 200
+ } catch (error: any) {
+ console.error('❌ Error in distribute:', {
+ message: error.message,
+ responseData: error.response?.data,
+ responseStatus: error.response?.status,
+ requestHeaders: error.config?.headers,
+ })
+
+ return false
}
}
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml
index e299bae72..965963caa 100644
--- a/web/pnpm-lock.yaml
+++ b/web/pnpm-lock.yaml
@@ -67,9 +67,15 @@ dependencies:
'@sanity/webhook':
specifier: ^2.0.0
version: 2.0.0
+ '@types/axios':
+ specifier: ^0.14.4
+ version: 0.14.4
algoliasearch:
specifier: ^4.16.0
version: 4.16.0
+ axios:
+ specifier: ^1.7.9
+ version: 1.7.9
date-fns:
specifier: ^2.29.3
version: 2.29.3
@@ -7042,6 +7048,15 @@ packages:
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
dev: true
+ /@types/axios@0.14.4:
+ resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==}
+ deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed.
+ dependencies:
+ axios: 1.7.9
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
/@types/babel__core@7.20.5:
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
dependencies:
@@ -7898,8 +7913,8 @@ packages:
- debug
dev: true
- /axios@1.7.7:
- resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==}
+ /axios@1.7.9:
+ resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
dependencies:
follow-redirects: 1.15.9(debug@4.3.7)
form-data: 4.0.0
@@ -9091,7 +9106,7 @@ packages:
/easy-soap-request@5.4.0:
resolution: {integrity: sha512-9LGj3v1ZB1GAYCI127zXxAhubNGP/+j8v44t8DQ2kuFC8kTjG9n3B9WRm4YaoIS1jZRX3YcX5D8Cj0cgdToDLA==}
dependencies:
- axios: 1.7.7
+ axios: 1.7.9
transitivePeerDependencies:
- debug
dev: false
@@ -11274,10 +11289,12 @@ packages:
/lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+ deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
dev: false
/lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
dev: false
/lodash.isplainobject@4.0.6: