diff --git a/backend/routes/communications.js b/backend/routes/communications.js index 91b27f5..367bfd8 100644 --- a/backend/routes/communications.js +++ b/backend/routes/communications.js @@ -22,7 +22,6 @@ const path = require("path") const fs = require("fs") const FileType = require("file-type") const { v4: uuidv4 } = require("uuid") - const limiter = rateLimit({ windowMs: 10 * 1000, max: 8, @@ -31,6 +30,13 @@ const limiter = rateLimit({ legacyHeaders: false, keyGenerator: (req, res) => req.user.id || req.ip }) +const whitelist = [ + "image/png", + "image/jpeg", + "image/jpg", + "image/webp", + "image/gif" +] const storage = multer.diskStorage({ destination: function (req, file, cb) { @@ -177,6 +183,7 @@ router.get("/", auth, async (req, res, next) => { as: "chat", attributes: [ "id", + "icon", "name", "updatedAt", "createdAt", @@ -2110,5 +2117,48 @@ router.post("/create", auth, async (req, res, next) => { next(err) } }) - +router.post( + "/avatar/:id", + auth, + upload.single("avatar"), + async (req, res, next) => { + try { + const chat = await ChatAssociation.findOne({ + where: { + userId: req.user.id, + id: req.params.id, + rank: "admin" + } + }) + if (!chat) throw Errors.chatNotFoundOrNotAdmin + if (req.file) { + const meta = await FileType.fromFile(req.file.path) + if (!whitelist.includes(meta.mime)) { + throw Errors.invalidFileType + } + const attachment = await Attachment.create({ + userId: req.user.id, + type: "avatar", + attachment: req.file.filename, + name: req.file.originalname, + extension: meta.ext, + size: req.file.size + }) + await Chat.update( + { + icon: attachment.attachment + }, + { + where: { + id: chat.chatId + } + } + ) + res.sendStatus(204) + } + } catch (err) { + next(err) + } + } +) module.exports = router diff --git a/frontend/package.json b/frontend/package.json index 21f2b82..bfc163c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "colubrina", - "version": "1.0.34", + "version": "1.0.35", "description": "Simple instant communication.", "private": true, "author": "Troplo ", diff --git a/frontend/src/assets/styles.css b/frontend/src/assets/styles.css index 858d03d..63fd957 100644 --- a/frontend/src/assets/styles.css +++ b/frontend/src/assets/styles.css @@ -187,7 +187,7 @@ div .theme--dark.v-calendar-daily .v-calendar-daily__day { } ::-webkit-scrollbar-thumb { - background: var(--v-text-lighten3) !important; + background: var(--v-text-base) !important; border: solid 3px var(--v-bg-base) !important; border-radius: 7px !important; } @@ -202,4 +202,4 @@ div .theme--dark.v-calendar-daily .v-calendar-daily__day { :root { overflow-y: auto !important; -} \ No newline at end of file +} diff --git a/frontend/src/components/Header.vue b/frontend/src/components/Header.vue index 60acea7..be77a59 100644 --- a/frontend/src/components/Header.vue +++ b/frontend/src/components/Header.vue @@ -180,6 +180,15 @@ " v-model="settings.item.chat.name" > + Members - - mdi-account-group - - + + mdi-account-group @@ -750,7 +762,9 @@ {{ getDirectRecipient(item).name }} - {{ item.chat.name }} + + {{ item.chat.name }} + @@ -900,6 +914,7 @@ export default { copyTooltip: false, settings: { dialog: false, + avatar: null, addMembers: { dialog: false, users: [], @@ -986,6 +1001,28 @@ export default { this.route.modal = false this.route.value = "" }, + doUpload() { + if (this.settings.avatar) { + let formData = new FormData() + formData.append("avatar", this.settings.avatar) + this.axios + .post( + "/api/v1/communications/avatar/" + this.settings.item.id, + formData, + { + headers: { + "Content-Type": "multipart/form-data" + } + } + ) + .then(() => { + this.$toast.success("Avatar updated") + }) + .catch((e) => { + AjaxErrorHandler(this.$store)(e) + }) + } + }, submitFeedback() { this.axios .post("/api/v1/feedback", {