Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 85 additions & 78 deletions src/user/picture.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,7 @@ const file = require('../file');
const image = require('../image');
const meta = require('../meta');

module.exports = function (User) {
User.getAllowedProfileImageExtensions = function () {
const exts = User.getAllowedImageTypes().map(type => mime.getExtension(type));
if (exts.includes('jpeg')) {
exts.push('jpg');
}
return exts;
};

User.getAllowedImageTypes = function () {
return ['image/png', 'image/jpeg', 'image/bmp', 'image/gif'];
};

function initCoverMethods(User) {
User.updateCoverPosition = async function (uid, position) {
// Reject anything that isn't two percentages
if (!/^[\d.]+%\s[\d.]+%$/.test(position)) {
Expand Down Expand Up @@ -52,7 +40,7 @@ module.exports = function (User) {
const filename = `${data.uid}-profilecover-${Date.now()}${extension}`;
const uploadData = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture);

await deleteCurrentPicture(data.uid, 'cover:url');
await deleteCurrentPicture(User, data.uid, 'cover:url');
await User.setUserField(data.uid, 'cover:url', uploadData.url);

if (data.position) {
Expand All @@ -66,7 +54,13 @@ module.exports = function (User) {
await file.delete(picture.path);
}
};
User.removeCoverPicture = async function (data) {
await deletePicture(User, data.uid, 'cover:url');
await db.deleteObjectFields(`user:${data.uid}`, ['cover:url', 'cover:position']);
};
}

function initProfileImageMethods(User) {
// uploads a image file as profile picture
User.uploadCroppedPictureFile = async function (data) {
const userPhoto = data.file;
Expand Down Expand Up @@ -102,15 +96,14 @@ module.exports = function (User) {
name: 'profileAvatar',
});

await deleteCurrentPicture(data.uid, 'uploadedpicture');
await deleteCurrentPicture(User, data.uid, 'uploadedpicture');
await User.updateProfile(data.callerUid, {
uid: data.uid,
uploadedpicture: uploadedImage.url,
picture: uploadedImage.url,
}, ['uploadedpicture', 'picture']);
return uploadedImage;
};

// uploads image data in base64 as profile picture
User.uploadCroppedPicture = async function (data) {
const picture = {
Expand Down Expand Up @@ -142,7 +135,7 @@ module.exports = function (User) {
const filename = generateProfileImageFilename(data.uid, extension);
const uploadedImage = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture);

await deleteCurrentPicture(data.uid, 'uploadedpicture');
await deleteCurrentPicture(User, data.uid, 'uploadedpicture');
await User.updateProfile(data.callerUid, {
uid: data.uid,
uploadedpicture: uploadedImage.url,
Expand All @@ -153,81 +146,95 @@ module.exports = function (User) {
await file.delete(picture.path);
}
};

async function deleteCurrentPicture(uid, field) {
if (meta.config['profile:keepAllUserImages']) {
return;
}
await deletePicture(uid, field);
}

async function deletePicture(uid, field) {
const uploadPath = await getPicturePath(uid, field);
if (uploadPath) {
await file.delete(uploadPath);
}
}

function validateUpload(data, maxSize, allowedTypes) {
if (!data.imageData) {
throw new Error('[[error:invalid-data]]');
}
const size = image.sizeFromBase64(data.imageData);
if (size > maxSize * 1024) {
throw new Error(`[[error:file-too-big, ${maxSize}]]`);
}

const type = image.mimeFromBase64(data.imageData);
if (!type || !allowedTypes.includes(type)) {
throw new Error('[[error:invalid-image]]');
}
}

async function convertToPNG(path) {
const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1;
if (!convertToPNG) {
return path;
}
const newPath = await image.normalise(path);
await file.delete(path);
return newPath;
}

function generateProfileImageFilename(uid, extension) {
const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1;
return `${uid}-profileavatar-${Date.now()}${convertToPNG ? '.png' : extension}`;
}

User.removeCoverPicture = async function (data) {
await deletePicture(data.uid, 'cover:url');
await db.deleteObjectFields(`user:${data.uid}`, ['cover:url', 'cover:position']);
};

User.removeProfileImage = async function (uid) {
const userData = await User.getUserFields(uid, ['uploadedpicture', 'picture']);
await deletePicture(uid, 'uploadedpicture');
await deletePicture(User, uid, 'uploadedpicture');
await User.setUserFields(uid, {
uploadedpicture: '',
// if current picture is uploaded picture, reset to user icon
picture: userData.uploadedpicture === userData.picture ? '' : userData.picture,
});
return userData;
};
}

function initGetters(User) {
User.getAllowedProfileImageExtensions = function () {
const exts = User.getAllowedImageTypes().map(type => mime.getExtension(type));
if (exts.includes('jpeg')) {
exts.push('jpg');
}
return exts;
};

User.getAllowedImageTypes = function () {
return ['image/png', 'image/jpeg', 'image/bmp', 'image/gif'];
};

User.getLocalCoverPath = async function (uid) {
return getPicturePath(uid, 'cover:url');
return getPicturePath(User, uid, 'cover:url');
};

User.getLocalAvatarPath = async function (uid) {
return getPicturePath(uid, 'uploadedpicture');
return getPicturePath(User, uid, 'uploadedpicture');
};
}

async function getPicturePath(uid, field) {
const value = await User.getUserField(uid, field);
if (!value || !value.startsWith(`${nconf.get('relative_path')}/assets/uploads/profile/uid-${uid}`)) {
return false;
}
const filename = value.split('/').pop();
return path.join(nconf.get('upload_path'), `profile/uid-${uid}`, filename);
function validateUpload(data, maxSize, allowedTypes) {
if (!data.imageData) {
throw new Error('[[error:invalid-data]]');
}
const size = image.sizeFromBase64(data.imageData);
if (size > maxSize * 1024) {
throw new Error(`[[error:file-too-big, ${maxSize}]]`);
}

const type = image.mimeFromBase64(data.imageData);
if (!type || !allowedTypes.includes(type)) {
throw new Error('[[error:invalid-image]]');
}
}
function generateProfileImageFilename(uid, extension) {
const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1;
return `${uid}-profileavatar-${Date.now()}${convertToPNG ? '.png' : extension}`;
}

async function getPicturePath(User, uid, field) {
const value = await User.getUserField(uid, field);
if (!value || !value.startsWith(`${nconf.get('relative_path')}/assets/uploads/profile/uid-${uid}`)) {
return false;
}
const filename = value.split('/').pop();
return path.join(nconf.get('upload_path'), `profile/uid-${uid}`, filename);
}


async function deleteCurrentPicture(User, uid, field) {
if (meta.config['profile:keepAllUserImages']) {
return;
}
await deletePicture(User, uid, field);
}

async function deletePicture(User, uid, field) {
const uploadPath = await getPicturePath(User, uid, field);
if (uploadPath) {
await file.delete(uploadPath);
}
};
}

async function convertToPNG(path) {
const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1;
if (!convertToPNG) {
return path;
}
const newPath = await image.normalise(path);
await file.delete(path);
return newPath;
}

module.exports = function (User) {
initGetters(User);
initCoverMethods(User);
initProfileImageMethods(User);
};