mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: update seen_at pat column (#2516)
https://linear.app/unleash/issue/2-451/update-last-seen-column-for-pats
This commit is contained in:
parent
4d8817698a
commit
7ce38ffe89
@ -228,6 +228,17 @@ class UserStore implements IUserStore {
|
||||
.first();
|
||||
return rowToUser(row);
|
||||
}
|
||||
|
||||
async markSeenAt(secrets: string[]): Promise<void> {
|
||||
const now = new Date();
|
||||
try {
|
||||
await this.db('personal_access_tokens')
|
||||
.whereIn('secret', secrets)
|
||||
.update({ seen_at: now });
|
||||
} catch (err) {
|
||||
this.logger.error('Could not update lastSeen, error: ', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserStore;
|
||||
|
@ -17,6 +17,7 @@ const patMiddleware = (
|
||||
apiToken,
|
||||
);
|
||||
req.user = user;
|
||||
userService.addPATSeen(apiToken);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
|
@ -28,6 +28,8 @@ import PasswordMismatch from '../error/password-mismatch';
|
||||
import BadDataError from '../error/bad-data-error';
|
||||
import { isDefined } from '../util/isDefined';
|
||||
import { TokenUserSchema } from '../openapi/spec/token-user-schema';
|
||||
import { IFlagResolver } from 'lib/types/experimental';
|
||||
import { minutesToMilliseconds } from 'date-fns';
|
||||
|
||||
const systemUser = new User({ id: -1, username: 'system' });
|
||||
|
||||
@ -78,12 +80,22 @@ class UserService {
|
||||
|
||||
private passwordResetTimeouts: { [key: string]: NodeJS.Timeout } = {};
|
||||
|
||||
private seenTimer: NodeJS.Timeout;
|
||||
|
||||
private lastSeenSecrets: Set<string> = new Set<string>();
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
constructor(
|
||||
stores: Pick<IUnleashStores, 'userStore' | 'eventStore'>,
|
||||
{
|
||||
getLogger,
|
||||
authentication,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'authentication'>,
|
||||
flagResolver,
|
||||
}: Pick<
|
||||
IUnleashConfig,
|
||||
'getLogger' | 'authentication' | 'flagResolver'
|
||||
>,
|
||||
services: {
|
||||
accessService: AccessService;
|
||||
resetTokenService: ResetTokenService;
|
||||
@ -92,6 +104,7 @@ class UserService {
|
||||
settingService: SettingService;
|
||||
},
|
||||
) {
|
||||
this.flagResolver = flagResolver;
|
||||
this.logger = getLogger('service/user-service.js');
|
||||
this.store = stores.userStore;
|
||||
this.eventStore = stores.eventStore;
|
||||
@ -103,6 +116,9 @@ class UserService {
|
||||
if (authentication && authentication.createAdminUser) {
|
||||
process.nextTick(() => this.initAdminUser());
|
||||
}
|
||||
if (this.flagResolver.isEnabled('tokensLastSeen')) {
|
||||
this.updateLastSeen();
|
||||
}
|
||||
}
|
||||
|
||||
validatePassword(password: string): boolean {
|
||||
@ -426,6 +442,30 @@ class UserService {
|
||||
async getUserByPersonalAccessToken(secret: string): Promise<IUser> {
|
||||
return this.store.getUserByPersonalAccessToken(secret);
|
||||
}
|
||||
|
||||
async updateLastSeen(): Promise<void> {
|
||||
if (this.lastSeenSecrets.size > 0) {
|
||||
const toStore = [...this.lastSeenSecrets];
|
||||
this.lastSeenSecrets = new Set<string>();
|
||||
await this.store.markSeenAt(toStore);
|
||||
}
|
||||
|
||||
this.seenTimer = setTimeout(
|
||||
async () => this.updateLastSeen(),
|
||||
minutesToMilliseconds(3),
|
||||
).unref();
|
||||
}
|
||||
|
||||
addPATSeen(secret: string): void {
|
||||
if (this.flagResolver.isEnabled('tokensLastSeen')) {
|
||||
this.lastSeenSecrets.add(secret);
|
||||
}
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
clearTimeout(this.seenTimer);
|
||||
this.seenTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserService;
|
||||
|
@ -33,4 +33,5 @@ export interface IUserStore extends Store<IUser, number> {
|
||||
successfullyLogin(user: IUser): Promise<void>;
|
||||
count(): Promise<number>;
|
||||
getUserByPersonalAccessToken(secret: string): Promise<IUser>;
|
||||
markSeenAt(secrets: string[]): Promise<void>;
|
||||
}
|
||||
|
5
src/test/fixtures/fake-user-store.ts
vendored
5
src/test/fixtures/fake-user-store.ts
vendored
@ -142,6 +142,11 @@ class UserStoreMock implements IUserStore {
|
||||
getUserByPersonalAccessToken(secret: string): Promise<IUser> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async markSeenAt(secrets: string[]): Promise<void> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserStoreMock;
|
||||
|
Loading…
Reference in New Issue
Block a user