mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge pull request #2807 from gradido/2800-feature-backend-read-communities-data-from-database
feat(backend): read communities data from database
This commit is contained in:
commit
acbbf36029
@ -2,7 +2,6 @@ import { RIGHTS } from './RIGHTS'
|
|||||||
|
|
||||||
export const INALIENABLE_RIGHTS = [
|
export const INALIENABLE_RIGHTS = [
|
||||||
RIGHTS.LOGIN,
|
RIGHTS.LOGIN,
|
||||||
RIGHTS.GET_COMMUNITY_INFO,
|
|
||||||
RIGHTS.COMMUNITIES,
|
RIGHTS.COMMUNITIES,
|
||||||
RIGHTS.CREATE_USER,
|
RIGHTS.CREATE_USER,
|
||||||
RIGHTS.SEND_RESET_PASSWORD_EMAIL,
|
RIGHTS.SEND_RESET_PASSWORD_EMAIL,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ export enum RIGHTS {
|
|||||||
LOGIN = 'LOGIN',
|
LOGIN = 'LOGIN',
|
||||||
VERIFY_LOGIN = 'VERIFY_LOGIN',
|
VERIFY_LOGIN = 'VERIFY_LOGIN',
|
||||||
BALANCE = 'BALANCE',
|
BALANCE = 'BALANCE',
|
||||||
GET_COMMUNITY_INFO = 'GET_COMMUNITY_INFO',
|
|
||||||
COMMUNITIES = 'COMMUNITIES',
|
COMMUNITIES = 'COMMUNITIES',
|
||||||
LIST_GDT_ENTRIES = 'LIST_GDT_ENTRIES',
|
LIST_GDT_ENTRIES = 'LIST_GDT_ENTRIES',
|
||||||
EXIST_PID = 'EXIST_PID',
|
EXIST_PID = 'EXIST_PID',
|
||||||
|
|||||||
@ -1,33 +1,47 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field, Int } from 'type-graphql'
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
|
import { Community as DbCommunity } from '@entity/Community'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class Community {
|
export class Community {
|
||||||
constructor(json?: any) {
|
constructor(dbCom: DbCommunity) {
|
||||||
if (json) {
|
this.id = dbCom.id
|
||||||
this.id = Number(json.id)
|
this.foreign = dbCom.foreign
|
||||||
this.name = json.name
|
this.publicKey = dbCom.publicKey.toString()
|
||||||
this.url = json.url
|
this.url =
|
||||||
this.description = json.description
|
(dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') +
|
||||||
this.registerUrl = json.registerUrl
|
'api/' +
|
||||||
}
|
dbCom.apiVersion
|
||||||
|
this.lastAnnouncedAt = dbCom.lastAnnouncedAt
|
||||||
|
this.verifiedAt = dbCom.verifiedAt
|
||||||
|
this.lastErrorAt = dbCom.lastErrorAt
|
||||||
|
this.createdAt = dbCom.createdAt
|
||||||
|
this.updatedAt = dbCom.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
@Field(() => Int)
|
@Field(() => Int)
|
||||||
id: number
|
id: number
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
foreign: boolean
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
name: string
|
publicKey: string
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
url: string
|
url: string
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => Date, { nullable: true })
|
||||||
description: string
|
lastAnnouncedAt: Date | null
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => Date, { nullable: true })
|
||||||
registerUrl: string
|
verifiedAt: Date | null
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
lastErrorAt: Date | null
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
createdAt: Date | null
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
updatedAt: Date | null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,25 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
import { createTestClient } from 'apollo-server-testing'
|
import { getCommunities } from '@/seeds/graphql/queries'
|
||||||
import createServer from '@/server/createServer'
|
import { Community as DbCommunity } from '@entity/Community'
|
||||||
import CONFIG from '@/config'
|
import { testEnvironment } from '@test/helpers'
|
||||||
|
|
||||||
jest.mock('@/config')
|
|
||||||
|
|
||||||
let query: any
|
let query: any
|
||||||
|
|
||||||
// to do: We need a setup for the tests that closes the connection
|
// to do: We need a setup for the tests that closes the connection
|
||||||
let con: any
|
let con: any
|
||||||
|
let testEnv: any
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const server = await createServer({})
|
testEnv = await testEnvironment()
|
||||||
con = server.con
|
query = testEnv.query
|
||||||
query = createTestClient(server.apollo).query
|
con = testEnv.con
|
||||||
|
await DbCommunity.clear()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -26,74 +27,90 @@ afterAll(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('CommunityResolver', () => {
|
describe('CommunityResolver', () => {
|
||||||
const getCommunityInfoQuery = `
|
describe('getCommunities', () => {
|
||||||
query {
|
let homeCom1: DbCommunity
|
||||||
getCommunityInfo {
|
let homeCom2: DbCommunity
|
||||||
name
|
let homeCom3: DbCommunity
|
||||||
description
|
let foreignCom1: DbCommunity
|
||||||
url
|
let foreignCom2: DbCommunity
|
||||||
registerUrl
|
let foreignCom3: DbCommunity
|
||||||
}
|
describe('with empty list', () => {
|
||||||
}
|
it('returns no community entry', async () => {
|
||||||
`
|
// const result: Community[] = await query({ query: getCommunities })
|
||||||
|
// expect(result.length).toEqual(0)
|
||||||
const communities = `
|
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||||
query {
|
data: {
|
||||||
communities {
|
getCommunities: [],
|
||||||
id
|
|
||||||
name
|
|
||||||
url
|
|
||||||
description
|
|
||||||
registerUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
describe('getCommunityInfo', () => {
|
|
||||||
it('returns the default values', async () => {
|
|
||||||
await expect(query({ query: getCommunityInfoQuery })).resolves.toMatchObject({
|
|
||||||
data: {
|
|
||||||
getCommunityInfo: {
|
|
||||||
name: 'Gradido Entwicklung',
|
|
||||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
|
||||||
url: 'http://localhost/',
|
|
||||||
registerUrl: 'http://localhost/register',
|
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
describe('communities', () => {
|
describe('only home-communities entries', () => {
|
||||||
describe('PRODUCTION = false', () => {
|
beforeEach(async () => {
|
||||||
beforeEach(() => {
|
jest.clearAllMocks()
|
||||||
CONFIG.PRODUCTION = false
|
|
||||||
|
homeCom1 = DbCommunity.create()
|
||||||
|
homeCom1.foreign = false
|
||||||
|
homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||||
|
homeCom1.apiVersion = '1_0'
|
||||||
|
homeCom1.endPoint = 'http://localhost'
|
||||||
|
homeCom1.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(homeCom1)
|
||||||
|
|
||||||
|
homeCom2 = DbCommunity.create()
|
||||||
|
homeCom2.foreign = false
|
||||||
|
homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||||
|
homeCom2.apiVersion = '1_1'
|
||||||
|
homeCom2.endPoint = 'http://localhost'
|
||||||
|
homeCom2.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(homeCom2)
|
||||||
|
|
||||||
|
homeCom3 = DbCommunity.create()
|
||||||
|
homeCom3.foreign = false
|
||||||
|
homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||||
|
homeCom3.apiVersion = '2_0'
|
||||||
|
homeCom3.endPoint = 'http://localhost'
|
||||||
|
homeCom3.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(homeCom3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns three communities', async () => {
|
it('returns three home-community entries', async () => {
|
||||||
await expect(query({ query: communities })).resolves.toMatchObject({
|
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||||
data: {
|
data: {
|
||||||
communities: [
|
getCommunities: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Gradido Entwicklung',
|
foreign: homeCom1.foreign,
|
||||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
url: 'http://localhost/',
|
url: expect.stringMatching('http://localhost/api/1_0'),
|
||||||
registerUrl: 'http://localhost/register-community',
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom1.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: 'Gradido Staging',
|
foreign: homeCom2.foreign,
|
||||||
description: 'Der Testserver der Gradido-Akademie.',
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
url: 'https://stage1.gradido.net/',
|
url: expect.stringMatching('http://localhost/api/1_1'),
|
||||||
registerUrl: 'https://stage1.gradido.net/register-community',
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom2.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
name: 'Gradido-Akademie',
|
foreign: homeCom3.foreign,
|
||||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
url: 'https://gradido.net',
|
url: expect.stringMatching('http://localhost/api/2_0'),
|
||||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom3.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -101,21 +118,104 @@ describe('CommunityResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('PRODUCTION = true', () => {
|
describe('plus foreign-communities entries', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
CONFIG.PRODUCTION = true
|
jest.clearAllMocks()
|
||||||
|
|
||||||
|
foreignCom1 = DbCommunity.create()
|
||||||
|
foreignCom1.foreign = true
|
||||||
|
foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||||
|
foreignCom1.apiVersion = '1_0'
|
||||||
|
foreignCom1.endPoint = 'http://remotehost'
|
||||||
|
foreignCom1.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(foreignCom1)
|
||||||
|
|
||||||
|
foreignCom2 = DbCommunity.create()
|
||||||
|
foreignCom2.foreign = true
|
||||||
|
foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||||
|
foreignCom2.apiVersion = '1_1'
|
||||||
|
foreignCom2.endPoint = 'http://remotehost'
|
||||||
|
foreignCom2.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(foreignCom2)
|
||||||
|
|
||||||
|
foreignCom3 = DbCommunity.create()
|
||||||
|
foreignCom3.foreign = true
|
||||||
|
foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||||
|
foreignCom3.apiVersion = '1_2'
|
||||||
|
foreignCom3.endPoint = 'http://remotehost'
|
||||||
|
foreignCom3.createdAt = new Date()
|
||||||
|
await DbCommunity.insert(foreignCom3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns one community', async () => {
|
it('returns 3x home and 3x foreign-community entries', async () => {
|
||||||
await expect(query({ query: communities })).resolves.toMatchObject({
|
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||||
data: {
|
data: {
|
||||||
communities: [
|
getCommunities: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
foreign: homeCom1.foreign,
|
||||||
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
|
url: expect.stringMatching('http://localhost/api/1_0'),
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom1.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
foreign: homeCom2.foreign,
|
||||||
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
|
url: expect.stringMatching('http://localhost/api/1_1'),
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom2.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
name: 'Gradido-Akademie',
|
foreign: homeCom3.foreign,
|
||||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||||
url: 'https://gradido.net',
|
url: expect.stringMatching('http://localhost/api/2_0'),
|
||||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: homeCom3.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
foreign: foreignCom1.foreign,
|
||||||
|
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||||
|
url: expect.stringMatching('http://remotehost/api/1_0'),
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: foreignCom1.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
foreign: foreignCom2.foreign,
|
||||||
|
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||||
|
url: expect.stringMatching('http://remotehost/api/1_1'),
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: foreignCom2.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
foreign: foreignCom3.foreign,
|
||||||
|
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||||
|
url: expect.stringMatching('http://remotehost/api/1_2'),
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: foreignCom3.createdAt.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,58 +1,18 @@
|
|||||||
import { Resolver, Query, Authorized } from 'type-graphql'
|
import { Resolver, Query, Authorized } from 'type-graphql'
|
||||||
|
|
||||||
import { Community } from '@model/Community'
|
import { Community } from '@model/Community'
|
||||||
|
import { Community as DbCommunity } from '@entity/Community'
|
||||||
|
|
||||||
import { RIGHTS } from '@/auth/RIGHTS'
|
import { RIGHTS } from '@/auth/RIGHTS'
|
||||||
import CONFIG from '@/config'
|
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class CommunityResolver {
|
export class CommunityResolver {
|
||||||
@Authorized([RIGHTS.GET_COMMUNITY_INFO])
|
|
||||||
@Query(() => Community)
|
|
||||||
getCommunityInfo(): Community {
|
|
||||||
return new Community({
|
|
||||||
name: CONFIG.COMMUNITY_NAME,
|
|
||||||
description: CONFIG.COMMUNITY_DESCRIPTION,
|
|
||||||
url: CONFIG.COMMUNITY_URL,
|
|
||||||
registerUrl: CONFIG.COMMUNITY_REGISTER_URL,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Authorized([RIGHTS.COMMUNITIES])
|
@Authorized([RIGHTS.COMMUNITIES])
|
||||||
@Query(() => [Community])
|
@Query(() => [Community])
|
||||||
communities(): Community[] {
|
async getCommunities(): Promise<Community[]> {
|
||||||
if (CONFIG.PRODUCTION)
|
const dbCommunities: DbCommunity[] = await DbCommunity.find({
|
||||||
return [
|
order: { foreign: 'ASC', publicKey: 'ASC', apiVersion: 'ASC' },
|
||||||
new Community({
|
})
|
||||||
id: 3,
|
return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom))
|
||||||
name: 'Gradido-Akademie',
|
|
||||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
|
||||||
url: 'https://gradido.net',
|
|
||||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
return [
|
|
||||||
new Community({
|
|
||||||
id: 1,
|
|
||||||
name: 'Gradido Entwicklung',
|
|
||||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
|
||||||
url: 'http://localhost/',
|
|
||||||
registerUrl: 'http://localhost/register-community',
|
|
||||||
}),
|
|
||||||
new Community({
|
|
||||||
id: 2,
|
|
||||||
name: 'Gradido Staging',
|
|
||||||
description: 'Der Testserver der Gradido-Akademie.',
|
|
||||||
url: 'https://stage1.gradido.net/',
|
|
||||||
registerUrl: 'https://stage1.gradido.net/register-community',
|
|
||||||
}),
|
|
||||||
new Community({
|
|
||||||
id: 3,
|
|
||||||
name: 'Gradido-Akademie',
|
|
||||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
|
||||||
url: 'https://gradido.net',
|
|
||||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,6 +133,22 @@ export const communities = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const getCommunities = gql`
|
||||||
|
query {
|
||||||
|
getCommunities {
|
||||||
|
id
|
||||||
|
foreign
|
||||||
|
publicKey
|
||||||
|
url
|
||||||
|
lastAnnouncedAt
|
||||||
|
verifiedAt
|
||||||
|
lastErrorAt
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export const queryTransactionLink = gql`
|
export const queryTransactionLink = gql`
|
||||||
query ($code: String!) {
|
query ($code: String!) {
|
||||||
queryTransactionLink(code: $code) {
|
queryTransactionLink(code: $code) {
|
||||||
|
|||||||
@ -25,13 +25,13 @@ export class Community extends BaseEntity {
|
|||||||
endPoint: string
|
endPoint: string
|
||||||
|
|
||||||
@Column({ name: 'last_announced_at', type: 'datetime', nullable: true })
|
@Column({ name: 'last_announced_at', type: 'datetime', nullable: true })
|
||||||
lastAnnouncedAt: Date
|
lastAnnouncedAt: Date | null
|
||||||
|
|
||||||
@Column({ name: 'verified_at', type: 'datetime', nullable: true })
|
@Column({ name: 'verified_at', type: 'datetime', nullable: true })
|
||||||
verifiedAt: Date
|
verifiedAt: Date | null
|
||||||
|
|
||||||
@Column({ name: 'last_error_at', type: 'datetime', nullable: true })
|
@Column({ name: 'last_error_at', type: 'datetime', nullable: true })
|
||||||
lastErrorAt: Date
|
lastErrorAt: Date | null
|
||||||
|
|
||||||
@CreateDateColumn({
|
@CreateDateColumn({
|
||||||
name: 'created_at',
|
name: 'created_at',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user