send all file

This commit is contained in:
Peter Maquiran
2024-08-15 14:29:11 +01:00
parent bf50c923d1
commit 2aae4da3cd
9 changed files with 123 additions and 63 deletions
+7 -7
View File
@@ -200,7 +200,7 @@
"webpack": "^5.88.2", "webpack": "^5.88.2",
"wordcloud": "^1.1.2", "wordcloud": "^1.1.2",
"ws": "^7.5.9", "ws": "^7.5.9",
"zod": "^3.22.2", "zod": "^3.23.8",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
@@ -44378,9 +44378,9 @@
} }
}, },
"node_modules/zod": { "node_modules/zod": {
"version": "3.22.2", "version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
@@ -78365,9 +78365,9 @@
"dev": true "dev": true
}, },
"zod": { "zod": {
"version": "3.22.2", "version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==" "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g=="
}, },
"zone.js": { "zone.js": {
"version": "0.11.4", "version": "0.11.4",
+1 -1
View File
@@ -217,7 +217,7 @@
"webpack": "^5.88.2", "webpack": "^5.88.2",
"wordcloud": "^1.1.2", "wordcloud": "^1.1.2",
"ws": "^7.5.9", "ws": "^7.5.9",
"zod": "^3.22.2", "zod": "^3.23.8",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
+5 -8
View File
@@ -1,12 +1,13 @@
import { z } from "zod"; import { z } from "zod";
import { MessageAttachmentFileType, MessageAttachmentSource } from "../../data/dto/message/messageOutputDTO"; import { MessageAttachmentFileType, MessageAttachmentSource } from "../../data/dto/message/messageOutputDTO";
import { SafeResourceUrl } from "@angular/platform-browser"; import { SafeResourceUrl } from "@angular/platform-browser";
import { base64Schema } from "src/app/utils/zod";
const MessageEntitySchema = z.object({ export const MessageEntitySchema = z.object({
$id: z.any().optional(), $id: z.any().optional(),
id: z.string().optional(), id: z.string().optional(),
roomId: z.string().uuid(), roomId: z.string(),
message: z.string(), message: z.string().optional(),
messageType: z.number(), messageType: z.number(),
canEdit: z.boolean(), canEdit: z.boolean(),
oneShot: z.boolean(), oneShot: z.boolean(),
@@ -22,15 +23,11 @@ const MessageEntitySchema = z.object({
attachments: z.array(z.object({ attachments: z.array(z.object({
fileType: z.nativeEnum(MessageAttachmentFileType), fileType: z.nativeEnum(MessageAttachmentFileType),
source: z.nativeEnum(MessageAttachmentSource), source: z.nativeEnum(MessageAttachmentSource),
file: z.string().optional(), file: base64Schema.optional(),
fileName: z.string().optional(), fileName: z.string().optional(),
applicationId: z.string().optional(), applicationId: z.string().optional(),
docId: z.string().optional() docId: z.string().optional()
})), })),
attachmentsSource: z.array(z.object({
file: z.string(),
id: z.string(),
})),
}) })
type Message = z.infer<typeof MessageEntitySchema>; type Message = z.infer<typeof MessageEntitySchema>;
@@ -1,12 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MessageEntity } from '../entity/message'; import { MessageEntity, MessageEntitySchema, } from '../entity/message';
import { MessageRepositoryService } from "src/app/module/chat/data/repository/message-respository.service" import { MessageRepositoryService } from "src/app/module/chat/data/repository/message-respository.service"
import { AttachmentRepositoryService } from "src/app/module/chat/data/repository/attachment-repository.service" import { AttachmentRepositoryService } from "src/app/module/chat/data/repository/attachment-repository.service"
import { z } from 'zod'; import { z, ZodError } from 'zod';
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { InstanceId } from '../chat-service.service'; import { InstanceId } from '../chat-service.service';
import { createDataURL } from 'src/app/utils/ToBase64'; import { createDataURL } from 'src/app/utils/ToBase64';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { zodSafeValidation } from 'src/app/utils/zodValidation';
const MessageInputUseCaseSchema = z.object({ const MessageInputUseCaseSchema = z.object({
memberId: z.number(), memberId: z.number(),
@@ -24,48 +25,61 @@ export class MessageCreateUseCaseService {
constructor( constructor(
private MessageRepositoryService: MessageRepositoryService, private MessageRepositoryService: MessageRepositoryService,
private AttachmentRepositoryService: AttachmentRepositoryService, private AttachmentRepositoryService: AttachmentRepositoryService,
private sanitizer: DomSanitizer private sanitizer: DomSanitizer,
) { } ) { }
async execute(message: MessageEntity) { async execute(message: MessageEntity) {
message.sendAttemp++; const validation = zodSafeValidation<MessageEntity>(MessageEntitySchema, message)
message.requestId = InstanceId +'@'+ uuidv4(); if(validation.isOk()) {
message.sendAttemp++;
const createMessageLocally = await this.MessageRepositoryService.createMessageLocally(message) message.requestId = InstanceId +'@'+ uuidv4();
if(createMessageLocally.isOk()) { const createMessageLocally = await this.MessageRepositoryService.createMessageLocally(message)
console.log('==========================',message); if(createMessageLocally.isOk()) {
if(message.hasAttachment) {
for (const attachment of message.attachments) { console.log('==========================',message);
if(message.hasAttachment) {
const createAttachmentLocally = this.AttachmentRepositoryService.create({ for (const attachment of message.attachments) {
$messageId: createMessageLocally.value.$id,
file: createDataURL(attachment.file, attachment.mimeType) const createAttachmentLocally = this.AttachmentRepositoryService.create({
}) $messageId: createMessageLocally.value.$id,
file: createDataURL(attachment.file, attachment.mimeType)
})
attachment.safeFile = createDataURL(attachment.file, attachment.mimeType)
}
attachment.safeFile = createDataURL(attachment.file, attachment.mimeType)
} }
const sendToServer = await this.MessageRepositoryService.sendMessage(message)
if(!sendToServer.isOk()) {
console.log('sendToServer error', sendToServer.error)
}
return sendToServer
} }
const sendToServer = await this.MessageRepositoryService.sendMessage(message) const result = await this.MessageRepositoryService.sendMessage(message)
return result
} else {
if(!sendToServer.isOk()) { if(validation.error.formErrors.fieldErrors.attachments) {
console.log('sendToServer error', sendToServer.error) console.log(message.attachments)
console.error('invalid attachment', validation.error.formErrors.fieldErrors.attachments)
} }
return sendToServer
} }
const result = await this.MessageRepositoryService.sendMessage(message)
return result
} }
} }
@@ -56,7 +56,7 @@
</div> </div>
<div *ngFor="let attachment of message.attachments; let i = index"> <div *ngFor="let attachment of message.attachments; let i = index">
<div *ngIf="attachment.fileType == 1"> <div *ngIf="attachment.source == MessageAttachmentFileSource.Webtrix">
<ion-icon src="assets/icon/webtrix.svg" class="file-icon font-25"></ion-icon> <ion-icon src="assets/icon/webtrix.svg" class="file-icon font-25"></ion-icon>
<ion-label>{{ attachment.fileName}}</ion-label> <ion-label>{{ attachment.fileName}}</ion-label>
@@ -66,10 +66,33 @@
</div> </div>
<div *ngIf="attachment.fileType == 2"> <div *ngIf="attachment.fileType == MessageAttachmentFileType.Image">
<img [src]="attachment.safeFile"> <img [src]="attachment.safeFile">
</div> </div>
<div *ngIf="attachment.fileType == MessageAttachmentFileType.Audio">
<audio controls>
<source [src]="attachment.safeFile" >
Your browser does not support the audio element.
</audio>
</div>
<div *ngIf="attachment.fileType == MessageAttachmentFileType.Doc">
<fa-icon *ngIf="attachment.mimeType == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
<fa-icon *ngIf="attachment.mimeType == 'application/word'" icon="file-word" class="word-icon">
</fa-icon>
<fa-icon *ngIf="attachment.mimeType == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'" icon="file-word" class="word-icon"></fa-icon>
<fa-icon
*ngIf="attachment.mimeType == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"
icon="file-word" class="excel-icon"></fa-icon>
<ion-icon *ngIf="attachment.mimeType == 'application/webtrix'" src="assets/icon/webtrix.svg">
</ion-icon>
<ion-icon *ngIf="attachment.mimeType == 'application/meeting'" src="assets/icon/webtrix.svg">
</ion-icon>
<ion-label>{{ attachment.fileName}}</ion-label>
</div>
</div> </div>
</div> </div>
@@ -137,6 +137,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
messageSendSubject: Subscription messageSendSubject: Subscription
messages1: {[key: string]: MessageEntity[]} = {} messages1: {[key: string]: MessageEntity[]} = {}
MessageAttachmentFileType = MessageAttachmentFileType
MessageAttachmentFileSource = MessageAttachmentSource
constructor( constructor(
public popoverController: PopoverController, public popoverController: PopoverController,
@@ -875,7 +877,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
} }
message.attachments = [{ message.attachments = [{
fileName: res.data.selected.Assunto, fileName: res.data.selected.Assunto,
source: MessageAttachmentSource.Webtrix, source: MessageAttachmentSource.Device,
fileType: MessageAttachmentFileType.Doc, fileType: MessageAttachmentFileType.Doc,
applicationId: res.data.selected.ApplicationType, applicationId: res.data.selected.ApplicationType,
docId: res.data.selected.Id, docId: res.data.selected.Id,
@@ -927,7 +929,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
} }
message.attachments = [{ message.attachments = [{
file: file.value.base64String, file: file.value.base64String.split(',')[1],
fileName: "foto", fileName: "foto",
source: MessageAttachmentSource.Device, source: MessageAttachmentSource.Device,
fileType: MessageAttachmentFileType.Image, fileType: MessageAttachmentFileType.Image,
@@ -984,7 +986,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
} }
message.attachments = [{ message.attachments = [{
file: fileBase64.value, file: fileBase64.value.split(',')[1],
fileName: file.value.name, fileName: file.value.name,
source: MessageAttachmentSource.Device, source: MessageAttachmentSource.Device,
fileType: MessageAttachmentFileType.Doc, fileType: MessageAttachmentFileType.Doc,
+31 -18
View File
@@ -23,28 +23,41 @@ export const zodDataUrlSchema = z.string().refine(value => zodDataUrlRegex.test(
message: 'Invalid data URL', message: 'Invalid data URL',
}); });
//===============================================================================
/** /**
* Validates if a string is a valid data URL. * A schema for validating Base64 encoded strings.
* *
* @param url - The string to validate as a data URL. * This schema checks if the string is valid Base64 and ensures that the first 20 characters
* @returns {void} - Logs the result of the validation. * do not contain a comma.
* *
* @example * @example
* validateDataUrl('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDCAAAAC0BEMAAW9R3AAAAAElFTkSuQmCC'); * ```typescript
* // Output: Valid data URL: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDCAAAAC0BEMAAW9R3AAAAAElFTkSuQmCC * const validString = 'SGVsbG8sIHdvcmxkIQ=='; // Base64 for "Hello, world!"
* const invalidString = 'SGVsbG8sIHdvcmxkIQ,,=='; // Invalid due to commas
* *
* validateDataUrl('invalid-url'); * console.log(base64Schema.safeParse(validString).success); // true
* // Output: Validation error: [ ... ] * console.log(base64Schema.safeParse(invalidString).success); // false
* ```
*/ */
const validateDataUrl = (url: string) => { export const base64Schema = z.string().refine(value => {
const result: any = zodDataUrlSchema.safeParse(url); // Regular expression for Base64 validation
if (result.success) { const isBase64 = /^[A-Za-z0-9+/=]*$/.test(value) && (value.length % 4 === 0);
console.log('Valid data URL:', url); // Check if the first 20 characters do not contain a comma
} else { return isBase64 && !value.substring(0, 20).includes(',');
console.error('Validation error:', result.error.errors); }, {
} message: 'Invalid Base64 string or comma found in the first 20 characters'
}; });
// Test the schema /**
validateDataUrl('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDCAAAAC0BEMAAW9R3AAAAAElFTkSuQmCC'); * Validates a given string against the Base64 schema.
validateDataUrl('invalid-url'); *
* @param input - The string to validate.
* @returns `true` if the input is valid according to the schema, `false` otherwise.
*
* @example
* ```typescript
* console.log(validateInput('SGVsbG8sIHdvcmxkIQ==')); // true
* console.log(validateInput('SGVsbG8sIHdvcmxkIQ,,==')); // false
* ```
*/
+11
View File
@@ -0,0 +1,11 @@
import { err, ok } from 'neverthrow';
import { ZodError, ZodSchema, z } from 'zod';
export function zodSafeValidation<T>(schema: ZodSchema, data) {
const validation = (schema as ZodSchema<T>).safeParse(data)
if(validation.success) {
return ok(validation.data)
} else {
return err((validation.error))
}
}