123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- import { ReactiveCache } from '/imports/reactiveCache';
- import { Meteor } from 'meteor/meteor';
- import { SimpleSchema } from 'meteor/aldeed:simple-schema';
- import { STORAGE_NAME_FILESYSTEM, STORAGE_NAME_GRIDFS, STORAGE_NAME_S3 } from '/models/lib/fileStoreStrategy';
- // Attachment Storage Settings Collection
- AttachmentStorageSettings = new Mongo.Collection('attachmentStorageSettings');
- // Schema for attachment storage settings
- AttachmentStorageSettings.attachSchema(
- new SimpleSchema({
- // Default storage backend for new uploads
- defaultStorage: {
- type: String,
- allowedValues: [STORAGE_NAME_FILESYSTEM, STORAGE_NAME_GRIDFS, STORAGE_NAME_S3],
- defaultValue: STORAGE_NAME_FILESYSTEM,
- label: 'Default Storage Backend'
- },
-
- // Storage backend configuration
- storageConfig: {
- type: Object,
- optional: true,
- label: 'Storage Configuration'
- },
-
- 'storageConfig.filesystem': {
- type: Object,
- optional: true,
- label: 'Filesystem Configuration'
- },
-
- 'storageConfig.filesystem.enabled': {
- type: Boolean,
- defaultValue: true,
- label: 'Filesystem Storage Enabled'
- },
-
- 'storageConfig.filesystem.path': {
- type: String,
- optional: true,
- label: 'Filesystem Storage Path'
- },
-
- 'storageConfig.gridfs': {
- type: Object,
- optional: true,
- label: 'GridFS Configuration'
- },
-
- 'storageConfig.gridfs.enabled': {
- type: Boolean,
- defaultValue: true,
- label: 'GridFS Storage Enabled'
- },
-
- 'storageConfig.s3': {
- type: Object,
- optional: true,
- label: 'S3 Configuration'
- },
-
- 'storageConfig.s3.enabled': {
- type: Boolean,
- defaultValue: false,
- label: 'S3 Storage Enabled'
- },
-
- 'storageConfig.s3.endpoint': {
- type: String,
- optional: true,
- label: 'S3 Endpoint'
- },
-
- 'storageConfig.s3.bucket': {
- type: String,
- optional: true,
- label: 'S3 Bucket'
- },
-
- 'storageConfig.s3.region': {
- type: String,
- optional: true,
- label: 'S3 Region'
- },
-
- 'storageConfig.s3.sslEnabled': {
- type: Boolean,
- defaultValue: true,
- label: 'S3 SSL Enabled'
- },
-
- 'storageConfig.s3.port': {
- type: Number,
- defaultValue: 443,
- label: 'S3 Port'
- },
-
- // Upload settings
- uploadSettings: {
- type: Object,
- optional: true,
- label: 'Upload Settings'
- },
-
- 'uploadSettings.maxFileSize': {
- type: Number,
- optional: true,
- label: 'Maximum File Size (bytes)'
- },
-
- 'uploadSettings.allowedMimeTypes': {
- type: Array,
- optional: true,
- label: 'Allowed MIME Types'
- },
-
- 'uploadSettings.allowedMimeTypes.$': {
- type: String,
- label: 'MIME Type'
- },
-
- // Migration settings
- migrationSettings: {
- type: Object,
- optional: true,
- label: 'Migration Settings'
- },
-
- 'migrationSettings.autoMigrate': {
- type: Boolean,
- defaultValue: false,
- label: 'Auto Migrate to Default Storage'
- },
-
- 'migrationSettings.batchSize': {
- type: Number,
- defaultValue: 10,
- min: 1,
- max: 100,
- label: 'Migration Batch Size'
- },
-
- 'migrationSettings.delayMs': {
- type: Number,
- defaultValue: 1000,
- min: 100,
- max: 10000,
- label: 'Migration Delay (ms)'
- },
-
- 'migrationSettings.cpuThreshold': {
- type: Number,
- defaultValue: 70,
- min: 10,
- max: 90,
- label: 'CPU Threshold (%)'
- },
-
- // Metadata
- createdAt: {
- type: Date,
- autoValue() {
- if (this.isInsert) {
- return new Date();
- } else if (this.isUpsert) {
- return { $setOnInsert: new Date() };
- } else {
- this.unset();
- }
- },
- label: 'Created At'
- },
-
- updatedAt: {
- type: Date,
- autoValue() {
- if (this.isUpdate || this.isUpsert) {
- return new Date();
- }
- },
- label: 'Updated At'
- },
-
- createdBy: {
- type: String,
- optional: true,
- label: 'Created By'
- },
-
- updatedBy: {
- type: String,
- optional: true,
- label: 'Updated By'
- }
- })
- );
- // Helper methods
- AttachmentStorageSettings.helpers({
- // Get default storage backend
- getDefaultStorage() {
- return this.defaultStorage || STORAGE_NAME_FILESYSTEM;
- },
-
- // Check if storage backend is enabled
- isStorageEnabled(storageName) {
- if (!this.storageConfig) return false;
-
- switch (storageName) {
- case STORAGE_NAME_FILESYSTEM:
- return this.storageConfig.filesystem?.enabled !== false;
- case STORAGE_NAME_GRIDFS:
- return this.storageConfig.gridfs?.enabled !== false;
- case STORAGE_NAME_S3:
- return this.storageConfig.s3?.enabled === true;
- default:
- return false;
- }
- },
-
- // Get storage configuration
- getStorageConfig(storageName) {
- if (!this.storageConfig) return null;
-
- switch (storageName) {
- case STORAGE_NAME_FILESYSTEM:
- return this.storageConfig.filesystem;
- case STORAGE_NAME_GRIDFS:
- return this.storageConfig.gridfs;
- case STORAGE_NAME_S3:
- return this.storageConfig.s3;
- default:
- return null;
- }
- },
-
- // Get upload settings
- getUploadSettings() {
- return this.uploadSettings || {};
- },
-
- // Get migration settings
- getMigrationSettings() {
- return this.migrationSettings || {};
- }
- });
- // Server-side methods
- if (Meteor.isServer) {
- // Get or create default settings
- Meteor.methods({
- 'getAttachmentStorageSettings'() {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized', 'Must be logged in');
- }
- const user = ReactiveCache.getUser(this.userId);
- if (!user || !user.isAdmin) {
- throw new Meteor.Error('not-authorized', 'Admin access required');
- }
- let settings = AttachmentStorageSettings.findOne({});
-
- if (!settings) {
- // Create default settings
- settings = {
- defaultStorage: STORAGE_NAME_FILESYSTEM,
- storageConfig: {
- filesystem: {
- enabled: true,
- path: process.env.WRITABLE_PATH ? `${process.env.WRITABLE_PATH}/attachments` : '/data/attachments'
- },
- gridfs: {
- enabled: true
- },
- s3: {
- enabled: false
- }
- },
- uploadSettings: {
- maxFileSize: process.env.ATTACHMENTS_UPLOAD_MAX_SIZE ? parseInt(process.env.ATTACHMENTS_UPLOAD_MAX_SIZE) : 0,
- allowedMimeTypes: process.env.ATTACHMENTS_UPLOAD_MIME_TYPES ? process.env.ATTACHMENTS_UPLOAD_MIME_TYPES.split(',').map(t => t.trim()) : []
- },
- migrationSettings: {
- autoMigrate: false,
- batchSize: 10,
- delayMs: 1000,
- cpuThreshold: 70
- },
- createdBy: this.userId,
- updatedBy: this.userId
- };
-
- AttachmentStorageSettings.insert(settings);
- settings = AttachmentStorageSettings.findOne({});
- }
-
- return settings;
- },
-
- 'updateAttachmentStorageSettings'(settings) {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized', 'Must be logged in');
- }
- const user = ReactiveCache.getUser(this.userId);
- if (!user || !user.isAdmin) {
- throw new Meteor.Error('not-authorized', 'Admin access required');
- }
- // Validate settings
- const schema = AttachmentStorageSettings.simpleSchema();
- schema.validate(settings);
-
- // Update settings
- const result = AttachmentStorageSettings.upsert(
- {},
- {
- $set: {
- ...settings,
- updatedBy: this.userId,
- updatedAt: new Date()
- }
- }
- );
-
- return result;
- },
-
- 'getDefaultAttachmentStorage'() {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized', 'Must be logged in');
- }
- const settings = AttachmentStorageSettings.findOne({});
- return settings ? settings.getDefaultStorage() : STORAGE_NAME_FILESYSTEM;
- },
-
- 'setDefaultAttachmentStorage'(storageName) {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized', 'Must be logged in');
- }
- const user = ReactiveCache.getUser(this.userId);
- if (!user || !user.isAdmin) {
- throw new Meteor.Error('not-authorized', 'Admin access required');
- }
- if (![STORAGE_NAME_FILESYSTEM, STORAGE_NAME_GRIDFS, STORAGE_NAME_S3].includes(storageName)) {
- throw new Meteor.Error('invalid-storage', 'Invalid storage backend');
- }
- const result = AttachmentStorageSettings.upsert(
- {},
- {
- $set: {
- defaultStorage: storageName,
- updatedBy: this.userId,
- updatedAt: new Date()
- }
- }
- );
-
- return result;
- }
- });
- // Publication for settings
- Meteor.publish('attachmentStorageSettings', function() {
- if (!this.userId) {
- return this.ready();
- }
- const user = ReactiveCache.getUser(this.userId);
- if (!user || !user.isAdmin) {
- return this.ready();
- }
- return AttachmentStorageSettings.find({});
- });
- }
- export default AttachmentStorageSettings;
|