123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- import { ReactiveCache } from '/imports/reactiveCache';
- import { Meteor } from 'meteor/meteor';
- import { MongoInternals } from 'meteor/mongo';
- /**
- * Backward compatibility layer for CollectionFS to Meteor-Files migration
- * Handles reading attachments from old CollectionFS database structure
- */
- // Old CollectionFS collections
- const OldAttachmentsFiles = new Mongo.Collection('cfs_gridfs.attachments.files');
- const OldAttachmentsFileRecord = new Mongo.Collection('cfs.attachments.filerecord');
- /**
- * Check if an attachment exists in the new Meteor-Files structure
- * @param {string} attachmentId - The attachment ID to check
- * @returns {boolean} - True if exists in new structure
- */
- export function isNewAttachmentStructure(attachmentId) {
- if (Meteor.isServer) {
- return !!ReactiveCache.getAttachment(attachmentId);
- }
- return false;
- }
- /**
- * Get attachment data from old CollectionFS structure
- * @param {string} attachmentId - The attachment ID
- * @returns {Object|null} - Attachment data in new format or null if not found
- */
- export function getOldAttachmentData(attachmentId) {
- if (Meteor.isServer) {
- try {
- // First try to get from old filerecord collection
- const fileRecord = OldAttachmentsFileRecord.findOne({ _id: attachmentId });
- if (!fileRecord) {
- return null;
- }
- // Get file data from old files collection
- const fileData = OldAttachmentsFiles.findOne({ _id: attachmentId });
- if (!fileData) {
- return null;
- }
- // Convert old structure to new structure
- const convertedAttachment = {
- _id: attachmentId,
- name: fileRecord.original?.name || fileData.filename || 'Unknown',
- size: fileRecord.original?.size || fileData.length || 0,
- type: fileRecord.original?.type || fileData.contentType || 'application/octet-stream',
- extension: getFileExtension(fileRecord.original?.name || fileData.filename || ''),
- extensionWithDot: getFileExtensionWithDot(fileRecord.original?.name || fileData.filename || ''),
- meta: {
- boardId: fileRecord.boardId,
- swimlaneId: fileRecord.swimlaneId,
- listId: fileRecord.listId,
- cardId: fileRecord.cardId,
- userId: fileRecord.userId,
- source: 'legacy'
- },
- uploadedAt: fileRecord.uploadedAt || fileData.uploadDate || new Date(),
- updatedAt: fileRecord.original?.updatedAt || fileData.uploadDate || new Date(),
- // Legacy compatibility fields
- isImage: isImageFile(fileRecord.original?.type || fileData.contentType),
- isVideo: isVideoFile(fileRecord.original?.type || fileData.contentType),
- isAudio: isAudioFile(fileRecord.original?.type || fileData.contentType),
- isText: isTextFile(fileRecord.original?.type || fileData.contentType),
- isJSON: isJSONFile(fileRecord.original?.type || fileData.contentType),
- isPDF: isPDFFile(fileRecord.original?.type || fileData.contentType),
- // Legacy link method for compatibility
- link: function(version = 'original') {
- return `/cfs/files/attachments/${this._id}`;
- },
- // Legacy versions structure for compatibility
- versions: {
- original: {
- path: `/cfs/files/attachments/${this._id}`,
- size: this.size,
- type: this.type,
- storage: 'gridfs'
- }
- }
- };
- return convertedAttachment;
- } catch (error) {
- console.error('Error reading old attachment data:', error);
- return null;
- }
- }
- return null;
- }
- /**
- * Get file extension from filename
- * @param {string} filename - The filename
- * @returns {string} - File extension without dot
- */
- function getFileExtension(filename) {
- if (!filename) return '';
- const lastDot = filename.lastIndexOf('.');
- if (lastDot === -1) return '';
- return filename.substring(lastDot + 1).toLowerCase();
- }
- /**
- * Get file extension with dot
- * @param {string} filename - The filename
- * @returns {string} - File extension with dot
- */
- function getFileExtensionWithDot(filename) {
- const ext = getFileExtension(filename);
- return ext ? `.${ext}` : '';
- }
- /**
- * Check if file is an image
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if image
- */
- function isImageFile(mimeType) {
- return mimeType && mimeType.startsWith('image/');
- }
- /**
- * Check if file is a video
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if video
- */
- function isVideoFile(mimeType) {
- return mimeType && mimeType.startsWith('video/');
- }
- /**
- * Check if file is audio
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if audio
- */
- function isAudioFile(mimeType) {
- return mimeType && mimeType.startsWith('audio/');
- }
- /**
- * Check if file is text
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if text
- */
- function isTextFile(mimeType) {
- return mimeType && mimeType.startsWith('text/');
- }
- /**
- * Check if file is JSON
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if JSON
- */
- function isJSONFile(mimeType) {
- return mimeType === 'application/json';
- }
- /**
- * Check if file is PDF
- * @param {string} mimeType - MIME type
- * @returns {boolean} - True if PDF
- */
- function isPDFFile(mimeType) {
- return mimeType === 'application/pdf';
- }
- /**
- * Get attachment with backward compatibility
- * @param {string} attachmentId - The attachment ID
- * @returns {Object|null} - Attachment data or null if not found
- */
- export function getAttachmentWithBackwardCompatibility(attachmentId) {
- // First try new structure
- if (isNewAttachmentStructure(attachmentId)) {
- return ReactiveCache.getAttachment(attachmentId);
- }
- // Fall back to old structure
- return getOldAttachmentData(attachmentId);
- }
- /**
- * Get attachments for a card with backward compatibility
- * @param {Object} query - Query object
- * @returns {Array} - Array of attachments
- */
- export function getAttachmentsWithBackwardCompatibility(query) {
- const newAttachments = ReactiveCache.getAttachments(query);
- const oldAttachments = [];
- if (Meteor.isServer) {
- try {
- // Query old structure for the same card
- const cardId = query['meta.cardId'];
- if (cardId) {
- const oldFileRecords = OldAttachmentsFileRecord.find({ cardId }).fetch();
- for (const fileRecord of oldFileRecords) {
- const oldAttachment = getOldAttachmentData(fileRecord._id);
- if (oldAttachment) {
- oldAttachments.push(oldAttachment);
- }
- }
- }
- } catch (error) {
- console.error('Error reading old attachments:', error);
- }
- }
- // Combine and deduplicate
- const allAttachments = [...newAttachments, ...oldAttachments];
- const uniqueAttachments = allAttachments.filter((attachment, index, self) =>
- index === self.findIndex(a => a._id === attachment._id)
- );
- return uniqueAttachments;
- }
- /**
- * Get file stream from old GridFS structure
- * @param {string} attachmentId - The attachment ID
- * @returns {Object|null} - GridFS file stream or null if not found
- */
- export function getOldAttachmentStream(attachmentId) {
- if (Meteor.isServer) {
- try {
- const db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
- const bucket = new MongoInternals.NpmModule.GridFSBucket(db, {
- bucketName: 'cfs_gridfs.attachments'
- });
- const downloadStream = bucket.openDownloadStreamByName(attachmentId);
- return downloadStream;
- } catch (error) {
- console.error('Error creating GridFS stream:', error);
- return null;
- }
- }
- return null;
- }
- /**
- * Get file data from old GridFS structure
- * @param {string} attachmentId - The attachment ID
- * @returns {Buffer|null} - File data buffer or null if not found
- */
- export function getOldAttachmentDataBuffer(attachmentId) {
- if (Meteor.isServer) {
- try {
- const db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
- const bucket = new MongoInternals.NpmModule.GridFSBucket(db, {
- bucketName: 'cfs_gridfs.attachments'
- });
- return new Promise((resolve, reject) => {
- const chunks = [];
- const downloadStream = bucket.openDownloadStreamByName(attachmentId);
- downloadStream.on('data', (chunk) => {
- chunks.push(chunk);
- });
- downloadStream.on('end', () => {
- resolve(Buffer.concat(chunks));
- });
- downloadStream.on('error', (error) => {
- reject(error);
- });
- });
- } catch (error) {
- console.error('Error reading GridFS data:', error);
- return null;
- }
- }
- return null;
- }
|