mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-28 14:04:43 -04:00
refactor(database): run knex migrations on startup
Co-authored-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
d67e44f540
commit
21a1f35281
85 changed files with 830 additions and 418 deletions
|
@ -4,6 +4,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AliasDto } from '@hedgedoc/commons';
|
||||
import {
|
||||
Alias,
|
||||
FieldNameAlias,
|
||||
FieldNameNote,
|
||||
Note,
|
||||
TableAlias,
|
||||
TypeInsertAlias,
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import base32Encode from 'base32-encode';
|
||||
import { randomBytes } from 'crypto';
|
||||
|
@ -11,14 +19,6 @@ import { Knex } from 'knex';
|
|||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import {
|
||||
Alias,
|
||||
FieldNameAlias,
|
||||
FieldNameNote,
|
||||
Note,
|
||||
TableAlias,
|
||||
} from '../database/types';
|
||||
import { TypeInsertAlias } from '../database/types/alias';
|
||||
import {
|
||||
AlreadyInDBError,
|
||||
ForbiddenIdError,
|
||||
|
|
|
@ -4,14 +4,18 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ApiTokenDto, ApiTokenWithSecretDto } from '@hedgedoc/commons';
|
||||
import {
|
||||
ApiToken,
|
||||
FieldNameApiToken,
|
||||
TableApiToken,
|
||||
TypeInsertApiToken,
|
||||
} from '@hedgedoc/database';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Cron, Timeout } from '@nestjs/schedule';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import { ApiToken, FieldNameApiToken, TableApiToken } from '../database/types';
|
||||
import { TypeInsertApiToken } from '../database/types/api-token';
|
||||
import {
|
||||
NotInDBError,
|
||||
TokenNotValidError,
|
||||
|
@ -71,7 +75,7 @@ export class ApiTokenService {
|
|||
}
|
||||
|
||||
const tokenHash = token[FieldNameApiToken.secretHash];
|
||||
const validUntil = token[FieldNameApiToken.validUntil];
|
||||
const validUntil = new Date(token[FieldNameApiToken.validUntil]);
|
||||
this.ensureTokenIsValid(secret, tokenHash, validUntil);
|
||||
|
||||
await transaction(TableApiToken)
|
||||
|
@ -133,6 +137,10 @@ export class ApiTokenService {
|
|||
return this.toAuthTokenWithSecretDto(
|
||||
{
|
||||
...token,
|
||||
[FieldNameApiToken.validUntil]:
|
||||
token[FieldNameApiToken.validUntil].toISOString(),
|
||||
[FieldNameApiToken.createdAt]:
|
||||
token[FieldNameApiToken.createdAt].toISOString(),
|
||||
[FieldNameApiToken.lastUsedAt]: null,
|
||||
},
|
||||
secret,
|
||||
|
@ -206,9 +214,13 @@ export class ApiTokenService {
|
|||
return {
|
||||
label: apiToken[FieldNameApiToken.label],
|
||||
keyId: apiToken[FieldNameApiToken.id],
|
||||
createdAt: apiToken[FieldNameApiToken.createdAt].toISOString(),
|
||||
validUntil: apiToken[FieldNameApiToken.validUntil].toISOString(),
|
||||
lastUsedAt: apiToken[FieldNameApiToken.lastUsedAt]?.toISOString() ?? null,
|
||||
createdAt: new Date(apiToken[FieldNameApiToken.createdAt]).toISOString(),
|
||||
validUntil: new Date(
|
||||
apiToken[FieldNameApiToken.validUntil],
|
||||
).toISOString(),
|
||||
lastUsedAt: apiToken[FieldNameApiToken.lastUsedAt]
|
||||
? new Date(apiToken[FieldNameApiToken.lastUsedAt]).toISOString()
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
ApiTokenDto,
|
||||
ApiTokenWithSecretDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
|
@ -21,7 +22,6 @@ import { ApiTags } from '@nestjs/swagger';
|
|||
|
||||
import { ApiTokenService } from '../../../api-token/api-token.service';
|
||||
import { SessionGuard } from '../../../auth/session.guard';
|
||||
import { FieldNameUser, User } from '../../../database/types';
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { OpenApi } from '../../utils/decorators/openapi.decorator';
|
||||
import { RequestUserId } from '../../utils/decorators/request-user-id.decorator';
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
LdapLoginDto,
|
||||
LdapLoginResponseDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { FieldNameIdentity } from '@hedgedoc/database';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
|
@ -20,7 +21,6 @@ import { ApiTags } from '@nestjs/swagger';
|
|||
|
||||
import { IdentityService } from '../../../../auth/identity.service';
|
||||
import { LdapService } from '../../../../auth/ldap/ldap.service';
|
||||
import { FieldNameIdentity } from '../../../../database/types';
|
||||
import { NotInDBError } from '../../../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../../../logger/console-logger.service';
|
||||
import { UsersService } from '../../../../users/users.service';
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
RegisterDto,
|
||||
UpdatePasswordDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { FieldNameIdentity, FieldNameUser } from '@hedgedoc/database';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
|
@ -22,7 +23,6 @@ import { ApiTags } from '@nestjs/swagger';
|
|||
|
||||
import { LocalService } from '../../../../auth/local/local.service';
|
||||
import { SessionGuard } from '../../../../auth/session.guard';
|
||||
import { FieldNameIdentity, FieldNameUser } from '../../../../database/types';
|
||||
import { NoLocalIdentityError } from '../../../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../../../logger/console-logger.service';
|
||||
import { UsersService } from '../../../../users/users.service';
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { FieldNameIdentity } from '@hedgedoc/database';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
|
@ -18,7 +19,6 @@ import { ApiTags } from '@nestjs/swagger';
|
|||
|
||||
import { IdentityService } from '../../../../auth/identity.service';
|
||||
import { OidcService } from '../../../../auth/oidc/oidc.service';
|
||||
import { FieldNameIdentity } from '../../../../database/types';
|
||||
import { ConsoleLoggerService } from '../../../../logger/console-logger.service';
|
||||
import { UsersService } from '../../../../users/users.service';
|
||||
import { OpenApi } from '../../../utils/decorators/openapi.decorator';
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AliasService } from '../../../alias/alias.service';
|
||||
import { User } from '../../../database/types';
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { NoteService } from '../../../notes/note.service';
|
||||
import { PermissionService } from '../../../permissions/permission.service';
|
||||
|
|
|
@ -12,9 +12,9 @@ import {
|
|||
NoteMetadataDto,
|
||||
NoteMetadataSchema,
|
||||
} from '@hedgedoc/commons';
|
||||
import { User } from '@hedgedoc/database';
|
||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { User } from 'src/database/types';
|
||||
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { MediaService } from '../../../media/media.service';
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaUploadDto, MediaUploadSchema } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameMediaUpload,
|
||||
FieldNameNote,
|
||||
FieldNameUser,
|
||||
Note,
|
||||
User,
|
||||
} from '@hedgedoc/database';
|
||||
import {
|
||||
BadRequestException,
|
||||
Controller,
|
||||
|
@ -24,13 +31,6 @@ import {
|
|||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import {
|
||||
FieldNameMediaUpload,
|
||||
FieldNameNote,
|
||||
FieldNameUser,
|
||||
Note,
|
||||
User,
|
||||
} from '../../../database/types';
|
||||
import { PermissionError } from '../../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { MediaService } from '../../../media/media.service';
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Note } from '@hedgedoc/database';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { Note } from '../../database/types';
|
||||
import { NoteService } from '../../notes/note.service';
|
||||
import { extractNoteIdFromRequest } from './extract-note-id-from-request';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameNote, Note } from '@hedgedoc/database';
|
||||
import { isArray } from 'class-validator';
|
||||
|
||||
import { FieldNameNote, Note } from '../../database/types';
|
||||
import { NoteService } from '../../notes/note.service';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Note } from '@hedgedoc/database';
|
||||
import { CallHandler, ExecutionContext } from '@nestjs/common';
|
||||
import { HttpArgumentsHost } from '@nestjs/common/interfaces/features/arguments-host.interface';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { Note } from '../../database/types';
|
||||
import { NoteService } from '../../notes/note.service';
|
||||
import { NoteService } from '../../../notes/note.service';
|
||||
import { CompleteRequest } from '../request.type';
|
||||
import { GetNoteIdInterceptor } from './get-note-id.interceptor';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
describe('get note interceptor', () => {
|
||||
const mockNote = Mock.of<Note>({});
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { FieldNameNote, FieldNameUser, Note, User } from '@hedgedoc/database';
|
||||
import { Request } from 'express';
|
||||
import { SessionState } from 'src/sessions/session-state.type';
|
||||
|
||||
import { FieldNameNote, FieldNameUser, Note, User } from '../../database/types';
|
||||
|
||||
export type CompleteRequest = Request & {
|
||||
userId?: User[FieldNameUser.id];
|
||||
authProviderType?: AuthProviderType;
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { HttpAdapterHost } from '@nestjs/core';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { WsAdapter } from '@nestjs/platform-ws';
|
||||
import { Knex } from 'knex';
|
||||
import { getConnectionToken } from 'nest-knexjs';
|
||||
|
||||
import { AppConfig } from './config/app.config';
|
||||
import { AuthConfig } from './config/auth.config';
|
||||
import { MediaConfig } from './config/media.config';
|
||||
import { ErrorExceptionMapping } from './errors/error-mapping';
|
||||
import { ConsoleLoggerService } from './logger/console-logger.service';
|
||||
import { BackendType } from './media/backends/backend-type.enum';
|
||||
import { SessionService } from './sessions/session.service';
|
||||
import { setupSessionMiddleware } from './utils/session';
|
||||
import { setupValidationPipe } from './utils/setup-pipes';
|
||||
|
@ -42,6 +44,12 @@ export async function setupApp(
|
|||
);
|
||||
}
|
||||
|
||||
logger.log('Starting database migrations... ', 'AppBootstrap');
|
||||
const knexConnectionToken = getConnectionToken();
|
||||
const knex: Knex = app.get<Knex>(knexConnectionToken);
|
||||
await knex.migrate.latest();
|
||||
logger.log('Finished database migrations... ', 'AppBootstrap');
|
||||
|
||||
// Setup session handling
|
||||
setupSessionMiddleware(
|
||||
app,
|
||||
|
@ -65,7 +73,7 @@ export async function setupApp(
|
|||
app.useGlobalPipes(setupValidationPipe(logger));
|
||||
|
||||
// Map URL paths to directories
|
||||
if (mediaConfig.backend.use === BackendType.FILESYSTEM) {
|
||||
if (mediaConfig.backend.use === MediaBackendType.FILESYSTEM) {
|
||||
logger.log(
|
||||
`Serving the local folder '${mediaConfig.backend.filesystem.uploadPath}' under '/uploads'`,
|
||||
'AppBootstrap',
|
||||
|
|
|
@ -8,18 +8,19 @@ import {
|
|||
PendingUserConfirmationDto,
|
||||
PendingUserInfoDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import AuthConfiguration, { AuthConfig } from '../config/auth.config';
|
||||
import {
|
||||
FieldNameIdentity,
|
||||
FieldNameUser,
|
||||
Identity,
|
||||
TableIdentity,
|
||||
TypeInsertIdentity,
|
||||
User,
|
||||
} from '../database/types';
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import AuthConfiguration, { AuthConfig } from '../config/auth.config';
|
||||
import { NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { UsersService } from '../users/users.service';
|
||||
|
@ -52,7 +53,7 @@ export class IdentityService {
|
|||
/**
|
||||
* Retrieve an identity from the information received from an auth provider.
|
||||
*
|
||||
* @param userId - the userId of the wanted identity
|
||||
* @param authProviderUserId - the userId of the wanted identity
|
||||
* @param authProviderType - the providerType of the wanted identity
|
||||
* @param authProviderIdentifier - optional name of the provider if multiple exist
|
||||
* @return
|
||||
|
@ -96,15 +97,12 @@ export class IdentityService {
|
|||
transaction?: Knex,
|
||||
): Promise<void> {
|
||||
const dbActor = transaction ?? this.knex;
|
||||
const date = new Date();
|
||||
const identity: Identity = {
|
||||
const identity: TypeInsertIdentity = {
|
||||
[FieldNameIdentity.userId]: userId,
|
||||
[FieldNameIdentity.providerType]: authProviderType,
|
||||
[FieldNameIdentity.providerIdentifier]: authProviderIdentifier,
|
||||
[FieldNameIdentity.providerUserId]: authProviderUserId,
|
||||
[FieldNameIdentity.passwordHash]: passwordHash ?? null,
|
||||
[FieldNameIdentity.createdAt]: date,
|
||||
[FieldNameIdentity.updatedAt]: date,
|
||||
};
|
||||
await dbActor(TableIdentity).insert(identity);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameIdentity,
|
||||
FieldNameUser,
|
||||
Identity,
|
||||
TableIdentity,
|
||||
User,
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
OptionsGraph,
|
||||
|
@ -23,13 +30,6 @@ import { Knex } from 'knex';
|
|||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import authConfiguration, { AuthConfig } from '../../config/auth.config';
|
||||
import {
|
||||
FieldNameIdentity,
|
||||
FieldNameUser,
|
||||
Identity,
|
||||
TableIdentity,
|
||||
User,
|
||||
} from '../../database/types';
|
||||
import {
|
||||
InvalidCredentialsError,
|
||||
PasswordTooWeakError,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType, PendingUserInfoDto } from '@hedgedoc/commons';
|
||||
import { Identity } from '@hedgedoc/database';
|
||||
import {
|
||||
ForbiddenException,
|
||||
Inject,
|
||||
|
@ -20,7 +21,6 @@ import authConfiguration, {
|
|||
AuthConfig,
|
||||
OidcConfig,
|
||||
} from '../../config/auth.config';
|
||||
import { Identity } from '../../database/types';
|
||||
import { NotInDBError } from '../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { IdentityService } from '../identity.service';
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import { BackendType } from '../media/backends/backend-type.enum';
|
||||
import mediaConfig, {
|
||||
AzureMediaConfig,
|
||||
FilesystemMediaConfig,
|
||||
|
@ -39,7 +39,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.FILESYSTEM,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.FILESYSTEM,
|
||||
HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH: uploadPath,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
|
@ -48,7 +48,7 @@ describe('mediaConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = mediaConfig() as { backend: FilesystemMediaConfig };
|
||||
expect(config.backend.use).toEqual(BackendType.FILESYSTEM);
|
||||
expect(config.backend.use).toEqual(MediaBackendType.FILESYSTEM);
|
||||
expect(config.backend.filesystem.uploadPath).toEqual(uploadPath);
|
||||
restore();
|
||||
});
|
||||
|
@ -57,7 +57,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_ACCESS_KEY: accessKeyId,
|
||||
HD_MEDIA_BACKEND_S3_SECRET_KEY: secretAccessKey,
|
||||
HD_MEDIA_BACKEND_S3_BUCKET: bucket,
|
||||
|
@ -71,7 +71,7 @@ describe('mediaConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = mediaConfig() as { backend: S3MediaConfig };
|
||||
expect(config.backend.use).toEqual(BackendType.S3);
|
||||
expect(config.backend.use).toEqual(MediaBackendType.S3);
|
||||
expect(config.backend.s3.accessKeyId).toEqual(accessKeyId);
|
||||
expect(config.backend.s3.secretAccessKey).toEqual(secretAccessKey);
|
||||
expect(config.backend.s3.bucket).toEqual(bucket);
|
||||
|
@ -85,7 +85,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.AZURE,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.AZURE,
|
||||
HD_MEDIA_BACKEND_AZURE_CONNECTION_STRING: azureConnectionString,
|
||||
HD_MEDIA_BACKEND_AZURE_CONTAINER: container,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -95,7 +95,7 @@ describe('mediaConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = mediaConfig() as { backend: AzureMediaConfig };
|
||||
expect(config.backend.use).toEqual(BackendType.AZURE);
|
||||
expect(config.backend.use).toEqual(MediaBackendType.AZURE);
|
||||
expect(config.backend.azure.connectionString).toEqual(
|
||||
azureConnectionString,
|
||||
);
|
||||
|
@ -107,7 +107,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.IMGUR,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.IMGUR,
|
||||
HD_MEDIA_BACKEND_IMGUR_CLIENT_ID: clientID,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
|
@ -116,7 +116,7 @@ describe('mediaConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = mediaConfig() as { backend: ImgurMediaConfig };
|
||||
expect(config.backend.use).toEqual(BackendType.IMGUR);
|
||||
expect(config.backend.use).toEqual(MediaBackendType.IMGUR);
|
||||
expect(config.backend.imgur.clientId).toEqual(clientID);
|
||||
restore();
|
||||
});
|
||||
|
@ -125,7 +125,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING: webdavConnectionString,
|
||||
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR: uploadDir,
|
||||
HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL: publicUrl,
|
||||
|
@ -136,7 +136,7 @@ describe('mediaConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = mediaConfig() as { backend: WebdavMediaConfig };
|
||||
expect(config.backend.use).toEqual(BackendType.WEBDAV);
|
||||
expect(config.backend.use).toEqual(MediaBackendType.WEBDAV);
|
||||
expect(config.backend.webdav.connectionString).toEqual(
|
||||
webdavConnectionString,
|
||||
);
|
||||
|
@ -152,7 +152,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.FILESYSTEM,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.FILESYSTEM,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -171,7 +171,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_SECRET_KEY: secretAccessKey,
|
||||
HD_MEDIA_BACKEND_S3_BUCKET: bucket,
|
||||
HD_MEDIA_BACKEND_S3_ENDPOINT: endPoint,
|
||||
|
@ -190,7 +190,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_ACCESS_KEY: accessKeyId,
|
||||
HD_MEDIA_BACKEND_S3_BUCKET: bucket,
|
||||
HD_MEDIA_BACKEND_S3_ENDPOINT: endPoint,
|
||||
|
@ -209,7 +209,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_ACCESS_KEY: accessKeyId,
|
||||
HD_MEDIA_BACKEND_S3_SECRET_KEY: secretAccessKey,
|
||||
HD_MEDIA_BACKEND_S3_ENDPOINT: endPoint,
|
||||
|
@ -228,7 +228,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_ACCESS_KEY: accessKeyId,
|
||||
HD_MEDIA_BACKEND_S3_SECRET_KEY: secretAccessKey,
|
||||
HD_MEDIA_BACKEND_S3_BUCKET: bucket,
|
||||
|
@ -247,7 +247,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.S3,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.S3,
|
||||
HD_MEDIA_BACKEND_S3_ACCESS_KEY: accessKeyId,
|
||||
HD_MEDIA_BACKEND_S3_SECRET_KEY: secretAccessKey,
|
||||
HD_MEDIA_BACKEND_S3_BUCKET: bucket,
|
||||
|
@ -270,7 +270,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.AZURE,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.AZURE,
|
||||
HD_MEDIA_BACKEND_AZURE_CONTAINER: container,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
|
@ -287,7 +287,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.AZURE,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.AZURE,
|
||||
HD_MEDIA_BACKEND_AZURE_CONNECTION_STRING: azureConnectionString,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
|
@ -307,7 +307,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.IMGUR,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.IMGUR,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -326,7 +326,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR: uploadDir,
|
||||
HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL: publicUrl,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -344,7 +344,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING: 'not-an-url',
|
||||
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR: uploadDir,
|
||||
HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL: publicUrl,
|
||||
|
@ -363,7 +363,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING: webdavConnectionString,
|
||||
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR: uploadDir,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -381,7 +381,7 @@ describe('mediaConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MEDIA_BACKEND: BackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND: MediaBackendType.WEBDAV,
|
||||
HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING: webdavConnectionString,
|
||||
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR: uploadDir,
|
||||
HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL: 'not-an-url',
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import z from 'zod';
|
||||
|
||||
import { BackendType } from '../media/backends/backend-type.enum';
|
||||
import { parseOptionalBoolean } from './utils';
|
||||
import {
|
||||
buildErrorMessage,
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
} from './zod-error-message';
|
||||
|
||||
const azureSchema = z.object({
|
||||
use: z.literal(BackendType.AZURE),
|
||||
use: z.literal(MediaBackendType.AZURE),
|
||||
azure: z.object({
|
||||
connectionString: z
|
||||
.string()
|
||||
|
@ -24,21 +24,21 @@ const azureSchema = z.object({
|
|||
});
|
||||
|
||||
const filesystemSchema = z.object({
|
||||
use: z.literal(BackendType.FILESYSTEM),
|
||||
use: z.literal(MediaBackendType.FILESYSTEM),
|
||||
filesystem: z.object({
|
||||
uploadPath: z.string().describe('HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH'),
|
||||
}),
|
||||
});
|
||||
|
||||
const imgurSchema = z.object({
|
||||
use: z.literal(BackendType.IMGUR),
|
||||
use: z.literal(MediaBackendType.IMGUR),
|
||||
imgur: z.object({
|
||||
clientId: z.string().describe('HD_MEDIA_BACKEND_IMGUR_CLIENT_ID'),
|
||||
}),
|
||||
});
|
||||
|
||||
const s3Schema = z.object({
|
||||
use: z.literal(BackendType.S3),
|
||||
use: z.literal(MediaBackendType.S3),
|
||||
s3: z.object({
|
||||
accessKeyId: z.string().describe('HD_MEDIA_BACKEND_S3_ACCESS_KEY'),
|
||||
secretAccessKey: z.string().describe('HD_MEDIA_BACKEND_S3_SECRET_KEY'),
|
||||
|
@ -53,7 +53,7 @@ const s3Schema = z.object({
|
|||
});
|
||||
|
||||
const webdavSchema = z.object({
|
||||
use: z.literal(BackendType.WEBDAV),
|
||||
use: z.literal(MediaBackendType.WEBDAV),
|
||||
webdav: z.object({
|
||||
connectionString: z
|
||||
.string()
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { ConfigFactoryKeyHost, registerAs } from '@nestjs/config';
|
||||
import { ConfigFactory } from '@nestjs/config/dist/interfaces';
|
||||
|
||||
import { BackendType } from '../../media/backends/backend-type.enum';
|
||||
import { MediaConfig } from '../media.config';
|
||||
|
||||
export function createDefaultMockMediaConfig(): MediaConfig {
|
||||
return {
|
||||
backend: {
|
||||
use: BackendType.FILESYSTEM,
|
||||
use: MediaBackendType.FILESYSTEM,
|
||||
filesystem: {
|
||||
uploadPath:
|
||||
'test_uploads' + Math.floor(Math.random() * 100000).toString(),
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType, NoteType, SpecialGroup } from '@hedgedoc/commons';
|
||||
import type { Knex } from 'knex';
|
||||
|
||||
import { BackendType } from '../../media/backends/backend-type.enum';
|
||||
import {
|
||||
/* eslint-disable */
|
||||
const {
|
||||
AuthProviderType,
|
||||
FieldNameAlias,
|
||||
FieldNameApiToken,
|
||||
FieldNameAuthorshipInfo,
|
||||
|
@ -22,6 +15,9 @@ import {
|
|||
FieldNameRevisionTag,
|
||||
FieldNameUser,
|
||||
FieldNameUserPinnedNote,
|
||||
MediaBackendType,
|
||||
NoteType,
|
||||
SpecialGroup,
|
||||
TableAlias,
|
||||
TableApiToken,
|
||||
TableAuthorshipInfo,
|
||||
|
@ -36,9 +32,9 @@ import {
|
|||
TableRevisionTag,
|
||||
TableUser,
|
||||
TableUserPinnedNote,
|
||||
} from '../types';
|
||||
} = require('@hedgedoc/database');
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const up = async function (knex) {
|
||||
// Create the user table first as it's referenced by other tables
|
||||
await knex.schema.createTable(TableUser, (table) => {
|
||||
table.increments(FieldNameUser.id).primary();
|
||||
|
@ -212,8 +208,8 @@ export async function up(knex: Knex): Promise<void> {
|
|||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameRevision.uuid)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableRevision);
|
||||
.inTable(TableRevision)
|
||||
.onDelete('CASCADE');
|
||||
table.string(FieldNameRevisionTag.tag).notNullable();
|
||||
table.primary([
|
||||
FieldNameRevisionTag.revisionUuid,
|
||||
|
@ -228,15 +224,15 @@ export async function up(knex: Knex): Promise<void> {
|
|||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameRevision.uuid)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableRevision);
|
||||
.inTable(TableRevision)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.integer(FieldNameAuthorshipInfo.authorId)
|
||||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameUser.id)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableUser);
|
||||
.inTable(TableUser)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.integer(FieldNameAuthorshipInfo.startPosition)
|
||||
.unsigned()
|
||||
|
@ -254,15 +250,15 @@ export async function up(knex: Knex): Promise<void> {
|
|||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameNote.id)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableNote);
|
||||
.inTable(TableNote)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.integer(FieldNameNoteUserPermission.userId)
|
||||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameUser.id)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableUser);
|
||||
.inTable(TableUser)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.boolean(FieldNameNoteUserPermission.canEdit)
|
||||
.notNullable()
|
||||
|
@ -280,15 +276,15 @@ export async function up(knex: Knex): Promise<void> {
|
|||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameNote.id)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableNote);
|
||||
.inTable(TableNote)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.integer(FieldNameNoteGroupPermission.groupId)
|
||||
.unsigned()
|
||||
.notNullable()
|
||||
.references(FieldNameGroup.id)
|
||||
.onDelete('CASCADE')
|
||||
.inTable(TableGroup);
|
||||
.inTable(TableGroup)
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.boolean(FieldNameNoteGroupPermission.canEdit)
|
||||
.notNullable()
|
||||
|
@ -319,11 +315,11 @@ export async function up(knex: Knex): Promise<void> {
|
|||
.enu(
|
||||
FieldNameMediaUpload.backendType,
|
||||
[
|
||||
BackendType.AZURE,
|
||||
BackendType.FILESYSTEM,
|
||||
BackendType.IMGUR,
|
||||
BackendType.S3,
|
||||
BackendType.WEBDAV,
|
||||
MediaBackendType.AZURE,
|
||||
MediaBackendType.FILESYSTEM,
|
||||
MediaBackendType.IMGUR,
|
||||
MediaBackendType.S3,
|
||||
MediaBackendType.WEBDAV,
|
||||
],
|
||||
{
|
||||
useNative: true,
|
||||
|
@ -356,9 +352,9 @@ export async function up(knex: Knex): Promise<void> {
|
|||
FieldNameUserPinnedNote.noteId,
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
const down = async function (knex) {
|
||||
// Drop tables in reverse order of creation to avoid integer key constraints
|
||||
await knex.schema.dropTableIfExists(TableUserPinnedNote);
|
||||
await knex.schema.dropTableIfExists(TableMediaUpload);
|
||||
|
@ -374,4 +370,9 @@ export async function down(knex: Knex): Promise<void> {
|
|||
await knex.schema.dropTableIfExists(TableNote);
|
||||
await knex.schema.dropTableIfExists(TableGroup);
|
||||
await knex.schema.dropTableIfExists(TableUser);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
up,
|
||||
down,
|
||||
};
|
|
@ -4,15 +4,15 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { hashPassword } from '../../utils/password';
|
||||
import {
|
||||
FieldNameIdentity,
|
||||
FieldNameUser,
|
||||
TableIdentity,
|
||||
TableUser,
|
||||
} from '../types';
|
||||
} from '@hedgedoc/database';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { hashPassword } from '../../utils/password';
|
||||
|
||||
export async function seed(knex: Knex): Promise<void> {
|
||||
// Clear tables beforehand
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameApiToken, TableApiToken } from '@hedgedoc/database';
|
||||
import { createHash } from 'crypto';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { FieldNameApiToken, TableApiToken } from '../types';
|
||||
|
||||
export async function seed(knex: Knex): Promise<void> {
|
||||
// Clear table beforehand
|
||||
await knex(TableApiToken).del();
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { NoteType } from '@hedgedoc/commons';
|
||||
import { createPatch } from 'diff';
|
||||
import { readFileSync } from 'fs';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { extractRevisionMetadataFromContent } from '../../revisions/utils/extract-revision-metadata-from-content';
|
||||
import {
|
||||
FieldNameAlias,
|
||||
FieldNameAuthorshipInfo,
|
||||
|
@ -24,7 +19,12 @@ import {
|
|||
TableNoteUserPermission,
|
||||
TableRevision,
|
||||
TableRevisionTag,
|
||||
} from '../types';
|
||||
} from '@hedgedoc/database';
|
||||
import { createPatch } from 'diff';
|
||||
import { readFileSync } from 'fs';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { extractRevisionMetadataFromContent } from '../../revisions/utils/extract-revision-metadata-from-content';
|
||||
|
||||
export async function seed(knex: Knex): Promise<void> {
|
||||
// Clear tables beforehand
|
||||
|
@ -160,18 +160,21 @@ export async function seed(knex: Knex): Promise<void> {
|
|||
[FieldNameAuthorshipInfo.authorId]: 1,
|
||||
[FieldNameAuthorshipInfo.startPosition]: 0,
|
||||
[FieldNameAuthorshipInfo.endPosition]: guestNoteContent.length,
|
||||
[FieldNameAuthorshipInfo.createdAt]: new Date(),
|
||||
},
|
||||
{
|
||||
[FieldNameAuthorshipInfo.revisionUuid]: userNoteRevisionUuid,
|
||||
[FieldNameAuthorshipInfo.authorId]: 2,
|
||||
[FieldNameAuthorshipInfo.startPosition]: 0,
|
||||
[FieldNameAuthorshipInfo.endPosition]: userNoteContent.length,
|
||||
[FieldNameAuthorshipInfo.createdAt]: new Date(),
|
||||
},
|
||||
{
|
||||
[FieldNameAuthorshipInfo.revisionUuid]: userSlideRevisionUuid,
|
||||
[FieldNameAuthorshipInfo.authorId]: 2,
|
||||
[FieldNameAuthorshipInfo.startPosition]: 0,
|
||||
[FieldNameAuthorshipInfo.endPosition]: userSlideContent.length,
|
||||
[FieldNameAuthorshipInfo.createdAt]: new Date(),
|
||||
},
|
||||
]);
|
||||
await knex(TableNoteGroupPermission).insert([
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export { Alias, FieldNameAlias, TableAlias } from './alias';
|
||||
export { ApiToken, FieldNameApiToken, TableApiToken } from './api-token';
|
||||
export {
|
||||
AuthorshipInfo,
|
||||
FieldNameAuthorshipInfo,
|
||||
TableAuthorshipInfo,
|
||||
} from './authorship-info';
|
||||
export { Group, FieldNameGroup, TableGroup } from './group';
|
||||
export { GroupUser, FieldNameGroupUser, TableGroupUser } from './group-user';
|
||||
export { Identity, FieldNameIdentity, TableIdentity } from './identity';
|
||||
export {
|
||||
MediaUpload,
|
||||
FieldNameMediaUpload,
|
||||
TableMediaUpload,
|
||||
} from './media-upload';
|
||||
export { Note, FieldNameNote, TableNote } from './note';
|
||||
export {
|
||||
NoteGroupPermission,
|
||||
FieldNameNoteGroupPermission,
|
||||
TableNoteGroupPermission,
|
||||
} from './note-group-permission';
|
||||
export {
|
||||
NoteUserPermission,
|
||||
FieldNameNoteUserPermission,
|
||||
TableNoteUserPermission,
|
||||
} from './note-user-permission';
|
||||
export { Revision, FieldNameRevision, TableRevision } from './revision';
|
||||
export {
|
||||
RevisionTag,
|
||||
FieldNameRevisionTag,
|
||||
TableRevisionTag,
|
||||
} from './revision-tag';
|
||||
export { User, FieldNameUser, TableUser } from './user';
|
||||
export {
|
||||
UserPinnedNote,
|
||||
FieldNameUserPinnedNote,
|
||||
TableUserPinnedNote,
|
||||
} from './user-pinned-note';
|
|
@ -3,15 +3,18 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Knex } from 'knex';
|
||||
|
||||
import { Alias, TypeInsertAlias, TypeUpdateAlias } from './alias';
|
||||
import { ApiToken, TypeInsertApiToken, TypeUpdateApiToken } from './api-token';
|
||||
import { Group, TypeInsertGroup, TypeUpdateGroup } from './group';
|
||||
import { Identity, TypeInsertIdentity, TypeUpdateIdentity } from './identity';
|
||||
import {
|
||||
Alias,
|
||||
ApiToken,
|
||||
AuthorshipInfo,
|
||||
Group,
|
||||
GroupUser,
|
||||
Identity,
|
||||
MediaUpload,
|
||||
Note,
|
||||
NoteGroupPermission,
|
||||
NoteUserPermission,
|
||||
Revision,
|
||||
RevisionTag,
|
||||
TableAlias,
|
||||
TableApiToken,
|
||||
|
@ -27,24 +30,28 @@ import {
|
|||
TableRevisionTag,
|
||||
TableUser,
|
||||
TableUserPinnedNote,
|
||||
UserPinnedNote,
|
||||
} from './index';
|
||||
import {
|
||||
MediaUpload,
|
||||
TypeInsertAlias,
|
||||
TypeInsertApiToken,
|
||||
TypeInsertAuthorshipInfo,
|
||||
TypeInsertGroup,
|
||||
TypeInsertIdentity,
|
||||
TypeInsertMediaUpload,
|
||||
TypeInsertNote,
|
||||
TypeInsertRevision,
|
||||
TypeInsertUser,
|
||||
TypeUpdateAlias,
|
||||
TypeUpdateApiToken,
|
||||
TypeUpdateGroup,
|
||||
TypeUpdateIdentity,
|
||||
TypeUpdateMediaUpload,
|
||||
} from './media-upload';
|
||||
import { Note, TypeInsertNote, TypeUpdateNote } from './note';
|
||||
import {
|
||||
NoteGroupPermission,
|
||||
TypeUpdateNote,
|
||||
TypeUpdateNoteGroupPermission,
|
||||
} from './note-group-permission';
|
||||
import {
|
||||
NoteUserPermission,
|
||||
TypeUpdateNoteUserPermission,
|
||||
} from './note-user-permission';
|
||||
import { Revision, TypeInsertRevision } from './revision';
|
||||
import { TypeInsertUser, TypeUpdateUser, User } from './user';
|
||||
TypeUpdateUser,
|
||||
User,
|
||||
UserPinnedNote,
|
||||
} from '@hedgedoc/database';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
declare module 'knex/types/tables.js' {
|
||||
|
@ -59,7 +66,10 @@ declare module 'knex/types/tables.js' {
|
|||
TypeInsertApiToken,
|
||||
TypeUpdateApiToken
|
||||
>;
|
||||
[TableAuthorshipInfo]: AuthorshipInfo;
|
||||
[TableAuthorshipInfo]: Knex.CompositeTableType<
|
||||
AuthorshipInfo,
|
||||
TypeInsertAuthorshipInfo
|
||||
>;
|
||||
[TableGroup]: Knex.CompositeTableType<
|
||||
Group,
|
||||
TypeInsertGroup,
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
AuthProviderDto,
|
||||
AuthProviderType,
|
||||
BrandingDto,
|
||||
FrontendConfigDto,
|
||||
SpecialUrlDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { AuthProviderDto } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { URL } from 'url';
|
||||
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { GroupInfoDto } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameGroup,
|
||||
TableGroup,
|
||||
TypeInsertGroup,
|
||||
} from '@hedgedoc/database';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import { FieldNameGroup, TableGroup } from '../database/types';
|
||||
import { TypeInsertGroup } from '../database/types/group';
|
||||
import { AlreadyInDBError, NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
|
||||
|
@ -72,11 +75,13 @@ export class GroupsService {
|
|||
* Fetches a groupId by its identifier name
|
||||
*
|
||||
* @param name Name of the group to query
|
||||
* @param transaction The optional database transaction to use
|
||||
* @return The groupId
|
||||
* @throws {NotInDBError} if there is no group with this name
|
||||
*/
|
||||
async getGroupIdByName(name: string): Promise<number> {
|
||||
const group = await this.knex(TableGroup)
|
||||
async getGroupIdByName(name: string, transaction?: Knex): Promise<number> {
|
||||
const dbActor = transaction ?? this.knex;
|
||||
const group = await dbActor(TableGroup)
|
||||
.select(FieldNameGroup.id)
|
||||
.where(FieldNameGroup.name, name)
|
||||
.first();
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
generateBlobSASQueryParameters,
|
||||
StorageSharedKeyCredential,
|
||||
} from '@azure/storage-blob';
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { FileTypeResult } from 'file-type';
|
||||
|
||||
|
@ -21,7 +22,6 @@ import mediaConfiguration, {
|
|||
import { MediaBackendError } from '../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { MediaBackend } from '../media-backend.interface';
|
||||
import { BackendType } from './backend-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class AzureBackend implements MediaBackend {
|
||||
|
@ -36,7 +36,7 @@ export class AzureBackend implements MediaBackend {
|
|||
) {
|
||||
this.logger.setContext(AzureBackend.name);
|
||||
this.config = (this.mediaConfig.backend as AzureMediaConfig).azure;
|
||||
if (this.mediaConfig.backend.use === BackendType.AZURE) {
|
||||
if (this.mediaConfig.backend.use === MediaBackendType.AZURE) {
|
||||
// only create the client if the backend is configured to azure
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(
|
||||
this.config.connectionString,
|
||||
|
|
|
@ -3,11 +3,3 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum BackendType {
|
||||
FILESYSTEM = 'filesystem',
|
||||
S3 = 's3',
|
||||
IMGUR = 'imgur',
|
||||
AZURE = 'azure',
|
||||
WEBDAV = 'webdav',
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import * as MinioModule from 'minio';
|
||||
import { Client, ClientOptions } from 'minio';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { MediaConfig } from '../../config/media.config';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { BackendType } from './backend-type.enum';
|
||||
import { S3Backend } from './s3-backend';
|
||||
|
||||
jest.mock('minio');
|
||||
|
@ -43,7 +43,7 @@ describe('s3 backend', () => {
|
|||
function mockMediaConfig(endPoint: string): MediaConfig {
|
||||
return Mock.of<MediaConfig>({
|
||||
backend: {
|
||||
use: BackendType.S3,
|
||||
use: MediaBackendType.S3,
|
||||
s3: {
|
||||
accessKeyId: mockedS3AccessKeyId,
|
||||
secretAccessKey: mockedS3SecretAccessKey,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { FileTypeResult } from 'file-type';
|
||||
import { Client } from 'minio';
|
||||
|
@ -15,7 +16,6 @@ import mediaConfiguration, {
|
|||
import { MediaBackendError } from '../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { MediaBackend } from '../media-backend.interface';
|
||||
import { BackendType } from './backend-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class S3Backend implements MediaBackend {
|
||||
|
@ -33,7 +33,7 @@ export class S3Backend implements MediaBackend {
|
|||
private mediaConfig: MediaConfig,
|
||||
) {
|
||||
this.logger.setContext(S3Backend.name);
|
||||
if (this.mediaConfig.backend.use !== BackendType.S3) {
|
||||
if (this.mediaConfig.backend.use !== MediaBackendType.S3) {
|
||||
return;
|
||||
}
|
||||
this.config = this.mediaConfig.backend.s3;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { FileTypeResult } from 'file-type';
|
||||
import fetch, { Response } from 'node-fetch';
|
||||
|
@ -15,7 +16,6 @@ import mediaConfiguration, {
|
|||
import { MediaBackendError } from '../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { MediaBackend } from '../media-backend.interface';
|
||||
import { BackendType } from './backend-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class WebdavBackend implements MediaBackend {
|
||||
|
@ -29,7 +29,7 @@ export class WebdavBackend implements MediaBackend {
|
|||
private mediaConfig: MediaConfig,
|
||||
) {
|
||||
this.logger.setContext(WebdavBackend.name);
|
||||
if (this.mediaConfig.backend.use === BackendType.WEBDAV) {
|
||||
if (this.mediaConfig.backend.use === MediaBackendType.WEBDAV) {
|
||||
this.config = this.mediaConfig.backend.webdav;
|
||||
const url = new URL(this.config.connectionString);
|
||||
this.baseUrl = url.toString();
|
||||
|
|
|
@ -3,15 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { MediaUploadDto } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import * as FileType from 'file-type';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
import { v7 as uuidV7 } from 'uuid';
|
||||
|
||||
import mediaConfiguration, { MediaConfig } from '../config/media.config';
|
||||
import { MediaBackendType, MediaUploadDto } from '@hedgedoc/commons';
|
||||
import {
|
||||
Alias,
|
||||
FieldNameAlias,
|
||||
|
@ -24,12 +16,18 @@ import {
|
|||
TableMediaUpload,
|
||||
TableUser,
|
||||
User,
|
||||
} from '../database/types';
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import * as FileType from 'file-type';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
import { v7 as uuidV7 } from 'uuid';
|
||||
|
||||
import mediaConfiguration, { MediaConfig } from '../config/media.config';
|
||||
import { ClientError, NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { NoteService } from '../notes/note.service';
|
||||
import { AzureBackend } from './backends/azure-backend';
|
||||
import { BackendType } from './backends/backend-type.enum';
|
||||
import { FilesystemBackend } from './backends/filesystem-backend';
|
||||
import { ImgurBackend } from './backends/imgur-backend';
|
||||
import { S3Backend } from './backends/s3-backend';
|
||||
|
@ -39,7 +37,7 @@ import { MediaBackend } from './media-backend.interface';
|
|||
@Injectable()
|
||||
export class MediaService {
|
||||
mediaBackend: MediaBackend;
|
||||
mediaBackendType: BackendType;
|
||||
mediaBackendType: MediaBackendType;
|
||||
|
||||
constructor(
|
||||
private readonly logger: ConsoleLoggerService,
|
||||
|
@ -246,18 +244,18 @@ export class MediaService {
|
|||
.where(FieldNameMediaUpload.uuid, uuid);
|
||||
}
|
||||
|
||||
private chooseBackendType(): BackendType {
|
||||
private chooseBackendType(): MediaBackendType {
|
||||
switch (this.mediaConfig.backend.use as string) {
|
||||
case 'filesystem':
|
||||
return BackendType.FILESYSTEM;
|
||||
return MediaBackendType.FILESYSTEM;
|
||||
case 'azure':
|
||||
return BackendType.AZURE;
|
||||
return MediaBackendType.AZURE;
|
||||
case 'imgur':
|
||||
return BackendType.IMGUR;
|
||||
return MediaBackendType.IMGUR;
|
||||
case 's3':
|
||||
return BackendType.S3;
|
||||
return MediaBackendType.S3;
|
||||
case 'webdav':
|
||||
return BackendType.WEBDAV;
|
||||
return MediaBackendType.WEBDAV;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unexpected media backend ${this.mediaConfig.backend.use}`,
|
||||
|
@ -265,17 +263,17 @@ export class MediaService {
|
|||
}
|
||||
}
|
||||
|
||||
private getBackendFromType(type: BackendType): MediaBackend {
|
||||
private getBackendFromType(type: MediaBackendType): MediaBackend {
|
||||
switch (type) {
|
||||
case BackendType.FILESYSTEM:
|
||||
case MediaBackendType.FILESYSTEM:
|
||||
return this.moduleRef.get(FilesystemBackend);
|
||||
case BackendType.S3:
|
||||
case MediaBackendType.S3:
|
||||
return this.moduleRef.get(S3Backend);
|
||||
case BackendType.AZURE:
|
||||
case MediaBackendType.AZURE:
|
||||
return this.moduleRef.get(AzureBackend);
|
||||
case BackendType.IMGUR:
|
||||
case MediaBackendType.IMGUR:
|
||||
return this.moduleRef.get(ImgurBackend);
|
||||
case BackendType.WEBDAV:
|
||||
case MediaBackendType.WEBDAV:
|
||||
return this.moduleRef.get(WebdavBackend);
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +307,9 @@ export class MediaService {
|
|||
uuid: mediaUpload[FieldNameMediaUpload.uuid],
|
||||
fileName: mediaUpload[FieldNameMediaUpload.fileName],
|
||||
noteId: mediaUpload[FieldNameAlias.alias],
|
||||
createdAt: mediaUpload[FieldNameMediaUpload.createdAt].toISOString(),
|
||||
createdAt: new Date(
|
||||
mediaUpload[FieldNameMediaUpload.createdAt],
|
||||
).toISOString(),
|
||||
username: mediaUpload[FieldNameUser.username],
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -9,14 +9,6 @@ import {
|
|||
NotePermissionsDto,
|
||||
SpecialGroup,
|
||||
} from '@hedgedoc/commons';
|
||||
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import { AliasService } from '../alias/alias.service';
|
||||
import { DefaultAccessLevel } from '../config/default-access-level.enum';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import {
|
||||
FieldNameAlias,
|
||||
FieldNameGroup,
|
||||
|
@ -36,7 +28,15 @@ import {
|
|||
TableNoteUserPermission,
|
||||
TableUser,
|
||||
User,
|
||||
} from '../database/types';
|
||||
} from '@hedgedoc/database';
|
||||
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import { AliasService } from '../alias/alias.service';
|
||||
import { DefaultAccessLevel } from '../config/default-access-level.enum';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import {
|
||||
ForbiddenIdError,
|
||||
GenericDBError,
|
||||
|
@ -141,6 +141,7 @@ export class NoteService {
|
|||
await this.revisionsService.createRevision(
|
||||
noteId,
|
||||
noteContent,
|
||||
true,
|
||||
transaction,
|
||||
);
|
||||
|
||||
|
@ -162,6 +163,7 @@ export class NoteService {
|
|||
if (everyoneAccessLevel !== DefaultAccessLevel.NONE) {
|
||||
const everyoneAccessGroupId = await this.groupsService.getGroupIdByName(
|
||||
SpecialGroup.EVERYONE,
|
||||
transaction,
|
||||
);
|
||||
await this.permissionService.setGroupPermission(
|
||||
noteId,
|
||||
|
@ -173,7 +175,10 @@ export class NoteService {
|
|||
|
||||
if (loggedInUsersAccessLevel !== DefaultAccessLevel.NONE) {
|
||||
const loggedInUsersAccessGroupId =
|
||||
await this.groupsService.getGroupIdByName(SpecialGroup.LOGGED_IN);
|
||||
await this.groupsService.getGroupIdByName(
|
||||
SpecialGroup.LOGGED_IN,
|
||||
transaction,
|
||||
);
|
||||
await this.permissionService.setGroupPermission(
|
||||
noteId,
|
||||
loggedInUsersAccessGroupId,
|
||||
|
@ -415,6 +420,12 @@ export class NoteService {
|
|||
'toNoteMetadataDto',
|
||||
);
|
||||
}
|
||||
const createdAtString = note[FieldNameNote.createdAt];
|
||||
const version = note[FieldNameNote.version];
|
||||
this.logger.debug(`createdAt: ${createdAtString}`);
|
||||
this.logger.debug(`createversion: ${version}`);
|
||||
const createdAt = new Date(createdAtString).toISOString();
|
||||
|
||||
const latestRevision = await this.revisionsService.getLatestRevision(
|
||||
noteId,
|
||||
transaction,
|
||||
|
@ -423,28 +434,40 @@ export class NoteService {
|
|||
latestRevision[FieldNameRevision.uuid],
|
||||
transaction,
|
||||
);
|
||||
const permissions = await this.toNotePermissionsDto(noteId, transaction);
|
||||
|
||||
const updateUsers = await this.revisionsService.getRevisionUserInfo(
|
||||
latestRevision[FieldNameRevision.uuid],
|
||||
transaction,
|
||||
);
|
||||
updateUsers.users.sort(
|
||||
(userA, userB) => userB.createdAt.getTime() - userA.createdAt.getTime(),
|
||||
);
|
||||
const lastEdit = updateUsers.users[0];
|
||||
const editedBy = updateUsers.users.map((user) => user.username);
|
||||
const permissions = await this.toNotePermissionsDto(noteId, transaction);
|
||||
updateUsers.users.sort();
|
||||
|
||||
let lastUpdatedBy;
|
||||
let editedBy;
|
||||
let updatedAt;
|
||||
if (updateUsers.users.length > 0) {
|
||||
const lastEdit = updateUsers.users[0];
|
||||
lastUpdatedBy = lastEdit.username;
|
||||
editedBy = updateUsers.users.map((user) => user.username);
|
||||
updatedAt = new Date(lastEdit.createdAt).toISOString();
|
||||
} else {
|
||||
lastUpdatedBy = permissions.owner;
|
||||
editedBy = permissions.owner ? [permissions.owner] : [];
|
||||
updatedAt = createdAt;
|
||||
}
|
||||
|
||||
return {
|
||||
aliases: aliases.map((alias) => alias[FieldNameAlias.alias]),
|
||||
primaryAlias: primaryAlias[FieldNameAlias.alias],
|
||||
title: latestRevision.title,
|
||||
description: latestRevision.description,
|
||||
tags: tags,
|
||||
createdAt: note[FieldNameNote.createdAt].toISOString(),
|
||||
editedBy: editedBy,
|
||||
permissions: permissions,
|
||||
version: note[FieldNameNote.version],
|
||||
updatedAt: lastEdit.createdAt.toISOString(),
|
||||
lastUpdatedBy: lastEdit.username,
|
||||
tags,
|
||||
createdAt,
|
||||
editedBy,
|
||||
permissions,
|
||||
version,
|
||||
updatedAt,
|
||||
lastUpdatedBy,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,6 @@ import {
|
|||
PermissionLevel,
|
||||
SpecialGroup,
|
||||
} from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import {
|
||||
FieldNameGroup,
|
||||
FieldNameGroupUser,
|
||||
|
@ -29,7 +23,13 @@ import {
|
|||
TableNoteGroupPermission,
|
||||
TableNoteUserPermission,
|
||||
TableUser,
|
||||
} from '../database/types';
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import { GenericDBError, NotInDBError } from '../errors/errors';
|
||||
import { NoteEvent, NoteEventMap } from '../events';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
|
@ -334,6 +334,7 @@ export class PermissionService {
|
|||
* @param noteId - the if of the note
|
||||
* @param groupId - the name of the group for which the permission should be set
|
||||
* @param canEdit - specifies if the group can edit the note
|
||||
* @param transaction The optional transaction for the database
|
||||
*/
|
||||
async setGroupPermission(
|
||||
noteId: number,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameUser } from '@hedgedoc/database';
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
|
@ -14,7 +15,6 @@ import { Reflector } from '@nestjs/core';
|
|||
|
||||
import { extractNoteIdFromRequest } from '../api/utils/extract-note-id-from-request';
|
||||
import { CompleteRequest } from '../api/utils/request.type';
|
||||
import { FieldNameUser } from '../database/types';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { NoteService } from '../notes/note.service';
|
||||
import { UsersService } from '../users/users.service';
|
||||
|
|
|
@ -9,9 +9,9 @@ import {
|
|||
YDocSyncServerAdapter,
|
||||
} from '@hedgedoc/commons';
|
||||
import * as HedgeDocCommonsModule from '@hedgedoc/commons';
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { FieldNameUser, User } from '../../database/types';
|
||||
import * as NameRandomizerModule from './random-word-lists/name-randomizer';
|
||||
import { RealtimeConnection } from './realtime-connection';
|
||||
import { RealtimeNote } from './realtime-note';
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameRevision } from '@hedgedoc/database';
|
||||
import { Optional } from '@mrdrogdrog/optional';
|
||||
import { BeforeApplicationShutdown, Inject, Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
|
||||
import appConfiguration, { AppConfig } from '../../config/app.config';
|
||||
import { FieldNameRevision } from '../../database/types';
|
||||
import { NoteEvent } from '../../events';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { NotePermissionLevel } from '../../permissions/note-permission.enum';
|
||||
|
@ -47,6 +47,7 @@ export class RealtimeNoteService implements BeforeApplicationShutdown {
|
|||
.createRevision(
|
||||
realtimeNote.getNoteId(),
|
||||
realtimeNote.getRealtimeDoc().getCurrentContent(),
|
||||
false,
|
||||
undefined,
|
||||
realtimeNote.getRealtimeDoc().encodeStateAsUpdate(),
|
||||
)
|
||||
|
|
|
@ -7,9 +7,9 @@ import {
|
|||
MockedBackendTransportAdapter,
|
||||
YDocSyncServerAdapter,
|
||||
} from '@hedgedoc/commons';
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { FieldNameUser, User } from '../../../database/types';
|
||||
import { RealtimeConnection } from '../realtime-connection';
|
||||
import { RealtimeNote } from '../realtime-note';
|
||||
import { RealtimeUserStatusAdapter } from '../realtime-user-status-adapter';
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { DisconnectReason, MessageTransporter } from '@hedgedoc/commons';
|
||||
import { FieldNameUser } from '@hedgedoc/database';
|
||||
import { OnGatewayConnection, WebSocketGateway } from '@nestjs/websockets';
|
||||
import { IncomingMessage } from 'http';
|
||||
import WebSocket from 'ws';
|
||||
|
||||
import { FieldNameUser } from '../../database/types';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { NoteService } from '../../notes/note.service';
|
||||
import { NotePermissionLevel } from '../../permissions/note-permission.enum';
|
||||
|
|
|
@ -4,15 +4,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { RevisionDto, RevisionMetadataDto } from '@hedgedoc/commons';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Cron, Timeout } from '@nestjs/schedule';
|
||||
import { createPatch } from 'diff';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
import { v7 as uuidv7 } from 'uuid';
|
||||
|
||||
import { AliasService } from '../alias/alias.service';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import {
|
||||
AuthorshipInfo,
|
||||
FieldNameAlias,
|
||||
|
@ -30,7 +21,16 @@ import {
|
|||
TableRevisionTag,
|
||||
TableUser,
|
||||
User,
|
||||
} from '../database/types';
|
||||
} from '@hedgedoc/database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Cron, Timeout } from '@nestjs/schedule';
|
||||
import { createPatch } from 'diff';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
import { v7 as uuidv7 } from 'uuid';
|
||||
|
||||
import { AliasService } from '../alias/alias.service';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import { GenericDBError, NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { extractRevisionMetadataFromContent } from './utils/extract-revision-metadata-from-content';
|
||||
|
@ -129,7 +129,7 @@ export class RevisionsService {
|
|||
recordMap.set(revision[FieldNameRevision.uuid], {
|
||||
uuid: revision[FieldNameRevision.uuid],
|
||||
length: (revision[FieldNameRevision.content] ?? '').length,
|
||||
createdAt: revision[FieldNameRevision.createdAt].toISOString(),
|
||||
createdAt: revision[FieldNameRevision.createdAt],
|
||||
authorUsernames:
|
||||
revision[FieldNameUser.username] !== null
|
||||
? [revision[FieldNameUser.username]]
|
||||
|
@ -217,7 +217,7 @@ export class RevisionsService {
|
|||
uuid: revision[FieldNameRevision.uuid],
|
||||
content: revision[FieldNameRevision.content],
|
||||
length: (revision[FieldNameRevision.content] ?? '').length,
|
||||
createdAt: revision[FieldNameRevision.createdAt].toISOString(),
|
||||
createdAt: revision[FieldNameRevision.createdAt],
|
||||
title: revision[FieldNameRevision.title],
|
||||
description: revision[FieldNameRevision.description],
|
||||
patch: revision.patch,
|
||||
|
@ -241,7 +241,7 @@ export class RevisionsService {
|
|||
.first();
|
||||
if (revision === undefined) {
|
||||
throw new NotInDBError(
|
||||
`No revisions for note ${noteId} found`,
|
||||
'No revisions for note found',
|
||||
this.logger.getContext(),
|
||||
'getLatestRevision',
|
||||
);
|
||||
|
@ -249,8 +249,12 @@ export class RevisionsService {
|
|||
return revision;
|
||||
}
|
||||
|
||||
async getRevisionUserInfo(revisionUuid: string): Promise<RevisionUserInfo> {
|
||||
const authorUsernamesAndGuestUuids = (await this.knex(TableAuthorshipInfo)
|
||||
async getRevisionUserInfo(
|
||||
revisionUuid: string,
|
||||
transaction?: Knex,
|
||||
): Promise<RevisionUserInfo> {
|
||||
const dbActor = transaction ?? this.knex;
|
||||
const authorUsernamesAndGuestUuids = (await dbActor(TableAuthorshipInfo)
|
||||
.join(
|
||||
TableUser,
|
||||
`${TableAuthorshipInfo}.${FieldNameAuthorshipInfo.authorId}`,
|
||||
|
@ -293,6 +297,7 @@ export class RevisionsService {
|
|||
* @async
|
||||
* @param noteId The note for which the revision should be created
|
||||
* @param newContent The new note content
|
||||
* @param firstRevision Whether this is called for the first revision of a note
|
||||
* @param transaction The optional pre-existing database transaction to use
|
||||
* @param yjsStateVector The yjs state vector that describes the new content
|
||||
* @return {Revision} the created revision
|
||||
|
@ -301,6 +306,7 @@ export class RevisionsService {
|
|||
async createRevision(
|
||||
noteId: number,
|
||||
newContent: string,
|
||||
firstRevision: boolean = false,
|
||||
transaction?: Knex,
|
||||
yjsStateVector?: ArrayBuffer,
|
||||
): Promise<void> {
|
||||
|
@ -309,6 +315,7 @@ export class RevisionsService {
|
|||
await this.innerCreateRevision(
|
||||
noteId,
|
||||
newContent,
|
||||
firstRevision,
|
||||
newTransaction,
|
||||
yjsStateVector,
|
||||
);
|
||||
|
@ -318,6 +325,7 @@ export class RevisionsService {
|
|||
await this.innerCreateRevision(
|
||||
noteId,
|
||||
newContent,
|
||||
firstRevision,
|
||||
transaction,
|
||||
yjsStateVector,
|
||||
);
|
||||
|
@ -326,13 +334,13 @@ export class RevisionsService {
|
|||
private async innerCreateRevision(
|
||||
noteId: number,
|
||||
newContent: string,
|
||||
firstRevision: boolean,
|
||||
transaction: Knex,
|
||||
yjsStateVector?: ArrayBuffer,
|
||||
): Promise<void> {
|
||||
const latestRevision =
|
||||
noteId === undefined
|
||||
? null
|
||||
: await this.getLatestRevision(noteId, transaction);
|
||||
const latestRevision = firstRevision
|
||||
? null
|
||||
: await this.getLatestRevision(noteId, transaction);
|
||||
const oldContent = latestRevision?.content;
|
||||
if (oldContent === newContent) {
|
||||
return undefined;
|
||||
|
@ -346,6 +354,7 @@ export class RevisionsService {
|
|||
latestRevision?.content ?? '',
|
||||
newContent,
|
||||
);
|
||||
|
||||
const { title, description, tags, noteType } =
|
||||
extractRevisionMetadataFromContent(newContent);
|
||||
const revisionIds = await transaction(TableRevision).insert(
|
||||
|
@ -369,12 +378,14 @@ export class RevisionsService {
|
|||
);
|
||||
}
|
||||
const revisionId = revisionIds[0][FieldNameRevision.uuid];
|
||||
await transaction(TableRevisionTag).insert(
|
||||
tags.map((tag) => ({
|
||||
[FieldNameRevisionTag.tag]: tag,
|
||||
[FieldNameRevisionTag.revisionUuid]: revisionId,
|
||||
})),
|
||||
);
|
||||
if (tags.length > 0) {
|
||||
await transaction(TableRevisionTag).insert(
|
||||
tags.map((tag) => ({
|
||||
[FieldNameRevisionTag.tag]: tag,
|
||||
[FieldNameRevisionTag.revisionUuid]: revisionId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getTagsByRevisionUuid(
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType, PendingUserInfoDto } from '@hedgedoc/commons';
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import { Cookie } from 'express-session';
|
||||
|
||||
import { FieldNameUser, User } from '../database/types';
|
||||
|
||||
export interface SessionState {
|
||||
/** Details about the currently used session cookie */
|
||||
cookie: Cookie;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import { Optional } from '@mrdrogdrog/optional';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { parse as parseCookie } from 'cookie';
|
||||
|
@ -10,7 +11,6 @@ import { unsign } from 'cookie-signature';
|
|||
import { IncomingMessage } from 'http';
|
||||
|
||||
import authConfiguration, { AuthConfig } from '../config/auth.config';
|
||||
import { FieldNameUser, User } from '../database/types';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { HEDGEDOC_SESSION } from '../utils/session';
|
||||
import { KeyvSessionStore } from './keyv-session-store';
|
||||
|
|
|
@ -5,17 +5,21 @@
|
|||
*/
|
||||
import {
|
||||
AuthProviderType,
|
||||
LoginUserInfoDto,
|
||||
REGEX_USERNAME,
|
||||
UserInfoDto,
|
||||
} from '@hedgedoc/commons';
|
||||
import { LoginUserInfoDto } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameUser,
|
||||
TableUser,
|
||||
TypeUpdateUser,
|
||||
User,
|
||||
} from '@hedgedoc/database';
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { InjectConnection } from 'nest-knexjs';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { FieldNameUser, TableUser, User } from '../database/types';
|
||||
import { TypeUpdateUser } from '../database/types/user';
|
||||
import { GenericDBError, NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { generateRandomName } from '../realtime/realtime-note/random-word-lists/name-randomizer';
|
||||
|
@ -209,11 +213,12 @@ export class UsersService {
|
|||
transaction?: Knex,
|
||||
): Promise<boolean> {
|
||||
const dbActor = transaction ? transaction : this.knex;
|
||||
const username = await dbActor(TableUser)
|
||||
const usernameResponse = await dbActor(TableUser)
|
||||
.select(FieldNameUser.username)
|
||||
.where(FieldNameUser.id, userId)
|
||||
.first();
|
||||
return username !== null && username !== undefined;
|
||||
const username = usernameResponse?.[FieldNameUser.username] ?? null;
|
||||
return username !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
export * from './media-upload.dto.js'
|
||||
export * from './media-backend-type.enum.js'
|
||||
|
|
13
commons/src/dtos/media/media-backend-type.enum.ts
Normal file
13
commons/src/dtos/media/media-backend-type.enum.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum MediaBackendType {
|
||||
FILESYSTEM = 'filesystem',
|
||||
S3 = 's3',
|
||||
IMGUR = 'imgur',
|
||||
AZURE = 'azure',
|
||||
WEBDAV = 'webdav',
|
||||
}
|
40
database/.eslintrc.cjs
Normal file
40
database/.eslintrc.cjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"./tsconfig.test.json"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"jest",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"jest": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": ["error",
|
||||
require('./.prettierrc.json')
|
||||
],
|
||||
"jest/no-disabled-tests": "warn",
|
||||
"jest/no-focused-tests": "error",
|
||||
"jest/no-identical-title": "error",
|
||||
"jest/prefer-to-have-length": "warn",
|
||||
"jest/valid-expect": "error"
|
||||
}
|
||||
}
|
31
database/.gitignore
vendored
Normal file
31
database/.gitignore
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
|
||||
# package manager
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
9
database/.npmignore
Normal file
9
database/.npmignore
Normal file
|
@ -0,0 +1,9 @@
|
|||
.idea
|
||||
.babelrc
|
||||
.eslintrc
|
||||
.travis.yml
|
||||
karma.conf.js
|
||||
tests.webpack.js
|
||||
webpack.config.*.js
|
||||
coverage/
|
||||
test/
|
3
database/.npmignore.license
Normal file
3
database/.npmignore.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
1
database/.prettierignore
Normal file
1
database/.prettierignore
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules/
|
4
database/.prettierignore.license
Normal file
4
database/.prettierignore.license
Normal file
|
@ -0,0 +1,4 @@
|
|||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
|
11
database/.prettierrc.json
Normal file
11
database/.prettierrc.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"parser": "typescript",
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": true,
|
||||
"arrowParens": "always"
|
||||
}
|
3
database/.prettierrc.json.license
Normal file
3
database/.prettierrc.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
23
database/build.sh
Executable file
23
database/build.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo "🦔 > Clear dist directory.."
|
||||
rm -rf dist
|
||||
|
||||
echo "🦔 > Compile to CJS.."
|
||||
tsc --project tsconfig.cjs.json
|
||||
|
||||
echo "🦔 > Fix CJS package.json.."
|
||||
cat > dist/cjs/package.json <<!EOF
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
!EOF
|
||||
|
||||
echo "🦔 > Done!"
|
27
database/jest.config.json
Normal file
27
database/jest.config.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"testRegex" : "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
|
||||
"testPathIgnorePatterns" : [
|
||||
"/dist/"
|
||||
],
|
||||
"moduleFileExtensions" : [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js"
|
||||
],
|
||||
"extensionsToTreatAsEsm" : [
|
||||
".ts"
|
||||
],
|
||||
"moduleNameMapper" : {
|
||||
"^(\\.{1,2}/.*)\\.js$" : "$1"
|
||||
},
|
||||
"transformIgnorePatterns": ["<rootDir>/node_modules/"],
|
||||
"transform" : {
|
||||
"^.+\\.tsx?$" : [
|
||||
"ts-jest",
|
||||
{
|
||||
"tsconfig" : "tsconfig.test.json",
|
||||
"useESM" : true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
3
database/jest.config.json.license
Normal file
3
database/jest.config.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
47
database/package.json
Normal file
47
database/package.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "@hedgedoc/database",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"description": "CJS code required for the database migrations",
|
||||
"author": "The HedgeDoc Authors",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"build": "./build.sh",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"lint:fix": "eslint --fix --ext .ts src"
|
||||
},
|
||||
"type": "module",
|
||||
"source": "src/index.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
"types": "dist/cjs/index.d.ts",
|
||||
"exports": {
|
||||
"require": {
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"LICENSES/*",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"dist/**"
|
||||
],
|
||||
"browserslist": [
|
||||
"node> 12"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hedgedoc/hedgedoc.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.14.0",
|
||||
"@typescript-eslint/parser": "8.14.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-jest": "28.9.0",
|
||||
"eslint-plugin-prettier": "5.2.3",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "5.6.3"
|
||||
},
|
||||
"packageManager": "yarn@4.5.3"
|
||||
}
|
3
database/package.json.license
Normal file
3
database/package.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
6
database/src/index.ts
Normal file
6
database/src/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
export * from './types/index.js'
|
|
@ -12,13 +12,13 @@
|
|||
*/
|
||||
export interface Alias {
|
||||
/** The alias as defined by the user. Is unique. */
|
||||
[FieldNameAlias.alias]: string;
|
||||
[FieldNameAlias.alias]: string
|
||||
|
||||
/** The id of the associated {@link Note}. */
|
||||
[FieldNameAlias.noteId]: number;
|
||||
[FieldNameAlias.noteId]: number
|
||||
|
||||
/** Whether the alias is the primary one for the note. */
|
||||
[FieldNameAlias.isPrimary]: boolean;
|
||||
[FieldNameAlias.isPrimary]: boolean
|
||||
}
|
||||
|
||||
export enum FieldNameAlias {
|
||||
|
@ -27,7 +27,7 @@ export enum FieldNameAlias {
|
|||
isPrimary = 'is_primary',
|
||||
}
|
||||
|
||||
export const TableAlias = 'alias';
|
||||
export const TableAlias = 'alias'
|
||||
|
||||
export type TypeInsertAlias = Alias;
|
||||
export type TypeUpdateAlias = Pick<Alias, FieldNameAlias.isPrimary>;
|
||||
export type TypeInsertAlias = Alias
|
||||
export type TypeUpdateAlias = Pick<Alias, FieldNameAlias.isPrimary>
|
|
@ -11,25 +11,25 @@
|
|||
*/
|
||||
export interface ApiToken {
|
||||
/** The id of the token, a short random ASCII string. Is unique */
|
||||
[FieldNameApiToken.id]: string;
|
||||
[FieldNameApiToken.id]: string
|
||||
|
||||
/** The {@link User} whose permissions the token has */
|
||||
[FieldNameApiToken.userId]: number;
|
||||
[FieldNameApiToken.userId]: number
|
||||
|
||||
/** The user-defined label for the token, such as "CLI" */
|
||||
[FieldNameApiToken.label]: string;
|
||||
[FieldNameApiToken.label]: string
|
||||
|
||||
/** Hashed version of the token's secret */
|
||||
[FieldNameApiToken.secretHash]: string;
|
||||
[FieldNameApiToken.secretHash]: string
|
||||
|
||||
/** Expiry date of the token */
|
||||
[FieldNameApiToken.validUntil]: Date;
|
||||
[FieldNameApiToken.validUntil]: string
|
||||
|
||||
/** Date when the API token was created */
|
||||
[FieldNameApiToken.createdAt]: Date;
|
||||
[FieldNameApiToken.createdAt]: string
|
||||
|
||||
/** When the token was last used. When it was never used yet, this field is null */
|
||||
[FieldNameApiToken.lastUsedAt]: Date | null;
|
||||
[FieldNameApiToken.lastUsedAt]: string | null
|
||||
}
|
||||
|
||||
export enum FieldNameApiToken {
|
||||
|
@ -42,7 +42,24 @@ export enum FieldNameApiToken {
|
|||
lastUsedAt = 'last_used_at',
|
||||
}
|
||||
|
||||
export const TableApiToken = 'api_token';
|
||||
export const TableApiToken = 'api_token'
|
||||
|
||||
export type TypeInsertApiToken = Omit<ApiToken, FieldNameApiToken.lastUsedAt>;
|
||||
export type TypeUpdateApiToken = Pick<ApiToken, FieldNameApiToken.lastUsedAt>;
|
||||
type TypeApiTokenDate = Omit<
|
||||
ApiToken,
|
||||
| FieldNameApiToken.validUntil
|
||||
| FieldNameApiToken.createdAt
|
||||
| FieldNameApiToken.lastUsedAt
|
||||
> & {
|
||||
[FieldNameApiToken.validUntil]: Date
|
||||
[FieldNameApiToken.createdAt]: Date
|
||||
[FieldNameApiToken.lastUsedAt]: Date | null
|
||||
}
|
||||
|
||||
export type TypeInsertApiToken = Omit<
|
||||
TypeApiTokenDate,
|
||||
FieldNameApiToken.lastUsedAt
|
||||
>
|
||||
export type TypeUpdateApiToken = Pick<
|
||||
TypeApiTokenDate,
|
||||
FieldNameApiToken.lastUsedAt
|
||||
>
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FieldNameApiToken } from './api-token'
|
||||
|
||||
/**
|
||||
* The AuthorshipInfo holds the information from where to where one {@link User} has changed a {@link Note}
|
||||
*
|
||||
|
@ -11,19 +13,19 @@
|
|||
*/
|
||||
export interface AuthorshipInfo {
|
||||
/** The id of the {@link Revision} this belongs to. */
|
||||
[FieldNameAuthorshipInfo.revisionUuid]: string;
|
||||
[FieldNameAuthorshipInfo.revisionUuid]: string
|
||||
|
||||
/** The id of the author of the edit. */
|
||||
[FieldNameAuthorshipInfo.authorId]: number;
|
||||
[FieldNameAuthorshipInfo.authorId]: number
|
||||
|
||||
/** The start position of the change in the note as a positive index. */
|
||||
[FieldNameAuthorshipInfo.startPosition]: number;
|
||||
[FieldNameAuthorshipInfo.startPosition]: number
|
||||
|
||||
/** The end position of the change in the note as a positive index. */
|
||||
[FieldNameAuthorshipInfo.endPosition]: number;
|
||||
[FieldNameAuthorshipInfo.endPosition]: number
|
||||
|
||||
/** The timestamp when the authorship entry was created. */
|
||||
[FieldNameAuthorshipInfo.createdAt]: Date;
|
||||
[FieldNameAuthorshipInfo.createdAt]: string
|
||||
}
|
||||
|
||||
export enum FieldNameAuthorshipInfo {
|
||||
|
@ -34,4 +36,12 @@ export enum FieldNameAuthorshipInfo {
|
|||
createdAt = 'created_at',
|
||||
}
|
||||
|
||||
export const TableAuthorshipInfo = 'authorship_info';
|
||||
type TypeAuthorshipInfoDate = Omit<
|
||||
AuthorshipInfo,
|
||||
FieldNameAuthorshipInfo.createdAt
|
||||
> & {
|
||||
[FieldNameAuthorshipInfo.createdAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertAuthorshipInfo = TypeAuthorshipInfoDate
|
||||
export const TableAuthorshipInfo = 'authorship_info'
|
|
@ -9,10 +9,10 @@
|
|||
*/
|
||||
export interface GroupUser {
|
||||
/** The id of the {@link Group} a {@link User} is part of */
|
||||
[FieldNameGroupUser.groupId]: number;
|
||||
[FieldNameGroupUser.groupId]: number
|
||||
|
||||
/** The id of the {@link User} */
|
||||
[FieldNameGroupUser.userId]: number;
|
||||
[FieldNameGroupUser.userId]: number
|
||||
}
|
||||
|
||||
export enum FieldNameGroupUser {
|
||||
|
@ -20,4 +20,4 @@ export enum FieldNameGroupUser {
|
|||
userId = 'user_id',
|
||||
}
|
||||
|
||||
export const TableGroupUser = 'group_user';
|
||||
export const TableGroupUser = 'group_user'
|
|
@ -4,6 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum SpecialGroup {
|
||||
EVERYONE = '_EVERYONE',
|
||||
LOGGED_IN = '_LOGGED_IN',
|
||||
}
|
||||
|
||||
/**
|
||||
* A group represents one or multiple {@link User}s and can be used for permission management.
|
||||
* There are special groups that are created by the system and cannot be deleted, these include the set of all
|
||||
|
@ -11,16 +16,16 @@
|
|||
*/
|
||||
export interface Group {
|
||||
/** The unique id for internal referencing */
|
||||
[FieldNameGroup.id]: number;
|
||||
[FieldNameGroup.id]: number
|
||||
|
||||
/** The public identifier of the group (username for the group) */
|
||||
[FieldNameGroup.name]: string;
|
||||
[FieldNameGroup.name]: string
|
||||
|
||||
/** The display name of the group */
|
||||
[FieldNameGroup.displayName]: string;
|
||||
[FieldNameGroup.displayName]: string
|
||||
|
||||
/** Whether the group is one of the special groups */
|
||||
[FieldNameGroup.isSpecial]: boolean;
|
||||
[FieldNameGroup.isSpecial]: boolean
|
||||
}
|
||||
|
||||
export enum FieldNameGroup {
|
||||
|
@ -30,9 +35,9 @@ export enum FieldNameGroup {
|
|||
isSpecial = 'is_special',
|
||||
}
|
||||
|
||||
export const TableGroup = 'group';
|
||||
export type TypeInsertGroup = Omit<Group, FieldNameGroup.id>;
|
||||
export const TableGroup = 'group'
|
||||
export type TypeInsertGroup = Omit<Group, FieldNameGroup.id>
|
||||
export type TypeUpdateGroup = Pick<
|
||||
Group,
|
||||
FieldNameGroup.name | FieldNameGroup.displayName
|
||||
>;
|
||||
>
|
|
@ -3,32 +3,39 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
|
||||
export enum AuthProviderType {
|
||||
GUEST = 'guest',
|
||||
TOKEN = 'token',
|
||||
LOCAL = 'local',
|
||||
LDAP = 'ldap',
|
||||
OIDC = 'oidc',
|
||||
}
|
||||
|
||||
/**
|
||||
* An auth identity holds the information how a {@link User} can authenticate themselves using a certain auth provider
|
||||
*/
|
||||
export interface Identity {
|
||||
/** The id of the user */
|
||||
[FieldNameIdentity.userId]: number;
|
||||
[FieldNameIdentity.userId]: number
|
||||
|
||||
/** The type of the auth provider */
|
||||
[FieldNameIdentity.providerType]: AuthProviderType;
|
||||
[FieldNameIdentity.providerType]: AuthProviderType
|
||||
|
||||
/** The identifier of the auth provider, e.g. gitlab */
|
||||
[FieldNameIdentity.providerIdentifier]: string | null;
|
||||
[FieldNameIdentity.providerIdentifier]: string | null
|
||||
|
||||
/** Timestamp when this identity was created */
|
||||
[FieldNameIdentity.createdAt]: Date;
|
||||
[FieldNameIdentity.createdAt]: string
|
||||
|
||||
/** Timestamp when this identity was last updated */
|
||||
[FieldNameIdentity.updatedAt]: Date;
|
||||
[FieldNameIdentity.updatedAt]: string
|
||||
|
||||
/** The remote id of the user at the auth provider or null for local identities */
|
||||
[FieldNameIdentity.providerUserId]: string | null;
|
||||
[FieldNameIdentity.providerUserId]: string | null
|
||||
|
||||
/** The hashed password for local identities or null for other auth providers */
|
||||
[FieldNameIdentity.passwordHash]: string | null;
|
||||
[FieldNameIdentity.passwordHash]: string | null
|
||||
}
|
||||
|
||||
export enum FieldNameIdentity {
|
||||
|
@ -41,13 +48,21 @@ export enum FieldNameIdentity {
|
|||
passwordHash = 'password_hash',
|
||||
}
|
||||
|
||||
export const TableIdentity = 'identity';
|
||||
export const TableIdentity = 'identity'
|
||||
|
||||
type TypeIdentityDate = Omit<
|
||||
Identity,
|
||||
FieldNameIdentity.createdAt | FieldNameIdentity.updatedAt
|
||||
> & {
|
||||
[FieldNameIdentity.createdAt]: Date
|
||||
[FieldNameIdentity.updatedAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertIdentity = Omit<
|
||||
Identity,
|
||||
FieldNameIdentity.createdAt | FieldNameIdentity.updatedAt
|
||||
>;
|
||||
>
|
||||
export type TypeUpdateIdentity = Pick<
|
||||
Identity,
|
||||
TypeIdentityDate,
|
||||
FieldNameIdentity.passwordHash | FieldNameIdentity.updatedAt
|
||||
>;
|
||||
>
|
20
database/src/types/index.ts
Normal file
20
database/src/types/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export * from './alias.js'
|
||||
export * from './api-token.js'
|
||||
export * from './authorship-info.js'
|
||||
export * from './group.js'
|
||||
export * from './group-user.js'
|
||||
export * from './identity.js'
|
||||
export * from './media-upload.js'
|
||||
export * from './note.js'
|
||||
export * from './note-group-permission.js'
|
||||
export * from './note-user-permission.js'
|
||||
export * from './revision.js'
|
||||
export * from './revision-tag.js'
|
||||
export * from './user.js'
|
||||
export * from './user-pinned-note.js'
|
|
@ -3,7 +3,14 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { BackendType } from '../../media/backends/backend-type.enum';
|
||||
|
||||
export enum MediaBackendType {
|
||||
FILESYSTEM = 'filesystem',
|
||||
S3 = 's3',
|
||||
IMGUR = 'imgur',
|
||||
AZURE = 'azure',
|
||||
WEBDAV = 'webdav',
|
||||
}
|
||||
|
||||
/**
|
||||
* A media upload object represents an uploaded file. While the file itself is stored in the configured storage backend,
|
||||
|
@ -12,25 +19,25 @@ import { BackendType } from '../../media/backends/backend-type.enum';
|
|||
*/
|
||||
export interface MediaUpload {
|
||||
/** UUID (v7) identifying the media upload. Is public and unique */
|
||||
[FieldNameMediaUpload.uuid]: string;
|
||||
[FieldNameMediaUpload.uuid]: string
|
||||
|
||||
/** The id of the attached {@link Note} or null if the media upload was detached from a note */
|
||||
[FieldNameMediaUpload.noteId]: number | null;
|
||||
[FieldNameMediaUpload.noteId]: number | null
|
||||
|
||||
/** The id of the {@link User} who uploaded the media file */
|
||||
[FieldNameMediaUpload.userId]: number;
|
||||
[FieldNameMediaUpload.userId]: number
|
||||
|
||||
/** The name of the uploaded file */
|
||||
[FieldNameMediaUpload.fileName]: string;
|
||||
[FieldNameMediaUpload.fileName]: string
|
||||
|
||||
/** The backend where this upload is stored */
|
||||
[FieldNameMediaUpload.backendType]: BackendType;
|
||||
[FieldNameMediaUpload.backendType]: MediaBackendType
|
||||
|
||||
/** Additional data required by the backend storage to identify the uploaded file */
|
||||
[FieldNameMediaUpload.backendData]: string | null;
|
||||
[FieldNameMediaUpload.backendData]: string | null
|
||||
|
||||
/** Timestamp when the file was uploaded */
|
||||
[FieldNameMediaUpload.createdAt]: Date;
|
||||
[FieldNameMediaUpload.createdAt]: string
|
||||
}
|
||||
|
||||
export enum FieldNameMediaUpload {
|
||||
|
@ -43,13 +50,17 @@ export enum FieldNameMediaUpload {
|
|||
createdAt = 'created_at',
|
||||
}
|
||||
|
||||
export const TableMediaUpload = 'media_upload';
|
||||
export const TableMediaUpload = 'media_upload'
|
||||
|
||||
type TypeMediaUploadDate = Omit<MediaUpload, FieldNameMediaUpload.createdAt> & {
|
||||
[FieldNameMediaUpload.createdAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertMediaUpload = Omit<
|
||||
MediaUpload,
|
||||
TypeMediaUploadDate,
|
||||
FieldNameMediaUpload.createdAt | FieldNameMediaUpload.uuid
|
||||
>;
|
||||
>
|
||||
export type TypeUpdateMediaUpload = Pick<
|
||||
MediaUpload,
|
||||
TypeMediaUploadDate,
|
||||
FieldNameMediaUpload.noteId
|
||||
>;
|
||||
>
|
|
@ -8,13 +8,13 @@
|
|||
*/
|
||||
export interface NoteGroupPermission {
|
||||
/** The id of the {@link Group} to give the {@link Note} permission to. */
|
||||
[FieldNameNoteGroupPermission.groupId]: number;
|
||||
[FieldNameNoteGroupPermission.groupId]: number
|
||||
|
||||
/** The id of the {@link Note} to give the {@link Group} permission to. */
|
||||
[FieldNameNoteGroupPermission.noteId]: number;
|
||||
[FieldNameNoteGroupPermission.noteId]: number
|
||||
|
||||
/** Whether the {@link Group} can edit the {@link Note} or not. */
|
||||
[FieldNameNoteGroupPermission.canEdit]: boolean;
|
||||
[FieldNameNoteGroupPermission.canEdit]: boolean
|
||||
}
|
||||
|
||||
export enum FieldNameNoteGroupPermission {
|
||||
|
@ -23,9 +23,9 @@ export enum FieldNameNoteGroupPermission {
|
|||
canEdit = 'can_edit',
|
||||
}
|
||||
|
||||
export const TableNoteGroupPermission = 'note_group_permission';
|
||||
export const TableNoteGroupPermission = 'note_group_permission'
|
||||
|
||||
export type TypeUpdateNoteGroupPermission = Pick<
|
||||
NoteGroupPermission,
|
||||
FieldNameNoteGroupPermission.canEdit
|
||||
>;
|
||||
>
|
|
@ -8,13 +8,13 @@
|
|||
*/
|
||||
export interface NoteUserPermission {
|
||||
/** The id of the {@link User} to give the {@link Note} permission to. */
|
||||
[FieldNameNoteUserPermission.userId]: number;
|
||||
[FieldNameNoteUserPermission.userId]: number
|
||||
|
||||
/** The id of the {@link Note} to give the {@link User} permission to. */
|
||||
[FieldNameNoteUserPermission.noteId]: number;
|
||||
[FieldNameNoteUserPermission.noteId]: number
|
||||
|
||||
/** Whether the {@link User} can edit the {@link Note} or not. */
|
||||
[FieldNameNoteUserPermission.canEdit]: boolean;
|
||||
[FieldNameNoteUserPermission.canEdit]: boolean
|
||||
}
|
||||
|
||||
export enum FieldNameNoteUserPermission {
|
||||
|
@ -23,9 +23,9 @@ export enum FieldNameNoteUserPermission {
|
|||
canEdit = 'can_edit',
|
||||
}
|
||||
|
||||
export const TableNoteUserPermission = 'note_user_permission';
|
||||
export const TableNoteUserPermission = 'note_user_permission'
|
||||
|
||||
export type TypeUpdateNoteUserPermission = Pick<
|
||||
NoteUserPermission,
|
||||
FieldNameNoteUserPermission.canEdit
|
||||
>;
|
||||
>
|
|
@ -11,16 +11,16 @@
|
|||
*/
|
||||
export interface Note {
|
||||
/** The unique id of the note for internal referencing */
|
||||
[FieldNameNote.id]: number;
|
||||
[FieldNameNote.id]: number
|
||||
|
||||
/** The {@link User} id of the note owner */
|
||||
[FieldNameNote.ownerId]: number;
|
||||
[FieldNameNote.ownerId]: number
|
||||
|
||||
/** The HedgeDoc major version this note was created in. This is used to migrate certain features from HD1 to HD2 */
|
||||
[FieldNameNote.version]: number;
|
||||
[FieldNameNote.version]: number
|
||||
|
||||
/** Timestamp when the note was created */
|
||||
[FieldNameNote.createdAt]: Date;
|
||||
[FieldNameNote.createdAt]: string
|
||||
}
|
||||
|
||||
export enum FieldNameNote {
|
||||
|
@ -30,10 +30,14 @@ export enum FieldNameNote {
|
|||
createdAt = 'created_at',
|
||||
}
|
||||
|
||||
export const TableNote = 'note';
|
||||
export const TableNote = 'note'
|
||||
|
||||
type TypeNoteDate = Omit<Note, FieldNameNote.createdAt> & {
|
||||
[FieldNameNote.createdAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertNote = Omit<
|
||||
Note,
|
||||
TypeNoteDate,
|
||||
FieldNameNote.createdAt | FieldNameNote.id
|
||||
>;
|
||||
export type TypeUpdateNote = Pick<Note, FieldNameNote.ownerId>;
|
||||
>
|
||||
export type TypeUpdateNote = Pick<TypeNoteDate, FieldNameNote.ownerId>
|
|
@ -8,10 +8,10 @@
|
|||
*/
|
||||
export interface RevisionTag {
|
||||
/** The id of {@link Revision} the {@link RevisionTag Tags} are asspcoated with. */
|
||||
[FieldNameRevisionTag.revisionUuid]: string;
|
||||
[FieldNameRevisionTag.revisionUuid]: string
|
||||
|
||||
/** The {@link RevisionTag Tag} text. */
|
||||
[FieldNameRevisionTag.tag]: string;
|
||||
[FieldNameRevisionTag.tag]: string
|
||||
}
|
||||
|
||||
export enum FieldNameRevisionTag {
|
||||
|
@ -19,4 +19,4 @@ export enum FieldNameRevisionTag {
|
|||
tag = 'tag',
|
||||
}
|
||||
|
||||
export const TableRevisionTag = 'revision_tag';
|
||||
export const TableRevisionTag = 'revision_tag'
|
|
@ -3,38 +3,42 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { NoteType } from '@hedgedoc/commons';
|
||||
|
||||
export enum NoteType {
|
||||
DOCUMENT = 'document',
|
||||
SLIDE = 'slide',
|
||||
}
|
||||
|
||||
/**
|
||||
* A revision represents the content of a {@link Note} at a specific point in time.
|
||||
*/
|
||||
export interface Revision {
|
||||
/** The unique id of the revision for internal referencing */
|
||||
[FieldNameRevision.uuid]: string;
|
||||
[FieldNameRevision.uuid]: string
|
||||
|
||||
/** The id of the note that this revision belongs to */
|
||||
[FieldNameRevision.noteId]: number;
|
||||
[FieldNameRevision.noteId]: number
|
||||
|
||||
/** The changes between this revision and the previous one in patch file format */
|
||||
[FieldNameRevision.patch]: string;
|
||||
[FieldNameRevision.patch]: string
|
||||
|
||||
/** The content of the note at this revision */
|
||||
[FieldNameRevision.content]: string;
|
||||
[FieldNameRevision.content]: string
|
||||
|
||||
/** The stored Y.js state for realtime editing */
|
||||
[FieldNameRevision.yjsStateVector]: null | ArrayBuffer;
|
||||
[FieldNameRevision.yjsStateVector]: null | ArrayBuffer
|
||||
|
||||
/** Whether the note is a document or presentation at this revision */
|
||||
[FieldNameRevision.noteType]: NoteType;
|
||||
[FieldNameRevision.noteType]: NoteType
|
||||
|
||||
/** The extracted note title from this revision */
|
||||
[FieldNameRevision.title]: string;
|
||||
[FieldNameRevision.title]: string
|
||||
|
||||
/** The extracted description from this revision */
|
||||
[FieldNameRevision.description]: string;
|
||||
[FieldNameRevision.description]: string
|
||||
|
||||
/** Timestamp when this revision was created */
|
||||
[FieldNameRevision.createdAt]: Date;
|
||||
[FieldNameRevision.createdAt]: string
|
||||
}
|
||||
|
||||
export enum FieldNameRevision {
|
||||
|
@ -49,6 +53,13 @@ export enum FieldNameRevision {
|
|||
createdAt = 'created_at',
|
||||
}
|
||||
|
||||
export const TableRevision = 'revision';
|
||||
export const TableRevision = 'revision'
|
||||
|
||||
export type TypeInsertRevision = Omit<Revision, FieldNameRevision.createdAt>;
|
||||
type TypeRevisionDate = Omit<Revision, FieldNameRevision.createdAt> & {
|
||||
[FieldNameRevision.createdAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertRevision = Omit<
|
||||
TypeRevisionDate,
|
||||
FieldNameRevision.createdAt
|
||||
>
|
|
@ -10,10 +10,10 @@
|
|||
*/
|
||||
export interface UserPinnedNote {
|
||||
/** The id of the {@link User} */
|
||||
user_id: number;
|
||||
user_id: number
|
||||
|
||||
/** The id of the {@link Note} */
|
||||
note_id: number;
|
||||
note_id: number
|
||||
}
|
||||
|
||||
export enum FieldNameUserPinnedNote {
|
||||
|
@ -21,4 +21,4 @@ export enum FieldNameUserPinnedNote {
|
|||
noteId = 'note_id',
|
||||
}
|
||||
|
||||
export const TableUserPinnedNote = 'user_pinned_note';
|
||||
export const TableUserPinnedNote = 'user_pinned_note'
|
|
@ -17,28 +17,28 @@
|
|||
*/
|
||||
export interface User {
|
||||
/** The unique id of the user for internal referencing */
|
||||
[FieldNameUser.id]: number;
|
||||
[FieldNameUser.id]: number
|
||||
|
||||
/** The user's chosen username or null if it is a guest user */
|
||||
[FieldNameUser.username]: string | null;
|
||||
[FieldNameUser.username]: string | null
|
||||
|
||||
/** The guest user's UUID or null if it is a registered user */
|
||||
[FieldNameUser.guestUuid]: string | null;
|
||||
[FieldNameUser.guestUuid]: string | null
|
||||
|
||||
/** The user's chosen display name */
|
||||
[FieldNameUser.displayName]: string;
|
||||
[FieldNameUser.displayName]: string
|
||||
|
||||
/** Timestamp when the user was created */
|
||||
[FieldNameUser.createdAt]: Date;
|
||||
[FieldNameUser.createdAt]: string
|
||||
|
||||
/** URL to the user's profile picture if present */
|
||||
[FieldNameUser.photoUrl]: string | null;
|
||||
[FieldNameUser.photoUrl]: string | null
|
||||
|
||||
/** The user's email address if present */
|
||||
[FieldNameUser.email]: string | null;
|
||||
[FieldNameUser.email]: string | null
|
||||
|
||||
/** The index which author style (e.g. color) should be used for this user */
|
||||
[FieldNameUser.authorStyle]: number;
|
||||
[FieldNameUser.authorStyle]: number
|
||||
}
|
||||
|
||||
export const enum FieldNameUser {
|
||||
|
@ -52,16 +52,20 @@ export const enum FieldNameUser {
|
|||
authorStyle = 'author_style',
|
||||
}
|
||||
|
||||
export const TableUser = 'user';
|
||||
export const TableUser = 'user'
|
||||
|
||||
type TypeUserDate = Omit<User, FieldNameUser.createdAt> & {
|
||||
[FieldNameUser.createdAt]: Date
|
||||
}
|
||||
|
||||
export type TypeInsertUser = Omit<
|
||||
User,
|
||||
TypeUserDate,
|
||||
FieldNameUser.id | FieldNameUser.createdAt
|
||||
>;
|
||||
>
|
||||
export type TypeUpdateUser = Pick<
|
||||
User,
|
||||
| FieldNameUser.displayName
|
||||
| FieldNameUser.photoUrl
|
||||
| FieldNameUser.email
|
||||
| FieldNameUser.authorStyle
|
||||
>;
|
||||
>
|
21
database/tsconfig.base.json
Normal file
21
database/tsconfig.base.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"lib": [
|
||||
"es2022",
|
||||
"dom"
|
||||
],
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"declarationMap":true,
|
||||
"sourceMap": true,
|
||||
"typeRoots": ["./types"]
|
||||
},
|
||||
"include": ["./src", "./types"],
|
||||
"exclude": ["./dist", "**/*.test.ts"]
|
||||
}
|
3
database/tsconfig.base.json.license
Normal file
3
database/tsconfig.base.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2023 Tilman Vatteroth
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
10
database/tsconfig.cjs.json
Normal file
10
database/tsconfig.cjs.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends" : "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"target": "ES2015",
|
||||
"outDir": "dist/cjs",
|
||||
"declarationDir": "dist/cjs",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
}
|
3
database/tsconfig.cjs.json.license
Normal file
3
database/tsconfig.cjs.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2023 Tilman Vatteroth
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
4
database/tsconfig.test.json
Normal file
4
database/tsconfig.test.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends" : "./tsconfig.esm.json",
|
||||
"exclude": ["./dist"]
|
||||
}
|
3
database/tsconfig.test.json.license
Normal file
3
database/tsconfig.test.json.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2023 Tilman Vatteroth
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
|
@ -6,6 +6,7 @@
|
|||
"backend",
|
||||
"frontend",
|
||||
"commons",
|
||||
"database",
|
||||
"dev-reverse-proxy",
|
||||
"docs",
|
||||
"html-to-react",
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
"dist/**"
|
||||
]
|
||||
},
|
||||
"@hedgedoc/database#build": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
"dist/**"
|
||||
]
|
||||
},
|
||||
"@hedgedoc/markdown-it-plugins#build": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -2824,6 +2824,21 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@hedgedoc/database@workspace:database":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@hedgedoc/database@workspace:database"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.14.0"
|
||||
"@typescript-eslint/parser": "npm:8.14.0"
|
||||
eslint: "npm:8.57.1"
|
||||
eslint-config-prettier: "npm:9.1.0"
|
||||
eslint-plugin-jest: "npm:28.9.0"
|
||||
eslint-plugin-prettier: "npm:5.2.3"
|
||||
prettier: "npm:3.3.3"
|
||||
typescript: "npm:5.6.3"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@hedgedoc/dev-reverse-proxy@workspace:dev-reverse-proxy":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@hedgedoc/dev-reverse-proxy@workspace:dev-reverse-proxy"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue