move profile icons into the database

This commit is contained in:
Girish Ramakrishnan
2021-04-29 12:49:48 -07:00
parent 7b8fd3596e
commit b8ea9de439
11 changed files with 117 additions and 82 deletions
-1
View File
@@ -42,7 +42,6 @@ exports = module.exports = {
// this is not part of appdata because an icon may be set before install
APP_ICONS_DIR: path.join(baseDir(), 'boxdata/appicons'),
PROFILE_ICONS_DIR: path.join(baseDir(), 'boxdata/profileicons'),
MAIL_DATA_DIR: path.join(baseDir(), 'boxdata/mail'),
SFTP_KEYS_DIR: path.join(baseDir(), 'boxdata/sftp/ssh'),
ACME_ACCOUNT_KEY_FILE: path.join(baseDir(), 'boxdata/acme/acme.key'),
+28 -16
View File
@@ -18,8 +18,9 @@ var assert = require('assert'),
BoxError = require('../boxerror.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
users = require('../users.js'),
safe = require('safetydance'),
settings = require('../settings.js'),
users = require('../users.js'),
_ = require('underscore');
function authorize(req, res, next) {
@@ -37,17 +38,21 @@ function authorize(req, res, next) {
function get(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
next(new HttpSuccess(200, {
id: req.user.id,
username: req.user.username,
email: req.user.email,
fallbackEmail: req.user.fallbackEmail,
displayName: req.user.displayName,
twoFactorAuthenticationEnabled: req.user.twoFactorAuthenticationEnabled,
role: req.user.role,
source: req.user.source,
avatarUrl: users.getAvatarUrlSync(req.user)
}));
users.getAvatarUrl(req.user, function (error, avatarUrl) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {
id: req.user.id,
username: req.user.username,
email: req.user.email,
fallbackEmail: req.user.fallbackEmail,
displayName: req.user.displayName,
twoFactorAuthenticationEnabled: req.user.twoFactorAuthenticationEnabled,
role: req.user.role,
source: req.user.source,
avatarUrl
}));
});
}
function update(req, res, next) {
@@ -72,7 +77,10 @@ function setAvatar(req, res, next) {
if (!req.files.avatar) return next(new HttpError(400, 'avatar is missing'));
users.setAvatar(req.user.id, req.files.avatar.path, function (error) {
const avatar = safe.fs.readFileSync(req.files.avatar.path);
if (!avatar) return next(BoxError.toHttpError(new BoxError(BoxError.FS_ERROR, safe.error.message)));
users.setAvatar(req.user.id, avatar, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
@@ -82,17 +90,21 @@ function setAvatar(req, res, next) {
function clearAvatar(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
users.clearAvatar(req.user.id, function (error) {
users.setAvatar(req.user.id, null, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
});
}
function getAvatar(req, res) {
function getAvatar(req, res, next) {
assert.strictEqual(typeof req.params.identifier, 'string');
res.sendFile(users.getAvatarFileSync(req.params.identifier));
users.getAvatar(req.params.identifier, function (error, avatar) {
if (error) return next(BoxError.toHttpError(error));
res.send(avatar);
});
}
function changePassword(req, res, next) {
+2 -2
View File
@@ -967,8 +967,8 @@ describe('Users API', function () {
expect(result.body.role).to.equal('user');
done();
});
});
});
});
});
});
});
-24
View File
@@ -11,8 +11,6 @@ exports = module.exports = {
createInvite,
sendInvite,
setGroups,
setAvatar,
clearAvatar,
makeOwner,
disableTwoFactorAuthentication,
@@ -210,28 +208,6 @@ function changePassword(req, res, next) {
});
}
function setAvatar(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
if (!req.files.avatar) return next(new HttpError(400, 'avatar is missing'));
users.setAvatar(req.resource.id, req.files.avatar.path, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
});
}
function clearAvatar(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
users.clearAvatar(req.resource.id, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
});
}
// This route transfers ownership from token user to user specified in path param
function makeOwner(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
-2
View File
@@ -178,8 +178,6 @@ function initializeExpressSync() {
router.post('/api/v1/users/:userId/make_owner', json, token, authorizeOwner, routes.users.load, routes.users.makeOwner);
router.post('/api/v1/users/:userId/send_invite', json, token, authorizeUserManager, routes.users.load, routes.users.sendInvite);
router.post('/api/v1/users/:userId/create_invite', json, token, authorizeUserManager, routes.users.load, routes.users.createInvite);
router.post('/api/v1/users/:userId/avatar', json, token, authorizeUserManager, routes.users.load, multipart, routes.users.setAvatar);
router.del ('/api/v1/users/:userId/avatar', token, authorizeUserManager, routes.users.load, routes.users.clearAvatar);
router.post('/api/v1/users/:userId/twofactorauthentication_disable', json, token, authorizeUserManager, routes.users.load, routes.users.disableTwoFactorAuthentication);
// Group management
+29 -5
View File
@@ -13,6 +13,8 @@ exports = module.exports = {
del,
update,
count,
getAvatar,
setAvatar,
addAppPassword,
getAppPasswords,
@@ -25,13 +27,13 @@ exports = module.exports = {
var assert = require('assert'),
BoxError = require('./boxerror.js'),
database = require('./database.js'),
debug = require('debug')('box:userdb'),
mysql = require('mysql');
var USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'createdAt', 'resetToken', 'displayName',
// the avatar field is special and not added here to reduce response sizes
const USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'createdAt', 'resetToken', 'displayName',
'twoFactorAuthenticationEnabled', 'twoFactorAuthenticationSecret', 'active', 'source', 'role', 'resetTokenCreationTime' ].join(',');
var APP_PASSWORD_FIELDS = [ 'id', 'name', 'userId', 'identifier', 'hashedPassword', 'creationTime' ].join(',');
const APP_PASSWORD_FIELDS = [ 'id', 'name', 'userId', 'identifier', 'hashedPassword', 'creationTime' ].join(',');
function postProcess(result) {
assert.strictEqual(typeof result, 'object');
@@ -209,8 +211,6 @@ function getByAccessToken(accessToken, callback) {
assert.strictEqual(typeof accessToken, 'string');
assert.strictEqual(typeof callback, 'function');
debug('getByAccessToken: ' + accessToken);
database.query('SELECT ' + USERS_FIELDS + ' FROM users, tokens WHERE tokens.accessToken = ?', [ accessToken ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'User not found'));
@@ -322,3 +322,27 @@ function delAppPassword(id, callback) {
});
}
function getAvatar(id, callback) {
assert.strictEqual(typeof id, 'string');
assert.strictEqual(typeof callback, 'function');
database.query('SELECT avatar FROM users WHERE id = ?', [ id ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'User not found'));
callback(null, result[0].avatar);
});
}
function setAvatar(id, avatar, callback) {
assert.strictEqual(typeof id, 'string');
assert(avatar === null || typeof Buffer.isBuffer(avatar));
assert.strictEqual(typeof callback, 'function');
database.query('UPDATE users SET avatar=? WHERE id = ?', [ avatar, id ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'User not found'));
callback(null);
});
}
+22 -29
View File
@@ -31,10 +31,9 @@ exports = module.exports = {
sendPasswordResetByIdentifier,
setupAccount,
getAvatarUrlSync,
getAvatarFileSync,
getAvatarUrl,
setAvatar,
clearAvatar,
getAvatar,
count,
@@ -62,11 +61,9 @@ let assert = require('assert'),
debug = require('debug')('box:user'),
eventlog = require('./eventlog.js'),
externalLdap = require('./externalldap.js'),
fs = require('fs'),
groups = require('./groups.js'),
hat = require('./hat.js'),
mailer = require('./mailer.js'),
path = require('path'),
paths = require('./paths.js'),
qrcode = require('qrcode'),
safe = require('safetydance'),
@@ -816,38 +813,34 @@ function delAppPassword(id, callback) {
});
}
function getAvatarFileSync(id) {
assert.strictEqual(typeof id, 'string');
return path.join(paths.PROFILE_ICONS_DIR, id);
}
function getAvatarUrlSync(user) {
function getAvatarUrl(user, callback) {
assert.strictEqual(typeof user, 'object');
if (fs.existsSync(path.join(paths.PROFILE_ICONS_DIR, user.id))) return `${settings.adminOrigin()}/api/v1/profile/avatar/${user.id}`;
const emailHash = require('crypto').createHash('md5').update(user.email).digest('hex');
return `https://www.gravatar.com/avatar/${emailHash}.jpg`;
}
function setAvatar(id, filename, callback) {
assert.strictEqual(typeof id, 'string');
assert.strictEqual(typeof filename, 'string');
assert.strictEqual(typeof callback, 'function');
// rename() was failing on some servers with EXDEV
fs.copyFile(filename, path.join(paths.PROFILE_ICONS_DIR, id), function (error) {
if (error) return callback(new BoxError(BoxError.FS_ERROR, error.message));
userdb.getAvatar(user.id, function (error, avatar) {
if (error) return callback(error);
if (avatar) return callback(null, `${settings.adminOrigin()}/api/v1/profile/avatar/${user.id}`);
fs.unlink(filename, () => callback()); // ignore any unlink error
const emailHash = require('crypto').createHash('md5').update(user.email).digest('hex');
return callback(null, `https://www.gravatar.com/avatar/${emailHash}.jpg`);
});
}
function clearAvatar(id, callback) {
function getAvatar(id, callback) {
assert.strictEqual(typeof id, 'string');
assert.strictEqual(typeof callback, 'function');
safe.fs.unlinkSync(path.join(paths.PROFILE_ICONS_DIR, id));
callback();
userdb.getAvatar(id, function (error, avatar) {
if (error) return callback(error);
return callback(null, avatar);
});
}
function setAvatar(id, avatar, callback) {
assert.strictEqual(typeof id, 'string');
assert(avatar === null || Buffer.isBuffer(avatar));
assert.strictEqual(typeof callback, 'function');
userdb.setAvatar(id, avatar, callback);
}