Skip to content

Commit 16f8e23

Browse files
committed
init commit
1 parent 3515b7f commit 16f8e23

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Periodically delete unused accounts
2+
3+
This sample demonstrates how to delete the accounts of users who have not signed-in in the last month.
4+
5+
6+
## Functions Code
7+
8+
See the file [functions/index.js](functions/index.js) for the code.
9+
10+
**Note:** This function uses Cloud Scheduler, which can have associated costs. Your project must be on the Blaze payment plan as these features require billing information. See the [Cloud Scheduler pricing page](https://cloud.google.com/scheduler/pricing) for more information.
11+
12+
The dependencies are listed in [functions/package.json](functions/package.json).
13+
14+
## Deploy and test
15+
16+
To set up the sample:
17+
18+
- Create a Firebase Project using the [Firebase Developer Console](https://console.firebase.google.com)
19+
- Download this sample e.g. `git clone https://github.com/firebase/functions-samples`
20+
- Enter the sample directory `cd functions-samples/delete-unused-accounts-cron`
21+
- Setup the sample with your project `firebase use --add` and follow the instructions.
22+
- Install node dependencies of your Functions `cd functions; npm install; cd -`
23+
- Deploy your project using `firebase deploy`.
24+
- The pubsub task should then run once a day and delete any inactive users. You can manually run the task by [navigating to Cloud Scheduler in the Google Cloud Platform Console](https://console.cloud.google.com/cloudscheduler).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = {
2+
root: true,
3+
env: {
4+
es6: true,
5+
node: true,
6+
},
7+
extends: [
8+
"eslint:recommended",
9+
"google",
10+
],
11+
rules: {
12+
quotes: ["error", "double"],
13+
},
14+
};
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright 2022 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
'use strict';
17+
18+
const functions = require('firebase-functions/v2');
19+
const admin = require('firebase-admin');
20+
admin.initializeApp();
21+
const PromisePool = require('es6-promise-pool').default;
22+
// Maximum concurrent account deletions.
23+
const MAX_CONCURRENT = 3;
24+
25+
/**
26+
* Run once a day at midnight, to cleanup the users
27+
* Manually run the task here https://console.cloud.google.com/cloudscheduler
28+
*/
29+
exports.accountcleanup = functions.scheduler.onSchedule('every day 00:00', async (event) => {
30+
// Fetch all user details.
31+
const inactiveUsers = await getInactiveUsers();
32+
// Use a pool so that we delete maximum `MAX_CONCURRENT` users in parallel.
33+
const promisePool = new PromisePool(() => deleteInactiveUser(inactiveUsers), MAX_CONCURRENT);
34+
await promisePool.start();
35+
functions.logger.log('User cleanup finished');
36+
});
37+
38+
/**
39+
* Deletes one inactive user from the list.
40+
*/
41+
function deleteInactiveUser(inactiveUsers) {
42+
if (inactiveUsers.length > 0) {
43+
const userToDelete = inactiveUsers.pop();
44+
45+
// Delete the inactive user.
46+
return admin.auth().deleteUser(userToDelete.uid).then(() => {
47+
return functions.logger.log(
48+
'Deleted user account',
49+
userToDelete.uid,
50+
'because of inactivity'
51+
);
52+
}).catch((error) => {
53+
return functions.logger.error(
54+
'Deletion of inactive user account',
55+
userToDelete.uid,
56+
'failed:',
57+
error
58+
);
59+
});
60+
} else {
61+
return null;
62+
}
63+
}
64+
65+
/**
66+
* Returns the list of all inactive users.
67+
*/
68+
async function getInactiveUsers(users = [], nextPageToken) {
69+
const result = await admin.auth().listUsers(1000, nextPageToken);
70+
// Find users that have not signed in in the last 30 days.
71+
const inactiveUsers = result.users.filter(
72+
user => Date.parse(user.metadata.lastRefreshTime || user.metadata.lastSignInTime) < (Date.now() - 30 * 24 * 60 * 60 * 1000));
73+
74+
// Concat with list of previously found inactive users if there was more than 1000 users.
75+
users = users.concat(inactiveUsers);
76+
77+
// If there are more users to fetch we fetch them.
78+
if (result.pageToken) {
79+
return getInactiveUsers(users, result.pageToken);
80+
}
81+
82+
return users;
83+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "delete-unused-accounts-cron-functions",
3+
"description": "Periodically delete unused Firebase accounts",
4+
"dependencies": {
5+
"es6-promise-pool": "^2.5.0",
6+
"firebase-admin": "^10.2.0",
7+
"firebase-functions": "^4.0.0"
8+
},
9+
"devDependencies": {
10+
"eslint": "^6.8.0",
11+
"eslint-plugin-promise": "^4.2.1"
12+
},
13+
"scripts": {
14+
"lint": "./node_modules/.bin/eslint --max-warnings=0 .",
15+
"serve": "firebase emulators:start --only functions",
16+
"shell": "firebase functions:shell",
17+
"start": "npm run shell",
18+
"deploy": "firebase deploy --only functions",
19+
"logs": "firebase functions:log",
20+
"compile": "cp ../../tsconfig.template.json ./tsconfig-compile.json && tsc --project tsconfig-compile.json"
21+
},
22+
"engines": {
23+
"node": "16"
24+
},
25+
"private": true
26+
}

0 commit comments

Comments
 (0)