mirror of
https://github.com/standardnotes/server
synced 2026-02-16 05:02:12 -05:00
Compare commits
12 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dea171115 | ||
|
|
aef9254713 | ||
|
|
31b7396006 | ||
|
|
be0a2649da | ||
|
|
bf8f91f83d | ||
|
|
effdfebc19 | ||
|
|
f4816e6c9a | ||
|
|
152a5cbd27 | ||
|
|
1488763115 | ||
|
|
bbb35d16fc | ||
|
|
ef07045ee9 | ||
|
|
3ba673b424 |
24
.github/workflows/common-e2e.yml
vendored
24
.github/workflows/common-e2e.yml
vendored
@@ -19,7 +19,7 @@ on:
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
name: (Docker) E2E Test Suite
|
||||
name: (Self Hosting) E2E Test Suite
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -56,17 +56,8 @@ jobs:
|
||||
- name: Wait for server to start
|
||||
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
||||
|
||||
- name: Define if vault tests are enabled
|
||||
id: vaults
|
||||
run: |
|
||||
if [ "${{ matrix.secondary_db_enabled }}" = "true" ] && [ "${{ matrix.transition_mode_enabled }}" = "true" ]; then
|
||||
echo "vault-tests=enabled" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "vault-tests=disabled" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Run E2E Test Suite
|
||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html?vaults=${{ steps.vaults.outputs.vault-tests }}
|
||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html?vaults=enabled
|
||||
|
||||
- name: Show logs on failure
|
||||
if: ${{ failure() }}
|
||||
@@ -170,17 +161,8 @@ jobs:
|
||||
- name: Wait for server to start
|
||||
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
|
||||
|
||||
- name: Define if vault tests are enabled
|
||||
id: vaults
|
||||
run: |
|
||||
if [ "${{ matrix.secondary_db_enabled }}" = "true" ] && [ "${{ matrix.transition_mode_enabled }}" = "true" ]; then
|
||||
echo "vault-tests=enabled" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "vault-tests=disabled" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Run E2E Test Suite
|
||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html?vaults=${{ steps.vaults.outputs.vault-tests }}
|
||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html?vaults=enabled
|
||||
|
||||
- name: Show logs on failure
|
||||
if: ${{ failure() }}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
# Setup environment variables
|
||||
|
||||
export MODE="self-hosted"
|
||||
|
||||
#########
|
||||
# PORTS #
|
||||
#########
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODE=microservice # microservice | home-server
|
||||
MODE=microservice # microservice | home-server | self-hosted
|
||||
LOG_LEVEL=debug
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.72.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.72.0...@standardnotes/api-gateway@1.72.1) (2023-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow self hosted to use new model of items ([#714](https://github.com/standardnotes/api-gateway/issues/714)) ([aef9254](https://github.com/standardnotes/api-gateway/commit/aef9254713560c00a90a3e84e3cd94417e8f30d2))
|
||||
|
||||
# [1.72.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.71.1...@standardnotes/api-gateway@1.72.0) (2023-08-24)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.72.0",
|
||||
"version": "1.72.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODE=microservice # microservice | home-server
|
||||
MODE=microservice # microservice | home-server | self-hosted
|
||||
LOG_LEVEL=debug
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.135.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.135.1...@standardnotes/auth-server@1.135.2) (2023-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow self hosted to use new model of items ([#714](https://github.com/standardnotes/server/issues/714)) ([aef9254](https://github.com/standardnotes/server/commit/aef9254713560c00a90a3e84e3cd94417e8f30d2))
|
||||
|
||||
## [1.135.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.135.0...@standardnotes/auth-server@1.135.1) (2023-08-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** account enumeration with pseudo u2f and mfa ([#709](https://github.com/standardnotes/server/issues/709)) ([bbb35d1](https://github.com/standardnotes/server/commit/bbb35d16fc4f6a57fe774a648fbda13ec64a8865))
|
||||
|
||||
# [1.135.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.134.0...@standardnotes/auth-server@1.135.0) (2023-08-24)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.135.0",
|
||||
"version": "1.135.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -257,7 +257,7 @@ describe('VerifyMFA', () => {
|
||||
})
|
||||
|
||||
it('should not pass if user is not found and pseudo u2f is required', async () => {
|
||||
booleanSelector.select = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)
|
||||
booleanSelector.select = jest.fn().mockReturnValueOnce(true).mockReturnValueOnce(true)
|
||||
userRepository.findOneByUsernameOrEmail = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(
|
||||
|
||||
@@ -48,33 +48,33 @@ export class VerifyMFA implements UseCaseInterface {
|
||||
|
||||
const user = await this.userRepository.findOneByUsernameOrEmail(username)
|
||||
if (user == null) {
|
||||
const mfaSelectorHash = crypto
|
||||
const secondFactorSelectorHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(`mfa-selector-${dto.email}${this.pseudoKeyParamsKey}`)
|
||||
.digest('hex')
|
||||
const u2fSelectorHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(`u2f-selector-${dto.email}${this.pseudoKeyParamsKey}`)
|
||||
.update(`second-factor-selector-${dto.email}${this.pseudoKeyParamsKey}`)
|
||||
.digest('hex')
|
||||
|
||||
const isPseudoMFARequired = this.booleanSelector.select(mfaSelectorHash, [true, false])
|
||||
const isPseudoSecondFactorRequired = this.booleanSelector.select(secondFactorSelectorHash, [true, false])
|
||||
if (isPseudoSecondFactorRequired) {
|
||||
const u2fSelectorHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(`u2f-selector-${dto.email}${this.pseudoKeyParamsKey}`)
|
||||
.digest('hex')
|
||||
|
||||
const isPseudoU2FRequired = this.booleanSelector.select(u2fSelectorHash, [true, false])
|
||||
const isPseudoU2FRequired = this.booleanSelector.select(u2fSelectorHash, [true, false])
|
||||
|
||||
if (isPseudoMFARequired) {
|
||||
return {
|
||||
success: false,
|
||||
errorTag: ErrorTag.MfaRequired,
|
||||
errorMessage: 'Please enter your two-factor authentication code.',
|
||||
errorPayload: { mfa_key: `mfa_${uuidv4()}` },
|
||||
}
|
||||
}
|
||||
|
||||
if (isPseudoU2FRequired) {
|
||||
return {
|
||||
success: false,
|
||||
errorTag: ErrorTag.U2FRequired,
|
||||
errorMessage: 'Please authenticate with your U2F device.',
|
||||
if (isPseudoU2FRequired) {
|
||||
return {
|
||||
success: false,
|
||||
errorTag: ErrorTag.U2FRequired,
|
||||
errorMessage: 'Please authenticate with your U2F device.',
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
errorTag: ErrorTag.MfaRequired,
|
||||
errorMessage: 'Please enter your two-factor authentication code.',
|
||||
errorPayload: { mfa_key: `mfa_${uuidv4()}` },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODE=microservice # microservice | home-server
|
||||
MODE=microservice # microservice | home-server | self-hosted
|
||||
LOG_LEVEL=debug
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.1...@standardnotes/files-server@1.22.2) (2023-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow self hosted to use new model of items ([#714](https://github.com/standardnotes/files/issues/714)) ([aef9254](https://github.com/standardnotes/files/commit/aef9254713560c00a90a3e84e3cd94417e8f30d2))
|
||||
|
||||
## [1.22.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.0...@standardnotes/files-server@1.22.1) (2023-08-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.22.1",
|
||||
"version": "1.22.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.15.5](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.4...@standardnotes/home-server@1.15.5) (2023-08-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.4](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.3...@standardnotes/home-server@1.15.4) (2023-08-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.3](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.2...@standardnotes/home-server@1.15.3) (2023-08-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.2](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.1...@standardnotes/home-server@1.15.2) (2023-08-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.1](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.0...@standardnotes/home-server@1.15.1) (2023-08-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.15.1",
|
||||
"version": "1.15.5",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODE=microservice # microservice | home-server
|
||||
MODE=microservice # microservice | home-server | self-hosted
|
||||
LOG_LEVEL=info
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.12](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.26.11...@standardnotes/revisions-server@1.26.12) (2023-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow self hosted to use new model of items ([#714](https://github.com/standardnotes/server/issues/714)) ([aef9254](https://github.com/standardnotes/server/commit/aef9254713560c00a90a3e84e3cd94417e8f30d2))
|
||||
|
||||
## [1.26.11](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.26.10...@standardnotes/revisions-server@1.26.11) (2023-08-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.26.11",
|
||||
"version": "1.26.12",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODE=microservice # microservice | home-server
|
||||
MODE=microservice # microservice | home-server | self-hosted
|
||||
LOG_LEVEL=info
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.85.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.85.0...@standardnotes/syncing-server@1.85.1) (2023-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow self hosted to use new model of items ([#714](https://github.com/standardnotes/syncing-server-js/issues/714)) ([aef9254](https://github.com/standardnotes/syncing-server-js/commit/aef9254713560c00a90a3e84e3cd94417e8f30d2))
|
||||
|
||||
# [1.85.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.84.2...@standardnotes/syncing-server@1.85.0) (2023-08-28)
|
||||
|
||||
### Features
|
||||
|
||||
* **syncing-server:** distinguish between legacy and current items model usage ([#712](https://github.com/standardnotes/syncing-server-js/issues/712)) ([bf8f91f](https://github.com/standardnotes/syncing-server-js/commit/bf8f91f83d9d206ebfbcd9b2c9318786bd0040da))
|
||||
* **syncing-server:** turn mysql items model into legacy ([#711](https://github.com/standardnotes/syncing-server-js/issues/711)) ([effdfeb](https://github.com/standardnotes/syncing-server-js/commit/effdfebc193c66d830bb4d516d408a9c126f3d62))
|
||||
|
||||
## [1.84.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.84.1...@standardnotes/syncing-server@1.84.2) (2023-08-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** items sorting in MongoDB ([#710](https://github.com/standardnotes/syncing-server-js/issues/710)) ([152a5cb](https://github.com/standardnotes/syncing-server-js/commit/152a5cbd27375adbad8b070d1778b256a6dce1f4))
|
||||
* **syncing-server:** logs severity on creating duplicates ([1488763](https://github.com/standardnotes/syncing-server-js/commit/14887631153b78117ec7433353bb32709209a617))
|
||||
|
||||
## [1.84.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.84.0...@standardnotes/syncing-server@1.84.1) (2023-08-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** handling mixed values of deleted flag in MongoDB ([#708](https://github.com/standardnotes/syncing-server-js/issues/708)) ([3ba673b](https://github.com/standardnotes/syncing-server-js/commit/3ba673b424ae3bb6b64b2360323d7373636c6cd5))
|
||||
|
||||
# [1.84.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.83.0...@standardnotes/syncing-server@1.84.0) (2023-08-24)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class initDatabase1606470249552 implements MigrationInterface {
|
||||
name = 'initDatabase1606470249552'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await this.fixUpdatedAtTimestampsFromLegacyMigration(queryRunner)
|
||||
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `items` (`uuid` varchar(36) NOT NULL, `duplicate_of` varchar(36) NULL, `items_key_id` varchar(255) NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `user_uuid` varchar(36) NULL, `deleted` tinyint(1) NULL DEFAULT 0, `last_user_agent` text NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `created_at_timestamp` BIGINT NOT NULL, `updated_at_timestamp` BIGINT NOT NULL, INDEX `index_items_on_content_type` (`content_type`), INDEX `index_items_on_user_uuid` (`user_uuid`), INDEX `index_items_on_deleted` (`deleted`), INDEX `updated_at_timestamp` (`updated_at_timestamp`), INDEX `index_items_on_updated_at` (`updated_at`), INDEX `user_uuid_and_updated_at_timestamp_and_created_at_timestamp` (`user_uuid`, `updated_at_timestamp`, `created_at_timestamp`), INDEX `index_items_on_user_uuid_and_updated_at_and_created_at` (`user_uuid`, `updated_at`, `created_at`), INDEX `index_items_on_user_uuid_and_content_type` (`user_uuid`, `content_type`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `items_key_id` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `creation_date` date NULL, `created_at` datetime(6) NULL, `updated_at` datetime(6) NULL, INDEX `index_revisions_on_item_uuid` (`item_uuid`), INDEX `index_revisions_on_creation_date` (`creation_date`), INDEX `index_revisions_on_created_at` (`created_at`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `item_revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `revision_uuid` varchar(36) NOT NULL, INDEX `index_item_revisions_on_item_uuid` (`item_uuid`), INDEX `index_item_revisions_on_revision_uuid` (`revision_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(_queryRunner: QueryRunner): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
private async fixUpdatedAtTimestampsFromLegacyMigration(queryRunner: QueryRunner): Promise<void> {
|
||||
const itemsTableExistsQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "items"',
|
||||
)
|
||||
const itemsTableExists = itemsTableExistsQueryResult[0].count === 1
|
||||
if (!itemsTableExists) {
|
||||
return
|
||||
}
|
||||
|
||||
const updatedAtTimestampColumnExistsQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = "items" AND column_name = "updated_at_timestamp"',
|
||||
)
|
||||
const updatedAtTimestampColumnExists = updatedAtTimestampColumnExistsQueryResult[0].count === 1
|
||||
if (updatedAtTimestampColumnExists) {
|
||||
return
|
||||
}
|
||||
|
||||
await queryRunner.query('ALTER TABLE `items` ADD COLUMN `updated_at_timestamp` BIGINT NOT NULL')
|
||||
await queryRunner.query('ALTER TABLE `items` ADD COLUMN `created_at_timestamp` BIGINT NOT NULL')
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `items` ADD INDEX `user_uuid_and_updated_at_timestamp_and_created_at_timestamp` (`user_uuid`, `updated_at_timestamp`, `created_at_timestamp`)',
|
||||
)
|
||||
await queryRunner.query('ALTER TABLE `items` ADD INDEX `updated_at_timestamp` (`updated_at_timestamp`)')
|
||||
await queryRunner.query('UPDATE `items` SET `created_at_timestamp` = UNIX_TIMESTAMP(`created_at`) * 1000000')
|
||||
await queryRunner.query('UPDATE `items` SET `updated_at_timestamp` = UNIX_TIMESTAMP(`updated_at`) * 1000000')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addExtensionSettings1617615657558 implements MigrationInterface {
|
||||
name = 'addExtensionSettings1617615657558'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `extension_settings` (`uuid` varchar(36) NOT NULL, `extension_id` varchar(255) NULL, `mute_emails` tinyint(1) NULL DEFAULT 0, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX `index_extension_settings_on_extension_id` (`extension_id`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(_queryRunner: QueryRunner): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class dropUnusedIndexes1629964808297 implements MigrationInterface {
|
||||
name = 'dropUnusedIndexes1629964808297'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const indexItemsOnUserAndTimestamp = await queryRunner.manager.query(
|
||||
'SHOW INDEX FROM `items` where `key_name` = "index_items_on_user_uuid_and_updated_at_and_created_at"',
|
||||
)
|
||||
const indexItemsOnUserAndTimestampExists = indexItemsOnUserAndTimestamp && indexItemsOnUserAndTimestamp.length > 0
|
||||
if (indexItemsOnUserAndTimestampExists) {
|
||||
await queryRunner.query('ALTER TABLE `items` DROP INDEX index_items_on_user_uuid_and_updated_at_and_created_at')
|
||||
}
|
||||
|
||||
const indexItemsOnUpdatedAt = await queryRunner.manager.query(
|
||||
'SHOW INDEX FROM `items` where `key_name` = "index_items_on_updated_at"',
|
||||
)
|
||||
const indexItemsOnUpdatedAtExists = indexItemsOnUpdatedAt && indexItemsOnUpdatedAt.length > 0
|
||||
if (indexItemsOnUpdatedAtExists) {
|
||||
await queryRunner.query('ALTER TABLE `items` DROP INDEX index_items_on_updated_at')
|
||||
}
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class refactorCalculatingIntegrityHash1630318893601 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` ADD INDEX `user_uuid_and_deleted` (`user_uuid`, `deleted`)')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class restrictContentType1630417724617 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('UPDATE `items` SET content_type = "Unknown" WHERE `content_type` IS NULL')
|
||||
await queryRunner.query('ALTER TABLE `items` CHANGE `content_type` `content_type` varchar(255) NOT NULL')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
export class addRevisionForDuplicatedItems1631529502150 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const itemRevisions = await queryRunner.manager.query(
|
||||
'SELECT r.uuid as originalRevisionUuid, ir.item_uuid as properItemUuid, ir.uuid as relationUuid FROM revisions r INNER JOIN item_revisions ir ON ir.revision_uuid = r.uuid AND ir.item_uuid <> r.item_uuid',
|
||||
)
|
||||
|
||||
for (const itemRevision of itemRevisions) {
|
||||
const revisionUuid = v4()
|
||||
|
||||
await queryRunner.manager.query(
|
||||
`INSERT INTO revisions (uuid, item_uuid, content, content_type, items_key_id, enc_item_key, auth_hash, creation_date, created_at, updated_at) SELECT "${revisionUuid}", "${itemRevision['properItemUuid']}", content, content_type, items_key_id, enc_item_key, auth_hash, creation_date, created_at, updated_at FROM revisions WHERE uuid = "${itemRevision['originalRevisionUuid']}"`,
|
||||
)
|
||||
await queryRunner.manager.query(
|
||||
`UPDATE item_revisions SET revision_uuid = "${revisionUuid}" WHERE uuid = "${itemRevision['relationUuid']}"`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class dropItemRevisionsJoiningTable1631530260504 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP TABLE `item_revisions`')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `item_revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `revision_uuid` varchar(36) NOT NULL, INDEX `index_item_revisions_on_item_uuid` (`item_uuid`), INDEX `index_item_revisions_on_revision_uuid` (`revision_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class cleanupOrphanItemsAndRevisions1632219307742 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const usersTableExistsQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "users"',
|
||||
)
|
||||
const usersTableExists = usersTableExistsQueryResult[0].count === 1
|
||||
if (usersTableExists) {
|
||||
const orphanedItems = await queryRunner.manager.query(
|
||||
'SELECT i.uuid as uuid FROM items i LEFT JOIN users u ON i.user_uuid = u.uuid WHERE u.uuid IS NULL',
|
||||
)
|
||||
|
||||
for (const orphanedItem of orphanedItems) {
|
||||
await queryRunner.manager.query(`DELETE FROM revisions WHERE item_uuid = "${orphanedItem['uuid']}"`)
|
||||
await queryRunner.manager.query(`DELETE FROM items WHERE uuid = "${orphanedItem['uuid']}"`)
|
||||
}
|
||||
}
|
||||
|
||||
await queryRunner.manager.query('DELETE FROM items WHERE user_uuid IS NULL')
|
||||
|
||||
const orphanedRevisions = await queryRunner.manager.query(
|
||||
'SELECT r.uuid as uuid FROM revisions r LEFT JOIN items i ON r.item_uuid = i.uuid WHERE i.uuid IS NULL',
|
||||
)
|
||||
|
||||
for (const orphanedRevision of orphanedRevisions) {
|
||||
await queryRunner.manager.query(`DELETE FROM revisions WHERE uuid = "${orphanedRevision['uuid']}"`)
|
||||
}
|
||||
|
||||
await queryRunner.manager.query('DELETE FROM revisions WHERE item_uuid IS NULL')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addRevisionsItemsRelation1632221263106 implements MigrationInterface {
|
||||
name = 'addRevisionsItemsRelation1632221263106'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const indexRevisionsOnItemUuid = await queryRunner.manager.query(
|
||||
'SHOW INDEX FROM `revisions` where `key_name` = "index_revisions_on_item_uuid"',
|
||||
)
|
||||
const indexRevisionsOnItemUuidExists = indexRevisionsOnItemUuid && indexRevisionsOnItemUuid.length > 0
|
||||
if (indexRevisionsOnItemUuidExists) {
|
||||
await queryRunner.query('DROP INDEX `index_revisions_on_item_uuid` ON `revisions`')
|
||||
}
|
||||
|
||||
await queryRunner.query('ALTER TABLE `revisions` CHANGE `item_uuid` `item_uuid` varchar(36) NOT NULL')
|
||||
await queryRunner.query('ALTER TABLE `items` CHANGE `user_uuid` `user_uuid` varchar(36) NOT NULL')
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `revisions` ADD CONSTRAINT `FK_ab3b92e54701fe3010022a31d90` FOREIGN KEY (`item_uuid`) REFERENCES `items`(`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `revisions` DROP FOREIGN KEY `FK_ab3b92e54701fe3010022a31d90`')
|
||||
await queryRunner.query('ALTER TABLE `items` CHANGE `user_uuid` `user_uuid` varchar(36) NULL')
|
||||
await queryRunner.query('ALTER TABLE `revisions` CHANGE `item_uuid` `item_uuid` varchar(36) NULL')
|
||||
await queryRunner.query('CREATE INDEX `index_revisions_on_item_uuid` ON `revisions` (`item_uuid`)')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addItemContentSize1637738491169 implements MigrationInterface {
|
||||
name = 'addItemContentSize1637738491169'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` ADD `content_size` INT UNSIGNED NULL')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `content_size`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class removeExtensionSettings1639134926025 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP TABLE `extension_settings`')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class removeSfExtensionItems1642073387521 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.manager.query('DELETE FROM items WHERE content_type = "SF|Extension"')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class removeUserAgent1647501696205 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `last_user_agent`')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addUpdatedWithSession1654518291191 implements MigrationInterface {
|
||||
name = 'addUpdatedWithSession1654518291191'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` ADD `updated_with_session` varchar(36) NULL')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `updated_with_session`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddNotifications1689671563304 implements MigrationInterface {
|
||||
name = 'AddNotifications1689671563304'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
|
||||
await queryRunner.query('DROP TABLE `notifications`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultAndKeySystemAssociations1689671563305 implements MigrationInterface {
|
||||
name = 'AddSharedVaultAndKeySystemAssociations1689671563305'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `shared_vault_associations` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `last_edited_by` varchar(36) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_associations` (`shared_vault_uuid`), INDEX `item_uuid_on_shared_vault_associations` (`item_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `key_system_associations` (`uuid` varchar(36) NOT NULL, `key_system_uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `key_system_uuid_on_key_system_associations` (`key_system_uuid`), INDEX `item_uuid_on_key_system_associations` (`item_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `item_uuid_on_key_system_associations` ON `key_system_associations`')
|
||||
await queryRunner.query('DROP INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations`')
|
||||
await queryRunner.query('DROP TABLE `key_system_associations`')
|
||||
await queryRunner.query('DROP INDEX `item_uuid_on_shared_vault_associations` ON `shared_vault_associations`')
|
||||
await queryRunner.query(
|
||||
'DROP INDEX `shared_vault_uuid_on_shared_vault_associations` ON `shared_vault_associations`',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE `shared_vault_associations`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultsWithUsersAndInvites1689677728282 implements MigrationInterface {
|
||||
name = 'AddSharedVaultsWithUsersAndInvites1689677728282'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `shared_vaults` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `file_upload_bytes_used` int NOT NULL, `file_upload_bytes_limit` int NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `user_uuid_on_shared_vaults` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `shared_vault_users` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_users` (`shared_vault_uuid`), INDEX `user_uuid_on_shared_vault_users` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `shared_vault_invites` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `sender_uuid` varchar(36) NOT NULL, `encrypted_message` text NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_invites` (`shared_vault_uuid`), INDEX `user_uuid_on_shared_vault_invites` (`user_uuid`), INDEX `sender_uuid_on_shared_vault_invites` (`sender_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `sender_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
|
||||
await queryRunner.query('DROP INDEX `user_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
|
||||
await queryRunner.query('DROP INDEX `shared_vault_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
|
||||
await queryRunner.query('DROP TABLE `shared_vault_invites`')
|
||||
await queryRunner.query('DROP INDEX `user_uuid_on_shared_vault_users` ON `shared_vault_users`')
|
||||
await queryRunner.query('DROP INDEX `shared_vault_uuid_on_shared_vault_users` ON `shared_vault_users`')
|
||||
await queryRunner.query('DROP TABLE `shared_vault_users`')
|
||||
await queryRunner.query('DROP INDEX `user_uuid_on_shared_vaults` ON `shared_vaults`')
|
||||
await queryRunner.query('DROP TABLE `shared_vaults`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddMessages1689745128577 implements MigrationInterface {
|
||||
name = 'AddMessages1689745128577'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `messages` (`uuid` varchar(36) NOT NULL, `recipient_uuid` varchar(36) NOT NULL, `sender_uuid` varchar(36) NOT NULL, `encrypted_message` text NOT NULL, `replaceability_identifier` varchar(255) NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `recipient_uuid_on_messages` (`recipient_uuid`), INDEX `sender_uuid_on_messages` (`sender_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `sender_uuid_on_messages` ON `messages`')
|
||||
await queryRunner.query('DROP INDEX `recipient_uuid_on_messages` ON `messages`')
|
||||
await queryRunner.query('DROP TABLE `messages`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class RenameKeyMessageIdentifier1689746180559 implements MigrationInterface {
|
||||
name = 'RenameKeyMessageIdentifier1689746180559'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations`')
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `key_system_associations` CHANGE `key_system_uuid` `key_system_identifier` varchar(36) NOT NULL',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations` (`key_system_identifier`)',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'DROP INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations`',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `key_system_associations` CHANGE `key_system_identifier` `key_system_uuid` varchar(36) NOT NULL',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations` (`key_system_uuid`)',
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class DeletePrivileges1690900526061 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const itemsWithPrivilegesContentTypeQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM items i WHERE i.content_type = "SN|Privileges"',
|
||||
)
|
||||
const itemsWithPrivilegesContentTypeCount = +itemsWithPrivilegesContentTypeQueryResult[0].count
|
||||
|
||||
const batchSize = 1_000
|
||||
const batchCount = Math.ceil(itemsWithPrivilegesContentTypeCount / batchSize)
|
||||
|
||||
for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {
|
||||
await queryRunner.startTransaction()
|
||||
await queryRunner.manager.query(`DELETE FROM items WHERE content_type = "SN|Privileges" LIMIT ${batchSize}`)
|
||||
await queryRunner.commitTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class UpdateUnknownContent1690975361562 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.manager.query('UPDATE items SET content_type = "Note" WHERE content_type = "Unknown"')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class RemoveRevisionsForeignKey1692176803410 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const revisionsTableExistsQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "revisions"',
|
||||
)
|
||||
const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
|
||||
if (revisionsTableExists) {
|
||||
try {
|
||||
await queryRunner.query('ALTER TABLE `revisions` DROP FOREIGN KEY `FK_ab3b92e54701fe3010022a31d90`')
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Error dropping foreign key: ', (error as Error).message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class RemoveAssociations1692264556858 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'DROP INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations`',
|
||||
)
|
||||
await queryRunner.query('DROP INDEX `item_uuid_on_key_system_associations` ON `key_system_associations`')
|
||||
await queryRunner.query('DROP TABLE `key_system_associations`')
|
||||
|
||||
await queryRunner.query('DROP INDEX `item_uuid_on_shared_vault_associations` ON `shared_vault_associations`')
|
||||
await queryRunner.query(
|
||||
'DROP INDEX `shared_vault_uuid_on_shared_vault_associations` ON `shared_vault_associations`',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE `shared_vault_associations`')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class RemoveSharedVaultLimit1692619430384 implements MigrationInterface {
|
||||
name = 'RemoveSharedVaultLimit1692619430384'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `shared_vaults` DROP COLUMN `file_upload_bytes_limit`')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `shared_vaults` ADD `file_upload_bytes_limit` int NOT NULL')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultInformation1693219736168 implements MigrationInterface {
|
||||
name = 'AddSharedVaultInformation1693219736168'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `items` ADD `last_edited_by` varchar(36) NULL')
|
||||
await queryRunner.query('ALTER TABLE `items` ADD `shared_vault_uuid` varchar(36) NULL')
|
||||
await queryRunner.query('ALTER TABLE `items` ADD `key_system_identifier` varchar(36) NULL')
|
||||
await queryRunner.query('CREATE INDEX `index_items_on_shared_vault_uuid` ON `items` (`shared_vault_uuid`)')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `index_items_on_shared_vault_uuid` ON `items`')
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `key_system_identifier`')
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `shared_vault_uuid`')
|
||||
await queryRunner.query('ALTER TABLE `items` DROP COLUMN `last_edited_by`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultInformation1693220037441 implements MigrationInterface {
|
||||
name = 'AddSharedVaultInformation1693220037441'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "index_items_on_user_uuid_and_content_type"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid_and_updated_at_timestamp_and_created_at_timestamp"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid_and_deleted"')
|
||||
await queryRunner.query('DROP INDEX "updated_at_timestamp"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_deleted"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_user_uuid"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_content_type"')
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE "temporary_items" ("uuid" varchar PRIMARY KEY NOT NULL, "duplicate_of" varchar(36), "items_key_id" varchar(255), "content" text, "content_type" varchar(255), "content_size" integer, "enc_item_key" text, "auth_hash" varchar(255), "user_uuid" varchar(36) NOT NULL, "deleted" tinyint(1) DEFAULT (0), "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL, "updated_with_session" varchar(36), "last_edited_by" varchar(36), "shared_vault_uuid" varchar(36), "key_system_identifier" varchar(36))',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'INSERT INTO "temporary_items"("uuid", "duplicate_of", "items_key_id", "content", "content_type", "content_size", "enc_item_key", "auth_hash", "user_uuid", "deleted", "created_at", "updated_at", "created_at_timestamp", "updated_at_timestamp", "updated_with_session") SELECT "uuid", "duplicate_of", "items_key_id", "content", "content_type", "content_size", "enc_item_key", "auth_hash", "user_uuid", "deleted", "created_at", "updated_at", "created_at_timestamp", "updated_at_timestamp", "updated_with_session" FROM "items"',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE "items"')
|
||||
await queryRunner.query('ALTER TABLE "temporary_items" RENAME TO "items"')
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "index_items_on_user_uuid_and_content_type" ON "items" ("user_uuid", "content_type") ',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "user_uuid_and_updated_at_timestamp_and_created_at_timestamp" ON "items" ("user_uuid", "updated_at_timestamp", "created_at_timestamp") ',
|
||||
)
|
||||
await queryRunner.query('CREATE INDEX "user_uuid_and_deleted" ON "items" ("user_uuid", "deleted") ')
|
||||
await queryRunner.query('CREATE INDEX "updated_at_timestamp" ON "items" ("updated_at_timestamp") ')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_deleted" ON "items" ("deleted") ')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_user_uuid" ON "items" ("user_uuid") ')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_content_type" ON "items" ("content_type") ')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "index_items_on_shared_vault_uuid"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid_and_deleted"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid_on_shared_vaults"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_content_type"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_user_uuid"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_deleted"')
|
||||
await queryRunner.query('DROP INDEX "updated_at_timestamp"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid_and_updated_at_timestamp_and_created_at_timestamp"')
|
||||
await queryRunner.query('DROP INDEX "index_items_on_user_uuid_and_content_type"')
|
||||
await queryRunner.query('ALTER TABLE "items" RENAME TO "temporary_items"')
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE "items" ("uuid" varchar PRIMARY KEY NOT NULL, "duplicate_of" varchar(36), "items_key_id" varchar(255), "content" text, "content_type" varchar(255), "content_size" integer, "enc_item_key" text, "auth_hash" varchar(255), "user_uuid" varchar(36) NOT NULL, "deleted" tinyint(1) DEFAULT (0), "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL, "updated_with_session" varchar(36), "last_edited_by" varchar(36), "shared_vault_uuid" varchar(36), "key_system_identifier" varchar(36))',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'INSERT INTO "items"("uuid", "duplicate_of", "items_key_id", "content", "content_type", "content_size", "enc_item_key", "auth_hash", "user_uuid", "deleted", "created_at", "updated_at", "created_at_timestamp", "updated_at_timestamp", "updated_with_session", "last_edited_by", "shared_vault_uuid", "key_system_identifier") SELECT "uuid", "duplicate_of", "items_key_id", "content", "content_type", "content_size", "enc_item_key", "auth_hash", "user_uuid", "deleted", "created_at", "updated_at", "created_at_timestamp", "updated_at_timestamp", "updated_with_session", "last_edited_by", "shared_vault_uuid", "key_system_identifier" FROM "temporary_items"',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE "temporary_items"')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_content_type" ON "items" ("content_type") ')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_user_uuid" ON "items" ("user_uuid") ')
|
||||
await queryRunner.query('CREATE INDEX "index_items_on_deleted" ON "items" ("deleted") ')
|
||||
await queryRunner.query('CREATE INDEX "updated_at_timestamp" ON "items" ("updated_at_timestamp") ')
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "user_uuid_and_updated_at_timestamp_and_created_at_timestamp" ON "items" ("user_uuid", "updated_at_timestamp", "created_at_timestamp") ',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "index_items_on_user_uuid_and_content_type" ON "items" ("user_uuid", "content_type") ',
|
||||
)
|
||||
await queryRunner.query('CREATE INDEX "user_uuid_and_deleted" ON "items" ("user_uuid", "deleted") ')
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.84.0",
|
||||
"version": "1.85.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import TYPES from './Types'
|
||||
import { AppDataSource } from './DataSource'
|
||||
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
||||
import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface'
|
||||
import { TypeORMItemRepository } from '../Infra/TypeORM/TypeORMItemRepository'
|
||||
import { SQLLegacyItemRepository } from '../Infra/TypeORM/SQLLegacyItemRepository'
|
||||
import { MongoRepository, Repository } from 'typeorm'
|
||||
import { Item } from '../Domain/Item/Item'
|
||||
import {
|
||||
@@ -61,8 +61,8 @@ import { S3ItemBackupService } from '../Infra/S3/S3ItemBackupService'
|
||||
import { ControllerContainer, ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
|
||||
import { BaseItemsController } from '../Infra/InversifyExpressUtils/Base/BaseItemsController'
|
||||
import { Transform } from 'stream'
|
||||
import { TypeORMItem } from '../Infra/TypeORM/TypeORMItem'
|
||||
import { ItemPersistenceMapper } from '../Mapping/Persistence/ItemPersistenceMapper'
|
||||
import { SQLLegacyItem } from '../Infra/TypeORM/SQLLegacyItem'
|
||||
import { SQLLegacyItemPersistenceMapper } from '../Mapping/Persistence/SQLLegacyItemPersistenceMapper'
|
||||
import { ItemHttpRepresentation } from '../Mapping/Http/ItemHttpRepresentation'
|
||||
import { ItemHttpMapper } from '../Mapping/Http/ItemHttpMapper'
|
||||
import { SavedItemHttpRepresentation } from '../Mapping/Http/SavedItemHttpRepresentation'
|
||||
@@ -158,6 +158,9 @@ import { TransitionItemsFromPrimaryToSecondaryDatabaseForUser } from '../Domain/
|
||||
import { SharedVaultFileMovedEventHandler } from '../Domain/Handler/SharedVaultFileMovedEventHandler'
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { SQLItem } from '../Infra/TypeORM/SQLItem'
|
||||
import { SQLItemPersistenceMapper } from '../Mapping/Persistence/SQLItemPersistenceMapper'
|
||||
import { SQLItemRepository } from '../Infra/TypeORM/SQLItemRepository'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
|
||||
@@ -210,6 +213,8 @@ export class ContainerConfigLoader {
|
||||
container.bind<TimerInterface>(TYPES.Sync_Timer).toConstantValue(new Timer())
|
||||
|
||||
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||
const isConfiguredForSelfHosting = env.get('MODE', true) === 'self-hosted'
|
||||
const isConfiguredForHomeServerOrSelfHosting = isConfiguredForHomeServer || isConfiguredForSelfHosting
|
||||
const isSecondaryDatabaseEnabled = env.get('SECONDARY_DB_ENABLED', true) === 'true'
|
||||
|
||||
container.bind<Env>(TYPES.Sync_Env).toConstantValue(env)
|
||||
@@ -303,8 +308,11 @@ export class ContainerConfigLoader {
|
||||
|
||||
// Mapping
|
||||
container
|
||||
.bind<MapperInterface<Item, TypeORMItem>>(TYPES.Sync_ItemPersistenceMapper)
|
||||
.toConstantValue(new ItemPersistenceMapper())
|
||||
.bind<MapperInterface<Item, SQLLegacyItem>>(TYPES.Sync_SQLLegacyItemPersistenceMapper)
|
||||
.toConstantValue(new SQLLegacyItemPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<Item, SQLItem>>(TYPES.Sync_SQLItemPersistenceMapper)
|
||||
.toConstantValue(new SQLItemPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<ItemHash, ItemHashHttpRepresentation>>(TYPES.Sync_ItemHashHttpMapper)
|
||||
.toConstantValue(new ItemHashHttpMapper())
|
||||
@@ -360,8 +368,11 @@ export class ContainerConfigLoader {
|
||||
|
||||
// ORM
|
||||
container
|
||||
.bind<Repository<TypeORMItem>>(TYPES.Sync_ORMItemRepository)
|
||||
.toDynamicValue(() => appDataSource.getRepository(TypeORMItem))
|
||||
.bind<Repository<SQLLegacyItem>>(TYPES.Sync_ORMLegacyItemRepository)
|
||||
.toDynamicValue(() => appDataSource.getRepository(SQLLegacyItem))
|
||||
container
|
||||
.bind<Repository<SQLItem>>(TYPES.Sync_ORMItemRepository)
|
||||
.toConstantValue(appDataSource.getRepository(SQLItem))
|
||||
container
|
||||
.bind<Repository<TypeORMSharedVault>>(TYPES.Sync_ORMSharedVaultRepository)
|
||||
.toConstantValue(appDataSource.getRepository(TypeORMSharedVault))
|
||||
@@ -401,19 +412,25 @@ export class ContainerConfigLoader {
|
||||
|
||||
// Repositories
|
||||
container
|
||||
.bind<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository)
|
||||
.bind<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository)
|
||||
.toConstantValue(
|
||||
new TypeORMItemRepository(
|
||||
container.get<Repository<TypeORMItem>>(TYPES.Sync_ORMItemRepository),
|
||||
container.get<MapperInterface<Item, TypeORMItem>>(TYPES.Sync_ItemPersistenceMapper),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
isConfiguredForHomeServerOrSelfHosting
|
||||
? new SQLItemRepository(
|
||||
container.get<Repository<SQLItem>>(TYPES.Sync_ORMItemRepository),
|
||||
container.get<MapperInterface<Item, SQLItem>>(TYPES.Sync_SQLItemPersistenceMapper),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
)
|
||||
: new SQLLegacyItemRepository(
|
||||
container.get<Repository<SQLLegacyItem>>(TYPES.Sync_ORMLegacyItemRepository),
|
||||
container.get<MapperInterface<Item, SQLLegacyItem>>(TYPES.Sync_SQLLegacyItemPersistenceMapper),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<ItemRepositoryResolverInterface>(TYPES.Sync_ItemRepositoryResolver)
|
||||
.toConstantValue(
|
||||
new TypeORMItemRepositoryResolver(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
),
|
||||
)
|
||||
@@ -777,7 +794,7 @@ export class ContainerConfigLoader {
|
||||
)
|
||||
.toConstantValue(
|
||||
new TransitionItemsFromPrimaryToSecondaryDatabaseForUser(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
container.get<TimerInterface>(TYPES.Sync_Timer),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
@@ -843,7 +860,7 @@ export class ContainerConfigLoader {
|
||||
.bind<DuplicateItemSyncedEventHandler>(TYPES.Sync_DuplicateItemSyncedEventHandler)
|
||||
.toConstantValue(
|
||||
new DuplicateItemSyncedEventHandler(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
|
||||
@@ -854,7 +871,7 @@ export class ContainerConfigLoader {
|
||||
.bind<AccountDeletionRequestedEventHandler>(TYPES.Sync_AccountDeletionRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new AccountDeletionRequestedEventHandler(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
@@ -863,7 +880,7 @@ export class ContainerConfigLoader {
|
||||
.bind<ItemRevisionCreationRequestedEventHandler>(TYPES.Sync_ItemRevisionCreationRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new ItemRevisionCreationRequestedEventHandler(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
container.get<ItemBackupServiceInterface>(TYPES.Sync_ItemBackupService),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
|
||||
@@ -918,7 +935,7 @@ export class ContainerConfigLoader {
|
||||
.toConstantValue(
|
||||
new ExtensionsHttpService(
|
||||
container.get<AxiosInstance>(TYPES.Sync_HTTPClient),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled ? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository) : null,
|
||||
container.get<ContentDecoderInterface>(TYPES.Sync_ContentDecoder),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
|
||||
@@ -964,7 +981,7 @@ export class ContainerConfigLoader {
|
||||
.bind<EmailBackupRequestedEventHandler>(TYPES.Sync_EmailBackupRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new EmailBackupRequestedEventHandler(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_MySQLItemRepository),
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
isSecondaryDatabaseEnabled
|
||||
? container.get<ItemRepositoryInterface>(TYPES.Sync_MongoDBItemRepository)
|
||||
: null,
|
||||
|
||||
@@ -2,13 +2,14 @@ import { DataSource, EntityTarget, LoggerOptions, MongoRepository, ObjectLiteral
|
||||
import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
|
||||
import { Env } from './Env'
|
||||
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
|
||||
import { TypeORMItem } from '../Infra/TypeORM/TypeORMItem'
|
||||
import { SQLLegacyItem } from '../Infra/TypeORM/SQLLegacyItem'
|
||||
import { TypeORMNotification } from '../Infra/TypeORM/TypeORMNotification'
|
||||
import { TypeORMSharedVault } from '../Infra/TypeORM/TypeORMSharedVault'
|
||||
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
|
||||
import { TypeORMSharedVaultInvite } from '../Infra/TypeORM/TypeORMSharedVaultInvite'
|
||||
import { TypeORMMessage } from '../Infra/TypeORM/TypeORMMessage'
|
||||
import { MongoDBItem } from '../Infra/TypeORM/MongoDBItem'
|
||||
import { SQLItem } from '../Infra/TypeORM/SQLItem'
|
||||
|
||||
export class AppDataSource {
|
||||
private _dataSource: DataSource | undefined
|
||||
@@ -67,22 +68,30 @@ export class AppDataSource {
|
||||
this.env.load()
|
||||
|
||||
const isConfiguredForMySQL = this.env.get('DB_TYPE') === 'mysql'
|
||||
const isConfiguredForHomeServerOrSelfHosting =
|
||||
this.env.get('MODE', true) === 'home-server' || this.env.get('MODE', true) === 'self-hosted'
|
||||
|
||||
const maxQueryExecutionTime = this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
? +this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
: 45_000
|
||||
|
||||
const migrationsSourceDirectoryName = isConfiguredForMySQL
|
||||
? isConfiguredForHomeServerOrSelfHosting
|
||||
? 'mysql'
|
||||
: 'mysql-legacy'
|
||||
: 'sqlite'
|
||||
|
||||
const commonDataSourceOptions = {
|
||||
maxQueryExecutionTime,
|
||||
entities: [
|
||||
TypeORMItem,
|
||||
isConfiguredForHomeServerOrSelfHosting ? SQLItem : SQLLegacyItem,
|
||||
TypeORMNotification,
|
||||
TypeORMSharedVault,
|
||||
TypeORMSharedVaultUser,
|
||||
TypeORMSharedVaultInvite,
|
||||
TypeORMMessage,
|
||||
],
|
||||
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
|
||||
migrations: [`${__dirname}/../../migrations/${migrationsSourceDirectoryName}/*.js`],
|
||||
migrationsRun: true,
|
||||
logging: <LoggerOptions>this.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ const TYPES = {
|
||||
Sync_Env: Symbol.for('Sync_Env'),
|
||||
// Repositories
|
||||
Sync_ItemRepositoryResolver: Symbol.for('Sync_ItemRepositoryResolver'),
|
||||
Sync_MySQLItemRepository: Symbol.for('Sync_MySQLItemRepository'),
|
||||
Sync_SQLItemRepository: Symbol.for('Sync_SQLItemRepository'),
|
||||
Sync_MongoDBItemRepository: Symbol.for('Sync_MongoDBItemRepository'),
|
||||
Sync_SharedVaultRepository: Symbol.for('Sync_SharedVaultRepository'),
|
||||
Sync_SharedVaultInviteRepository: Symbol.for('Sync_SharedVaultInviteRepository'),
|
||||
@@ -17,6 +17,7 @@ const TYPES = {
|
||||
Sync_MessageRepository: Symbol.for('Sync_MessageRepository'),
|
||||
// ORM
|
||||
Sync_ORMItemRepository: Symbol.for('Sync_ORMItemRepository'),
|
||||
Sync_ORMLegacyItemRepository: Symbol.for('Sync_ORMLegacyItemRepository'),
|
||||
Sync_ORMSharedVaultRepository: Symbol.for('Sync_ORMSharedVaultRepository'),
|
||||
Sync_ORMSharedVaultInviteRepository: Symbol.for('Sync_ORMSharedVaultInviteRepository'),
|
||||
Sync_ORMSharedVaultUserRepository: Symbol.for('Sync_ORMSharedVaultUserRepository'),
|
||||
@@ -131,7 +132,8 @@ const TYPES = {
|
||||
Sync_MessagePersistenceMapper: Symbol.for('Sync_MessagePersistenceMapper'),
|
||||
Sync_MessageHttpMapper: Symbol.for('Sync_MessageHttpMapper'),
|
||||
Sync_NotificationHttpMapper: Symbol.for('Sync_NotificationHttpMapper'),
|
||||
Sync_ItemPersistenceMapper: Symbol.for('Sync_ItemPersistenceMapper'),
|
||||
Sync_SQLLegacyItemPersistenceMapper: Symbol.for('Sync_SQLLegacyItemPersistenceMapper'),
|
||||
Sync_SQLItemPersistenceMapper: Symbol.for('Sync_SQLItemPersistenceMapper'),
|
||||
Sync_MongoDBItemPersistenceMapper: Symbol.for('Sync_MongoDBItemPersistenceMapper'),
|
||||
Sync_ItemHttpMapper: Symbol.for('Sync_ItemHttpMapper'),
|
||||
Sync_ItemHashHttpMapper: Symbol.for('Sync_ItemHashHttpMapper'),
|
||||
|
||||
@@ -74,6 +74,7 @@ describe('DuplicateItemSyncedEventHandler', () => {
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.warn = jest.fn()
|
||||
logger.debug = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<DuplicateItemSyncedEvent>
|
||||
event.createdAt = new Date(1)
|
||||
|
||||
@@ -31,13 +31,13 @@ export class DuplicateItemSyncedEventHandler implements DomainEventHandlerInterf
|
||||
const item = await itemRepository.findByUuidAndUserUuid(event.payload.itemUuid, event.payload.userUuid)
|
||||
|
||||
if (item === null) {
|
||||
this.logger.warn(`Could not find item with uuid ${event.payload.itemUuid}`)
|
||||
this.logger.debug(`Could not find item with uuid ${event.payload.itemUuid}`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!item.props.duplicateOf) {
|
||||
this.logger.warn(`Item ${event.payload.itemUuid} does not point to any duplicate`)
|
||||
this.logger.debug(`Item ${event.payload.itemUuid} does not point to any duplicate`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ export class MongoDBItem {
|
||||
declare lastEditedBy: string | null
|
||||
|
||||
@Column()
|
||||
@Index('index_items_on_shared_vault_uuid')
|
||||
declare sharedVaultUuid: string | null
|
||||
|
||||
@Column()
|
||||
|
||||
@@ -48,7 +48,7 @@ export class MongoDBItemRepository implements ItemRepositoryInterface {
|
||||
async findContentSizeForComputingTransferLimit(query: ItemQuery): Promise<ItemContentSizeDescriptor[]> {
|
||||
const options = this.createFindOptions(query)
|
||||
const rawItems = await this.mongoRepository.find({
|
||||
select: ['uuid', 'contentSize'],
|
||||
select: ['_id', 'contentSize'],
|
||||
...options,
|
||||
})
|
||||
|
||||
@@ -175,7 +175,11 @@ export class MongoDBItemRepository implements ItemRepositoryInterface {
|
||||
where: undefined,
|
||||
}
|
||||
if (query.sortBy !== undefined && query.sortOrder !== undefined) {
|
||||
options.order = { [query.sortBy]: query.sortOrder }
|
||||
const sortBySnakeToCamelCase = query.sortBy
|
||||
.toLowerCase()
|
||||
.replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', ''))
|
||||
|
||||
options.order = { [sortBySnakeToCamelCase]: query.sortOrder }
|
||||
}
|
||||
|
||||
if (query.uuids && query.uuids.length > 0) {
|
||||
@@ -185,7 +189,9 @@ export class MongoDBItemRepository implements ItemRepositoryInterface {
|
||||
}
|
||||
}
|
||||
if (query.deleted !== undefined) {
|
||||
options.where = { ...options.where, deleted: { $eq: query.deleted } }
|
||||
const deletedMixedValues = query.deleted === true ? [true, 1] : [false, 0]
|
||||
|
||||
options.where = { ...options.where, deleted: { $in: deletedMixedValues } }
|
||||
}
|
||||
if (query.contentType) {
|
||||
if (Array.isArray(query.contentType)) {
|
||||
|
||||
31
packages/syncing-server/src/Infra/TypeORM/SQLItem.ts
Normal file
31
packages/syncing-server/src/Infra/TypeORM/SQLItem.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Column, Entity, Index } from 'typeorm'
|
||||
|
||||
import { SQLLegacyItem } from './SQLLegacyItem'
|
||||
|
||||
@Entity({ name: 'items' })
|
||||
export class SQLItem extends SQLLegacyItem {
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
name: 'last_edited_by',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
})
|
||||
declare lastEditedBy: string | null
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
name: 'shared_vault_uuid',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
})
|
||||
@Index('index_items_on_shared_vault_uuid')
|
||||
declare sharedVaultUuid: string | null
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
name: 'key_system_identifier',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
})
|
||||
declare keySystemIdentifier: string | null
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm'
|
||||
import { MapperInterface } from '@standardnotes/domain-core'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { Item } from '../../Domain/Item/Item'
|
||||
import { SQLItem } from './SQLItem'
|
||||
import { SQLLegacyItemRepository } from './SQLLegacyItemRepository'
|
||||
import { ItemQuery } from '../../Domain/Item/ItemQuery'
|
||||
|
||||
export class SQLItemRepository extends SQLLegacyItemRepository {
|
||||
constructor(
|
||||
protected override ormRepository: Repository<SQLItem>,
|
||||
protected override mapper: MapperInterface<Item, SQLItem>,
|
||||
protected override logger: Logger,
|
||||
) {
|
||||
super(ormRepository, mapper, logger)
|
||||
}
|
||||
|
||||
protected override createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<SQLItem> {
|
||||
const queryBuilder = this.ormRepository.createQueryBuilder('item')
|
||||
|
||||
if (query.sortBy !== undefined && query.sortOrder !== undefined) {
|
||||
queryBuilder.orderBy(`item.${query.sortBy}`, query.sortOrder)
|
||||
}
|
||||
|
||||
if (query.includeSharedVaultUuids !== undefined && query.includeSharedVaultUuids.length > 0) {
|
||||
if (query.userUuid) {
|
||||
queryBuilder.where('(item.user_uuid = :userUuid OR item.shared_vault_uuid IN (:...includeSharedVaultUuids))', {
|
||||
userUuid: query.userUuid,
|
||||
includeSharedVaultUuids: query.includeSharedVaultUuids,
|
||||
})
|
||||
} else {
|
||||
queryBuilder.where('item.shared_vault_uuid IN (:...includeSharedVaultUuids)', {
|
||||
includeSharedVaultUuids: query.includeSharedVaultUuids,
|
||||
})
|
||||
}
|
||||
} else if (query.exclusiveSharedVaultUuids !== undefined && query.exclusiveSharedVaultUuids.length > 0) {
|
||||
queryBuilder.where('item.shared_vault_uuid IN (:...exclusiveSharedVaultUuids)', {
|
||||
exclusiveSharedVaultUuids: query.exclusiveSharedVaultUuids,
|
||||
})
|
||||
} else if (query.userUuid !== undefined) {
|
||||
queryBuilder.where('item.user_uuid = :userUuid', { userUuid: query.userUuid })
|
||||
}
|
||||
|
||||
if (query.uuids && query.uuids.length > 0) {
|
||||
queryBuilder.andWhere('item.uuid IN (:...uuids)', { uuids: query.uuids })
|
||||
}
|
||||
if (query.deleted !== undefined) {
|
||||
queryBuilder.andWhere('item.deleted = :deleted', { deleted: query.deleted })
|
||||
}
|
||||
if (query.contentType) {
|
||||
if (Array.isArray(query.contentType)) {
|
||||
queryBuilder.andWhere('item.content_type IN (:...contentTypes)', { contentTypes: query.contentType })
|
||||
} else {
|
||||
queryBuilder.andWhere('item.content_type = :contentType', { contentType: query.contentType })
|
||||
}
|
||||
}
|
||||
if (query.lastSyncTime && query.syncTimeComparison) {
|
||||
queryBuilder.andWhere(`item.updated_at_timestamp ${query.syncTimeComparison} :lastSyncTime`, {
|
||||
lastSyncTime: query.lastSyncTime,
|
||||
})
|
||||
}
|
||||
if (query.createdBetween !== undefined) {
|
||||
queryBuilder.andWhere('item.created_at >= :createdAfter AND item.created_at <= :createdBefore', {
|
||||
createdAfter: query.createdBetween[0].toISOString(),
|
||||
createdBefore: query.createdBetween[1].toISOString(),
|
||||
})
|
||||
}
|
||||
if (query.offset !== undefined) {
|
||||
queryBuilder.skip(query.offset)
|
||||
}
|
||||
if (query.limit !== undefined) {
|
||||
queryBuilder.take(query.limit)
|
||||
}
|
||||
|
||||
return queryBuilder
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
|
||||
'createdAtTimestamp',
|
||||
])
|
||||
@Index('user_uuid_and_deleted', ['userUuid', 'deleted'])
|
||||
export class TypeORMItem {
|
||||
export class SQLLegacyItem {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
declare uuid: string
|
||||
|
||||
@@ -6,14 +6,14 @@ import { Item } from '../../Domain/Item/Item'
|
||||
import { ItemQuery } from '../../Domain/Item/ItemQuery'
|
||||
import { ItemRepositoryInterface } from '../../Domain/Item/ItemRepositoryInterface'
|
||||
import { ExtendedIntegrityPayload } from '../../Domain/Item/ExtendedIntegrityPayload'
|
||||
import { TypeORMItem } from './TypeORMItem'
|
||||
import { SQLLegacyItem } from './SQLLegacyItem'
|
||||
import { ItemContentSizeDescriptor } from '../../Domain/Item/ItemContentSizeDescriptor'
|
||||
|
||||
export class TypeORMItemRepository implements ItemRepositoryInterface {
|
||||
export class SQLLegacyItemRepository implements ItemRepositoryInterface {
|
||||
constructor(
|
||||
private ormRepository: Repository<TypeORMItem>,
|
||||
private mapper: MapperInterface<Item, TypeORMItem>,
|
||||
private logger: Logger,
|
||||
protected ormRepository: Repository<SQLLegacyItem>,
|
||||
protected mapper: MapperInterface<Item, SQLLegacyItem>,
|
||||
protected logger: Logger,
|
||||
) {}
|
||||
|
||||
async save(item: Item): Promise<void> {
|
||||
@@ -179,7 +179,7 @@ export class TypeORMItemRepository implements ItemRepositoryInterface {
|
||||
.execute()
|
||||
}
|
||||
|
||||
private createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<TypeORMItem> {
|
||||
protected createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<SQLLegacyItem> {
|
||||
const queryBuilder = this.ormRepository.createQueryBuilder('item')
|
||||
|
||||
if (query.sortBy !== undefined && query.sortOrder !== undefined) {
|
||||
@@ -5,13 +5,13 @@ import { ItemRepositoryResolverInterface } from '../../Domain/Item/ItemRepositor
|
||||
|
||||
export class TypeORMItemRepositoryResolver implements ItemRepositoryResolverInterface {
|
||||
constructor(
|
||||
private mysqlItemRepository: ItemRepositoryInterface,
|
||||
private sqlItemRepository: ItemRepositoryInterface,
|
||||
private mongoDbItemRepository: ItemRepositoryInterface | null,
|
||||
) {}
|
||||
|
||||
resolve(roleNames: RoleNameCollection): ItemRepositoryInterface {
|
||||
if (!this.mongoDbItemRepository) {
|
||||
return this.mysqlItemRepository
|
||||
return this.sqlItemRepository
|
||||
}
|
||||
|
||||
const transitionRoleName = RoleName.create(RoleName.NAMES.TransitionUser).getValue()
|
||||
@@ -20,6 +20,6 @@ export class TypeORMItemRepositoryResolver implements ItemRepositoryResolverInte
|
||||
return this.mongoDbItemRepository
|
||||
}
|
||||
|
||||
return this.mysqlItemRepository
|
||||
return this.sqlItemRepository
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ export class MongoDBItemPersistenceMapper implements MapperInterface<Item, Mongo
|
||||
encItemKey: projection.encItemKey,
|
||||
authHash: projection.authHash,
|
||||
userUuid,
|
||||
deleted: projection.deleted,
|
||||
deleted: !!projection.deleted,
|
||||
dates,
|
||||
timestamps,
|
||||
updatedWithSession,
|
||||
@@ -127,7 +127,7 @@ export class MongoDBItemPersistenceMapper implements MapperInterface<Item, Mongo
|
||||
mongoDbItem.encItemKey = domain.props.encItemKey
|
||||
mongoDbItem.authHash = domain.props.authHash
|
||||
mongoDbItem.userUuid = domain.props.userUuid.value
|
||||
mongoDbItem.deleted = domain.props.deleted
|
||||
mongoDbItem.deleted = !!domain.props.deleted
|
||||
mongoDbItem.createdAt = domain.props.dates.createdAt
|
||||
mongoDbItem.updatedAt = domain.props.dates.updatedAt
|
||||
mongoDbItem.createdAtTimestamp = domain.props.timestamps.createdAt
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import { Timestamps, MapperInterface, UniqueEntityId, Uuid, ContentType, Dates } from '@standardnotes/domain-core'
|
||||
|
||||
import { Item } from '../../Domain/Item/Item'
|
||||
|
||||
import { SQLItem } from '../../Infra/TypeORM/SQLItem'
|
||||
import { KeySystemAssociation } from '../../Domain/KeySystem/KeySystemAssociation'
|
||||
import { SharedVaultAssociation } from '../../Domain/SharedVault/SharedVaultAssociation'
|
||||
|
||||
export class SQLItemPersistenceMapper implements MapperInterface<Item, SQLItem> {
|
||||
toDomain(projection: SQLItem): Item {
|
||||
const uuidOrError = Uuid.create(projection.uuid)
|
||||
if (uuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${uuidOrError.getError()}`)
|
||||
}
|
||||
const uuid = uuidOrError.getValue()
|
||||
|
||||
let duplicateOf = null
|
||||
if (projection.duplicateOf) {
|
||||
const duplicateOfOrError = Uuid.create(projection.duplicateOf)
|
||||
if (duplicateOfOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${duplicateOfOrError.getError()}`)
|
||||
}
|
||||
duplicateOf = duplicateOfOrError.getValue()
|
||||
}
|
||||
|
||||
const contentTypeOrError = ContentType.create(projection.contentType)
|
||||
if (contentTypeOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${contentTypeOrError.getError()}`)
|
||||
}
|
||||
const contentType = contentTypeOrError.getValue()
|
||||
|
||||
const userUuidOrError = Uuid.create(projection.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${userUuidOrError.getError()}`)
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const datesOrError = Dates.create(projection.createdAt, projection.updatedAt)
|
||||
if (datesOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${datesOrError.getError()}`)
|
||||
}
|
||||
const dates = datesOrError.getValue()
|
||||
|
||||
const timestampsOrError = Timestamps.create(projection.createdAtTimestamp, projection.updatedAtTimestamp)
|
||||
if (timestampsOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${timestampsOrError.getError()}`)
|
||||
}
|
||||
const timestamps = timestampsOrError.getValue()
|
||||
|
||||
let updatedWithSession = null
|
||||
if (projection.updatedWithSession) {
|
||||
const updatedWithSessionOrError = Uuid.create(projection.updatedWithSession)
|
||||
if (updatedWithSessionOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${updatedWithSessionOrError.getError()}`)
|
||||
}
|
||||
updatedWithSession = updatedWithSessionOrError.getValue()
|
||||
}
|
||||
|
||||
let sharedVaultAssociation: SharedVaultAssociation | undefined = undefined
|
||||
if (projection.sharedVaultUuid && projection.lastEditedBy) {
|
||||
const sharedVaultUuidOrError = Uuid.create(projection.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${sharedVaultUuidOrError.getError()}`)
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const lastEditedByOrError = Uuid.create(projection.lastEditedBy)
|
||||
if (lastEditedByOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${lastEditedByOrError.getError()}`)
|
||||
}
|
||||
const lastEditedBy = lastEditedByOrError.getValue()
|
||||
|
||||
const sharedVaultAssociationOrError = SharedVaultAssociation.create({
|
||||
sharedVaultUuid,
|
||||
lastEditedBy,
|
||||
})
|
||||
if (sharedVaultAssociationOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${sharedVaultAssociationOrError.getError()}`)
|
||||
}
|
||||
sharedVaultAssociation = sharedVaultAssociationOrError.getValue()
|
||||
}
|
||||
|
||||
let keySystemAssociation: KeySystemAssociation | undefined = undefined
|
||||
if (projection.keySystemIdentifier) {
|
||||
const keySystemAssociationOrError = KeySystemAssociation.create(projection.keySystemIdentifier)
|
||||
if (keySystemAssociationOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${keySystemAssociationOrError.getError()}`)
|
||||
}
|
||||
keySystemAssociation = keySystemAssociationOrError.getValue()
|
||||
}
|
||||
|
||||
const itemOrError = Item.create(
|
||||
{
|
||||
duplicateOf,
|
||||
itemsKeyId: projection.itemsKeyId,
|
||||
content: projection.content,
|
||||
contentType,
|
||||
contentSize: projection.contentSize ?? undefined,
|
||||
encItemKey: projection.encItemKey,
|
||||
authHash: projection.authHash,
|
||||
userUuid,
|
||||
deleted: projection.deleted,
|
||||
dates,
|
||||
timestamps,
|
||||
updatedWithSession,
|
||||
sharedVaultAssociation,
|
||||
keySystemAssociation,
|
||||
},
|
||||
new UniqueEntityId(uuid.value),
|
||||
)
|
||||
if (itemOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${itemOrError.getError()}`)
|
||||
}
|
||||
|
||||
return itemOrError.getValue()
|
||||
}
|
||||
|
||||
toProjection(domain: Item): SQLItem {
|
||||
const typeorm = new SQLItem()
|
||||
|
||||
typeorm.uuid = domain.id.toString()
|
||||
typeorm.duplicateOf = domain.props.duplicateOf ? domain.props.duplicateOf.value : null
|
||||
typeorm.itemsKeyId = domain.props.itemsKeyId
|
||||
typeorm.content = domain.props.content
|
||||
typeorm.contentType = domain.props.contentType.value
|
||||
typeorm.contentSize = domain.props.contentSize ?? null
|
||||
typeorm.encItemKey = domain.props.encItemKey
|
||||
typeorm.authHash = domain.props.authHash
|
||||
typeorm.userUuid = domain.props.userUuid.value
|
||||
typeorm.deleted = domain.props.deleted
|
||||
typeorm.createdAt = domain.props.dates.createdAt
|
||||
typeorm.updatedAt = domain.props.dates.updatedAt
|
||||
typeorm.createdAtTimestamp = domain.props.timestamps.createdAt
|
||||
typeorm.updatedAtTimestamp = domain.props.timestamps.updatedAt
|
||||
typeorm.updatedWithSession = domain.props.updatedWithSession ? domain.props.updatedWithSession.value : null
|
||||
typeorm.lastEditedBy = domain.props.sharedVaultAssociation
|
||||
? domain.props.sharedVaultAssociation.props.lastEditedBy.value
|
||||
: null
|
||||
typeorm.sharedVaultUuid = domain.props.sharedVaultAssociation
|
||||
? domain.props.sharedVaultAssociation.props.sharedVaultUuid.value
|
||||
: null
|
||||
typeorm.keySystemIdentifier = domain.props.keySystemAssociation
|
||||
? domain.props.keySystemAssociation.props.keySystemIdentifier
|
||||
: null
|
||||
|
||||
return typeorm
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import { Timestamps, MapperInterface, UniqueEntityId, Uuid, ContentType, Dates }
|
||||
|
||||
import { Item } from '../../Domain/Item/Item'
|
||||
|
||||
import { TypeORMItem } from '../../Infra/TypeORM/TypeORMItem'
|
||||
import { SQLLegacyItem } from '../../Infra/TypeORM/SQLLegacyItem'
|
||||
|
||||
export class ItemPersistenceMapper implements MapperInterface<Item, TypeORMItem> {
|
||||
toDomain(projection: TypeORMItem): Item {
|
||||
export class SQLLegacyItemPersistenceMapper implements MapperInterface<Item, SQLLegacyItem> {
|
||||
toDomain(projection: SQLLegacyItem): Item {
|
||||
const uuidOrError = Uuid.create(projection.uuid)
|
||||
if (uuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create item from projection: ${uuidOrError.getError()}`)
|
||||
@@ -78,8 +78,8 @@ export class ItemPersistenceMapper implements MapperInterface<Item, TypeORMItem>
|
||||
return itemOrError.getValue()
|
||||
}
|
||||
|
||||
toProjection(domain: Item): TypeORMItem {
|
||||
const typeorm = new TypeORMItem()
|
||||
toProjection(domain: Item): SQLLegacyItem {
|
||||
const typeorm = new SQLLegacyItem()
|
||||
|
||||
typeorm.uuid = domain.id.toString()
|
||||
typeorm.duplicateOf = domain.props.duplicateOf ? domain.props.duplicateOf.value : null
|
||||
Reference in New Issue
Block a user