@chat21/chat21-ionic 3.4.29-rc1 → 3.4.30-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,18 @@
8
8
  ### **Copyrigth**:
9
9
  *Tiledesk SRL*
10
10
 
11
+ # 3.4.29-rc1
12
+ - **changed**: API for upload a file/image into chat
13
+
14
+ # 3.4.29 in PROD
15
+ - **bug-fixed**: web (Chrome >= 144) `ion-content` stopped scrolling on some pages (conversation list / contacts directory / unassigned); removed the forced `--overflow: hidden` and handled scrolling on Ionic’s internal scroll container via `ion-content::part(scroll)`
16
+
17
+ # 3.4.28 in PROD
18
+ - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
19
+
20
+ # 3.4.27 in PROD
21
+ - **bug-fixed**: cannot find route if userFullname contains /
22
+
11
23
  # 3.4.29-rc1
12
24
  - **bug-fixed**: web (Chrome >= 144) `ion-content` stopped scrolling on some pages (conversation list / contacts directory / unassigned); removed the forced `--overflow: hidden` and handled scrolling on Ionic’s internal scroll container via `ion-content::part(scroll)`
13
25
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-ionic",
3
3
  "author": "Tiledesk SRL",
4
- "version": "3.4.29-rc1",
4
+ "version": "3.4.30-rc1",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -122,7 +122,6 @@ export class AppComponent implements OnInit {
122
122
  private navService: NavProxyService,
123
123
  // public chatPresenceHandler: ChatPresenceHandler,
124
124
  public typingService: TypingService,
125
- public uploadService: UploadService,
126
125
  public appStorageService: AppStorageService,
127
126
 
128
127
  // public chatConversationsHandler: ChatConversationsHandler,
@@ -556,7 +555,6 @@ export class AppComponent implements OnInit {
556
555
  if (pushEngine && pushEngine !== 'none') {
557
556
  this.notificationsService.initialize(this.tenant, vap_id_Key, platform)
558
557
  }
559
- this.uploadService.initialize();
560
558
 
561
559
  this.setLanguage(null)
562
560
  this.initAuthentication();
@@ -8,5 +8,6 @@
8
8
  [height]="height"
9
9
  [src]="metadata.src"
10
10
  (load)="onLoaded($event)"
11
+ (error)="onError($event)"
11
12
  (click)="openImageViewerModal(metadata.src, metadata.name)" />
12
13
  </div>
@@ -15,6 +15,7 @@ export class ImageComponent implements OnInit {
15
15
  loading: boolean = true
16
16
  modal: any
17
17
  span: any
18
+ private readonly fallbackSrc = 'assets/img/no_data_found.png'
18
19
 
19
20
  constructor() { }
20
21
 
@@ -26,6 +27,24 @@ export class ImageComponent implements OnInit {
26
27
  this.onElementRendered.emit({element: "image", status:true})
27
28
  }
28
29
 
30
+ onError(event: Event) {
31
+ this.loading = false
32
+ const img = event?.target as HTMLImageElement | null
33
+ if (!img) {
34
+ return
35
+ }
36
+ // avoid infinite loop if fallback image fails too
37
+ if (img.src && img.src.includes(this.fallbackSrc)) {
38
+ return
39
+ }
40
+ img.src = this.fallbackSrc
41
+ // also update metadata so click-to-open uses the fallback consistently
42
+ if (this.metadata) {
43
+ this.metadata.src = this.fallbackSrc
44
+ }
45
+ this.onElementRendered.emit({ element: 'image', status: true })
46
+ }
47
+
29
48
  _downloadImage(url: string, fileName: string) {
30
49
  // console.log('Image COMP - IMAGE URL ', url)
31
50
  // console.log('Image COMP - IMAGE FILENAME ', fileName)
@@ -12,7 +12,7 @@ import { LoaderPreviewPage } from 'src/app/modals/loader-preview/loader-preview.
12
12
  // Services
13
13
  import { UploadService } from 'src/chat21-core/providers/abstract/upload.service';
14
14
  // utils
15
- import { TYPE_MSG_EMAIL, TYPE_MSG_TEXT, CHANNEL_TYPE } from 'src/chat21-core/utils/constants';
15
+ import { TYPE_MSG_EMAIL, TYPE_MSG_TEXT, CHANNEL_TYPE, TYPE_DIRECT } from 'src/chat21-core/utils/constants';
16
16
  // Models
17
17
  import { UploadModel } from 'src/chat21-core/models/upload';
18
18
 
@@ -168,6 +168,11 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
168
168
 
169
169
  this.project = this.projectService.getProject();
170
170
  this.logger.log('[CONVS-DETAIL] - returnChangeTextArea ngOnChanges in [MSG-TEXT-AREA] project', this.project)
171
+ if (this.channelType === TYPE_DIRECT) {
172
+ this.uploadService.initialize();
173
+ } else {
174
+ this.uploadService.initialize(this.project?._id);
175
+ }
171
176
  // use case drop
172
177
  if (this.dropEvent) {
173
178
  this.presentModal(this.dropEvent)
@@ -401,7 +406,10 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
401
406
  this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] FIREBASE-UPLOAD presentModal onDidDismiss currentUpload', currentUpload);
402
407
  this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] FIREBASE-UPLOAD presentModal onDidDismiss detail.data', detail.data);
403
408
 
404
- that.uploadService.upload(that.loggedUser.uid, currentUpload).then((data) => {
409
+ const uploadPromise = (that.channelType === TYPE_DIRECT)
410
+ ? that.uploadService.upload(that.loggedUser.uid, currentUpload)
411
+ : that.uploadService.uploadFile(that.loggedUser.uid, currentUpload)
412
+ uploadPromise.then((data) => {
405
413
  metadata.src = data.src;
406
414
  metadata.downloadURL = data.downloadURL;
407
415
  this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] FIREBASE-UPLOAD presentModal invio msg metadata::: ', metadata);
@@ -83,6 +83,7 @@ import { WebsocketService } from 'src/app/services/websocket/websocket.service';
83
83
  import { Project } from 'src/chat21-core/models/projects';
84
84
  import { Globals } from 'src/app/utils/globals';
85
85
  import { ProjectService } from 'src/app/services/projects/project.service';
86
+ import { UploadService } from 'src/chat21-core/providers/abstract/upload.service';
86
87
  import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
87
88
  import { ProjectUser } from 'src/chat21-core/models/projectUsers';
88
89
  import { getOSCode, hasRole } from 'src/app/utils/utils';
@@ -246,6 +247,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
246
247
  public conversationHandlerBuilderService: ConversationHandlerBuilderService,
247
248
  public cannedResponsesService: CannedResponsesService,
248
249
  public imageRepoService: ImageRepoService,
250
+ public uploadService: UploadService,
249
251
  public presenceService: PresenceService,
250
252
  public toastController: ToastController,
251
253
  public tiledeskService: TiledeskService,
@@ -493,7 +495,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
493
495
  this.isEmailEnabled = (this.appConfigProvider.getConfig().emailSection === 'true' || this.appConfigProvider.getConfig().emailSection === true) ? true : false;
494
496
  this.isTicketEnabled = (this.appConfigProvider.getConfig().ticketSection === 'true' || this.appConfigProvider.getConfig().ticketSection === true) ? true : false;
495
497
  this.isWhatsappTemplatesEnabled = (this.appConfigProvider.getConfig().whatsappTemplatesSection === 'true' || this.appConfigProvider.getConfig().whatsappTemplatesSection === true) ? true : false;
496
-
498
+ this.fileUploadAccept = this.appConfigProvider.getConfig().fileUploadAccept
499
+
497
500
  this.cannedResponsesService.initialize(appconfig.apiUrl)
498
501
 
499
502
  if (checkPlatformIsMobile()) {
@@ -522,10 +525,10 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
522
525
  // this.initConversationsHandler(); // nk
523
526
  if (this.conversationWith) {
524
527
  this.disableTextarea = false
528
+ this.startConversation();
525
529
  this._getProjectIdByConversationWith(this.conversationWith)
526
530
  this.initConversationHandler()
527
531
  this.initGroupsHandler();
528
- this.startConversation();
529
532
  this.initSubscriptions();
530
533
  this.getLeadDetail();
531
534
  this.initializeTyping();
@@ -536,6 +539,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
536
539
  }
537
540
 
538
541
  _getProjectIdByConversationWith(conversationWith: string) {
542
+ console.log('[CONVS-DETAIL] - _getProjectIdByConversationWith conversationWith', conversationWith, this.channelType)
539
543
  if (this.channelType !== TYPE_DIRECT && !this.conversationWith.startsWith('group-')) {
540
544
  this.tiledeskService.getProjectIdByConvRecipient(conversationWith).subscribe((res) => {
541
545
  this.logger.log('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT RES + projectId', res, res.id_project)
Binary file
@@ -34,9 +34,12 @@ export abstract class UploadService {
34
34
  // abstract tenant = environment.tenant;
35
35
 
36
36
  // functions
37
- abstract initialize(): void;
37
+ abstract initialize(projectId?: string): void;
38
38
  abstract upload(userId: string, upload: UploadModel): Promise<{downloadURL: string, src: string}>;
39
+ abstract uploadFile(userId: string, upload: UploadModel): Promise<{downloadURL: string, src: string}>;
40
+ abstract uploadAsset(userId: string, upload: UploadModel, expiration?: number): Promise<{downloadURL: string, src: string}>;
39
41
  abstract uploadProfile(userId: string, upload: UploadModel): Promise<any>;
40
42
  abstract delete(userId: string, path: string): Promise<any>;
43
+ abstract deleteFile(userId: string, path: string): Promise<any>;
41
44
  abstract deleteProfile(userId: string, path: string): Promise<any>
42
45
  }
@@ -42,7 +42,7 @@ export class FirebaseUploadService extends UploadService {
42
42
  });
43
43
  }
44
44
 
45
- public initialize() {
45
+ public async initialize(projectId?: string) {
46
46
  this.logger.log('[FIREBASEUploadSERVICE] initialize');
47
47
  }
48
48
 
@@ -104,6 +104,107 @@ export class FirebaseUploadService extends UploadService {
104
104
 
105
105
  }
106
106
 
107
+ public uploadFile(userId: string, upload: UploadModel): Promise<{downloadURL: string, src: any}> {
108
+ const that = this;
109
+ const uid = this.createGuid();
110
+ const urlImagesNodeFirebase = '/public/images/' + userId + '/' + uid + '/' + upload.file.name;
111
+ this.logger.debug('[FIREBASEUploadSERVICE] pushUpload ', urlImagesNodeFirebase, upload.file);
112
+
113
+ // Create a root reference
114
+ const storageRef = firebase.storage().ref();
115
+ this.logger.debug('[FIREBASEUploadSERVICE] storageRef', storageRef);
116
+
117
+ // Create a reference to 'mountains.jpg'
118
+ const mountainsRef = storageRef.child(urlImagesNodeFirebase);
119
+ this.logger.debug('[FIREBASEUploadSERVICE] mountainsRef ', mountainsRef);
120
+
121
+ // const metadata = {};
122
+ const metadata = { name: upload.file.name, contentType: upload.file.type, contentDisposition: 'attachment; filename=' + upload.file.name };
123
+
124
+ let uploadTask = mountainsRef.put(upload.file, metadata);
125
+
126
+ return new Promise((resolve, reject) => {
127
+ uploadTask.on('state_changed', function progress(snapshot) {
128
+ // Observe state change events such as progress, pause, and resume
129
+ // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
130
+ var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
131
+ that.logger.debug('[FIREBASEUploadSERVICE] Upload is ' + progress + '% done');
132
+
133
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
134
+ // BehaviorSubject publish the upload progress state - the subscriber is in ion-conversastion-detail.component.ts > listenToUploadFileProgress()
135
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
136
+
137
+ that.BSStateUpload.next({ upload: progress, type: upload.file.type });
138
+
139
+ switch (snapshot.state) {
140
+ case firebase.storage.TaskState.PAUSED: // or 'paused'
141
+ that.logger.debug('[FIREBASEUploadSERVICE] Upload is paused');
142
+
143
+ break;
144
+ case firebase.storage.TaskState.RUNNING: // or 'running'
145
+ that.logger.debug('[FIREBASEUploadSERVICE] Upload is running');
146
+
147
+ break;
148
+ }
149
+ }, function error(error) {
150
+ // Handle unsuccessful uploads
151
+ reject(error)
152
+ }, async function complete() {
153
+ // Handle successful uploads on complete
154
+ that.logger.debug('[FIREBASEUploadSERVICE] Upload is complete', upload);
155
+
156
+ const downloadURL = await uploadTask.snapshot.ref.getDownloadURL();
157
+ resolve({downloadURL: downloadURL, src: downloadURL})
158
+ // that.BSStateUpload.next({upload: upload});
159
+
160
+ });
161
+ })
162
+ }
163
+
164
+ public uploadAsset(userId: string, upload: UploadModel, expiration: number = 60): Promise<{downloadURL: string, src: any}> {
165
+ // expiration is ignored on Firebase, but kept for API compatibility with NativeUploadService
166
+ const that = this;
167
+ const uid = this.createGuid();
168
+ const urlAssetsNodeFirebase = '/public/assets/' + userId + '/' + uid + '/' + upload.file.name;
169
+ this.logger.debug('[FIREBASEUploadSERVICE] uploadAsset ', urlAssetsNodeFirebase, upload.file, 'expiration:', expiration);
170
+
171
+ // Create a root reference
172
+ const storageRef = firebase.storage().ref();
173
+ this.logger.debug('[FIREBASEUploadSERVICE] storageRef', storageRef);
174
+
175
+ const assetRef = storageRef.child(urlAssetsNodeFirebase);
176
+ this.logger.debug('[FIREBASEUploadSERVICE] assetRef ', assetRef);
177
+
178
+ const metadata = { name: upload.file.name, contentType: upload.file.type, contentDisposition: 'attachment; filename=' + upload.file.name };
179
+
180
+ let uploadTask = assetRef.put(upload.file, metadata);
181
+
182
+ return new Promise((resolve, reject) => {
183
+ uploadTask.on('state_changed', function progress(snapshot) {
184
+ var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
185
+ that.logger.debug('[FIREBASEUploadSERVICE] uploadAsset is ' + progress + '% done');
186
+
187
+ that.BSStateUpload.next({ upload: progress, type: upload.file.type });
188
+
189
+ switch (snapshot.state) {
190
+ case firebase.storage.TaskState.PAUSED:
191
+ that.logger.debug('[FIREBASEUploadSERVICE] uploadAsset is paused');
192
+ break;
193
+ case firebase.storage.TaskState.RUNNING:
194
+ that.logger.debug('[FIREBASEUploadSERVICE] uploadAsset is running');
195
+ break;
196
+ }
197
+ }, function error(error) {
198
+ reject(error)
199
+ }, async function complete() {
200
+ that.logger.debug('[FIREBASEUploadSERVICE] uploadAsset is complete', upload);
201
+
202
+ const downloadURL = await uploadTask.snapshot.ref.getDownloadURL();
203
+ resolve({downloadURL: downloadURL, src: downloadURL})
204
+ });
205
+ })
206
+ }
207
+
107
208
  public uploadProfile(userId: string, upload: UploadModel): Promise<any> {
108
209
  const that = this;
109
210
  const urlImagesNodeFirebase = '/profiles/' + userId + '/photo.jpg'
@@ -192,6 +293,36 @@ export class FirebaseUploadService extends UploadService {
192
293
  })
193
294
  }
194
295
 
296
+ public async deleteFile(userId: string, path: string): Promise<any>{
297
+ const that = this;
298
+ const file_name_photo = 'photo.jpg';
299
+ const file_name_thumb_photo = 'thumb_photo.jpg';
300
+
301
+ that.logger.debug('[FIREBASEUploadSERVICE] delete image for USER', userId, path);
302
+
303
+ let uid = path.split(userId)[1].split('%2F')[1]; // get the UID of the image
304
+ let imageName = path.split(uid + '%2F')[1].split('?')[0];
305
+
306
+ // Create a root reference
307
+ const storageRef = firebase.storage().ref();
308
+ const ref = storageRef.child('public/images/' + userId + '/'+ uid + '/')
309
+ let arrayPromise = []
310
+ await ref.listAll().then((dir => {
311
+ dir.items.forEach(fileRef => arrayPromise.push(this.deleteFile(ref.fullPath, fileRef.name)));
312
+ })).catch(error => {
313
+ that.logger.error('[FIREBASEUploadSERVICE] delete: listAll error', error)
314
+ })
315
+
316
+ //AWAIT to return ALL the promise delete()
317
+ return new Promise((resolve, reject)=> {
318
+ Promise.all(arrayPromise).then(()=>{
319
+ resolve(true)
320
+ }).catch((error)=>{
321
+ reject(error)
322
+ })
323
+ })
324
+ }
325
+
195
326
  public async deleteProfile(userId: string, path: string): Promise<any>{
196
327
  const that = this;
197
328
  const file_name_photo = 'photo.jpg';
@@ -219,13 +350,5 @@ export class FirebaseUploadService extends UploadService {
219
350
  })
220
351
  }
221
352
 
222
- // // ------------------------------------
223
- // // Delete the file photo
224
- // // ------------------------------------
225
- private deleteFile(pathToFile, fileName){
226
- const ref = firebase.storage().ref(pathToFile);
227
- const childRef = ref.child(fileName);
228
- return childRef.delete()
229
- }
230
353
 
231
354
  }
@@ -16,7 +16,7 @@ export class NativeImageRepoService extends ImageRepoService {
16
16
  * @param uid
17
17
  */
18
18
  getImagePhotoUrl(uid: string): string {
19
- this.baseImageURL = this.getImageBaseUrl() + 'images'
19
+ this.baseImageURL = this.getImageBaseUrl() + 'files'
20
20
  let sender_id = '';
21
21
  if (uid.includes('bot_')) {
22
22
  sender_id = uid.slice(4)
@@ -6,6 +6,7 @@ import { UploadModel } from '../../models/upload';
6
6
  import { AppStorageService } from '../abstract/app-storage.service';
7
7
  import { LoggerService } from '../abstract/logger.service';
8
8
  import { LoggerInstance } from '../logger/loggerInstance';
9
+ import { first } from 'rxjs/operators';
9
10
 
10
11
  // @Injectable({ providedIn: 'root' })
11
12
  @Injectable()
@@ -14,8 +15,8 @@ export class NativeUploadService extends UploadService {
14
15
  BSStateUpload: BehaviorSubject<any> = new BehaviorSubject<any>(null)
15
16
 
16
17
  private tiledeskToken: string;
17
- private URL_TILEDESK_IMAGES: string;
18
18
  private URL_TILEDESK_FILE: string;
19
+ private URL_TILEDESK_UPLOAD: string;
19
20
  private logger: LoggerService = LoggerInstance.getInstance()
20
21
 
21
22
  constructor(
@@ -25,15 +26,17 @@ export class NativeUploadService extends UploadService {
25
26
  super();
26
27
  }
27
28
 
28
- initialize(): void {
29
- this.logger.info('[NATIVE UPLOAD] initialize')
30
- this.URL_TILEDESK_FILE = this.getBaseUrl() + 'files'
31
- this.URL_TILEDESK_IMAGES = this.getBaseUrl() + 'images'
29
+ initialize(projectId?: string): void {
30
+ this.logger.info('[NATIVE UPLOAD] initialize', this.getBaseUrl())
31
+ if (projectId) {
32
+ this.URL_TILEDESK_FILE = this.getBaseUrl() + projectId + '/files'
33
+ }
34
+ this.URL_TILEDESK_UPLOAD = this.getBaseUrl();
32
35
  this.tiledeskToken = this.appStorage.getItem('tiledeskToken')
33
36
  }
34
37
 
35
38
 
36
- upload(userId: string, upload: UploadModel): Promise<{ downloadURL: string, src: string}> {
39
+ upload(userId: string, upload: UploadModel): Promise<{downloadURL: string, src: string}> {
37
40
  this.logger.log('[NATIVE UPLOAD] - upload new image/file ... upload', upload)
38
41
  const headers = new HttpHeaders({
39
42
  Authorization: this.tiledeskToken,
@@ -45,12 +48,11 @@ export class NativeUploadService extends UploadService {
45
48
 
46
49
  const that = this;
47
50
  if ((upload.file.type.startsWith('image') && (!upload.file.type.includes('svg')))) {
48
- this.logger.log('[NATIVE UPLOAD] - upload new image')
49
51
  //USE IMAGE API
50
- const url = this.URL_TILEDESK_IMAGES + '/users'
52
+ const url = this.URL_TILEDESK_UPLOAD + 'images/users'
51
53
  return new Promise((resolve, reject) => {
52
54
  that.http.post(url, formData, requestOptions).subscribe(data => {
53
- const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['filename'];
55
+ const downloadURL = this.URL_TILEDESK_UPLOAD + 'images?path=' + encodeURIComponent(data?.['filename']);
54
56
  resolve({downloadURL : downloadURL, src: downloadURL})
55
57
  // that.BSStateUpload.next({upload: upload});
56
58
  }, (error) => {
@@ -58,13 +60,12 @@ export class NativeUploadService extends UploadService {
58
60
  });
59
61
  });
60
62
  } else {
61
- this.logger.log('[NATIVE UPLOAD] - upload new file')
62
63
  //USE FILE API
63
- const url = this.URL_TILEDESK_FILE + '/users'
64
+ const url = this.URL_TILEDESK_UPLOAD + 'files/users'
64
65
  return new Promise((resolve, reject) => {
65
66
  that.http.post(url, formData, requestOptions).subscribe(data => {
66
- const src = this.URL_TILEDESK_FILE + '?path=' + encodeURI(data['filename']);
67
- const downloadURL = this.URL_TILEDESK_FILE + '/download' + '?path=' + encodeURI(data['filename']);
67
+ const src = this.URL_TILEDESK_UPLOAD + 'files?path=' + encodeURI(data['filename']);
68
+ const downloadURL = this.URL_TILEDESK_UPLOAD + 'files/download' + '?path=' + encodeURI(data['filename']);
68
69
  resolve({downloadURL : downloadURL, src: src})
69
70
  // that.BSStateUpload.next({upload: upload});
70
71
  }, (error) => {
@@ -76,6 +77,62 @@ export class NativeUploadService extends UploadService {
76
77
 
77
78
  }
78
79
 
80
+ uploadFile(userId: string, upload: UploadModel): Promise<{downloadURL: string, src: string}> {
81
+ this.logger.log('[NATIVE UPLOAD] - upload new image/file ... upload', upload)
82
+ const headers = new HttpHeaders({
83
+ Authorization: this.tiledeskToken,
84
+ //'Content-Type': 'multipart/form-data',
85
+ });
86
+ const requestOptions = { headers: headers };
87
+ const formData = new FormData();
88
+ formData.append('file', upload.file);
89
+
90
+ const that = this;
91
+ const url = this.URL_TILEDESK_FILE + '/chat'
92
+ return new Promise((resolve, reject) => {
93
+ that.http.post(url, formData, requestOptions).pipe(first()).subscribe({
94
+ next: (data) => {
95
+ const downloadURL = this.getBaseUrl() + 'files' + '?path=' + encodeURIComponent(data['filename']);
96
+ resolve({downloadURL : downloadURL, src: downloadURL})
97
+ },
98
+ error: (error) => {
99
+ reject(error)
100
+ }
101
+ });
102
+ });
103
+ }
104
+
105
+ uploadAsset(userId: string, upload: UploadModel, expiration: number = 60): Promise<{downloadURL: string, src: string}> {
106
+ this.logger.log('[NATIVE UPLOAD] - upload new asset ... upload', upload, 'expiration:', expiration)
107
+ const headers = new HttpHeaders({
108
+ Authorization: this.tiledeskToken,
109
+ });
110
+ const requestOptions = { headers: headers };
111
+ const formData = new FormData();
112
+ formData.append('file', upload.file);
113
+
114
+ const that = this;
115
+ const url = this.URL_TILEDESK_FILE + `/assets?expiration=${expiration}`
116
+ return new Promise((resolve, reject) => {
117
+ that.http.post(url, formData, requestOptions).pipe(first()).subscribe({
118
+ next: (data) => {
119
+ // API responses can vary; try common fields first, otherwise fallback to filename/path.
120
+ const directUrl = data?.['downloadURL'] || data?.['url'] || data?.['src'];
121
+ const filenameOrPath = data?.['filename'] || data?.['path'];
122
+ const downloadURL = directUrl || (filenameOrPath ? (this.getBaseUrl() + 'files' + '?path=' + encodeURIComponent(filenameOrPath)) : null);
123
+ if (!downloadURL) {
124
+ reject(new Error('[NATIVE UPLOAD] uploadAsset: unexpected response payload'))
125
+ return;
126
+ }
127
+ resolve({ downloadURL: downloadURL, src: downloadURL })
128
+ },
129
+ error: (error) => {
130
+ reject(error)
131
+ }
132
+ });
133
+ });
134
+ }
135
+
79
136
  uploadProfile(userId: string, upload: UploadModel): Promise<any> {
80
137
  this.logger.log('[NATIVE UPLOAD] - upload new photo profile ... upload', upload)
81
138
  const headers = new HttpHeaders({
@@ -88,14 +145,18 @@ export class NativeUploadService extends UploadService {
88
145
 
89
146
  // USE IMAGE API
90
147
  const that = this;
91
- const url = this.URL_TILEDESK_IMAGES + `/users/photo?force=true&user_id=${userId}`
148
+ const botId = userId?.startsWith('bot_') ? userId.substring('bot_'.length) : userId
149
+ const url = this.URL_TILEDESK_FILE + `/users/photo?bot_id=${botId}`
92
150
  return new Promise((resolve, reject) => {
93
- that.http.put(url, formData, requestOptions).subscribe(data => {
94
- const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['thumbnail'];
95
- resolve(downloadURL)
96
- // that.BSStateUpload.next({upload: upload});
97
- }, (error) => {
98
- reject(error)
151
+ that.http.put(url, formData, requestOptions).pipe(first()).subscribe({
152
+ next: (data) => {
153
+ const downloadURL = this.getBaseUrl() + 'files?path=' + data['thumbnail'];
154
+ resolve(downloadURL)
155
+ // that.BSStateUpload.next({upload: upload});
156
+ },
157
+ error: (error) => {
158
+ reject(error)
159
+ }
99
160
  });
100
161
  });
101
162
  }
@@ -110,7 +171,7 @@ export class NativeUploadService extends UploadService {
110
171
 
111
172
  //USE IMAGE API
112
173
  const that = this;
113
- const url = this.URL_TILEDESK_IMAGES + '/users' + '?path=' + path.split('path=')[1]
174
+ const url = this.URL_TILEDESK_UPLOAD + 'images/users' + '?path=' + path.split('path=')[1]
114
175
  return new Promise((resolve, reject) => {
115
176
  that.http.delete(url, requestOptions).subscribe(data => {
116
177
  // const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['filename'];
@@ -122,6 +183,31 @@ export class NativeUploadService extends UploadService {
122
183
  });
123
184
  }
124
185
 
186
+ deleteFile(userId: string, path: string): Promise<any>{
187
+ this.logger.log('[NATIVE UPLOAD] - delete image ... upload', userId)
188
+ const headers = new HttpHeaders({
189
+ Authorization: this.tiledeskToken,
190
+ //'Content-Type': 'multipart/form-data',
191
+ });
192
+ const requestOptions = { headers: headers };
193
+
194
+ //USE IMAGE API
195
+ const that = this;
196
+ const url = this.URL_TILEDESK_FILE + '?path=' + path.split('path=')[1]
197
+ return new Promise((resolve, reject) => {
198
+ that.http.delete(url, requestOptions).pipe(first()).subscribe({
199
+ next: (data) => {
200
+ // const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['filename'];
201
+ resolve(true)
202
+ // that.BSStateUpload.next({upload: upload});
203
+ },
204
+ error: (error) => {
205
+ reject(error)
206
+ }
207
+ });
208
+ });
209
+ }
210
+
125
211
  deleteProfile(userId: string, path: string): Promise<any>{
126
212
  this.logger.log('[NATIVE UPLOAD] - delete image ... upload', userId)
127
213
  const headers = new HttpHeaders({
@@ -132,14 +218,17 @@ export class NativeUploadService extends UploadService {
132
218
 
133
219
  //USE IMAGE API
134
220
  const that = this;
135
- const url = this.URL_TILEDESK_IMAGES + '/users' + '?path=' + "uploads/users/"+ userId + "/images/photo.jpg"
221
+ const url = this.URL_TILEDESK_FILE + '?path=' + "uploads/users/"+ userId + "/images/photo.jpg"
136
222
  return new Promise((resolve, reject) => {
137
- that.http.delete(url, requestOptions).subscribe(data => {
138
- // const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['filename'];
139
- resolve(true)
140
- // that.BSStateUpload.next({upload: upload});
141
- }, (error) => {
142
- reject(error)
223
+ that.http.delete(url, requestOptions).pipe(first()).subscribe({
224
+ next: (data) => {
225
+ // const downloadURL = this.URL_TILEDESK_IMAGES + '?path=' + data['filename'];
226
+ resolve(true)
227
+ // that.BSStateUpload.next({upload: upload});
228
+ },
229
+ error: (error) => {
230
+ reject(error)
231
+ }
143
232
  });
144
233
  });
145
234
  }