You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
Server: Added item owner ID, and allow disabling db auto-migrations
This commit is contained in:
@ -90,12 +90,12 @@ const main = async () => {
|
|||||||
// run the scripts (faster)
|
// run the scripts (faster)
|
||||||
await execCommand2(['npm', 'run', 'build']);
|
await execCommand2(['npm', 'run', 'build']);
|
||||||
|
|
||||||
const focusUserNum = 400;
|
const focusUserNum = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
let userNum = randomInt(minUserNum, maxUserNum);
|
let userNum = randomInt(minUserNum, maxUserNum);
|
||||||
|
|
||||||
if (Math.random() >= .7) userNum = focusUserNum;
|
if (focusUserNum && Math.random() >= .7) userNum = focusUserNum;
|
||||||
|
|
||||||
void processUser(userNum);
|
void processUser(userNum);
|
||||||
await waitForProcessing(10);
|
await waitForProcessing(10);
|
||||||
|
Binary file not shown.
@ -282,8 +282,12 @@ async function main() {
|
|||||||
await setupAppContext(ctx, env, connectionCheck.connection, appLogger);
|
await setupAppContext(ctx, env, connectionCheck.connection, appLogger);
|
||||||
await initializeJoplinUtils(config(), ctx.joplinBase.models, ctx.joplinBase.services.mustache);
|
await initializeJoplinUtils(config(), ctx.joplinBase.models, ctx.joplinBase.services.mustache);
|
||||||
|
|
||||||
appLogger().info('Migrating database...');
|
if (config().database.autoMigration) {
|
||||||
await migrateLatest(ctx.joplinBase.db);
|
appLogger().info('Auto-migrating database...');
|
||||||
|
await migrateLatest(ctx.joplinBase.db);
|
||||||
|
} else {
|
||||||
|
appLogger().info('Skipped database auto-migration.');
|
||||||
|
}
|
||||||
|
|
||||||
appLogger().info('Starting services...');
|
appLogger().info('Starting services...');
|
||||||
await startServices(ctx.joplinBase.services);
|
await startServices(ctx.joplinBase.services);
|
||||||
|
@ -10,16 +10,36 @@ interface PackageJson {
|
|||||||
const packageJson: PackageJson = require(`${__dirname}/packageInfo.js`);
|
const packageJson: PackageJson = require(`${__dirname}/packageInfo.js`);
|
||||||
|
|
||||||
export interface EnvVariables {
|
export interface EnvVariables {
|
||||||
|
// ==================================================
|
||||||
|
// General config
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
APP_NAME?: string;
|
APP_NAME?: string;
|
||||||
|
APP_PORT?: string;
|
||||||
|
SIGNUP_ENABLED?: string;
|
||||||
|
TERMS_ENABLED?: string;
|
||||||
|
ACCOUNT_TYPES_ENABLED?: string;
|
||||||
|
ERROR_STACK_TRACES?: string;
|
||||||
|
COOKIES_SECURE?: string;
|
||||||
|
RUNNING_IN_DOCKER?: string;
|
||||||
|
|
||||||
|
// ==================================================
|
||||||
|
// URL config
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
APP_BASE_URL?: string;
|
APP_BASE_URL?: string;
|
||||||
USER_CONTENT_BASE_URL?: string;
|
USER_CONTENT_BASE_URL?: string;
|
||||||
API_BASE_URL?: string;
|
API_BASE_URL?: string;
|
||||||
JOPLINAPP_BASE_URL?: string;
|
JOPLINAPP_BASE_URL?: string;
|
||||||
|
|
||||||
APP_PORT?: string;
|
// ==================================================
|
||||||
|
// Database config
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
DB_CLIENT?: string;
|
DB_CLIENT?: string;
|
||||||
RUNNING_IN_DOCKER?: string;
|
DB_SLOW_QUERY_LOG_ENABLED?: string;
|
||||||
|
DB_SLOW_QUERY_LOG_MIN_DURATION?: string; // ms
|
||||||
|
DB_AUTO_MIGRATION?: string;
|
||||||
|
|
||||||
POSTGRES_PASSWORD?: string;
|
POSTGRES_PASSWORD?: string;
|
||||||
POSTGRES_DATABASE?: string;
|
POSTGRES_DATABASE?: string;
|
||||||
@ -27,6 +47,13 @@ export interface EnvVariables {
|
|||||||
POSTGRES_HOST?: string;
|
POSTGRES_HOST?: string;
|
||||||
POSTGRES_PORT?: string;
|
POSTGRES_PORT?: string;
|
||||||
|
|
||||||
|
// This must be the full path to the database file
|
||||||
|
SQLITE_DATABASE?: string;
|
||||||
|
|
||||||
|
// ==================================================
|
||||||
|
// Mailer config
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
MAILER_ENABLED?: string;
|
MAILER_ENABLED?: string;
|
||||||
MAILER_HOST?: string;
|
MAILER_HOST?: string;
|
||||||
MAILER_PORT?: string;
|
MAILER_PORT?: string;
|
||||||
@ -36,27 +63,16 @@ export interface EnvVariables {
|
|||||||
MAILER_NOREPLY_NAME?: string;
|
MAILER_NOREPLY_NAME?: string;
|
||||||
MAILER_NOREPLY_EMAIL?: string;
|
MAILER_NOREPLY_EMAIL?: string;
|
||||||
|
|
||||||
// This must be the full path to the database file
|
SUPPORT_EMAIL?: string;
|
||||||
SQLITE_DATABASE?: string;
|
SUPPORT_NAME?: string;
|
||||||
|
BUSINESS_EMAIL?: string;
|
||||||
|
|
||||||
|
// ==================================================
|
||||||
|
// Stripe config
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
STRIPE_SECRET_KEY?: string;
|
STRIPE_SECRET_KEY?: string;
|
||||||
STRIPE_WEBHOOK_SECRET?: string;
|
STRIPE_WEBHOOK_SECRET?: string;
|
||||||
|
|
||||||
SIGNUP_ENABLED?: string;
|
|
||||||
TERMS_ENABLED?: string;
|
|
||||||
ACCOUNT_TYPES_ENABLED?: string;
|
|
||||||
|
|
||||||
ERROR_STACK_TRACES?: string;
|
|
||||||
|
|
||||||
SUPPORT_EMAIL?: string;
|
|
||||||
SUPPORT_NAME?: string;
|
|
||||||
|
|
||||||
BUSINESS_EMAIL?: string;
|
|
||||||
|
|
||||||
COOKIES_SECURE?: string;
|
|
||||||
|
|
||||||
SLOW_QUERY_LOG_ENABLED?: string;
|
|
||||||
SLOW_QUERY_LOG_MIN_DURATION?: string; // ms
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let runningInDocker_: boolean = false;
|
let runningInDocker_: boolean = false;
|
||||||
@ -69,7 +85,8 @@ function envReadString(s: string, defaultValue: string = ''): string {
|
|||||||
return s === undefined || s === null ? defaultValue : s;
|
return s === undefined || s === null ? defaultValue : s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function envReadBool(s: string): boolean {
|
function envReadBool(s: string, defaultValue = false): boolean {
|
||||||
|
if (s === undefined || s === null) return defaultValue;
|
||||||
return s === '1';
|
return s === '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,8 +116,9 @@ function databaseConfigFromEnv(runningInDocker: boolean, env: EnvVariables): Dat
|
|||||||
const baseConfig: DatabaseConfig = {
|
const baseConfig: DatabaseConfig = {
|
||||||
client: DatabaseConfigClient.Null,
|
client: DatabaseConfigClient.Null,
|
||||||
name: '',
|
name: '',
|
||||||
slowQueryLogEnabled: envReadBool(env.SLOW_QUERY_LOG_ENABLED),
|
slowQueryLogEnabled: envReadBool(env.DB_SLOW_QUERY_LOG_ENABLED),
|
||||||
slowQueryLogMinDuration: envReadInt(env.SLOW_QUERY_LOG_MIN_DURATION, 10000),
|
slowQueryLogMinDuration: envReadInt(env.DB_SLOW_QUERY_LOG_MIN_DURATION, 10000),
|
||||||
|
autoMigration: envReadBool(env.DB_AUTO_MIGRATION, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (env.DB_CLIENT === 'pg') {
|
if (env.DB_CLIENT === 'pg') {
|
||||||
|
25
packages/server/src/migrations/20211027112530_item_owner.ts
Normal file
25
packages/server/src/migrations/20211027112530_item_owner.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { DbConnection } from '../db';
|
||||||
|
|
||||||
|
export async function up(db: DbConnection): Promise<any> {
|
||||||
|
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||||
|
table.string('owner_id', 32).defaultTo('').notNullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.raw(`
|
||||||
|
UPDATE items
|
||||||
|
SET owner_id = user_items.user_id
|
||||||
|
FROM user_items
|
||||||
|
WHERE user_items.item_id = items.id
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||||
|
table.string('owner_id', 32).notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: DbConnection): Promise<any> {
|
||||||
|
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||||
|
table.dropColumn('owner_id');
|
||||||
|
});
|
||||||
|
}
|
@ -579,6 +579,7 @@ export default class ItemModel extends BaseModel<Item> {
|
|||||||
|
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
if (!item.mime_type) item.mime_type = mimeUtils.fromFilename(item.name) || '';
|
if (!item.mime_type) item.mime_type = mimeUtils.fromFilename(item.name) || '';
|
||||||
|
if (!item.owner_id) item.owner_id = userId;
|
||||||
} else {
|
} else {
|
||||||
const beforeSaveItem = (await this.load(item.id, { fields: ['name', 'jop_type', 'jop_parent_id', 'jop_share_id'] }));
|
const beforeSaveItem = (await this.load(item.id, { fields: ['name', 'jop_type', 'jop_parent_id', 'jop_share_id'] }));
|
||||||
const resourceIds = beforeSaveItem.jop_type === ModelType.Note ? await this.models().itemResource().byItemId(item.id) : [];
|
const resourceIds = beforeSaveItem.jop_type === ModelType.Note ? await this.models().itemResource().byItemId(item.id) : [];
|
||||||
|
@ -49,6 +49,7 @@ describe('api_items', function() {
|
|||||||
expect(item.jop_type).toBe(ModelType.Note);
|
expect(item.jop_type).toBe(ModelType.Note);
|
||||||
expect(!item.content).toBe(true);
|
expect(!item.content).toBe(true);
|
||||||
expect(item.content_size).toBeGreaterThan(0);
|
expect(item.content_size).toBeGreaterThan(0);
|
||||||
|
expect(item.owner_id).toBe(user.id);
|
||||||
|
|
||||||
{
|
{
|
||||||
const item: NoteEntity = await models().item().loadAsJoplinItem(itemId);
|
const item: NoteEntity = await models().item().loadAsJoplinItem(itemId);
|
||||||
|
@ -145,19 +145,6 @@ export interface ShareUser extends WithDates, WithUuid {
|
|||||||
status?: ShareUserStatus;
|
status?: ShareUserStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Item extends WithDates, WithUuid {
|
|
||||||
name?: string;
|
|
||||||
mime_type?: string;
|
|
||||||
content?: Buffer;
|
|
||||||
content_size?: number;
|
|
||||||
jop_id?: Uuid;
|
|
||||||
jop_parent_id?: Uuid;
|
|
||||||
jop_share_id?: Uuid;
|
|
||||||
jop_type?: number;
|
|
||||||
jop_encryption_applied?: number;
|
|
||||||
jop_updated_time?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserItem extends WithDates {
|
export interface UserItem extends WithDates {
|
||||||
id?: number;
|
id?: number;
|
||||||
user_id?: Uuid;
|
user_id?: Uuid;
|
||||||
@ -257,6 +244,20 @@ export interface Event extends WithUuid {
|
|||||||
created_time?: number;
|
created_time?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Item extends WithDates, WithUuid {
|
||||||
|
name?: string;
|
||||||
|
mime_type?: string;
|
||||||
|
content?: Buffer;
|
||||||
|
content_size?: number;
|
||||||
|
jop_id?: Uuid;
|
||||||
|
jop_parent_id?: Uuid;
|
||||||
|
jop_share_id?: Uuid;
|
||||||
|
jop_type?: number;
|
||||||
|
jop_encryption_applied?: number;
|
||||||
|
jop_updated_time?: number;
|
||||||
|
owner_id?: Uuid;
|
||||||
|
}
|
||||||
|
|
||||||
export const databaseSchema: DatabaseTables = {
|
export const databaseSchema: DatabaseTables = {
|
||||||
sessions: {
|
sessions: {
|
||||||
id: { type: 'string' },
|
id: { type: 'string' },
|
||||||
@ -307,21 +308,6 @@ export const databaseSchema: DatabaseTables = {
|
|||||||
updated_time: { type: 'string' },
|
updated_time: { type: 'string' },
|
||||||
created_time: { type: 'string' },
|
created_time: { type: 'string' },
|
||||||
},
|
},
|
||||||
items: {
|
|
||||||
id: { type: 'string' },
|
|
||||||
name: { type: 'string' },
|
|
||||||
mime_type: { type: 'string' },
|
|
||||||
updated_time: { type: 'string' },
|
|
||||||
created_time: { type: 'string' },
|
|
||||||
content: { type: 'any' },
|
|
||||||
content_size: { type: 'number' },
|
|
||||||
jop_id: { type: 'string' },
|
|
||||||
jop_parent_id: { type: 'string' },
|
|
||||||
jop_share_id: { type: 'string' },
|
|
||||||
jop_type: { type: 'number' },
|
|
||||||
jop_encryption_applied: { type: 'number' },
|
|
||||||
jop_updated_time: { type: 'string' },
|
|
||||||
},
|
|
||||||
user_items: {
|
user_items: {
|
||||||
id: { type: 'number' },
|
id: { type: 'number' },
|
||||||
user_id: { type: 'string' },
|
user_id: { type: 'string' },
|
||||||
@ -428,5 +414,21 @@ export const databaseSchema: DatabaseTables = {
|
|||||||
name: { type: 'string' },
|
name: { type: 'string' },
|
||||||
created_time: { type: 'string' },
|
created_time: { type: 'string' },
|
||||||
},
|
},
|
||||||
|
items: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
mime_type: { type: 'string' },
|
||||||
|
updated_time: { type: 'string' },
|
||||||
|
created_time: { type: 'string' },
|
||||||
|
content: { type: 'any' },
|
||||||
|
content_size: { type: 'number' },
|
||||||
|
jop_id: { type: 'string' },
|
||||||
|
jop_parent_id: { type: 'string' },
|
||||||
|
jop_share_id: { type: 'string' },
|
||||||
|
jop_type: { type: 'number' },
|
||||||
|
jop_encryption_applied: { type: 'number' },
|
||||||
|
jop_updated_time: { type: 'string' },
|
||||||
|
owner_id: { type: 'string' },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// AUTO-GENERATED-TYPES
|
// AUTO-GENERATED-TYPES
|
||||||
|
@ -67,6 +67,7 @@ export interface DatabaseConfig {
|
|||||||
asyncStackTraces?: boolean;
|
asyncStackTraces?: boolean;
|
||||||
slowQueryLogEnabled?: boolean;
|
slowQueryLogEnabled?: boolean;
|
||||||
slowQueryLogMinDuration?: number;
|
slowQueryLogMinDuration?: number;
|
||||||
|
autoMigration?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MailerConfig {
|
export interface MailerConfig {
|
||||||
|
Reference in New Issue
Block a user