diff --git a/docs/content/dev/db-schema.plantuml b/docs/content/dev/db-schema.plantuml index 98ff6a3cb..7a9239184 100644 --- a/docs/content/dev/db-schema.plantuml +++ b/docs/content/dev/db-schema.plantuml @@ -40,8 +40,9 @@ entity "identity" { *id : number -- *userId : uuid <> + *providerType: text ' Identifies the external login provider and is set in the config - *providerName : text + providerName : text *syncSource : boolean *createdAt : date *updatedAt : date diff --git a/src/api/private/me/history/history.controller.spec.ts b/src/api/private/me/history/history.controller.spec.ts index a16de5aa0..410908181 100644 --- a/src/api/private/me/history/history.controller.spec.ts +++ b/src/api/private/me/history/history.controller.spec.ts @@ -17,6 +17,7 @@ import appConfigMock from '../../../../config/mock/app.config.mock'; import { Group } from '../../../../groups/group.entity'; import { HistoryEntry } from '../../../../history/history-entry.entity'; import { HistoryModule } from '../../../../history/history.module'; +import { Identity } from '../../../../identity/identity.entity'; import { LoggerModule } from '../../../../logger/logger.module'; import { Note } from '../../../../notes/note.entity'; import { NotesModule } from '../../../../notes/notes.module'; @@ -25,7 +26,6 @@ import { NoteGroupPermission } from '../../../../permissions/note-group-permissi import { NoteUserPermission } from '../../../../permissions/note-user-permission.entity'; import { Edit } from '../../../../revisions/edit.entity'; import { Revision } from '../../../../revisions/revision.entity'; -import { Identity } from '../../../../users/identity.entity'; import { Session } from '../../../../users/session.entity'; import { User } from '../../../../users/user.entity'; import { UsersModule } from '../../../../users/users.module'; diff --git a/src/api/private/me/me.controller.spec.ts b/src/api/private/me/me.controller.spec.ts index 33aef70e0..d03e7208b 100644 --- a/src/api/private/me/me.controller.spec.ts +++ b/src/api/private/me/me.controller.spec.ts @@ -14,6 +14,7 @@ import customizationConfigMock from '../../../config/mock/customization.config.m import externalServicesConfigMock from '../../../config/mock/external-services.config.mock'; import mediaConfigMock from '../../../config/mock/media.config.mock'; import { Group } from '../../../groups/group.entity'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -23,7 +24,6 @@ import { NoteGroupPermission } from '../../../permissions/note-group-permission. import { NoteUserPermission } from '../../../permissions/note-user-permission.entity'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { UsersModule } from '../../../users/users.module'; diff --git a/src/api/private/media/media.controller.spec.ts b/src/api/private/media/media.controller.spec.ts index cbed058e3..ffb9a9b66 100644 --- a/src/api/private/media/media.controller.spec.ts +++ b/src/api/private/media/media.controller.spec.ts @@ -15,6 +15,7 @@ import customizationConfigMock from '../../../config/mock/customization.config.m import externalConfigMock from '../../../config/mock/external-services.config.mock'; import mediaConfigMock from '../../../config/mock/media.config.mock'; import { Group } from '../../../groups/group.entity'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -25,7 +26,6 @@ import { NoteGroupPermission } from '../../../permissions/note-group-permission. import { NoteUserPermission } from '../../../permissions/note-user-permission.entity'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { UsersModule } from '../../../users/users.module'; diff --git a/src/api/private/notes/notes.controller.spec.ts b/src/api/private/notes/notes.controller.spec.ts index c3d32eff4..eb908ff47 100644 --- a/src/api/private/notes/notes.controller.spec.ts +++ b/src/api/private/notes/notes.controller.spec.ts @@ -19,6 +19,7 @@ import { Group } from '../../../groups/group.entity'; import { GroupsModule } from '../../../groups/groups.module'; import { HistoryEntry } from '../../../history/history-entry.entity'; import { HistoryModule } from '../../../history/history.module'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -31,7 +32,6 @@ import { PermissionsModule } from '../../../permissions/permissions.module'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; import { RevisionsModule } from '../../../revisions/revisions.module'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { UsersModule } from '../../../users/users.module'; diff --git a/src/api/private/tokens/tokens.controller.spec.ts b/src/api/private/tokens/tokens.controller.spec.ts index 1f5341bb6..56ecfd57e 100644 --- a/src/api/private/tokens/tokens.controller.spec.ts +++ b/src/api/private/tokens/tokens.controller.spec.ts @@ -10,8 +10,8 @@ import { getRepositoryToken } from '@nestjs/typeorm'; import { AuthToken } from '../../../auth/auth-token.entity'; import { AuthModule } from '../../../auth/auth.module'; import appConfigMock from '../../../config/mock/app.config.mock'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { TokensController } from './tokens.controller'; diff --git a/src/api/public/me/me.controller.spec.ts b/src/api/public/me/me.controller.spec.ts index d54398fb1..dd5bf3750 100644 --- a/src/api/public/me/me.controller.spec.ts +++ b/src/api/public/me/me.controller.spec.ts @@ -18,6 +18,7 @@ import mediaConfigMock from '../../../config/mock/media.config.mock'; import { Group } from '../../../groups/group.entity'; import { HistoryEntry } from '../../../history/history-entry.entity'; import { HistoryModule } from '../../../history/history.module'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -28,7 +29,6 @@ import { NoteGroupPermission } from '../../../permissions/note-group-permission. import { NoteUserPermission } from '../../../permissions/note-user-permission.entity'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { UsersModule } from '../../../users/users.module'; diff --git a/src/api/public/media/media.controller.spec.ts b/src/api/public/media/media.controller.spec.ts index 466086569..028ccba75 100644 --- a/src/api/public/media/media.controller.spec.ts +++ b/src/api/public/media/media.controller.spec.ts @@ -12,6 +12,7 @@ import { Author } from '../../../authors/author.entity'; import appConfigMock from '../../../config/mock/app.config.mock'; import mediaConfigMock from '../../../config/mock/media.config.mock'; import { Group } from '../../../groups/group.entity'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -22,7 +23,6 @@ import { NoteGroupPermission } from '../../../permissions/note-group-permission. import { NoteUserPermission } from '../../../permissions/note-user-permission.entity'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { MediaController } from './media.controller'; diff --git a/src/api/public/notes/notes.controller.spec.ts b/src/api/public/notes/notes.controller.spec.ts index aeb97ddb1..d4ec8bbf0 100644 --- a/src/api/public/notes/notes.controller.spec.ts +++ b/src/api/public/notes/notes.controller.spec.ts @@ -19,6 +19,7 @@ import { Group } from '../../../groups/group.entity'; import { GroupsModule } from '../../../groups/groups.module'; import { HistoryEntry } from '../../../history/history-entry.entity'; import { HistoryModule } from '../../../history/history.module'; +import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { MediaUpload } from '../../../media/media-upload.entity'; import { MediaModule } from '../../../media/media.module'; @@ -31,7 +32,6 @@ import { PermissionsModule } from '../../../permissions/permissions.module'; import { Edit } from '../../../revisions/edit.entity'; import { Revision } from '../../../revisions/revision.entity'; import { RevisionsModule } from '../../../revisions/revisions.module'; -import { Identity } from '../../../users/identity.entity'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; import { UsersModule } from '../../../users/users.module'; diff --git a/src/history/history.service.spec.ts b/src/history/history.service.spec.ts index ddfa763cb..559b2946b 100644 --- a/src/history/history.service.spec.ts +++ b/src/history/history.service.spec.ts @@ -13,6 +13,7 @@ import { Author } from '../authors/author.entity'; import appConfigMock from '../config/mock/app.config.mock'; import { NotInDBError } from '../errors/errors'; import { Group } from '../groups/group.entity'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; import { Note } from '../notes/note.entity'; import { NotesModule } from '../notes/notes.module'; @@ -21,7 +22,6 @@ import { NoteGroupPermission } from '../permissions/note-group-permission.entity import { NoteUserPermission } from '../permissions/note-user-permission.entity'; import { Edit } from '../revisions/edit.entity'; import { Revision } from '../revisions/revision.entity'; -import { Identity } from '../users/identity.entity'; import { Session } from '../users/session.entity'; import { User } from '../users/user.entity'; import { UsersModule } from '../users/users.module'; diff --git a/src/identity/identity.entity.ts b/src/identity/identity.entity.ts new file mode 100644 index 000000000..bc36e6f10 --- /dev/null +++ b/src/identity/identity.entity.ts @@ -0,0 +1,111 @@ +/* + * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { + Column, + CreateDateColumn, + Entity, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { User } from '../users/user.entity'; +import { ProviderType } from './provider-type.enum'; + +/** + * The identity represents a single way for a user to login. + * A 'user' can have any number of these. + * Each one holds a type (local, github, twitter, etc.), if this type can have multiple instances (e.g. gitlab), + * it also saves the name of the instance. Also if this identity shall be the syncSource is saved. + */ +@Entity() +export class Identity { + @PrimaryGeneratedColumn() + id: number; + + /** + * User that this identity corresponds to + */ + @ManyToOne((_) => User, (user) => user.identities, { + onDelete: 'CASCADE', // This deletes the Identity, when the associated User is deleted + }) + user: User; + + /** + * The ProviderType of the identity + */ + @Column() + providerType: string; + + /** + * The name of the provider. + * Only set if there are multiple provider of that type (e.g. gitlab) + */ + @Column({ + nullable: true, + type: 'text', + }) + providerName: string | null; + + /** + * If the identity should be used as the sync source. + * See [authentication doc](../../docs/content/dev/authentication.md) for clarification + */ + @Column() + syncSource: boolean; + + /** + * When the identity was created. + */ + @CreateDateColumn() + createdAt: Date; + + /** + * When the identity was last updated. + */ + @UpdateDateColumn() + updatedAt: Date; + + /** + * The unique identifier of a user from the login provider + */ + @Column({ + nullable: true, + type: 'text', + }) + providerUserId: string | null; + + /** + * Token used to access the OAuth provider in the users name. + */ + @Column({ + nullable: true, + type: 'text', + }) + oAuthAccessToken: string | null; + + /** + * The hash of the password + * Only set when the type of the identity is local + */ + @Column({ + nullable: true, + type: 'text', + }) + passwordHash: string | null; + + public static create( + user: User, + providerType: ProviderType, + syncSource = false, + ): Identity { + const newIdentity = new Identity(); + newIdentity.user = user; + newIdentity.providerType = providerType; + newIdentity.syncSource = syncSource; + return newIdentity; + } +} diff --git a/src/media/media.service.spec.ts b/src/media/media.service.spec.ts index 4dec3d89a..76ff471a3 100644 --- a/src/media/media.service.spec.ts +++ b/src/media/media.service.spec.ts @@ -15,6 +15,7 @@ import { Author } from '../authors/author.entity'; import mediaConfigMock from '../config/mock/media.config.mock'; import { ClientError, NotInDBError } from '../errors/errors'; import { Group } from '../groups/group.entity'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; import { Note } from '../notes/note.entity'; import { NotesModule } from '../notes/notes.module'; @@ -23,7 +24,6 @@ import { NoteGroupPermission } from '../permissions/note-group-permission.entity import { NoteUserPermission } from '../permissions/note-user-permission.entity'; import { Edit } from '../revisions/edit.entity'; import { Revision } from '../revisions/revision.entity'; -import { Identity } from '../users/identity.entity'; import { Session } from '../users/session.entity'; import { User } from '../users/user.entity'; import { UsersModule } from '../users/users.module'; diff --git a/src/notes/notes.service.spec.ts b/src/notes/notes.service.spec.ts index 20614a5f1..585a07b07 100644 --- a/src/notes/notes.service.spec.ts +++ b/src/notes/notes.service.spec.ts @@ -19,13 +19,13 @@ import { } from '../errors/errors'; import { Group } from '../groups/group.entity'; import { GroupsModule } from '../groups/groups.module'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; import { NoteGroupPermission } from '../permissions/note-group-permission.entity'; import { NoteUserPermission } from '../permissions/note-user-permission.entity'; import { Edit } from '../revisions/edit.entity'; import { Revision } from '../revisions/revision.entity'; import { RevisionsModule } from '../revisions/revisions.module'; -import { Identity } from '../users/identity.entity'; import { Session } from '../users/session.entity'; import { User } from '../users/user.entity'; import { UsersModule } from '../users/users.module'; diff --git a/src/permissions/permissions.service.spec.ts b/src/permissions/permissions.service.spec.ts index b6414c467..9413a73f7 100644 --- a/src/permissions/permissions.service.spec.ts +++ b/src/permissions/permissions.service.spec.ts @@ -11,13 +11,13 @@ import { AuthToken } from '../auth/auth-token.entity'; import { Author } from '../authors/author.entity'; import appConfigMock from '../config/mock/app.config.mock'; import { Group } from '../groups/group.entity'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; import { Note } from '../notes/note.entity'; import { NotesModule } from '../notes/notes.module'; import { Tag } from '../notes/tag.entity'; import { Edit } from '../revisions/edit.entity'; import { Revision } from '../revisions/revision.entity'; -import { Identity } from '../users/identity.entity'; import { Session } from '../users/session.entity'; import { User } from '../users/user.entity'; import { UsersModule } from '../users/users.module'; diff --git a/src/revisions/revisions.service.spec.ts b/src/revisions/revisions.service.spec.ts index c7824de63..cee143558 100644 --- a/src/revisions/revisions.service.spec.ts +++ b/src/revisions/revisions.service.spec.ts @@ -13,13 +13,13 @@ import { Author } from '../authors/author.entity'; import appConfigMock from '../config/mock/app.config.mock'; import { NotInDBError } from '../errors/errors'; import { Group } from '../groups/group.entity'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; import { Note } from '../notes/note.entity'; import { NotesModule } from '../notes/notes.module'; import { Tag } from '../notes/tag.entity'; import { NoteGroupPermission } from '../permissions/note-group-permission.entity'; import { NoteUserPermission } from '../permissions/note-user-permission.entity'; -import { Identity } from '../users/identity.entity'; import { Session } from '../users/session.entity'; import { User } from '../users/user.entity'; import { Edit } from './edit.entity'; diff --git a/src/seed.ts b/src/seed.ts index d866f01e3..cd8b7ce98 100644 --- a/src/seed.ts +++ b/src/seed.ts @@ -9,6 +9,7 @@ import { AuthToken } from './auth/auth-token.entity'; import { Author } from './authors/author.entity'; import { Group } from './groups/group.entity'; import { HistoryEntry } from './history/history-entry.entity'; +import { Identity } from './identity/identity.entity'; import { MediaUpload } from './media/media-upload.entity'; import { Note } from './notes/note.entity'; import { Tag } from './notes/tag.entity'; @@ -16,7 +17,6 @@ import { NoteGroupPermission } from './permissions/note-group-permission.entity' import { NoteUserPermission } from './permissions/note-user-permission.entity'; import { Edit } from './revisions/edit.entity'; import { Revision } from './revisions/revision.entity'; -import { Identity } from './users/identity.entity'; import { Session } from './users/session.entity'; import { User } from './users/user.entity'; diff --git a/src/users/identity.entity.ts b/src/users/identity.entity.ts deleted file mode 100644 index 95c25e89c..000000000 --- a/src/users/identity.entity.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ -import { - Column, - CreateDateColumn, - Entity, - ManyToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm'; - -import { User } from './user.entity'; - -@Entity() -export class Identity { - @PrimaryGeneratedColumn() - id: number; - - @ManyToOne((_) => User, (user) => user.identities, { - onDelete: 'CASCADE', // This deletes the Identity, when the associated User is deleted - }) - user: User; - - @Column() - providerName: string; - - @Column() - syncSource: boolean; - - @CreateDateColumn() - createdAt: Date; - - @UpdateDateColumn() - updatedAt: Date; - - @Column({ - nullable: true, - type: 'text', - }) - providerUserId: string | null; - - @Column({ - nullable: true, - type: 'text', - }) - oAuthAccessToken: string | null; - - @Column({ - nullable: true, - type: 'text', - }) - passwordHash: string | null; -} diff --git a/src/users/user.entity.ts b/src/users/user.entity.ts index 3d77437ed..3766b02d2 100644 --- a/src/users/user.entity.ts +++ b/src/users/user.entity.ts @@ -17,9 +17,9 @@ import { AuthToken } from '../auth/auth-token.entity'; import { Author } from '../authors/author.entity'; import { Group } from '../groups/group.entity'; import { HistoryEntry } from '../history/history-entry.entity'; +import { Identity } from '../identity/identity.entity'; import { MediaUpload } from '../media/media-upload.entity'; import { Note } from '../notes/note.entity'; -import { Identity } from './identity.entity'; @Entity() export class User { diff --git a/src/users/users.module.ts b/src/users/users.module.ts index 12a926764..29b6d7fe5 100644 --- a/src/users/users.module.ts +++ b/src/users/users.module.ts @@ -6,8 +6,8 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { Identity } from '../identity/identity.entity'; import { LoggerModule } from '../logger/logger.module'; -import { Identity } from './identity.entity'; import { Session } from './session.entity'; import { User } from './user.entity'; import { UsersService } from './users.service';