mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 05:09:43 +02:00
support project background + user avatar
This commit is contained in:
parent
84b0f91b44
commit
e84a2837ab
13 changed files with 223 additions and 46 deletions
|
@ -82,12 +82,12 @@ services:
|
||||||
# - TELEGRAM_THREAD_ID=
|
# - TELEGRAM_THREAD_ID=
|
||||||
|
|
||||||
# Attachments S3
|
# Attachments S3
|
||||||
# - ATTACHMENTS_S3=true
|
# - S3_ENABLE=true
|
||||||
# - ATTACHMENTS_S3_REGION=
|
# - S3_REGION=
|
||||||
# - ATTACHMENTS_S3_ENDPOINT=
|
# - S3_ENDPOINT=
|
||||||
# - ATTACHMENTS_S3_BUCKET=
|
# - S3_BUCKET=
|
||||||
# - ATTACHMENTS_S3_ACCESS_KEY=
|
# - S3_ACCESS_KEY=
|
||||||
# - ATTACHMENTS_S3_SECRET_KEY=
|
# - S3_SECRET_KEY=
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
@ -76,9 +76,9 @@ SECRET_KEY=notsecretkey
|
||||||
|
|
||||||
TZ=UTC
|
TZ=UTC
|
||||||
|
|
||||||
# ATTACHMENTS_S3=true
|
# S3_ENABLE=true
|
||||||
# ATTACHMENTS_S3_REGION=
|
# S3_REGION=
|
||||||
# ATTACHMENTS_S3_ENDPOINT=
|
# S3_ENDPOINT=
|
||||||
# ATTACHMENTS_S3_BUCKET=
|
# S3_BUCKET=
|
||||||
# ATTACHMENTS_S3_ACCESS_KEY=
|
# S3_ACCESS_KEY=
|
||||||
# ATTACHMENTS_S3_SECRET_KEY=
|
# S3_SECRET_KEY=
|
||||||
|
|
|
@ -53,16 +53,23 @@ module.exports = {
|
||||||
try {
|
try {
|
||||||
const type = attachment.type || 'local';
|
const type = attachment.type || 'local';
|
||||||
if (type === 's3') {
|
if (type === 's3') {
|
||||||
const client = await sails.helpers.attachments.getSimpleStorageServiceClient();
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
if (client) {
|
if (client) {
|
||||||
const file1 = `${attachment.dirname}/${attachment.filename}`;
|
if (attachment.url) {
|
||||||
const file2 = `${attachment.dirname}/thumbnails/cover-256.png`;
|
const parsedUrl = new URL(attachment.url);
|
||||||
await client.delete({ Key: file1 });
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
await client.delete({ Key: file2 });
|
|
||||||
}
|
}
|
||||||
} else {
|
if (attachment.thumb) {
|
||||||
|
const parsedUrl = new URL(attachment.thumb);
|
||||||
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
try {
|
||||||
rimraf.sync(path.join(sails.config.custom.attachmentsPath, attachment.dirname));
|
rimraf.sync(path.join(sails.config.custom.attachmentsPath, attachment.dirname));
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(error.stack); // eslint-disable-line no-console
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,11 @@ module.exports = {
|
||||||
const rootPath = path.join(sails.config.custom.attachmentsPath, dirname);
|
const rootPath = path.join(sails.config.custom.attachmentsPath, dirname);
|
||||||
const filePath = path.join(rootPath, filename);
|
const filePath = path.join(rootPath, filename);
|
||||||
|
|
||||||
if (sails.config.custom.attachmentsS3) {
|
if (sails.config.custom.s3Config) {
|
||||||
const client = await sails.helpers.attachments.getSimpleStorageServiceClient();
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
const s3Image = await client.upload({
|
const s3Image = await client.upload({
|
||||||
Body: fs.createReadStream(inputs.file.fd),
|
Body: fs.createReadStream(inputs.file.fd),
|
||||||
Key: `${dirname}/${filename}`,
|
Key: `attachments/${dirname}/${filename}`,
|
||||||
ContentType: inputs.file.type,
|
ContentType: inputs.file.type,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ module.exports = {
|
||||||
)
|
)
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
const s3Thumb = await client.upload({
|
const s3Thumb = await client.upload({
|
||||||
Key: `${dirname}/thumbnails/cover-256.${thumbnailsExtension}`,
|
Key: `attachments/${dirname}/thumbnails/cover-256.${thumbnailsExtension}`,
|
||||||
Body: resizeBuffer,
|
Body: resizeBuffer,
|
||||||
ContentType: inputs.file.type,
|
ContentType: inputs.file.type,
|
||||||
});
|
});
|
||||||
|
@ -83,6 +83,12 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rimraf.sync(inputs.file.fd);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
return fileData;
|
return fileData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirname = uuid();
|
const dirname = uuid();
|
||||||
const rootPath = path.join(sails.config.custom.projectBackgroundImagesPath, dirname);
|
|
||||||
|
|
||||||
fs.mkdirSync(rootPath);
|
|
||||||
|
|
||||||
let { width, pageHeight: height = metadata.height } = metadata;
|
let { width, pageHeight: height = metadata.height } = metadata;
|
||||||
if (metadata.orientation && metadata.orientation > 4) {
|
if (metadata.orientation && metadata.orientation > 4) {
|
||||||
|
@ -44,6 +41,64 @@ module.exports = {
|
||||||
|
|
||||||
const extension = metadata.format === 'jpeg' ? 'jpg' : metadata.format;
|
const extension = metadata.format === 'jpeg' ? 'jpg' : metadata.format;
|
||||||
|
|
||||||
|
if (sails.config.custom.s3Config) {
|
||||||
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
|
let originalUrl = '';
|
||||||
|
let thumbUrl = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const s3Original = await client.upload({
|
||||||
|
Body: await image.toBuffer(),
|
||||||
|
Key: `project-background-images/${dirname}/original.${extension}`,
|
||||||
|
ContentType: inputs.file.type,
|
||||||
|
});
|
||||||
|
originalUrl = s3Original.Location;
|
||||||
|
|
||||||
|
const resizeBuffer = await image
|
||||||
|
.resize(
|
||||||
|
336,
|
||||||
|
200,
|
||||||
|
width < 336 || height < 200
|
||||||
|
? {
|
||||||
|
kernel: sharp.kernel.nearest,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
|
.toBuffer();
|
||||||
|
const s3Thumb = await client.upload({
|
||||||
|
Body: resizeBuffer,
|
||||||
|
Key: `project-background-images/${dirname}/cover-336.${extension}`,
|
||||||
|
ContentType: inputs.file.type,
|
||||||
|
});
|
||||||
|
thumbUrl = s3Thumb.Location;
|
||||||
|
} catch (error1) {
|
||||||
|
try {
|
||||||
|
client.delete({ Key: `project-background-images/${dirname}/original.${extension}` });
|
||||||
|
} catch (error2) {
|
||||||
|
console.warn(error2.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
|
throw 'fileIsNotImage';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rimraf.sync(inputs.file.fd);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dirname,
|
||||||
|
extension,
|
||||||
|
original: originalUrl,
|
||||||
|
thumb: thumbUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootPath = path.join(sails.config.custom.projectBackgroundImagesPath, dirname);
|
||||||
|
|
||||||
|
fs.mkdirSync(rootPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await image.toFile(path.join(rootPath, `original.${extension}`));
|
await image.toFile(path.join(rootPath, `original.${extension}`));
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,21 @@ module.exports = {
|
||||||
(!project.backgroundImage ||
|
(!project.backgroundImage ||
|
||||||
project.backgroundImage.dirname !== inputs.record.backgroundImage.dirname)
|
project.backgroundImage.dirname !== inputs.record.backgroundImage.dirname)
|
||||||
) {
|
) {
|
||||||
|
try {
|
||||||
|
if (sails.config.custom.s3Config) {
|
||||||
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
|
if (client && inputs.record.backgroundImage && inputs.record.backgroundImage.original) {
|
||||||
|
const parsedUrl = new URL(inputs.record.backgroundImage.original);
|
||||||
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
|
}
|
||||||
|
if (client && inputs.record.backgroundImage && inputs.record.backgroundImage.thumb) {
|
||||||
|
const parsedUrl = new URL(inputs.record.backgroundImage.thumb);
|
||||||
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
rimraf.sync(
|
rimraf.sync(
|
||||||
path.join(
|
path.join(
|
||||||
|
|
|
@ -33,9 +33,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirname = uuid();
|
const dirname = uuid();
|
||||||
const rootPath = path.join(sails.config.custom.userAvatarsPath, dirname);
|
|
||||||
|
|
||||||
fs.mkdirSync(rootPath);
|
|
||||||
|
|
||||||
let { width, pageHeight: height = metadata.height } = metadata;
|
let { width, pageHeight: height = metadata.height } = metadata;
|
||||||
if (metadata.orientation && metadata.orientation > 4) {
|
if (metadata.orientation && metadata.orientation > 4) {
|
||||||
|
@ -44,6 +41,64 @@ module.exports = {
|
||||||
|
|
||||||
const extension = metadata.format === 'jpeg' ? 'jpg' : metadata.format;
|
const extension = metadata.format === 'jpeg' ? 'jpg' : metadata.format;
|
||||||
|
|
||||||
|
if (sails.config.custom.s3Config) {
|
||||||
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
|
let originalUrl = '';
|
||||||
|
let squareUrl = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const s3Original = await client.upload({
|
||||||
|
Body: await image.toBuffer(),
|
||||||
|
Key: `user-avatars/${dirname}/original.${extension}`,
|
||||||
|
ContentType: inputs.file.type,
|
||||||
|
});
|
||||||
|
originalUrl = s3Original.Location;
|
||||||
|
|
||||||
|
const resizeBuffer = await image
|
||||||
|
.resize(
|
||||||
|
100,
|
||||||
|
100,
|
||||||
|
width < 100 || height < 100
|
||||||
|
? {
|
||||||
|
kernel: sharp.kernel.nearest,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
|
.toBuffer();
|
||||||
|
const s3Square = await client.upload({
|
||||||
|
Body: resizeBuffer,
|
||||||
|
Key: `user-avatars/${dirname}/square-100.${extension}`,
|
||||||
|
ContentType: inputs.file.type,
|
||||||
|
});
|
||||||
|
squareUrl = s3Square.Location;
|
||||||
|
} catch (error1) {
|
||||||
|
try {
|
||||||
|
client.delete({ Key: `user-avatars/${dirname}/original.${extension}` });
|
||||||
|
} catch (error2) {
|
||||||
|
console.warn(error2.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
|
throw 'fileIsNotImage';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rimraf.sync(inputs.file.fd);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dirname,
|
||||||
|
extension,
|
||||||
|
original: originalUrl,
|
||||||
|
square: squareUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootPath = path.join(sails.config.custom.userAvatarsPath, dirname);
|
||||||
|
|
||||||
|
fs.mkdirSync(rootPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await image.toFile(path.join(rootPath, `original.${extension}`));
|
await image.toFile(path.join(rootPath, `original.${extension}`));
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,21 @@ module.exports = {
|
||||||
inputs.record.avatar &&
|
inputs.record.avatar &&
|
||||||
(!user.avatar || user.avatar.dirname !== inputs.record.avatar.dirname)
|
(!user.avatar || user.avatar.dirname !== inputs.record.avatar.dirname)
|
||||||
) {
|
) {
|
||||||
|
try {
|
||||||
|
if (sails.config.custom.s3Config) {
|
||||||
|
const client = await sails.helpers.utils.getSimpleStorageServiceClient();
|
||||||
|
if (client && inputs.record.avatar && inputs.record.avatar.original) {
|
||||||
|
const parsedUrl = new URL(inputs.record.avatar.original);
|
||||||
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
|
}
|
||||||
|
if (client && inputs.record.avatar && inputs.record.avatar.square) {
|
||||||
|
const parsedUrl = new URL(inputs.record.avatar.square);
|
||||||
|
await client.delete({ Key: parsedUrl.pathname.replace(/^\/+/, '') });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error.stack); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
rimraf.sync(path.join(sails.config.custom.userAvatarsPath, inputs.record.avatar.dirname));
|
rimraf.sync(path.join(sails.config.custom.userAvatarsPath, inputs.record.avatar.dirname));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -37,8 +37,8 @@ class S3Client {
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fn() {
|
fn() {
|
||||||
if (sails.config.custom.attachmentsS3) {
|
if (sails.config.custom.s3Config) {
|
||||||
return new S3Client(sails.config.custom.attachmentsS3);
|
return new S3Client(sails.config.custom.s3Config);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
|
@ -31,9 +31,11 @@ module.exports = {
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
allowNull: true,
|
||||||
},
|
},
|
||||||
thumb: {
|
thumb: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
allowNull: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
|
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
|
||||||
|
|
|
@ -79,11 +79,26 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
customToJSON() {
|
customToJSON() {
|
||||||
|
let url = '';
|
||||||
|
let coverUrl = '';
|
||||||
|
if (this.backgroundImage) {
|
||||||
|
if (this.backgroundImage.original) {
|
||||||
|
url = this.backgroundImage.original;
|
||||||
|
} else {
|
||||||
|
url = `${sails.config.custom.projectBackgroundImagesUrl}/${this.backgroundImage.dirname}/original.${this.backgroundImage.extension}`;
|
||||||
|
}
|
||||||
|
if (this.backgroundImage.thumb) {
|
||||||
|
coverUrl = this.backgroundImage.thumb;
|
||||||
|
} else {
|
||||||
|
coverUrl = `${sails.config.custom.projectBackgroundImagesUrl}/${this.backgroundImage.dirname}/cover-336.${this.backgroundImage.extension}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
..._.omit(this, ['backgroundImage']),
|
..._.omit(this, ['backgroundImage']),
|
||||||
backgroundImage: this.backgroundImage && {
|
backgroundImage: this.backgroundImage && {
|
||||||
url: `${sails.config.custom.projectBackgroundImagesUrl}/${this.backgroundImage.dirname}/original.${this.backgroundImage.extension}`,
|
url,
|
||||||
coverUrl: `${sails.config.custom.projectBackgroundImagesUrl}/${this.backgroundImage.dirname}/cover-336.${this.backgroundImage.extension}`,
|
coverUrl,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -148,6 +148,14 @@ module.exports = {
|
||||||
|
|
||||||
customToJSON() {
|
customToJSON() {
|
||||||
const isDefaultAdmin = this.email === sails.config.custom.defaultAdminEmail;
|
const isDefaultAdmin = this.email === sails.config.custom.defaultAdminEmail;
|
||||||
|
let avatarUrl = '';
|
||||||
|
if (this.avatar) {
|
||||||
|
if (this.avatar.square) {
|
||||||
|
avatarUrl = this.avatar.square;
|
||||||
|
} else {
|
||||||
|
avatarUrl = `${sails.config.custom.userAvatarsUrl}/${this.avatar.dirname}/square-100.${this.avatar.extension}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
..._.omit(this, ['password', 'isSso', 'avatar', 'passwordChangedAt']),
|
..._.omit(this, ['password', 'isSso', 'avatar', 'passwordChangedAt']),
|
||||||
|
@ -155,9 +163,7 @@ module.exports = {
|
||||||
isRoleLocked: (this.isSso && !sails.config.custom.oidcIgnoreRoles) || isDefaultAdmin,
|
isRoleLocked: (this.isSso && !sails.config.custom.oidcIgnoreRoles) || isDefaultAdmin,
|
||||||
isUsernameLocked: (this.isSso && !sails.config.custom.oidcIgnoreUsername) || isDefaultAdmin,
|
isUsernameLocked: (this.isSso && !sails.config.custom.oidcIgnoreUsername) || isDefaultAdmin,
|
||||||
isDeletionLocked: isDefaultAdmin,
|
isDeletionLocked: isDefaultAdmin,
|
||||||
avatarUrl:
|
avatarUrl,
|
||||||
this.avatar &&
|
|
||||||
`${sails.config.custom.userAvatarsUrl}/${this.avatar.dirname}/square-100.${this.avatar.extension}`,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,19 +36,20 @@ module.exports.custom = {
|
||||||
projectBackgroundImagesPath: path.join(sails.config.paths.public, 'project-background-images'),
|
projectBackgroundImagesPath: path.join(sails.config.paths.public, 'project-background-images'),
|
||||||
projectBackgroundImagesUrl: `${process.env.BASE_URL}/project-background-images`,
|
projectBackgroundImagesUrl: `${process.env.BASE_URL}/project-background-images`,
|
||||||
|
|
||||||
attachmentsS3:
|
|
||||||
process.env.ATTACHMENTS_S3 === 'true'
|
|
||||||
? {
|
|
||||||
accessKeyId: process.env.ATTACHMENTS_S3_ACCESS_KEY,
|
|
||||||
secretAccessKey: process.env.ATTACHMENTS_S3_SECRET_KEY,
|
|
||||||
region: process.env.ATTACHMENTS_S3_REGION,
|
|
||||||
endpoint: process.env.ATTACHMENTS_S3_ENDPOINT,
|
|
||||||
bucket: process.env.ATTACHMENTS_S3_BUCKET,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
attachmentsPath: path.join(sails.config.appPath, 'private', 'attachments'),
|
attachmentsPath: path.join(sails.config.appPath, 'private', 'attachments'),
|
||||||
attachmentsUrl: `${process.env.BASE_URL}/attachments`,
|
attachmentsUrl: `${process.env.BASE_URL}/attachments`,
|
||||||
|
|
||||||
|
s3Config:
|
||||||
|
process.env.S3_ENABLE === 'true'
|
||||||
|
? {
|
||||||
|
accessKeyId: process.env.S3_ACCESS_KEY,
|
||||||
|
secretAccessKey: process.env.S3_SECRET_KEY,
|
||||||
|
region: process.env.S3_REGION,
|
||||||
|
endpoint: process.env.S3_ENDPOINT,
|
||||||
|
bucket: process.env.S3_BUCKET,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
|
||||||
defaultAdminEmail:
|
defaultAdminEmail:
|
||||||
process.env.DEFAULT_ADMIN_EMAIL && process.env.DEFAULT_ADMIN_EMAIL.toLowerCase(),
|
process.env.DEFAULT_ADMIN_EMAIL && process.env.DEFAULT_ADMIN_EMAIL.toLowerCase(),
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue