Delete users not logged in for [n] Days

Description

Hello. Is there an advised method to delete all users that didn’t long in for [N] days? (We want to do this due to our privacy plan, so any personal data is deleted from users that didn’t use the rocket.chat service for while)

I don’t need this to be automatic, just run it manually once in a while.

I guess it consists of stopping the rocketchat service and running a database delete query?

Hi,

I think the way to do it it is via the API - something like this to check and you can then delete. Much safer than database mangling!

Thanks looks nice, but it’s called “deactivate”, I need them deleted for good, not just marked as deactivated (due to data privacy plan (EU General Data Protection Regulation))

That was a hint. You’ll need to find inactive users first.

There are other API calls if you look.

Try this one… you’ll probably need one to authenticate as well.

Hi there!

You can get the list of users hitting the users.list API endpoint with a GET request like so:

http://127.0.0.1:3000/api/v1/users.list?query={"lastLogin": {"$gt": { "$date": "2021-06-25" } }}&fields={"lastLogin": 1}

then, you will get a json list, as described at the users.list API endpoint documentation

your next step is to iterate over each user, and delete it accordingly, using the referred delete user api and passing the user _id field.

Let me know if you need further assistance.

Happy Rocking!

1 Like

Thanks, I hoped I wouldn’t have to code stuff. But okay.

Below the script I was using (in case someone else needs this to conform to EU law in their use case, I was surprised as I thought this would be a more common request)

Note, that count=0 does not work as the documentation says, albeit I configured Settings/General/REST API to unlimited to work. I worked around by configuring a ridiculously large limit as max and using that instead.

Also contrary to the documentation when getting userlist as an admin, I did not get all the fields by default, I explicitly had to request for lastLogin. (The only admin-only field the script cares about).

I’m certain there are a lot of Node.JS libraries I could have used to wrap get/post requests; I prefer to use the Node.JS core API directly tough.

Thanks, Axel

const http = require( 'http' );
const util = require( 'util' );
const expireDays = 180;
const dont =
{
	'axkibe': true,
};

const now = Date.now( );
const utilOpts = { depth: 50 };
console.inspect = function( ...args )
{
    for( let a = 0, alen = args.length; a < alen; a++ )
        args[ a ] = util.inspect( args[ a ], utilOpts );
    console.log.apply( console.log, args );
};

const get = function( url, headers )
{
	return new Promise( ( resolve, reject ) => {
		const req = http.request( {
			headers: headers,
			hostname: 'localhost',
			path: '/api/v1/' + url,
			port: 3000,
		}, ( res ) => {
			res.setEncoding( 'utf8' );
			let body = '';
			res.on( 'data', ( o ) => body += o );
			res.on( 'end', ( ) => resolve( JSON.parse( body ) ) );
		} );
		req.on( 'error', ( e ) => reject( e ) );
		req.end( );
    } );
};

const post = function( url, headers, data )
{
	return new Promise( ( resolve, reject ) => {
		const req = http.request( {
			headers: headers,
			hostname: 'localhost',
			method: 'POST',
			path: '/api/v1/' + url,
			port: 3000,
		}, ( res ) => {
			res.setEncoding( 'utf8' );
			let body = '';
			res.on( 'data', ( o ) => body += o );
			res.on( 'end', ( ) => resolve( JSON.parse( body ) ) );
		} );
		req.on( 'error', ( e ) => reject( e ) );
		req.write( JSON.stringify( data ) );
		req.end( );
    } );
};

const run = async function( )
{
	console.log( '* authenticating' );
	const auth = await post( 'login', { }, { user: 'axkibe', password: 'xxx' } );
	//console.inspect( auth );

	const headers = { 'X-Auth-Token': auth.data.authToken, 'X-User-Id': auth.data.userId };

	console.log( '* listing' );
	const list =
		await get(
			encodeURI('users.list?fields={"lastLogin":1}&count=9999999999999'),
			headers
		);
	//console.inspect( list );

	console.log( '* building expired list' );
	const expired = [ ];
	for( let user of list.users )
	{
		const last = Date.parse( user.lastLogin );
		const days = Math.floor( ( now - last ) / ( 1000 * 60 * 60 * 24 ) );
		if( isNaN( days) ) continue;
		if( dont[ user.username ] ) continue;
		if( days <= expireDays ) continue;
		console.log( '**', user.username, days );
		expired.push( user );
	}

	console.log( '* deleting' );
	for( let user of expired )
	{
		console.log( '**', user.username );
		await post( 'users.delete', headers, { userId: user._id, confirmRelinquish: true } );
	}
};


run( );
1 Like

Thanks for your held Duda!

Axel, I am pleased you got it sorted out. And thank you very much for posting your solution - that will help others.

Not only to cure this issue but how to run API calls through JS.

Are you using a cron job and if so can you post a sample?

No, I’m planning to run this script manually twice a year (at the beginning of a new term). Likely in combination with updating Rocket.Chat

But putting it into crontab (with crontab -e) should be trivial for those who want that.

2 Likes

Hola! Is this script still supposed to work? Just tried but no users are actually deleted. Listing works and I can see the output “deleting…” but no users are deleted although a lot of users matching the idle time. Any hints?

cheers!

Hi, sorry we are currently not using RocketChat anymore. So I cannot tell. But I vagly remember I had a similar problem which was the user authenticated with not having the permissions in RocketChat to delete the users.

Thanks! I’ll check it out!