|
|
@ -5,29 +5,36 @@ import Noco from '../Noco'; |
|
|
|
import { extractProps } from '../meta/helpers/extractProps'; |
|
|
|
import { extractProps } from '../meta/helpers/extractProps'; |
|
|
|
import NocoCache from '../cache/NocoCache'; |
|
|
|
import NocoCache from '../cache/NocoCache'; |
|
|
|
import { NcError } from '../meta/helpers/catchError'; |
|
|
|
import { NcError } from '../meta/helpers/catchError'; |
|
|
|
|
|
|
|
import { UserType } from 'nocodb-sdk'; |
|
|
|
|
|
|
|
import { NcError } from '../meta/helpers/catchError'; |
|
|
|
|
|
|
|
import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; |
|
|
|
|
|
|
|
import Noco from '../Noco'; |
|
|
|
|
|
|
|
import { extractProps } from '../meta/helpers/extractProps'; |
|
|
|
|
|
|
|
import NocoCache from '../cache/NocoCache'; |
|
|
|
|
|
|
|
|
|
|
|
export default class User implements UserType { |
|
|
|
export default class User implements UserType { |
|
|
|
id: string |
|
|
|
id: string; |
|
|
|
|
|
|
|
|
|
|
|
/** @format email */ |
|
|
|
/** @format email */ |
|
|
|
email: string |
|
|
|
email: string |
|
|
|
|
|
|
|
|
|
|
|
password?: string |
|
|
|
password?: string; |
|
|
|
salt?: string |
|
|
|
salt?: string; |
|
|
|
firstname: string |
|
|
|
firstname: string; |
|
|
|
lastname: string |
|
|
|
lastname: string; |
|
|
|
username?: string |
|
|
|
username?: string; |
|
|
|
refresh_token?: string |
|
|
|
refresh_token?: string; |
|
|
|
invite_token?: string |
|
|
|
invite_token?: string; |
|
|
|
invite_token_expires?: number | Date |
|
|
|
invite_token_expires?: number | Date; |
|
|
|
reset_password_expires?: number | Date |
|
|
|
reset_password_expires?: number | Date; |
|
|
|
reset_password_token?: string |
|
|
|
reset_password_token?: string; |
|
|
|
email_verification_token?: string |
|
|
|
email_verification_token?: string; |
|
|
|
email_verified: boolean |
|
|
|
email_verified: boolean; |
|
|
|
roles?: string |
|
|
|
roles?: string; |
|
|
|
token_version?: string |
|
|
|
token_version?: string; |
|
|
|
|
|
|
|
|
|
|
|
constructor(data: User) { |
|
|
|
constructor(data: User) { |
|
|
|
Object.assign(this, data) |
|
|
|
Object.assign(this, data); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static async insert(user: Partial<User>, ncMeta = Noco.ncMeta) { |
|
|
|
public static async insert(user: Partial<User>, ncMeta = Noco.ncMeta) { |
|
|
@ -48,23 +55,24 @@ export default class User implements UserType { |
|
|
|
'email_verified', |
|
|
|
'email_verified', |
|
|
|
'roles', |
|
|
|
'roles', |
|
|
|
'token_version', |
|
|
|
'token_version', |
|
|
|
]) |
|
|
|
]); |
|
|
|
|
|
|
|
|
|
|
|
if (insertObj.email) { |
|
|
|
if (insertObj.email) { |
|
|
|
insertObj.email = insertObj.email.toLowerCase() |
|
|
|
insertObj.email = insertObj.email.toLowerCase(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { id } = await ncMeta.metaInsert2( |
|
|
|
const { id } = await ncMeta.metaInsert2( |
|
|
|
null, |
|
|
|
null, |
|
|
|
null, |
|
|
|
null, |
|
|
|
MetaTable.USERS, |
|
|
|
MetaTable.USERS, |
|
|
|
insertObj, |
|
|
|
insertObj |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
await NocoCache.del(CacheScope.INSTANCE_META) |
|
|
|
await NocoCache.del(CacheScope.INSTANCE_META); |
|
|
|
|
|
|
|
|
|
|
|
return this.get(id, ncMeta) |
|
|
|
return this.get(id, ncMeta); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static async update(id, user: Partial<User>, ncMeta = Noco.ncMeta) { |
|
|
|
public static async update(id, user: Partial<User>, ncMeta = Noco.ncMeta) { |
|
|
|
const updateObj = extractProps(user, [ |
|
|
|
const updateObj = extractProps(user, [ |
|
|
|
'email', |
|
|
|
'email', |
|
|
@ -82,13 +90,13 @@ export default class User implements UserType { |
|
|
|
'email_verified', |
|
|
|
'email_verified', |
|
|
|
'roles', |
|
|
|
'roles', |
|
|
|
'token_version', |
|
|
|
'token_version', |
|
|
|
]) |
|
|
|
]); |
|
|
|
|
|
|
|
|
|
|
|
if (updateObj.email) { |
|
|
|
if (updateObj.email) { |
|
|
|
updateObj.email = updateObj.email.toLowerCase() |
|
|
|
updateObj.email = updateObj.email.toLowerCase(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// set email prop to avoid generation of invalid cache key
|
|
|
|
// set email prop to avoid generation of invalid cache key
|
|
|
|
updateObj.email = (await this.get(id, ncMeta))?.email?.toLowerCase() |
|
|
|
updateObj.email = (await this.get(id, ncMeta))?.email?.toLowerCase(); |
|
|
|
} |
|
|
|
} |
|
|
|
// get existing cache
|
|
|
|
// get existing cache
|
|
|
|
const keys = [ |
|
|
|
const keys = [ |
|
|
@ -96,43 +104,44 @@ export default class User implements UserType { |
|
|
|
`${CacheScope.USER}:${id}`, |
|
|
|
`${CacheScope.USER}:${id}`, |
|
|
|
// update user:<email>
|
|
|
|
// update user:<email>
|
|
|
|
`${CacheScope.USER}:${user.email}`, |
|
|
|
`${CacheScope.USER}:${user.email}`, |
|
|
|
] |
|
|
|
]; |
|
|
|
for (const key of keys) { |
|
|
|
for (const key of keys) { |
|
|
|
let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT) |
|
|
|
let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); |
|
|
|
if (o) { |
|
|
|
if (o) { |
|
|
|
o = { ...o, ...updateObj } |
|
|
|
o = { ...o, ...updateObj }; |
|
|
|
// set cache
|
|
|
|
// set cache
|
|
|
|
await NocoCache.set(key, o) |
|
|
|
await NocoCache.set(key, o); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// as <projectId> is unknown, delete user:<email>___<projectId> in cache
|
|
|
|
// as <projectId> is unknown, delete user:<email>___<projectId> in cache
|
|
|
|
await NocoCache.delAll(CacheScope.USER, `${user.email}___*`) |
|
|
|
await NocoCache.delAll(CacheScope.USER, `${user.email}___*`); |
|
|
|
|
|
|
|
|
|
|
|
// set meta
|
|
|
|
// set meta
|
|
|
|
return await ncMeta.metaUpdate(null, null, MetaTable.USERS, updateObj, id) |
|
|
|
return await ncMeta.metaUpdate(null, null, MetaTable.USERS, updateObj, id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static async getByEmail(_email: string, ncMeta = Noco.ncMeta) { |
|
|
|
public static async getByEmail(_email: string, ncMeta = Noco.ncMeta) { |
|
|
|
const email = _email?.toLowerCase() |
|
|
|
const email = _email?.toLowerCase(); |
|
|
|
let user = |
|
|
|
let user = |
|
|
|
email && |
|
|
|
email && |
|
|
|
(await NocoCache.get( |
|
|
|
(await NocoCache.get( |
|
|
|
`${CacheScope.USER}:${email}`, |
|
|
|
`${CacheScope.USER}:${email}`, |
|
|
|
CacheGetType.TYPE_OBJECT, |
|
|
|
CacheGetType.TYPE_OBJECT |
|
|
|
)) |
|
|
|
)); |
|
|
|
if (!user) { |
|
|
|
if (!user) { |
|
|
|
user = await ncMeta.metaGet2(null, null, MetaTable.USERS, { |
|
|
|
user = await ncMeta.metaGet2(null, null, MetaTable.USERS, { |
|
|
|
email, |
|
|
|
email, |
|
|
|
}) |
|
|
|
}); |
|
|
|
await NocoCache.set(`${CacheScope.USER}:${email}`, user) |
|
|
|
await NocoCache.set(`${CacheScope.USER}:${email}`, user); |
|
|
|
} |
|
|
|
} |
|
|
|
return user |
|
|
|
return user; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static async isFirst(ncMeta = Noco.ncMeta) { |
|
|
|
static async isFirst(ncMeta = Noco.ncMeta) { |
|
|
|
const isFirst = !(await NocoCache.getAll(`${CacheScope.USER}:*`))?.length |
|
|
|
const isFirst = !(await NocoCache.getAll(`${CacheScope.USER}:*`))?.length; |
|
|
|
if (isFirst) |
|
|
|
if (isFirst) |
|
|
|
return !(await ncMeta.metaGet2(null, null, MetaTable.USERS, {})) |
|
|
|
return !(await ncMeta.metaGet2(null, null, MetaTable.USERS, {})); |
|
|
|
return false |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static async count( |
|
|
|
public static async count( |
|
|
@ -141,15 +150,15 @@ export default class User implements UserType { |
|
|
|
}: { |
|
|
|
}: { |
|
|
|
query?: string; |
|
|
|
query?: string; |
|
|
|
} = {}, |
|
|
|
} = {}, |
|
|
|
ncMeta = Noco.ncMeta, |
|
|
|
ncMeta = Noco.ncMeta |
|
|
|
): Promise<number> { |
|
|
|
): Promise<number> { |
|
|
|
const qb = ncMeta.knex(MetaTable.USERS) |
|
|
|
const qb = ncMeta.knex(MetaTable.USERS); |
|
|
|
|
|
|
|
|
|
|
|
if (query) { |
|
|
|
if (query) { |
|
|
|
qb.where('email', 'like', `%${query.toLowerCase?.()}%`) |
|
|
|
qb.where('email', 'like', `%${query.toLowerCase?.()}%`); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (await qb.count('id', { as: 'count' }).first()).count |
|
|
|
return (await qb.count('id', { as: 'count' }).first()).count; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static async get(userId, ncMeta = Noco.ncMeta): Promise<UserType> { |
|
|
|
static async get(userId, ncMeta = Noco.ncMeta): Promise<UserType> { |
|
|
@ -157,20 +166,20 @@ export default class User implements UserType { |
|
|
|
userId && |
|
|
|
userId && |
|
|
|
(await NocoCache.get( |
|
|
|
(await NocoCache.get( |
|
|
|
`${CacheScope.USER}:${userId}`, |
|
|
|
`${CacheScope.USER}:${userId}`, |
|
|
|
CacheGetType.TYPE_OBJECT, |
|
|
|
CacheGetType.TYPE_OBJECT |
|
|
|
)) |
|
|
|
)); |
|
|
|
if (!user) { |
|
|
|
if (!user) { |
|
|
|
user = await ncMeta.metaGet2(null, null, MetaTable.USERS, userId) |
|
|
|
user = await ncMeta.metaGet2(null, null, MetaTable.USERS, userId); |
|
|
|
await NocoCache.set(`${CacheScope.USER}:${userId}`, user) |
|
|
|
await NocoCache.set(`${CacheScope.USER}:${userId}`, user); |
|
|
|
} |
|
|
|
} |
|
|
|
return user |
|
|
|
return user; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static async getByRefreshToken(refresh_token, ncMeta = Noco.ncMeta) { |
|
|
|
static async getByRefreshToken(refresh_token, ncMeta = Noco.ncMeta) { |
|
|
|
const user = await ncMeta.metaGet2(null, null, MetaTable.USERS, { |
|
|
|
const user = await ncMeta.metaGet2(null, null, MetaTable.USERS, { |
|
|
|
refresh_token, |
|
|
|
refresh_token, |
|
|
|
}) |
|
|
|
}); |
|
|
|
return user |
|
|
|
return user; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static async list( |
|
|
|
public static async list( |
|
|
@ -201,8 +210,7 @@ export default class User implements UserType { |
|
|
|
`${MetaTable.USERS}.email_verified`, |
|
|
|
`${MetaTable.USERS}.email_verified`, |
|
|
|
`${MetaTable.USERS}.created_at`, |
|
|
|
`${MetaTable.USERS}.created_at`, |
|
|
|
`${MetaTable.USERS}.updated_at`, |
|
|
|
`${MetaTable.USERS}.updated_at`, |
|
|
|
`${MetaTable.USERS}.invite_token`, |
|
|
|
`${MetaTable.USERS}.roles`, |
|
|
|
`${MetaTable.USERS}.roles` |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
.select( |
|
|
|
.select( |
|
|
|
ncMeta |
|
|
|
ncMeta |
|
|
@ -214,7 +222,7 @@ export default class User implements UserType { |
|
|
|
.as('projectsCount') |
|
|
|
.as('projectsCount') |
|
|
|
); |
|
|
|
); |
|
|
|
if (query) { |
|
|
|
if (query) { |
|
|
|
queryBuilder.where('email', 'like', `%${query.toLowerCase?.()}%`) |
|
|
|
queryBuilder.where('email', 'like', `%${query.toLowerCase?.()}%`); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return queryBuilder; |
|
|
|
return queryBuilder; |
|
|
|