mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
Create user last connection datetime
This commit is contained in:
parent
fe9cc80ccc
commit
643dacafbf
@ -29,6 +29,9 @@ export class User extends BaseEntity {
|
||||
@Column({name: 'first_login_at', type: Date, nullable: true})
|
||||
public firstLoginAt: Date | null;
|
||||
|
||||
@Column({name: 'last_connection_at', type: Date, nullable: true})
|
||||
public lastConnectionAt: Date | null;
|
||||
|
||||
@OneToOne(type => Organization, organization => organization.owner)
|
||||
public personalOrg: Organization;
|
||||
|
||||
|
@ -213,6 +213,7 @@ function isNonGuestGroup(group: Group): group is NonGuestGroup {
|
||||
export interface UserProfileChange {
|
||||
name?: string;
|
||||
isFirstTimeUser?: boolean;
|
||||
newConnection?: boolean;
|
||||
}
|
||||
|
||||
// Identifies a request to access a document. This combination of values is also used for caching
|
||||
@ -614,6 +615,14 @@ export class HomeDBManager extends EventEmitter {
|
||||
// any automation for first logins
|
||||
if (!props.isFirstTimeUser) { isWelcomed = true; }
|
||||
}
|
||||
if (props.newConnection === true) {
|
||||
// set last connection time to now (remove milliseconds for compatibility with other
|
||||
// timestamps in db set by typeorm, and since second level precision is fine)
|
||||
const nowish = new Date();
|
||||
nowish.setMilliseconds(0);
|
||||
user.lastConnectionAt = nowish;
|
||||
needsSave = true;
|
||||
}
|
||||
if (needsSave) {
|
||||
await user.save();
|
||||
}
|
||||
@ -701,12 +710,15 @@ export class HomeDBManager extends EventEmitter {
|
||||
user.name = (profile && (profile.name || email.split('@')[0])) || '';
|
||||
needUpdate = true;
|
||||
}
|
||||
if (profile && !user.firstLoginAt) {
|
||||
// set first login time to now (remove milliseconds for compatibility with other
|
||||
if (profile) {
|
||||
// set first login time and last connection time to now (remove milliseconds for compatibility with other
|
||||
// timestamps in db set by typeorm, and since second level precision is fine)
|
||||
const nowish = new Date();
|
||||
nowish.setMilliseconds(0);
|
||||
user.firstLoginAt = nowish;
|
||||
user.lastConnectionAt = nowish;
|
||||
if (!user.firstLoginAt) {
|
||||
user.firstLoginAt = nowish;
|
||||
}
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!user.picture && profile && profile.picture) {
|
||||
|
18
app/gen-server/migration/1713186031023-UserLastConnection.ts
Normal file
18
app/gen-server/migration/1713186031023-UserLastConnection.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { MigrationInterface, QueryRunner, TableColumn} from 'typeorm';
|
||||
|
||||
export class UserLastConnection1713186031023 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
const sqlite = queryRunner.connection.driver.options.type === 'sqlite';
|
||||
const datetime = sqlite ? "datetime" : "timestamp with time zone";
|
||||
await queryRunner.addColumn('users', new TableColumn({
|
||||
name: 'last_connection_at',
|
||||
type: datetime,
|
||||
isNullable: true
|
||||
}));
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.dropColumn('users', 'last_connection_at');
|
||||
}
|
||||
}
|
@ -501,6 +501,10 @@ export class Client {
|
||||
const user = this._profile ? await this._fetchUser(dbManager) : dbManager.getAnonymousUser();
|
||||
this._user = user ? dbManager.makeFullUser(user) : undefined;
|
||||
this._firstLoginAt = user?.firstLoginAt || null;
|
||||
if (this._user) {
|
||||
// Send the information to the dbManager that the user has a new activity
|
||||
await dbManager.updateUser(this._user.id, {newConnection: true});
|
||||
}
|
||||
}
|
||||
|
||||
private async _onMessage(message: string): Promise<void> {
|
||||
|
@ -21,9 +21,9 @@ export const TEST_HTTPS_OFFSET = process.env.GRIST_TEST_HTTPS_OFFSET ?
|
||||
|
||||
// Database fields that we permit in entities but don't want to cross the api.
|
||||
const INTERNAL_FIELDS = new Set([
|
||||
'apiKey', 'billingAccountId', 'firstLoginAt', 'filteredOut', 'ownerId', 'gracePeriodStart', 'stripeCustomerId',
|
||||
'stripeSubscriptionId', 'stripePlanId', 'stripeProductId', 'userId', 'isFirstTimeUser', 'allowGoogleLogin',
|
||||
'authSubject', 'usage', 'createdBy'
|
||||
'apiKey', 'billingAccountId', 'firstLoginAt', 'lastConnectionAt', 'filteredOut', 'ownerId', 'gracePeriodStart',
|
||||
'stripeCustomerId', 'stripeSubscriptionId', 'stripePlanId', 'stripeProductId', 'userId', 'isFirstTimeUser',
|
||||
'allowGoogleLogin', 'authSubject', 'usage', 'createdBy'
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -41,6 +41,8 @@ import {ForkIndexes1678737195050 as ForkIndexes} from 'app/gen-server/migration/
|
||||
import {ActivationPrefs1682636695021 as ActivationPrefs} from 'app/gen-server/migration/1682636695021-ActivationPrefs';
|
||||
import {AssistantLimit1685343047786 as AssistantLimit} from 'app/gen-server/migration/1685343047786-AssistantLimit';
|
||||
import {Shares1701557445716 as Shares} from 'app/gen-server/migration/1701557445716-Shares';
|
||||
import {UserLastConnection1713186031023
|
||||
as UserLastConnection} from 'app/gen-server/migration/1713186031023-UserLastConnection';
|
||||
|
||||
const home: HomeDBManager = new HomeDBManager();
|
||||
|
||||
@ -49,7 +51,7 @@ const migrations = [Initial, Login, PinDocs, UserPicture, DisplayEmail, DisplayE
|
||||
CustomerIndex, ExtraIndexes, OrgHost, DocRemovedAt, Prefs,
|
||||
ExternalBilling, DocOptions, Secret, UserOptions, GracePeriodStart,
|
||||
DocumentUsage, Activations, UserConnectId, UserUUID, UserUniqueRefUUID,
|
||||
Forks, ForkIndexes, ActivationPrefs, AssistantLimit, Shares];
|
||||
Forks, ForkIndexes, ActivationPrefs, AssistantLimit, Shares, UserLastConnection];
|
||||
|
||||
// Assert that the "members" acl rule and group exist (or not).
|
||||
function assertMembersGroup(org: Organization, exists: boolean) {
|
||||
|
Loading…
Reference in New Issue
Block a user