mirror of
https://github.com/wekan/wekan.git
synced 2025-09-22 01:50:48 +02:00
Ref: original & and use fileObj.meta
fileObj.meta is part of the ostrio:files API and be passed to the constructor. This is less hacky than trying tu update a persistet object after the fact.
This commit is contained in:
parent
16506e7a6a
commit
e702f17c7b
10 changed files with 124 additions and 159 deletions
|
@ -67,19 +67,19 @@ Template.cardAttachmentsPopup.events({
|
||||||
const uploader = Attachments.insert(
|
const uploader = Attachments.insert(
|
||||||
{
|
{
|
||||||
file: event.currentTarget.files[0],
|
file: event.currentTarget.files[0],
|
||||||
|
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||||
chunkSize: 'dynamic',
|
chunkSize: 'dynamic',
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
uploader.on('uploaded', (error, fileObj) => {
|
uploader.on('uploaded', (error, fileRef) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (fileObj.isImage) {
|
if (fileRef.isImage) {
|
||||||
card.setCover(fileObj._id);
|
card.setCover(fileRef._id);
|
||||||
}
|
}
|
||||||
Utils.addCommonMetaToAttachment(card, fileObj);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
uploader.on('end', (error, fileObj) => {
|
uploader.on('end', (error, fileRef) => {
|
||||||
Popup.back();
|
Popup.back();
|
||||||
});
|
});
|
||||||
uploader.start();
|
uploader.start();
|
||||||
|
@ -131,28 +131,27 @@ Template.previewClipboardImagePopup.onRendered(() => {
|
||||||
|
|
||||||
Template.previewClipboardImagePopup.events({
|
Template.previewClipboardImagePopup.events({
|
||||||
'click .js-upload-pasted-image'() {
|
'click .js-upload-pasted-image'() {
|
||||||
const results = pastedResults;
|
const card = this;
|
||||||
if (results && results.file) {
|
if (pastedResults && pastedResults.file) {
|
||||||
|
const file = pastedResults.file;
|
||||||
window.oPasted = pastedResults;
|
window.oPasted = pastedResults;
|
||||||
const card = this;
|
|
||||||
const uploader = Attachments.insert(
|
const uploader = Attachments.insert(
|
||||||
{
|
{
|
||||||
file: results.file,
|
file,
|
||||||
fileName:
|
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||||
results.name || results.file.type.replace('image/', 'clipboard.'),
|
fileName: file.name || file.type.replace('image/', 'clipboard.'),
|
||||||
chunkSize: 'dynamic',
|
chunkSize: 'dynamic',
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
uploader.on('uploaded', (error, fileObj) => {
|
uploader.on('uploaded', (error, fileRef) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (fileObj.isImage) {
|
if (fileRef.isImage) {
|
||||||
card.setCover(fileObj._id);
|
card.setCover(fileRef._id);
|
||||||
}
|
}
|
||||||
Utils.addCommonMetaToAttachment(card, fileObj);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
uploader.on('end', (error, fileObj) => {
|
uploader.on('end', (error, fileRef) => {
|
||||||
pastedResults = null;
|
pastedResults = null;
|
||||||
$(document.body).pasteImageReader(() => {});
|
$(document.body).pasteImageReader(() => {});
|
||||||
Popup.back();
|
Popup.back();
|
||||||
|
|
|
@ -160,28 +160,23 @@ BlazeComponent.extendComponent({
|
||||||
const currentCard = Utils.getCurrentCard();
|
const currentCard = Utils.getCurrentCard();
|
||||||
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
||||||
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
||||||
const insertImage = src => {
|
|
||||||
const img = document.createElement('img');
|
|
||||||
img.src = src;
|
|
||||||
img.setAttribute('width', '100%');
|
|
||||||
$summernote.summernote('insertNode', img);
|
|
||||||
};
|
|
||||||
const processUpload = function(file) {
|
const processUpload = function(file) {
|
||||||
const uploader = Attachments.insert(
|
const uploader = Attachments.insert(
|
||||||
{
|
{
|
||||||
file,
|
file,
|
||||||
|
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||||
chunkSize: 'dynamic',
|
chunkSize: 'dynamic',
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
uploader.on('uploaded', (error, fileObj) => {
|
uploader.on('uploaded', (error, fileRef) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (fileObj.isImage) {
|
if (fileRef.isImage) {
|
||||||
insertImage(
|
const img = document.createElement('img');
|
||||||
`${location.protocol}//${location.host}${fileObj.path}`,
|
img.src = fileRef.link();
|
||||||
);
|
img.setAttribute('width', '100%');
|
||||||
|
$summernote.summernote('insertNode', img);
|
||||||
}
|
}
|
||||||
Utils.addCommonMetaToAttachment(currentCard, fileObj);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
uploader.start();
|
uploader.start();
|
||||||
|
|
|
@ -93,7 +93,7 @@ template(name="changeAvatarPopup")
|
||||||
unless isSelected
|
unless isSelected
|
||||||
a.js-delete-avatar {{_ 'delete'}}
|
a.js-delete-avatar {{_ 'delete'}}
|
||||||
| -
|
| -
|
||||||
= original.name
|
= name
|
||||||
li: a.js-select-initials
|
li: a.js-select-initials
|
||||||
.member
|
.member
|
||||||
+userAvatarInitials(userId=currentUser._id)
|
+userAvatarInitials(userId=currentUser._id)
|
||||||
|
|
|
@ -229,13 +229,13 @@ BlazeComponent.extendComponent({
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
uploader.on('uploaded', (error, fileObj) => {
|
uploader.on('uploaded', (error, fileRef) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
self.setAvatar(fileObj.path);
|
self.setAvatar(fileRef.path);
|
||||||
// self.setAvatar(this.currentData().url(this.avatarUrlOptions()));
|
// self.setAvatar(this.currentData().url(this.avatarUrlOptions()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
uploader.on('error', (error, fileObj) => {
|
uploader.on('error', (error, fileData) => {
|
||||||
// XXX check for actually returned error
|
// XXX check for actually returned error
|
||||||
self.setError('avatar-too-big');
|
self.setError('avatar-too-big');
|
||||||
});
|
});
|
||||||
|
|
|
@ -162,23 +162,21 @@ Utils = {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
getCommonAttachmentMetaFrom(card) {
|
||||||
|
let meta;
|
||||||
|
if (card.isLinkedCard()) {
|
||||||
|
meta.boardId = Cards.findOne(card.linkedId).boardId;
|
||||||
|
meta.cardId = card.linkedId;
|
||||||
|
} else {
|
||||||
|
meta.boardId = card.boardId;
|
||||||
|
meta.swimlaneId = card.swimlaneId;
|
||||||
|
meta.listId = card.listId;
|
||||||
|
meta.cardId = card._id;
|
||||||
|
}
|
||||||
|
return meta;
|
||||||
|
},
|
||||||
MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
|
MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
|
||||||
COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO,
|
COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO,
|
||||||
addCommonMetaToAttachment(card, file) {
|
|
||||||
if (card.isLinkedCard()) {
|
|
||||||
file.boardId = Cards.findOne(card.linkedId).boardId;
|
|
||||||
file.cardId = card.linkedId;
|
|
||||||
} else {
|
|
||||||
file.boardId = card.boardId;
|
|
||||||
file.swimlaneId = card.swimlaneId;
|
|
||||||
file.listId = card.listId;
|
|
||||||
file.cardId = card._id;
|
|
||||||
}
|
|
||||||
file.userId = Meteor.userId();
|
|
||||||
if (file.original) {
|
|
||||||
file.original.name = file.name;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
shrinkImage(options) {
|
shrinkImage(options) {
|
||||||
// shrink image to certain size
|
// shrink image to certain size
|
||||||
const dataurl = options.dataurl,
|
const dataurl = options.dataurl,
|
||||||
|
|
|
@ -242,7 +242,7 @@ if (Meteor.isServer) {
|
||||||
}
|
}
|
||||||
if (activity.attachmentId) {
|
if (activity.attachmentId) {
|
||||||
const attachment = activity.attachment();
|
const attachment = activity.attachment();
|
||||||
params.attachment = attachment.original.name;
|
params.attachment = attachment.name;
|
||||||
params.attachmentId = attachment._id;
|
params.attachmentId = attachment._id;
|
||||||
}
|
}
|
||||||
if (activity.checklistId) {
|
if (activity.checklistId) {
|
||||||
|
|
|
@ -7,6 +7,21 @@ import { createOnAfterRemove } from './lib/fsHooks/createOnAfterRemove';
|
||||||
|
|
||||||
const attachmentBucket = createBucket('attachments');
|
const attachmentBucket = createBucket('attachments');
|
||||||
|
|
||||||
|
const insertActivity = (fileObj, activityType) =>
|
||||||
|
Activities.insert({
|
||||||
|
userId: fileObj.userId,
|
||||||
|
type: 'card',
|
||||||
|
activityType,
|
||||||
|
attachmentId: fileObj._id,
|
||||||
|
// this preserves the name so that notifications can be meaningful after
|
||||||
|
// this file is removed
|
||||||
|
attachmentName: fileObj.name,
|
||||||
|
boardId: fileObj.meta.boardId,
|
||||||
|
cardId: fileObj.meta.cardId,
|
||||||
|
listId: fileObj.meta.listId,
|
||||||
|
swimlaneId: fileObj.meta.swimlaneId,
|
||||||
|
});
|
||||||
|
|
||||||
// XXX Enforce a schema for the Attachments FilesCollection
|
// XXX Enforce a schema for the Attachments FilesCollection
|
||||||
// see: https://github.com/VeliovGroup/Meteor-Files/wiki/Schema
|
// see: https://github.com/VeliovGroup/Meteor-Files/wiki/Schema
|
||||||
|
|
||||||
|
@ -14,84 +29,46 @@ export const Attachments = new FilesCollection({
|
||||||
debug: false, // Change to `true` for debugging
|
debug: false, // Change to `true` for debugging
|
||||||
collectionName: 'attachments',
|
collectionName: 'attachments',
|
||||||
allowClientCode: false,
|
allowClientCode: false,
|
||||||
onAfterUpload(doc) {
|
onAfterUpload(fileRef) {
|
||||||
|
createOnAfterUpload(attachmentBucket)(fileRef);
|
||||||
// If the attachment doesn't have a source field
|
// If the attachment doesn't have a source field
|
||||||
// or its source is different than import
|
// or its source is different than import
|
||||||
if (!doc.source || doc.source !== 'import') {
|
if (!fileRef.meta.source || fileRef.meta.source !== 'import') {
|
||||||
// Add activity about adding the attachment
|
// Add activity about adding the attachment
|
||||||
Activities.insert({
|
insertActivity(fileRef, 'addAttachment');
|
||||||
userId,
|
|
||||||
type: 'card',
|
|
||||||
activityType: 'addAttachment',
|
|
||||||
attachmentId: doc._id,
|
|
||||||
// this preserves the name so that notifications can be meaningful after
|
|
||||||
// this file is removed
|
|
||||||
attachmentName: doc.original.name,
|
|
||||||
boardId: doc.boardId,
|
|
||||||
cardId: doc.cardId,
|
|
||||||
listId: doc.listId,
|
|
||||||
swimlaneId: doc.swimlaneId,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Don't add activity about adding the attachment as the activity
|
|
||||||
// be imported and delete source field
|
|
||||||
Attachments.update(
|
|
||||||
{
|
|
||||||
_id: doc._id,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$unset: {
|
|
||||||
source: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
createOnAfterUpload(attachmentBucket)(doc);
|
|
||||||
},
|
},
|
||||||
interceptDownload: createInterceptDownload(attachmentBucket),
|
interceptDownload: createInterceptDownload(attachmentBucket),
|
||||||
onAfterRemove(docs) {
|
onAfterRemove(files) {
|
||||||
docs.forEach(function(doc) {
|
createOnAfterRemove(attachmentBucket)(files);
|
||||||
Activities.insert({
|
files.forEach(fileObj => {
|
||||||
userId: doc.userId,
|
insertActivity(fileObj, 'deleteAttachment');
|
||||||
type: 'card',
|
|
||||||
activityType: 'deleteAttachment',
|
|
||||||
attachmentId: doc._id,
|
|
||||||
// this preserves the name so that notifications can be meaningful after
|
|
||||||
// this file is removed
|
|
||||||
attachmentName: doc.original.name,
|
|
||||||
boardId: doc.boardId,
|
|
||||||
cardId: doc.cardId,
|
|
||||||
listId: doc.listId,
|
|
||||||
swimlaneId: doc.swimlaneId,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
createOnAfterRemove(attachmentBucket)(docs);
|
|
||||||
},
|
},
|
||||||
// We authorize the attachment download either:
|
// We authorize the attachment download either:
|
||||||
// - if the board is public, everyone (even unconnected) can download it
|
// - if the board is public, everyone (even unconnected) can download it
|
||||||
// - if the board is private, only board members can download it
|
// - if the board is private, only board members can download it
|
||||||
downloadCallback(doc) {
|
protected(fileObj) {
|
||||||
const board = Boards.findOne(doc.boardId);
|
const board = Boards.findOne(fileObj.meta.boardId);
|
||||||
if (board.isPublic()) {
|
if (board.isPublic()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return board.hasMember(this.userId);
|
|
||||||
}
|
}
|
||||||
|
return board.hasMember(this.userId);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Meteor.isServer) {
|
if (Meteor.isServer) {
|
||||||
Attachments.allow({
|
Attachments.allow({
|
||||||
insert(userId, doc) {
|
insert(userId, fileObj) {
|
||||||
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
return allowIsBoardMember(userId, Boards.findOne(fileObj.boardId));
|
||||||
},
|
},
|
||||||
update(userId, doc) {
|
update(userId, fileObj) {
|
||||||
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
return allowIsBoardMember(userId, Boards.findOne(fileObj.boardId));
|
||||||
},
|
},
|
||||||
remove(userId, doc) {
|
remove(userId, fileObj) {
|
||||||
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
return allowIsBoardMember(userId, Boards.findOne(fileObj.boardId));
|
||||||
},
|
},
|
||||||
fetch: ['boardId'],
|
fetch: ['meta'],
|
||||||
});
|
});
|
||||||
|
|
||||||
Meteor.startup(() => {
|
Meteor.startup(() => {
|
||||||
|
|
|
@ -78,11 +78,11 @@ export class Exporter {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_id: attachment._id,
|
_id: attachment._id,
|
||||||
cardId: attachment.cardId,
|
cardId: attachment.meta.cardId,
|
||||||
//url: FlowRouter.url(attachment.url()),
|
//url: FlowRouter.url(attachment.url()),
|
||||||
file: filebase64,
|
file: filebase64,
|
||||||
name: attachment.original.name,
|
name: attachment.name,
|
||||||
type: attachment.original.type,
|
type: attachment.type,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
//When has a especific valid attachment return the single element
|
//When has a especific valid attachment return the single element
|
||||||
|
@ -209,7 +209,7 @@ export class Exporter {
|
||||||
delimiter: userDelimiter,
|
delimiter: userDelimiter,
|
||||||
header: true,
|
header: true,
|
||||||
newline: "\r\n",
|
newline: "\r\n",
|
||||||
skipEmptyLines: false,
|
skipEmptyLines: false,
|
||||||
escapeFormulae: true,
|
escapeFormulae: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -422,35 +422,33 @@ export class TrelloCreator {
|
||||||
}
|
}
|
||||||
const attachments = this.attachments[card.id];
|
const attachments = this.attachments[card.id];
|
||||||
const trelloCoverId = card.idAttachmentCover;
|
const trelloCoverId = card.idAttachmentCover;
|
||||||
// Simulating file.attachData on the client generates multiple errors
|
|
||||||
// - HEAD returns null, which causes exception down the line
|
|
||||||
// - the template then tries to display the url to the attachment which causes other errors
|
|
||||||
// so we make it server only, and let UI catch up once it is done, forget about latency comp.
|
|
||||||
if (attachments && Meteor.isServer) {
|
if (attachments && Meteor.isServer) {
|
||||||
attachments.forEach(att => {
|
attachments.forEach(att => {
|
||||||
// Simulating file.attachData on the client generates multiple errors
|
|
||||||
// - HEAD returns null, which causes exception down the line
|
|
||||||
// - the template then tries to display the url to the attachment which causes other errors
|
|
||||||
// so we make it server only, and let UI catch up once it is done, forget about latency comp.
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const opts = {
|
||||||
|
type: att.type ? att.type : undefined,
|
||||||
|
userId: self._user(att.userId),
|
||||||
|
meta: {
|
||||||
|
boardId,
|
||||||
|
cardId,
|
||||||
|
source: 'import',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const cb = (error, fileObj) => {
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
self.attachmentIds[att._id] = fileObj._id;
|
||||||
|
if (trelloCoverId === att._id) {
|
||||||
|
Cards.direct.update(cardId, {
|
||||||
|
$set: { coverId: fileObj._id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
if (att.url) {
|
if (att.url) {
|
||||||
Attachment.load(att.url, (error, fileObj) => {
|
Attachment.load(att.url, opts, cb, true);
|
||||||
if (error) {
|
} else if (att.file) {
|
||||||
throw error;
|
Attachment.write(att.file, opts, cb, true);
|
||||||
}
|
|
||||||
fileObj.boardId = boardId;
|
|
||||||
fileObj.cardId = cardId;
|
|
||||||
fileObj.userId = self._user(att.userId);
|
|
||||||
// The field source will only be used to prevent adding
|
|
||||||
// attachments' related activities automatically
|
|
||||||
fileObj.source = 'import';
|
|
||||||
self.attachmentIds[att._id] = fileObj._id;
|
|
||||||
if (trelloCoverId === att.id) {
|
|
||||||
Cards.direct.update(cardId, {
|
|
||||||
$set: { coverId: fileObj._id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -446,33 +446,31 @@ export class WekanCreator {
|
||||||
const wekanCoverId = card.coverId;
|
const wekanCoverId = card.coverId;
|
||||||
if (attachments && Meteor.isServer) {
|
if (attachments && Meteor.isServer) {
|
||||||
attachments.forEach(att => {
|
attachments.forEach(att => {
|
||||||
// Simulating file.attachData on the client generates multiple errors
|
|
||||||
// - HEAD returns null, which causes exception down the line
|
|
||||||
// - the template then tries to display the url to the attachment which causes other errors
|
|
||||||
// so we make it server only, and let UI catch up once it is done, forget about latency comp.
|
|
||||||
const self = this;
|
const self = this;
|
||||||
if (att.url || att.file) {
|
const opts = {
|
||||||
Attachment.load(
|
type: att.type ? att.type : undefined,
|
||||||
att.url ? att.url : Buffer.from(att.file, 'base64'),
|
userId: self._user(att.userId),
|
||||||
{ type: att.type ? att.ype : undefined },
|
meta: {
|
||||||
(error, fileObj) => {
|
boardId,
|
||||||
if (error) {
|
cardId,
|
||||||
throw error;
|
source: 'import',
|
||||||
}
|
},
|
||||||
fileObj.boardId = boardId;
|
};
|
||||||
fileObj.cardId = cardId;
|
const cb = (error, fileObj) => {
|
||||||
fileObj.userId = self._user(att.userId);
|
if (error) {
|
||||||
// The field source will only be used to prevent adding
|
throw error;
|
||||||
// attachments' related activities automatically
|
}
|
||||||
fileObj.source = 'import';
|
self.attachmentIds[att._id] = fileObj._id;
|
||||||
self.attachmentIds[att._id] = fileObj._id;
|
if (wekanCoverId === att._id) {
|
||||||
if (wekanCoverId === att._id) {
|
Cards.direct.update(cardId, {
|
||||||
Cards.direct.update(cardId, {
|
$set: { coverId: fileObj._id },
|
||||||
$set: { coverId: fileObj._id },
|
});
|
||||||
});
|
}
|
||||||
}
|
};
|
||||||
},
|
if (att.url) {
|
||||||
);
|
Attachment.load(att.url, opts, cb, true);
|
||||||
|
} else if (att.file) {
|
||||||
|
Attachment.write(att.file, opts, cb, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue