diff --git a/_static/main.js b/_static/main.js index 78fe007..19d9b0e 100644 --- a/_static/main.js +++ b/_static/main.js @@ -19,56 +19,3 @@ function getCookie(cname) { } return ""; } - -document.addEventListener('DOMContentLoaded', function() { - // Show the email modal if the user has not entered their email - let modal = document.getElementById('email-modal'); - let emailCookie = getCookie("email"); - let emailInput = document.getElementById("email-input"); - let body = document.body - if (emailCookie === false || emailCookie === "" || emailCookie === null) { - modal.style.display = 'flex'; - emailInput.value = ""; - body.style.overflow = "hidden"; - } - emailInput.focus() - - // When user click Enter, click the submit button - emailInput.addEventListener("keypress", function(event) { - if (event.key === "Enter") { - event.preventDefault(); - document.getElementById("email-submit").click(); - } - }); - - // Handle form submission - const form = document.getElementById('email-form'); - form.addEventListener('submit', async function(event) { - event.preventDefault(); - const formData = new FormData(form); - const email = formData.get('email'); - if (!email) return; - try { - const response = await fetch('https://state-of-open-source-ai.vercel.app/api/add-member', { - method: 'POST', - body: JSON.stringify({ email }), - headers: { - 'Content-Type': 'application/json', - }, - }); - - const responseData = await response.json(); - - if (response.ok) { - let modal = document.getElementById('email-modal'); - modal.style.display = 'none'; - setCookie("email", emailInput.value, 365); // might fail if cookies disabled - } else { - document.querySelector('.email-error').textContent = responseData.error || 'An unexpected error occurred. Please enter a valid email.'; - } - } catch (error) { - console.error('Error:', error); - document.querySelector('.email-error').textContent = 'An unexpected error occurred. Please try again.'; - } - }); -}); diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index 6096ed2..0000000 --- a/backend/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vercel -node_modules diff --git a/backend/api/add-member.js b/backend/api/add-member.js deleted file mode 100644 index 916ae14..0000000 --- a/backend/api/add-member.js +++ /dev/null @@ -1,62 +0,0 @@ -import jwt from 'jsonwebtoken'; -import axios from 'axios'; -import ZeroBounceSDK from '@zerobounce/zero-bounce-sdk'; - -export default async function handler(req, res) { - // Set CORS headers - const allowedOrigins = ['https://book.premai.io', 'http://localhost:8000']; - const origin = req.headers.origin; - if (allowedOrigins.includes(origin)) { - res.setHeader('Access-Control-Allow-Origin', origin); - } - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); - - if (req.method === 'OPTIONS') { - return res.status(200).end(); - } - - // Verify email address - const zeroBounce = new ZeroBounceSDK(); - zeroBounce.init(process.env.ZEROBOUNCE_API_KEY); - const email = req.body.email; - - try { - const response = await zeroBounce.validateEmail(email); - console.log("response", response); - if (response.status === 'valid') { - console.log(`Email ${email} is valid`); - } else { - console.error(response.status); - return res.status(400).json({ error: `Invalid email address ${email}. Status: ${response.status}` }); - } - } catch (error) { - console.error("ZeroBounce error", error); - return res.status(500).json({ error: error.message }); - } - - // Add member to Ghost - const BLOG_URL = "https://prem.ghost.io"; - const [id, secret] = process.env.GHOST_ADMIN_API_KEY.split(':'); - const token = jwt.sign({}, Buffer.from(secret, 'hex'), { - keyid: id, - algorithm: 'HS256', - expiresIn: '5m', - audience: `/admin/` - }); - - const url = `${BLOG_URL}/ghost/api/admin/members/`; - const headers = { Authorization: `Ghost ${token}` }; - const payload = {members: [{email, newsletters: [{id: "6575d0912c87960008d86bbd"}]}]}; - - try { - const response = await axios.post(url, payload, { headers }); - return res.status(200).json(response.data); - } catch (error) { - console.error("Ghost error", error.response.data.errors); - if (error.response.data.errors[0].context === 'Member already exists. Attempting to add member with existing email address') { - return res.status(200).json({}); - } - return res.status(500).json({ error: `${error.response.data.errors[0].message} Context: ${error.response.data.errors[0].context}` }); - } -} diff --git a/backend/package.json b/backend/package.json deleted file mode 100644 index 1c5aae0..0000000 --- a/backend/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "state-of-open-source-ai-email", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "type": "module", - "devDependencies": { - "@types/jsonwebtoken": "^9.0.5" - }, - "dependencies": { - "@zerobounce/zero-bounce-sdk": "^1.1.0", - "axios": "^1.6.8", - "jsonwebtoken": "^9.0.2" - } -} diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml deleted file mode 100644 index 2285a25..0000000 --- a/backend/pnpm-lock.yaml +++ /dev/null @@ -1,200 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@zerobounce/zero-bounce-sdk': - specifier: ^1.1.0 - version: 1.1.0 - axios: - specifier: ^1.6.8 - version: 1.6.8 - jsonwebtoken: - specifier: ^9.0.2 - version: 9.0.2 - -devDependencies: - '@types/jsonwebtoken': - specifier: ^9.0.5 - version: 9.0.6 - -packages: - - /@types/jsonwebtoken@9.0.6: - resolution: {integrity: sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==} - dependencies: - '@types/node': 20.11.28 - dev: true - - /@types/node@20.11.28: - resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@zerobounce/zero-bounce-sdk@1.1.0: - resolution: {integrity: sha512-n4AolTKQ4JYtn2J98tmts9rYnihPWywHqGg/XA2z+aY4M11mQp3YU2dw2BnxCUppe1By49P97X0eXl1VHW2G5A==} - dev: false - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - - /axios@1.6.8: - resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} - dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - - /buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - dev: false - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: false - - /ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - dependencies: - safe-buffer: 5.2.1 - dev: false - - /follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: false - - /jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} - engines: {node: '>=12', npm: '>=6'} - dependencies: - jws: 3.2.2 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.6.0 - dev: false - - /jwa@1.4.1: - resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - dev: false - - /jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - dev: false - - /lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - dev: false - - /lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - dev: false - - /lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - dev: false - - /lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - dev: false - - /lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - dev: false - - /lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - dev: false - - /lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - dev: false - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: false - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: false - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: false - - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false - - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: false - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: false