Skip to content

Commit

Permalink
Update index.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
OronNadiv committed Sep 4, 2024
1 parent f6bb5f5 commit 35527e5
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 128 deletions.
44 changes: 27 additions & 17 deletions functions/src/auth2Users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import got from 'got'
const moment = require('moment')
const gravatar = require('gravatar')


export interface Auth2UsersOptions {
syncGravatar: boolean
}

const Auth2Users = (admin: Admin.app.App) => {
const firestore = admin.firestore()
const auth = admin.auth()

const listAllUsers = async (nextPageToken?: string) => {
const listAllUsers = async (options: Auth2UsersOptions, nextPageToken?: string) => {
// List batch of users, 1000 at a time.
const listUsersResult = await auth.listUsers(1000, nextPageToken)
await each(listUsersResult.users, async (userRecord: UserRecord) => {
Expand All @@ -24,18 +29,7 @@ const Auth2Users = (admin: Admin.app.App) => {
displayName,
metadata: { creationTime, lastSignInTime },
} = userRecord
const gravatarUrl = gravatar.url(email, {
protocol: 'https',
default: '404'
})
let hasGravatar = false
try {
await got.get(gravatarUrl)
info('found gravatar.', {gravatarUrl})
hasGravatar = true
} catch (err) {
info('Error while fetching gravatar.', {gravatarUrl, error: err})
}


const createdAt = moment(creationTime)
.utc()
Expand All @@ -50,20 +44,36 @@ const Auth2Users = (admin: Admin.app.App) => {
email: email || '',
emailVerified,
displayName: displayName || '',
lastSignedInAt,
gravatarUrl: hasGravatar ? gravatarUrl : null
lastSignedInAt
}

if (options.syncGravatar) {
let hasGravatar = false
const gravatarUrl = gravatar.url(email, {
protocol: 'https',
default: '404'
})
try {
await got.get(gravatarUrl)
info('found gravatar.', { gravatarUrl })
hasGravatar = true
} catch (err) {
info('Error while fetching gravatar.', { gravatarUrl, error: err })
}
data.gravatarUrl = hasGravatar ? gravatarUrl : null
}

await userRef.set(data, { merge: true })
info(`Updated ${uid} ${createdAt} ${lastSignedInAt}`)
} catch (err) {
error('Error while syncing auth2user.', {'uid': userRecord.uid, 'error': err});
error('Error while syncing auth2user.', { 'uid': userRecord.uid, 'error': err });
}
})
info(
`checking listUsersResult.pageToken: ${listUsersResult.pageToken} num of results previously found: ${listUsersResult.users.length}`)
if (listUsersResult.pageToken) {
// List next batch of users.
await listAllUsers(listUsersResult.pageToken)
await listAllUsers(options, listUsersResult.pageToken)
} else {
info('Done. Exiting...')
return
Expand Down
2 changes: 1 addition & 1 deletion functions/src/auth2UsersCMD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const admin: Admin.app.App = Admin.initializeApp({
})

const auth2Users = Auth2Users(admin)
auth2Users()
auth2Users({ syncGravatar: true })
.then((res) => {
console.info('done', res)
return
Expand Down
222 changes: 112 additions & 110 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AddContact from './addContact'
import Auth2Users from './auth2Users'
import Auth2Users, { Auth2UsersOptions } from './auth2Users'
import Contacts2MailChimp from './contacts2MailChimp'
import DeleteUser from './deleteUser'
import GenerateICal from './generateICal'
Expand All @@ -11,17 +11,17 @@ import UpdateEvents from './updateEvents'
import Users2Contacts from './users2Contacts'
import * as functions from 'firebase-functions'
import * as Admin from 'firebase-admin'
import {EMAIL} from './fields'
import {props} from 'bluebird'
import { EMAIL } from './fields'
import { props } from 'bluebird'

const admin: Admin.app.App = Admin.initializeApp()
const firestore = admin.firestore()

const apiKey = functions.config().mailchimp.apikey
const {app_id, city_id} = functions.config().openweathermap
const { app_id, city_id } = functions.config().openweathermap
const {
membership_fee_in_cents,
secret_keys: {live, test}
secret_keys: { live, test }
} = functions.config().stripe

const addContactImpl = AddContact(admin)
Expand All @@ -34,16 +34,16 @@ const purgeUsersUnder13 = PurgeUsersUnder13(admin, apiKey, false)
const sendMembershipReminders = SendMembershipReminders(admin)
const stripeImpl = Stripe(admin, {
membershipFeeInCents: membership_fee_in_cents,
secretKeys: {live, test}
secretKeys: { live, test }
})
const users2Contacts = Users2Contacts(admin)
const updateEvents = UpdateEvents(admin, app_id, city_id)

const AUTH_2_USERS_TIMEOUT_IN_SECONDS = 180

const auth2UsersExec = async () => {
const auth2UsersExec = (options: Auth2UsersOptions) => async () => {
try {
await auth2Users()
await auth2Users(options)
console.info('Calling process.exit(0)')
setTimeout(function () {
process.exit(0)
Expand All @@ -58,127 +58,129 @@ const auth2UsersExec = async () => {
}

export const purgeUsersUnder13CronJob = functions.pubsub
.schedule('10 */6 * * *')
.onRun(async () => await purgeUsersUnder13())
export const auth2UsersCronJob = functions.pubsub
.runWith({timeoutSeconds: AUTH_2_USERS_TIMEOUT_IN_SECONDS})
.schedule('20 */6 * * *')
.onRun(async () => await auth2UsersExec)
export const auth2UsersOnCreate = functions.auth
.runWith({timeoutSeconds: AUTH_2_USERS_TIMEOUT_IN_SECONDS})
.user().onCreate(auth2UsersExec)
.schedule('10 */6 * * *')
.onRun(async () => await purgeUsersUnder13())
export const auth2UsersCronJob = functions
.runWith({ timeoutSeconds: AUTH_2_USERS_TIMEOUT_IN_SECONDS })
.pubsub
.schedule('20 */6 * * *')
.onRun(async () => await auth2UsersExec({ syncGravatar: true }))
export const auth2UsersOnCreate = functions
.runWith({ timeoutSeconds: AUTH_2_USERS_TIMEOUT_IN_SECONDS })
.auth
.user().onCreate(auth2UsersExec({ syncGravatar: false }))

export const users2ContactsCronJob = functions.pubsub
.schedule('30 */6 * * *')
.onRun(async () => {
try {
await users2Contacts()
console.info('users2ContactsCronJob: done')
} catch (err) {
console.error('users2ContactsCronJob: error:', err)
}
})
.schedule('30 */6 * * *')
.onRun(async () => {
try {
await users2Contacts()
console.info('users2ContactsCronJob: done')
} catch (err) {
console.error('users2ContactsCronJob: error:', err)
}
})

export const contacts2MailChimpCronJob = functions
.runWith({timeoutSeconds: 180})
.pubsub.schedule('40 */6 * * *')
.onRun(async () => {
try {
await contacts2MailChimp()
console.info('Calling process.exit(0)')
setTimeout(function () {
process.exit(0)
}, 5000)
} catch (err) {
console.error(err)
console.info('Calling process.exit(1)')
setTimeout(function () {
process.exit(1)
}, 5000)
}
})
.runWith({ timeoutSeconds: 180 })
.pubsub.schedule('40 */6 * * *')
.onRun(async () => {
try {
await contacts2MailChimp()
console.info('Calling process.exit(0)')
setTimeout(function () {
process.exit(0)
}, 5000)
} catch (err) {
console.error(err)
console.info('Calling process.exit(1)')
setTimeout(function () {
process.exit(1)
}, 5000)
}
})

export const updateEventsCronJob = functions.pubsub
.schedule('*/20 * * * *')
.onRun(async () => await updateEvents())
.schedule('*/20 * * * *')
.onRun(async () => await updateEvents())

export const waiver = functions
.https.onRequest(async (req: functions.https.Request, res: functions.Response) => {
res.redirect('https://docs.google.com/forms/d/e/1FAIpQLSfYxlbWAzK1jAcdE_5-ijxORNVz2YU4BdSVt2Dk-DByncIEkw/viewform')
})
.https.onRequest(async (req: functions.https.Request, res: functions.Response) => {
res.redirect('https://docs.google.com/forms/d/e/1FAIpQLSfYxlbWAzK1jAcdE_5-ijxORNVz2YU4BdSVt2Dk-DByncIEkw/viewform')
})

export const ical = functions
.runWith({memory: '512MB'})
.https.onRequest(async (req: functions.https.Request, res: functions.Response) => {
try {
const body = await generateICal()
res.set({
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
// 'content-security-policy': "script-src 'report-sample' 'nonce-b3O76BbGW8VYkTGK5Nxtvw' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /calendar/cspreport",
'content-type': 'text/calendar; charset=UTF-8',
// 'date': 'Sat, 15 Jun 2019 22:23:46 GMT',
expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
pragma: 'no-cache',
// 'server': 'GSE',
'strict-transport-security':
'max-age=31536000; includeSubDomains; preload',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '1; mode=block'
})
res.send(Buffer.from(body))
} catch (err) {
console.error('ical generation got an err:', err)
res.status(500).send('Internal Server Error')
}
})

export const stripe = functions.runWith({memory: '512MB'}).https.onCall(stripeImpl)
.runWith({ memory: '512MB' })
.https.onRequest(async (req: functions.https.Request, res: functions.Response) => {
try {
const body = await generateICal()
res.set({
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
// 'content-security-policy': "script-src 'report-sample' 'nonce-b3O76BbGW8VYkTGK5Nxtvw' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /calendar/cspreport",
'content-type': 'text/calendar; charset=UTF-8',
// 'date': 'Sat, 15 Jun 2019 22:23:46 GMT',
expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
pragma: 'no-cache',
// 'server': 'GSE',
'strict-transport-security':
'max-age=31536000; includeSubDomains; preload',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '1; mode=block'
})
res.send(Buffer.from(body))
} catch (err) {
console.error('ical generation got an err:', err)
res.status(500).send('Internal Server Error')
}
})

export const stripe = functions.runWith({ memory: '512MB' }).https.onCall(stripeImpl)

export const addContact = functions
.runWith({memory: '512MB'})
.https.onCall(addContactImpl)
.runWith({ memory: '512MB' })
.https.onCall(addContactImpl)

export const getMembers = functions
.runWith({timeoutSeconds: 30, memory: '512MB'})
.https.onCall(getMembersImpl)
.runWith({ timeoutSeconds: 30, memory: '512MB' })
.https.onCall(getMembersImpl)

export const deleteUser = functions
.runWith({timeoutSeconds: 30, memory: '512MB'})
.https.onCall(async (data, context) => {
if (!context || !context.auth || !context.auth.uid) {
.runWith({ timeoutSeconds: 30, memory: '512MB' })
.https.onCall(async (data, context) => {
if (!context || !context.auth || !context.auth.uid) {
throw new functions.https.HttpsError(
'unauthenticated',
'unauthenticated.'
)
}
const currentUID = context.auth.uid
const targetUID = data.uid
let targetEmail
if (targetUID !== currentUID) {
const { docUsersDelete, docUser } = await props({
docUsersDelete: firestore.doc('permissions/usersDelete').get(),
docUser: firestore.doc(`users/${targetUID}`).get()
})
const usersDelete = docUsersDelete.data()
const allowDelete = usersDelete && usersDelete[currentUID]
if (!allowDelete) {
throw new functions.https.HttpsError(
'unauthenticated',
'unauthenticated.'
'permission-denied',
'permission-denied.'
)
}
const currentUID = context.auth.uid
const targetUID = data.uid
let targetEmail
if (targetUID !== currentUID) {
const {docUsersDelete, docUser} = await props({
docUsersDelete: firestore.doc('permissions/usersDelete').get(),
docUser: firestore.doc(`users/${targetUID}`).get()
})
const usersDelete = docUsersDelete.data()
const allowDelete = usersDelete && usersDelete[currentUID]
if (!allowDelete) {
throw new functions.https.HttpsError(
'permission-denied',
'permission-denied.'
)
}
// @ts-ignore
targetEmail = docUser.data() && docUser.data()[EMAIL]
if (!targetEmail) {
throw new functions.https.HttpsError('not-found', 'not-found.')
}
} else {
targetEmail = context.auth.token[EMAIL]
// @ts-ignore
targetEmail = docUser.data() && docUser.data()[EMAIL]
if (!targetEmail) {
throw new functions.https.HttpsError('not-found', 'not-found.')
}
await deleteUserImpl({uid: targetUID, email: targetEmail})
})
} else {
targetEmail = context.auth.token[EMAIL]
}
await deleteUserImpl({ uid: targetUID, email: targetEmail })
})

export const sendMembershipRemindersCronJob = functions.pubsub
.schedule('0 19 * * *')
.onRun(async () => await sendMembershipReminders())
.schedule('0 19 * * *')
.onRun(async () => await sendMembershipReminders())

0 comments on commit 35527e5

Please sign in to comment.