@blackcode_sa/metaestetics-api 1.12.63 → 1.12.64
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.
|
@@ -1170,10 +1170,86 @@ interface ProcedureProduct {
|
|
|
1170
1170
|
isDefault?: boolean;
|
|
1171
1171
|
}
|
|
1172
1172
|
|
|
1173
|
+
/**
|
|
1174
|
+
* Enum for media access levels
|
|
1175
|
+
*/
|
|
1176
|
+
declare enum MediaAccessLevel {
|
|
1177
|
+
PUBLIC = "public",
|
|
1178
|
+
PRIVATE = "private",
|
|
1179
|
+
CONFIDENTIAL = "confidential"
|
|
1180
|
+
}
|
|
1173
1181
|
/**
|
|
1174
1182
|
* Type that allows a field to be either a URL string or a File object
|
|
1175
1183
|
*/
|
|
1176
1184
|
type MediaResource = string | File | Blob;
|
|
1185
|
+
/**
|
|
1186
|
+
* Media file metadata interface
|
|
1187
|
+
*/
|
|
1188
|
+
interface MediaMetadata {
|
|
1189
|
+
id: string;
|
|
1190
|
+
name: string;
|
|
1191
|
+
url: string;
|
|
1192
|
+
contentType: string;
|
|
1193
|
+
size: number;
|
|
1194
|
+
createdAt: Timestamp;
|
|
1195
|
+
accessLevel: MediaAccessLevel;
|
|
1196
|
+
ownerId: string;
|
|
1197
|
+
collectionName: string;
|
|
1198
|
+
path: string;
|
|
1199
|
+
updatedAt?: Timestamp;
|
|
1200
|
+
}
|
|
1201
|
+
declare class MediaService extends BaseService {
|
|
1202
|
+
constructor(...args: ConstructorParameters<typeof BaseService>);
|
|
1203
|
+
/**
|
|
1204
|
+
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
1205
|
+
* @param file - The file to upload.
|
|
1206
|
+
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
1207
|
+
* @param accessLevel - Access level (public, private, confidential).
|
|
1208
|
+
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
1209
|
+
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
1210
|
+
* @returns Promise with the media metadata.
|
|
1211
|
+
*/
|
|
1212
|
+
uploadMedia(file: File | Blob, ownerId: string, accessLevel: MediaAccessLevel, collectionName: string, originalFileName?: string): Promise<MediaMetadata>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Get media metadata from Firestore by its ID.
|
|
1215
|
+
* @param mediaId - ID of the media.
|
|
1216
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1217
|
+
*/
|
|
1218
|
+
getMediaMetadata(mediaId: string): Promise<MediaMetadata | null>;
|
|
1219
|
+
/**
|
|
1220
|
+
* Get media metadata from Firestore by its public URL.
|
|
1221
|
+
* @param url - The public URL of the media file.
|
|
1222
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1223
|
+
*/
|
|
1224
|
+
getMediaMetadataByUrl(url: string): Promise<MediaMetadata | null>;
|
|
1225
|
+
/**
|
|
1226
|
+
* Delete media from storage and remove metadata from Firestore.
|
|
1227
|
+
* @param mediaId - ID of the media to delete.
|
|
1228
|
+
*/
|
|
1229
|
+
deleteMedia(mediaId: string): Promise<void>;
|
|
1230
|
+
/**
|
|
1231
|
+
* Update media access level. This involves moving the file in Firebase Storage
|
|
1232
|
+
* to a new path reflecting the new access level, and updating its metadata.
|
|
1233
|
+
* @param mediaId - ID of the media to update.
|
|
1234
|
+
* @param newAccessLevel - New access level.
|
|
1235
|
+
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
1236
|
+
*/
|
|
1237
|
+
updateMediaAccessLevel(mediaId: string, newAccessLevel: MediaAccessLevel): Promise<MediaMetadata | null>;
|
|
1238
|
+
/**
|
|
1239
|
+
* List all media for an owner, optionally filtered by collection and access level.
|
|
1240
|
+
* @param ownerId - ID of the owner.
|
|
1241
|
+
* @param collectionName - Optional: Filter by collection name.
|
|
1242
|
+
* @param accessLevel - Optional: Filter by access level.
|
|
1243
|
+
* @param count - Optional: Number of items to fetch.
|
|
1244
|
+
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
1245
|
+
*/
|
|
1246
|
+
listMedia(ownerId: string, collectionName?: string, accessLevel?: MediaAccessLevel, count?: number, startAfterId?: string): Promise<MediaMetadata[]>;
|
|
1247
|
+
/**
|
|
1248
|
+
* Get download URL for media. (Convenience, as URL is in metadata)
|
|
1249
|
+
* @param mediaId - ID of the media.
|
|
1250
|
+
*/
|
|
1251
|
+
getMediaDownloadUrl(mediaId: string): Promise<string | null>;
|
|
1252
|
+
}
|
|
1177
1253
|
|
|
1178
1254
|
/**
|
|
1179
1255
|
* Aggregated summary information for a procedure.
|
|
@@ -6530,4 +6606,4 @@ declare class InvalidTreatmentBenefitError extends TreatmentBenefitError {
|
|
|
6530
6606
|
constructor(benefit: string);
|
|
6531
6607
|
}
|
|
6532
6608
|
|
|
6533
|
-
export { BRANDS_COLLECTION, BackofficeError, BlockingCondition, BlockingConditionError, type Brand, BrandService, CATEGORIES_COLLECTION, type Category, CategoryError, CategoryNotFoundError, CategoryService, CertificationLevel, type CertificationRequirement, CertificationSpecialty, CircularReferenceError, ConstantsService, Contraindication, type ContraindicationDynamic, ContraindicationError, type ContraindicationsDocument, type CreateDocumentTemplateData, Currency, DEFAULT_CERTIFICATION_REQUIREMENT, DOCUMENTATION_TEMPLATES_COLLECTION, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateServiceBackoffice, DynamicVariable, FILLED_DOCUMENTS_COLLECTION, HeadingLevel, type ICategoryService, type IProductService, type ITechnologyService, InvalidBlockingConditionError, InvalidCategoryDataError, InvalidContraindicationError, InvalidHierarchyError, InvalidRequirementDataError, InvalidSubcategoryDataError, InvalidTechnologyDataError, InvalidTimeframeError, InvalidTreatmentBenefitError, ListType, PRODUCTS_COLLECTION, PricingMeasure, ProcedureFamily, type ProcedureProduct, type Product, ProductService, REQUIREMENTS_COLLECTION, RelationshipError, type Requirement, RequirementError, type RequirementImportance, RequirementNotFoundError, RequirementService, RequirementType, SUBCATEGORIES_COLLECTION, type Subcategory, SubcategoryError, SubcategoryNotFoundError, SubcategoryService, TECHNOLOGIES_COLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyError, TechnologyNotFoundError, type TechnologyRequirements, TechnologyService, type TimeFrame, TimeUnit, TreatmentBenefit, type TreatmentBenefitDynamic, TreatmentBenefitError, type TreatmentBenefitsDocument, type UpdateDocumentTemplateData, blockingConditionSchemaBackoffice, categorySchema, categoryUpdateSchema, certificationLevelSchema, certificationRequirementSchema, certificationSpecialtySchema, contraindicationDynamicSchema, contraindicationSchemaBackoffice, createDocumentTemplateSchema, documentElementSchema, documentElementWithoutIdSchema, documentTemplateSchema, procedureFamilySchemaBackoffice, requirementSchema, requirementTypeSchema, requirementUpdateSchema, subcategorySchema, subcategoryUpdateSchema, technologyRequirementsSchema, technologySchema, technologyUpdateSchema, timeUnitSchemaBackoffice, timeframeSchema, treatmentBenefitDynamicSchema, treatmentBenefitSchemaBackoffice, updateDocumentTemplateSchema };
|
|
6609
|
+
export { BRANDS_COLLECTION, BackofficeError, BlockingCondition, BlockingConditionError, type Brand, BrandService, CATEGORIES_COLLECTION, type Category, CategoryError, CategoryNotFoundError, CategoryService, CertificationLevel, type CertificationRequirement, CertificationSpecialty, CircularReferenceError, ConstantsService, Contraindication, type ContraindicationDynamic, ContraindicationError, type ContraindicationsDocument, type CreateDocumentTemplateData, Currency, DEFAULT_CERTIFICATION_REQUIREMENT, DOCUMENTATION_TEMPLATES_COLLECTION, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateServiceBackoffice, DynamicVariable, FILLED_DOCUMENTS_COLLECTION, HeadingLevel, type ICategoryService, type IProductService, type ITechnologyService, InvalidBlockingConditionError, InvalidCategoryDataError, InvalidContraindicationError, InvalidHierarchyError, InvalidRequirementDataError, InvalidSubcategoryDataError, InvalidTechnologyDataError, InvalidTimeframeError, InvalidTreatmentBenefitError, ListType, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, PRODUCTS_COLLECTION, PricingMeasure, ProcedureFamily, type ProcedureProduct, type Product, ProductService, REQUIREMENTS_COLLECTION, RelationshipError, type Requirement, RequirementError, type RequirementImportance, RequirementNotFoundError, RequirementService, RequirementType, SUBCATEGORIES_COLLECTION, type Subcategory, SubcategoryError, SubcategoryNotFoundError, SubcategoryService, TECHNOLOGIES_COLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyError, TechnologyNotFoundError, type TechnologyRequirements, TechnologyService, type TimeFrame, TimeUnit, TreatmentBenefit, type TreatmentBenefitDynamic, TreatmentBenefitError, type TreatmentBenefitsDocument, type UpdateDocumentTemplateData, blockingConditionSchemaBackoffice, categorySchema, categoryUpdateSchema, certificationLevelSchema, certificationRequirementSchema, certificationSpecialtySchema, contraindicationDynamicSchema, contraindicationSchemaBackoffice, createDocumentTemplateSchema, documentElementSchema, documentElementWithoutIdSchema, documentTemplateSchema, procedureFamilySchemaBackoffice, requirementSchema, requirementTypeSchema, requirementUpdateSchema, subcategorySchema, subcategoryUpdateSchema, technologyRequirementsSchema, technologySchema, technologyUpdateSchema, timeUnitSchemaBackoffice, timeframeSchema, treatmentBenefitDynamicSchema, treatmentBenefitSchemaBackoffice, updateDocumentTemplateSchema };
|
|
@@ -1170,10 +1170,86 @@ interface ProcedureProduct {
|
|
|
1170
1170
|
isDefault?: boolean;
|
|
1171
1171
|
}
|
|
1172
1172
|
|
|
1173
|
+
/**
|
|
1174
|
+
* Enum for media access levels
|
|
1175
|
+
*/
|
|
1176
|
+
declare enum MediaAccessLevel {
|
|
1177
|
+
PUBLIC = "public",
|
|
1178
|
+
PRIVATE = "private",
|
|
1179
|
+
CONFIDENTIAL = "confidential"
|
|
1180
|
+
}
|
|
1173
1181
|
/**
|
|
1174
1182
|
* Type that allows a field to be either a URL string or a File object
|
|
1175
1183
|
*/
|
|
1176
1184
|
type MediaResource = string | File | Blob;
|
|
1185
|
+
/**
|
|
1186
|
+
* Media file metadata interface
|
|
1187
|
+
*/
|
|
1188
|
+
interface MediaMetadata {
|
|
1189
|
+
id: string;
|
|
1190
|
+
name: string;
|
|
1191
|
+
url: string;
|
|
1192
|
+
contentType: string;
|
|
1193
|
+
size: number;
|
|
1194
|
+
createdAt: Timestamp;
|
|
1195
|
+
accessLevel: MediaAccessLevel;
|
|
1196
|
+
ownerId: string;
|
|
1197
|
+
collectionName: string;
|
|
1198
|
+
path: string;
|
|
1199
|
+
updatedAt?: Timestamp;
|
|
1200
|
+
}
|
|
1201
|
+
declare class MediaService extends BaseService {
|
|
1202
|
+
constructor(...args: ConstructorParameters<typeof BaseService>);
|
|
1203
|
+
/**
|
|
1204
|
+
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
1205
|
+
* @param file - The file to upload.
|
|
1206
|
+
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
1207
|
+
* @param accessLevel - Access level (public, private, confidential).
|
|
1208
|
+
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
1209
|
+
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
1210
|
+
* @returns Promise with the media metadata.
|
|
1211
|
+
*/
|
|
1212
|
+
uploadMedia(file: File | Blob, ownerId: string, accessLevel: MediaAccessLevel, collectionName: string, originalFileName?: string): Promise<MediaMetadata>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Get media metadata from Firestore by its ID.
|
|
1215
|
+
* @param mediaId - ID of the media.
|
|
1216
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1217
|
+
*/
|
|
1218
|
+
getMediaMetadata(mediaId: string): Promise<MediaMetadata | null>;
|
|
1219
|
+
/**
|
|
1220
|
+
* Get media metadata from Firestore by its public URL.
|
|
1221
|
+
* @param url - The public URL of the media file.
|
|
1222
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1223
|
+
*/
|
|
1224
|
+
getMediaMetadataByUrl(url: string): Promise<MediaMetadata | null>;
|
|
1225
|
+
/**
|
|
1226
|
+
* Delete media from storage and remove metadata from Firestore.
|
|
1227
|
+
* @param mediaId - ID of the media to delete.
|
|
1228
|
+
*/
|
|
1229
|
+
deleteMedia(mediaId: string): Promise<void>;
|
|
1230
|
+
/**
|
|
1231
|
+
* Update media access level. This involves moving the file in Firebase Storage
|
|
1232
|
+
* to a new path reflecting the new access level, and updating its metadata.
|
|
1233
|
+
* @param mediaId - ID of the media to update.
|
|
1234
|
+
* @param newAccessLevel - New access level.
|
|
1235
|
+
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
1236
|
+
*/
|
|
1237
|
+
updateMediaAccessLevel(mediaId: string, newAccessLevel: MediaAccessLevel): Promise<MediaMetadata | null>;
|
|
1238
|
+
/**
|
|
1239
|
+
* List all media for an owner, optionally filtered by collection and access level.
|
|
1240
|
+
* @param ownerId - ID of the owner.
|
|
1241
|
+
* @param collectionName - Optional: Filter by collection name.
|
|
1242
|
+
* @param accessLevel - Optional: Filter by access level.
|
|
1243
|
+
* @param count - Optional: Number of items to fetch.
|
|
1244
|
+
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
1245
|
+
*/
|
|
1246
|
+
listMedia(ownerId: string, collectionName?: string, accessLevel?: MediaAccessLevel, count?: number, startAfterId?: string): Promise<MediaMetadata[]>;
|
|
1247
|
+
/**
|
|
1248
|
+
* Get download URL for media. (Convenience, as URL is in metadata)
|
|
1249
|
+
* @param mediaId - ID of the media.
|
|
1250
|
+
*/
|
|
1251
|
+
getMediaDownloadUrl(mediaId: string): Promise<string | null>;
|
|
1252
|
+
}
|
|
1177
1253
|
|
|
1178
1254
|
/**
|
|
1179
1255
|
* Aggregated summary information for a procedure.
|
|
@@ -6530,4 +6606,4 @@ declare class InvalidTreatmentBenefitError extends TreatmentBenefitError {
|
|
|
6530
6606
|
constructor(benefit: string);
|
|
6531
6607
|
}
|
|
6532
6608
|
|
|
6533
|
-
export { BRANDS_COLLECTION, BackofficeError, BlockingCondition, BlockingConditionError, type Brand, BrandService, CATEGORIES_COLLECTION, type Category, CategoryError, CategoryNotFoundError, CategoryService, CertificationLevel, type CertificationRequirement, CertificationSpecialty, CircularReferenceError, ConstantsService, Contraindication, type ContraindicationDynamic, ContraindicationError, type ContraindicationsDocument, type CreateDocumentTemplateData, Currency, DEFAULT_CERTIFICATION_REQUIREMENT, DOCUMENTATION_TEMPLATES_COLLECTION, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateServiceBackoffice, DynamicVariable, FILLED_DOCUMENTS_COLLECTION, HeadingLevel, type ICategoryService, type IProductService, type ITechnologyService, InvalidBlockingConditionError, InvalidCategoryDataError, InvalidContraindicationError, InvalidHierarchyError, InvalidRequirementDataError, InvalidSubcategoryDataError, InvalidTechnologyDataError, InvalidTimeframeError, InvalidTreatmentBenefitError, ListType, PRODUCTS_COLLECTION, PricingMeasure, ProcedureFamily, type ProcedureProduct, type Product, ProductService, REQUIREMENTS_COLLECTION, RelationshipError, type Requirement, RequirementError, type RequirementImportance, RequirementNotFoundError, RequirementService, RequirementType, SUBCATEGORIES_COLLECTION, type Subcategory, SubcategoryError, SubcategoryNotFoundError, SubcategoryService, TECHNOLOGIES_COLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyError, TechnologyNotFoundError, type TechnologyRequirements, TechnologyService, type TimeFrame, TimeUnit, TreatmentBenefit, type TreatmentBenefitDynamic, TreatmentBenefitError, type TreatmentBenefitsDocument, type UpdateDocumentTemplateData, blockingConditionSchemaBackoffice, categorySchema, categoryUpdateSchema, certificationLevelSchema, certificationRequirementSchema, certificationSpecialtySchema, contraindicationDynamicSchema, contraindicationSchemaBackoffice, createDocumentTemplateSchema, documentElementSchema, documentElementWithoutIdSchema, documentTemplateSchema, procedureFamilySchemaBackoffice, requirementSchema, requirementTypeSchema, requirementUpdateSchema, subcategorySchema, subcategoryUpdateSchema, technologyRequirementsSchema, technologySchema, technologyUpdateSchema, timeUnitSchemaBackoffice, timeframeSchema, treatmentBenefitDynamicSchema, treatmentBenefitSchemaBackoffice, updateDocumentTemplateSchema };
|
|
6609
|
+
export { BRANDS_COLLECTION, BackofficeError, BlockingCondition, BlockingConditionError, type Brand, BrandService, CATEGORIES_COLLECTION, type Category, CategoryError, CategoryNotFoundError, CategoryService, CertificationLevel, type CertificationRequirement, CertificationSpecialty, CircularReferenceError, ConstantsService, Contraindication, type ContraindicationDynamic, ContraindicationError, type ContraindicationsDocument, type CreateDocumentTemplateData, Currency, DEFAULT_CERTIFICATION_REQUIREMENT, DOCUMENTATION_TEMPLATES_COLLECTION, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateServiceBackoffice, DynamicVariable, FILLED_DOCUMENTS_COLLECTION, HeadingLevel, type ICategoryService, type IProductService, type ITechnologyService, InvalidBlockingConditionError, InvalidCategoryDataError, InvalidContraindicationError, InvalidHierarchyError, InvalidRequirementDataError, InvalidSubcategoryDataError, InvalidTechnologyDataError, InvalidTimeframeError, InvalidTreatmentBenefitError, ListType, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, PRODUCTS_COLLECTION, PricingMeasure, ProcedureFamily, type ProcedureProduct, type Product, ProductService, REQUIREMENTS_COLLECTION, RelationshipError, type Requirement, RequirementError, type RequirementImportance, RequirementNotFoundError, RequirementService, RequirementType, SUBCATEGORIES_COLLECTION, type Subcategory, SubcategoryError, SubcategoryNotFoundError, SubcategoryService, TECHNOLOGIES_COLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyError, TechnologyNotFoundError, type TechnologyRequirements, TechnologyService, type TimeFrame, TimeUnit, TreatmentBenefit, type TreatmentBenefitDynamic, TreatmentBenefitError, type TreatmentBenefitsDocument, type UpdateDocumentTemplateData, blockingConditionSchemaBackoffice, categorySchema, categoryUpdateSchema, certificationLevelSchema, certificationRequirementSchema, certificationSpecialtySchema, contraindicationDynamicSchema, contraindicationSchemaBackoffice, createDocumentTemplateSchema, documentElementSchema, documentElementWithoutIdSchema, documentTemplateSchema, procedureFamilySchemaBackoffice, requirementSchema, requirementTypeSchema, requirementUpdateSchema, subcategorySchema, subcategoryUpdateSchema, technologyRequirementsSchema, technologySchema, technologyUpdateSchema, timeUnitSchemaBackoffice, timeframeSchema, treatmentBenefitDynamicSchema, treatmentBenefitSchemaBackoffice, updateDocumentTemplateSchema };
|
package/dist/backoffice/index.js
CHANGED
|
@@ -53,6 +53,8 @@ __export(index_exports, {
|
|
|
53
53
|
InvalidTimeframeError: () => InvalidTimeframeError,
|
|
54
54
|
InvalidTreatmentBenefitError: () => InvalidTreatmentBenefitError,
|
|
55
55
|
ListType: () => ListType,
|
|
56
|
+
MediaAccessLevel: () => MediaAccessLevel,
|
|
57
|
+
MediaService: () => MediaService,
|
|
56
58
|
PRODUCTS_COLLECTION: () => PRODUCTS_COLLECTION,
|
|
57
59
|
PricingMeasure: () => PricingMeasure,
|
|
58
60
|
ProcedureFamily: () => ProcedureFamily,
|
|
@@ -1185,6 +1187,299 @@ var import_firestore7 = require("firebase/firestore");
|
|
|
1185
1187
|
var import_firestore5 = require("firebase/firestore");
|
|
1186
1188
|
var import_storage2 = require("firebase/storage");
|
|
1187
1189
|
var import_firestore6 = require("firebase/firestore");
|
|
1190
|
+
var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
1191
|
+
MediaAccessLevel2["PUBLIC"] = "public";
|
|
1192
|
+
MediaAccessLevel2["PRIVATE"] = "private";
|
|
1193
|
+
MediaAccessLevel2["CONFIDENTIAL"] = "confidential";
|
|
1194
|
+
return MediaAccessLevel2;
|
|
1195
|
+
})(MediaAccessLevel || {});
|
|
1196
|
+
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
1197
|
+
var MediaService = class extends BaseService {
|
|
1198
|
+
constructor(...args) {
|
|
1199
|
+
super(...args);
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
1203
|
+
* @param file - The file to upload.
|
|
1204
|
+
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
1205
|
+
* @param accessLevel - Access level (public, private, confidential).
|
|
1206
|
+
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
1207
|
+
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
1208
|
+
* @returns Promise with the media metadata.
|
|
1209
|
+
*/
|
|
1210
|
+
async uploadMedia(file, ownerId, accessLevel, collectionName, originalFileName) {
|
|
1211
|
+
const mediaId = this.generateId();
|
|
1212
|
+
const fileNameToUse = originalFileName || (file instanceof File ? file.name : file.toString());
|
|
1213
|
+
const uniqueFileName = `${mediaId}-${fileNameToUse}`;
|
|
1214
|
+
const filePath = `media/${accessLevel}/${ownerId}/${collectionName}/${uniqueFileName}`;
|
|
1215
|
+
console.log(`[MediaService] Uploading file to: ${filePath}`);
|
|
1216
|
+
const storageRef = (0, import_storage2.ref)(this.storage, filePath);
|
|
1217
|
+
try {
|
|
1218
|
+
const uploadResult = await (0, import_storage2.uploadBytes)(storageRef, file, {
|
|
1219
|
+
contentType: file.type
|
|
1220
|
+
});
|
|
1221
|
+
console.log("[MediaService] File uploaded successfully", uploadResult);
|
|
1222
|
+
const downloadURL = await (0, import_storage2.getDownloadURL)(uploadResult.ref);
|
|
1223
|
+
console.log("[MediaService] Got download URL:", downloadURL);
|
|
1224
|
+
const metadata = {
|
|
1225
|
+
id: mediaId,
|
|
1226
|
+
name: fileNameToUse,
|
|
1227
|
+
url: downloadURL,
|
|
1228
|
+
contentType: file.type,
|
|
1229
|
+
size: file.size,
|
|
1230
|
+
createdAt: import_firestore5.Timestamp.now(),
|
|
1231
|
+
accessLevel,
|
|
1232
|
+
ownerId,
|
|
1233
|
+
collectionName,
|
|
1234
|
+
path: filePath
|
|
1235
|
+
};
|
|
1236
|
+
const metadataDocRef = (0, import_firestore6.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1237
|
+
await (0, import_firestore6.setDoc)(metadataDocRef, metadata);
|
|
1238
|
+
console.log("[MediaService] Metadata stored in Firestore:", mediaId);
|
|
1239
|
+
return metadata;
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
console.error("[MediaService] Error during media upload:", error);
|
|
1242
|
+
throw error;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Get media metadata from Firestore by its ID.
|
|
1247
|
+
* @param mediaId - ID of the media.
|
|
1248
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1249
|
+
*/
|
|
1250
|
+
async getMediaMetadata(mediaId) {
|
|
1251
|
+
console.log(`[MediaService] Getting media metadata for ID: ${mediaId}`);
|
|
1252
|
+
const docRef = (0, import_firestore6.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1253
|
+
const docSnap = await (0, import_firestore6.getDoc)(docRef);
|
|
1254
|
+
if (docSnap.exists()) {
|
|
1255
|
+
console.log("[MediaService] Metadata found:", docSnap.data());
|
|
1256
|
+
return docSnap.data();
|
|
1257
|
+
}
|
|
1258
|
+
console.log("[MediaService] No metadata found for ID:", mediaId);
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Get media metadata from Firestore by its public URL.
|
|
1263
|
+
* @param url - The public URL of the media file.
|
|
1264
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1265
|
+
*/
|
|
1266
|
+
async getMediaMetadataByUrl(url) {
|
|
1267
|
+
console.log(`[MediaService] Getting media metadata by URL: ${url}`);
|
|
1268
|
+
const q = (0, import_firestore6.query)(
|
|
1269
|
+
(0, import_firestore6.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
1270
|
+
(0, import_firestore6.where)("url", "==", url),
|
|
1271
|
+
(0, import_firestore6.limit)(1)
|
|
1272
|
+
);
|
|
1273
|
+
try {
|
|
1274
|
+
const querySnapshot = await (0, import_firestore6.getDocs)(q);
|
|
1275
|
+
if (!querySnapshot.empty) {
|
|
1276
|
+
const metadata = querySnapshot.docs[0].data();
|
|
1277
|
+
console.log("[MediaService] Metadata found by URL:", metadata);
|
|
1278
|
+
return metadata;
|
|
1279
|
+
}
|
|
1280
|
+
console.log("[MediaService] No metadata found for URL:", url);
|
|
1281
|
+
return null;
|
|
1282
|
+
} catch (error) {
|
|
1283
|
+
console.error("[MediaService] Error fetching metadata by URL:", error);
|
|
1284
|
+
throw error;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Delete media from storage and remove metadata from Firestore.
|
|
1289
|
+
* @param mediaId - ID of the media to delete.
|
|
1290
|
+
*/
|
|
1291
|
+
async deleteMedia(mediaId) {
|
|
1292
|
+
console.log(`[MediaService] Deleting media with ID: ${mediaId}`);
|
|
1293
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1294
|
+
if (!metadata) {
|
|
1295
|
+
console.warn(
|
|
1296
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot delete.`
|
|
1297
|
+
);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
const storageFileRef = (0, import_storage2.ref)(this.storage, metadata.path);
|
|
1301
|
+
try {
|
|
1302
|
+
await (0, import_storage2.deleteObject)(storageFileRef);
|
|
1303
|
+
console.log(`[MediaService] File deleted from Storage: ${metadata.path}`);
|
|
1304
|
+
const metadataDocRef = (0, import_firestore6.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1305
|
+
await (0, import_firestore6.deleteDoc)(metadataDocRef);
|
|
1306
|
+
console.log(
|
|
1307
|
+
`[MediaService] Metadata deleted from Firestore for ID: ${mediaId}`
|
|
1308
|
+
);
|
|
1309
|
+
} catch (error) {
|
|
1310
|
+
console.error(`[MediaService] Error deleting media ${mediaId}:`, error);
|
|
1311
|
+
throw error;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Update media access level. This involves moving the file in Firebase Storage
|
|
1316
|
+
* to a new path reflecting the new access level, and updating its metadata.
|
|
1317
|
+
* @param mediaId - ID of the media to update.
|
|
1318
|
+
* @param newAccessLevel - New access level.
|
|
1319
|
+
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
1320
|
+
*/
|
|
1321
|
+
async updateMediaAccessLevel(mediaId, newAccessLevel) {
|
|
1322
|
+
var _a;
|
|
1323
|
+
console.log(
|
|
1324
|
+
`[MediaService] Attempting to update access level for media ID: ${mediaId} to ${newAccessLevel}`
|
|
1325
|
+
);
|
|
1326
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1327
|
+
if (!metadata) {
|
|
1328
|
+
console.warn(
|
|
1329
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot update access level.`
|
|
1330
|
+
);
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1333
|
+
if (metadata.accessLevel === newAccessLevel) {
|
|
1334
|
+
console.log(
|
|
1335
|
+
`[MediaService] Media ID ${mediaId} already has access level ${newAccessLevel}. Updating timestamp only.`
|
|
1336
|
+
);
|
|
1337
|
+
const metadataDocRef = (0, import_firestore6.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1338
|
+
try {
|
|
1339
|
+
await (0, import_firestore6.updateDoc)(metadataDocRef, { updatedAt: import_firestore5.Timestamp.now() });
|
|
1340
|
+
return { ...metadata, updatedAt: import_firestore5.Timestamp.now() };
|
|
1341
|
+
} catch (error) {
|
|
1342
|
+
console.error(
|
|
1343
|
+
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
1344
|
+
error
|
|
1345
|
+
);
|
|
1346
|
+
throw error;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
const oldStoragePath = metadata.path;
|
|
1350
|
+
const fileNamePart = `${metadata.id}-${metadata.name}`;
|
|
1351
|
+
const newStoragePath = `media/${newAccessLevel}/${metadata.ownerId}/${metadata.collectionName}/${fileNamePart}`;
|
|
1352
|
+
console.log(
|
|
1353
|
+
`[MediaService] Moving file for ${mediaId} from ${oldStoragePath} to ${newStoragePath}`
|
|
1354
|
+
);
|
|
1355
|
+
const oldStorageFileRef = (0, import_storage2.ref)(this.storage, oldStoragePath);
|
|
1356
|
+
const newStorageFileRef = (0, import_storage2.ref)(this.storage, newStoragePath);
|
|
1357
|
+
try {
|
|
1358
|
+
console.log(`[MediaService] Downloading bytes from ${oldStoragePath}`);
|
|
1359
|
+
const fileBytes = await (0, import_storage2.getBytes)(oldStorageFileRef);
|
|
1360
|
+
console.log(
|
|
1361
|
+
`[MediaService] Successfully downloaded ${fileBytes.byteLength} bytes from ${oldStoragePath}`
|
|
1362
|
+
);
|
|
1363
|
+
console.log(`[MediaService] Uploading bytes to ${newStoragePath}`);
|
|
1364
|
+
await (0, import_storage2.uploadBytes)(newStorageFileRef, fileBytes, {
|
|
1365
|
+
contentType: metadata.contentType
|
|
1366
|
+
});
|
|
1367
|
+
console.log(
|
|
1368
|
+
`[MediaService] Successfully uploaded bytes to ${newStoragePath}`
|
|
1369
|
+
);
|
|
1370
|
+
const newDownloadURL = await (0, import_storage2.getDownloadURL)(newStorageFileRef);
|
|
1371
|
+
console.log(
|
|
1372
|
+
`[MediaService] Got new download URL for ${newStoragePath}: ${newDownloadURL}`
|
|
1373
|
+
);
|
|
1374
|
+
const updateData = {
|
|
1375
|
+
accessLevel: newAccessLevel,
|
|
1376
|
+
path: newStoragePath,
|
|
1377
|
+
url: newDownloadURL,
|
|
1378
|
+
updatedAt: import_firestore5.Timestamp.now()
|
|
1379
|
+
};
|
|
1380
|
+
const metadataDocRef = (0, import_firestore6.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1381
|
+
console.log(
|
|
1382
|
+
`[MediaService] Updating Firestore metadata for ${mediaId} with new data:`,
|
|
1383
|
+
updateData
|
|
1384
|
+
);
|
|
1385
|
+
await (0, import_firestore6.updateDoc)(metadataDocRef, updateData);
|
|
1386
|
+
console.log(
|
|
1387
|
+
`[MediaService] Successfully updated Firestore metadata for ${mediaId}`
|
|
1388
|
+
);
|
|
1389
|
+
try {
|
|
1390
|
+
console.log(`[MediaService] Deleting old file from ${oldStoragePath}`);
|
|
1391
|
+
await (0, import_storage2.deleteObject)(oldStorageFileRef);
|
|
1392
|
+
console.log(
|
|
1393
|
+
`[MediaService] Successfully deleted old file from ${oldStoragePath}`
|
|
1394
|
+
);
|
|
1395
|
+
} catch (deleteError) {
|
|
1396
|
+
console.error(
|
|
1397
|
+
`[MediaService] Failed to delete old file from ${oldStoragePath} for media ID ${mediaId}. This file is now orphaned. Error:`,
|
|
1398
|
+
deleteError
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
return { ...metadata, ...updateData };
|
|
1402
|
+
} catch (error) {
|
|
1403
|
+
console.error(
|
|
1404
|
+
`[MediaService] Error updating media access level and moving file for ${mediaId}:`,
|
|
1405
|
+
error
|
|
1406
|
+
);
|
|
1407
|
+
if (newStorageFileRef && error.code !== "storage/object-not-found" && ((_a = error.message) == null ? void 0 : _a.includes("uploadBytes"))) {
|
|
1408
|
+
console.warn(
|
|
1409
|
+
`[MediaService] Attempting to delete partially uploaded file at ${newStoragePath} due to error.`
|
|
1410
|
+
);
|
|
1411
|
+
try {
|
|
1412
|
+
await (0, import_storage2.deleteObject)(newStorageFileRef);
|
|
1413
|
+
console.warn(
|
|
1414
|
+
`[MediaService] Cleaned up partially uploaded file at ${newStoragePath}.`
|
|
1415
|
+
);
|
|
1416
|
+
} catch (cleanupError) {
|
|
1417
|
+
console.error(
|
|
1418
|
+
`[MediaService] Failed to cleanup partially uploaded file at ${newStoragePath}:`,
|
|
1419
|
+
cleanupError
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
throw error;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* List all media for an owner, optionally filtered by collection and access level.
|
|
1428
|
+
* @param ownerId - ID of the owner.
|
|
1429
|
+
* @param collectionName - Optional: Filter by collection name.
|
|
1430
|
+
* @param accessLevel - Optional: Filter by access level.
|
|
1431
|
+
* @param count - Optional: Number of items to fetch.
|
|
1432
|
+
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
1433
|
+
*/
|
|
1434
|
+
async listMedia(ownerId, collectionName, accessLevel, count, startAfterId) {
|
|
1435
|
+
console.log(`[MediaService] Listing media for owner: ${ownerId}`);
|
|
1436
|
+
let qConstraints = [(0, import_firestore6.where)("ownerId", "==", ownerId)];
|
|
1437
|
+
if (collectionName) {
|
|
1438
|
+
qConstraints.push((0, import_firestore6.where)("collectionName", "==", collectionName));
|
|
1439
|
+
}
|
|
1440
|
+
if (accessLevel) {
|
|
1441
|
+
qConstraints.push((0, import_firestore6.where)("accessLevel", "==", accessLevel));
|
|
1442
|
+
}
|
|
1443
|
+
qConstraints.push((0, import_firestore6.orderBy)("createdAt", "desc"));
|
|
1444
|
+
if (count) {
|
|
1445
|
+
qConstraints.push((0, import_firestore6.limit)(count));
|
|
1446
|
+
}
|
|
1447
|
+
if (startAfterId) {
|
|
1448
|
+
const startAfterDoc = await this.getMediaMetadata(startAfterId);
|
|
1449
|
+
if (startAfterDoc) {
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
const finalQuery = (0, import_firestore6.query)(
|
|
1453
|
+
(0, import_firestore6.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
1454
|
+
...qConstraints
|
|
1455
|
+
);
|
|
1456
|
+
try {
|
|
1457
|
+
const querySnapshot = await (0, import_firestore6.getDocs)(finalQuery);
|
|
1458
|
+
const mediaList = querySnapshot.docs.map(
|
|
1459
|
+
(doc11) => doc11.data()
|
|
1460
|
+
);
|
|
1461
|
+
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
1462
|
+
return mediaList;
|
|
1463
|
+
} catch (error) {
|
|
1464
|
+
console.error("[MediaService] Error listing media:", error);
|
|
1465
|
+
throw error;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Get download URL for media. (Convenience, as URL is in metadata)
|
|
1470
|
+
* @param mediaId - ID of the media.
|
|
1471
|
+
*/
|
|
1472
|
+
async getMediaDownloadUrl(mediaId) {
|
|
1473
|
+
console.log(`[MediaService] Getting download URL for media ID: ${mediaId}`);
|
|
1474
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1475
|
+
if (metadata && metadata.url) {
|
|
1476
|
+
console.log(`[MediaService] URL found: ${metadata.url}`);
|
|
1477
|
+
return metadata.url;
|
|
1478
|
+
}
|
|
1479
|
+
console.log(`[MediaService] URL not found for media ID: ${mediaId}`);
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1188
1483
|
|
|
1189
1484
|
// src/backoffice/services/documentation-template.service.ts
|
|
1190
1485
|
var DocumentationTemplateServiceBackoffice = class {
|
|
@@ -3720,6 +4015,8 @@ var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
|
|
|
3720
4015
|
InvalidTimeframeError,
|
|
3721
4016
|
InvalidTreatmentBenefitError,
|
|
3722
4017
|
ListType,
|
|
4018
|
+
MediaAccessLevel,
|
|
4019
|
+
MediaService,
|
|
3723
4020
|
PRODUCTS_COLLECTION,
|
|
3724
4021
|
PricingMeasure,
|
|
3725
4022
|
ProcedureFamily,
|
|
@@ -1148,6 +1148,299 @@ import {
|
|
|
1148
1148
|
deleteDoc as deleteDoc2,
|
|
1149
1149
|
orderBy as orderBy4
|
|
1150
1150
|
} from "firebase/firestore";
|
|
1151
|
+
var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
1152
|
+
MediaAccessLevel2["PUBLIC"] = "public";
|
|
1153
|
+
MediaAccessLevel2["PRIVATE"] = "private";
|
|
1154
|
+
MediaAccessLevel2["CONFIDENTIAL"] = "confidential";
|
|
1155
|
+
return MediaAccessLevel2;
|
|
1156
|
+
})(MediaAccessLevel || {});
|
|
1157
|
+
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
1158
|
+
var MediaService = class extends BaseService {
|
|
1159
|
+
constructor(...args) {
|
|
1160
|
+
super(...args);
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
1164
|
+
* @param file - The file to upload.
|
|
1165
|
+
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
1166
|
+
* @param accessLevel - Access level (public, private, confidential).
|
|
1167
|
+
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
1168
|
+
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
1169
|
+
* @returns Promise with the media metadata.
|
|
1170
|
+
*/
|
|
1171
|
+
async uploadMedia(file, ownerId, accessLevel, collectionName, originalFileName) {
|
|
1172
|
+
const mediaId = this.generateId();
|
|
1173
|
+
const fileNameToUse = originalFileName || (file instanceof File ? file.name : file.toString());
|
|
1174
|
+
const uniqueFileName = `${mediaId}-${fileNameToUse}`;
|
|
1175
|
+
const filePath = `media/${accessLevel}/${ownerId}/${collectionName}/${uniqueFileName}`;
|
|
1176
|
+
console.log(`[MediaService] Uploading file to: ${filePath}`);
|
|
1177
|
+
const storageRef = ref(this.storage, filePath);
|
|
1178
|
+
try {
|
|
1179
|
+
const uploadResult = await uploadBytes(storageRef, file, {
|
|
1180
|
+
contentType: file.type
|
|
1181
|
+
});
|
|
1182
|
+
console.log("[MediaService] File uploaded successfully", uploadResult);
|
|
1183
|
+
const downloadURL = await getDownloadURL(uploadResult.ref);
|
|
1184
|
+
console.log("[MediaService] Got download URL:", downloadURL);
|
|
1185
|
+
const metadata = {
|
|
1186
|
+
id: mediaId,
|
|
1187
|
+
name: fileNameToUse,
|
|
1188
|
+
url: downloadURL,
|
|
1189
|
+
contentType: file.type,
|
|
1190
|
+
size: file.size,
|
|
1191
|
+
createdAt: Timestamp2.now(),
|
|
1192
|
+
accessLevel,
|
|
1193
|
+
ownerId,
|
|
1194
|
+
collectionName,
|
|
1195
|
+
path: filePath
|
|
1196
|
+
};
|
|
1197
|
+
const metadataDocRef = doc4(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1198
|
+
await setDoc2(metadataDocRef, metadata);
|
|
1199
|
+
console.log("[MediaService] Metadata stored in Firestore:", mediaId);
|
|
1200
|
+
return metadata;
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
console.error("[MediaService] Error during media upload:", error);
|
|
1203
|
+
throw error;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Get media metadata from Firestore by its ID.
|
|
1208
|
+
* @param mediaId - ID of the media.
|
|
1209
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1210
|
+
*/
|
|
1211
|
+
async getMediaMetadata(mediaId) {
|
|
1212
|
+
console.log(`[MediaService] Getting media metadata for ID: ${mediaId}`);
|
|
1213
|
+
const docRef = doc4(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1214
|
+
const docSnap = await getDoc4(docRef);
|
|
1215
|
+
if (docSnap.exists()) {
|
|
1216
|
+
console.log("[MediaService] Metadata found:", docSnap.data());
|
|
1217
|
+
return docSnap.data();
|
|
1218
|
+
}
|
|
1219
|
+
console.log("[MediaService] No metadata found for ID:", mediaId);
|
|
1220
|
+
return null;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Get media metadata from Firestore by its public URL.
|
|
1224
|
+
* @param url - The public URL of the media file.
|
|
1225
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1226
|
+
*/
|
|
1227
|
+
async getMediaMetadataByUrl(url) {
|
|
1228
|
+
console.log(`[MediaService] Getting media metadata by URL: ${url}`);
|
|
1229
|
+
const q = query4(
|
|
1230
|
+
collection4(this.db, MEDIA_METADATA_COLLECTION),
|
|
1231
|
+
where4("url", "==", url),
|
|
1232
|
+
limit4(1)
|
|
1233
|
+
);
|
|
1234
|
+
try {
|
|
1235
|
+
const querySnapshot = await getDocs4(q);
|
|
1236
|
+
if (!querySnapshot.empty) {
|
|
1237
|
+
const metadata = querySnapshot.docs[0].data();
|
|
1238
|
+
console.log("[MediaService] Metadata found by URL:", metadata);
|
|
1239
|
+
return metadata;
|
|
1240
|
+
}
|
|
1241
|
+
console.log("[MediaService] No metadata found for URL:", url);
|
|
1242
|
+
return null;
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
console.error("[MediaService] Error fetching metadata by URL:", error);
|
|
1245
|
+
throw error;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Delete media from storage and remove metadata from Firestore.
|
|
1250
|
+
* @param mediaId - ID of the media to delete.
|
|
1251
|
+
*/
|
|
1252
|
+
async deleteMedia(mediaId) {
|
|
1253
|
+
console.log(`[MediaService] Deleting media with ID: ${mediaId}`);
|
|
1254
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1255
|
+
if (!metadata) {
|
|
1256
|
+
console.warn(
|
|
1257
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot delete.`
|
|
1258
|
+
);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
const storageFileRef = ref(this.storage, metadata.path);
|
|
1262
|
+
try {
|
|
1263
|
+
await deleteObject(storageFileRef);
|
|
1264
|
+
console.log(`[MediaService] File deleted from Storage: ${metadata.path}`);
|
|
1265
|
+
const metadataDocRef = doc4(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1266
|
+
await deleteDoc2(metadataDocRef);
|
|
1267
|
+
console.log(
|
|
1268
|
+
`[MediaService] Metadata deleted from Firestore for ID: ${mediaId}`
|
|
1269
|
+
);
|
|
1270
|
+
} catch (error) {
|
|
1271
|
+
console.error(`[MediaService] Error deleting media ${mediaId}:`, error);
|
|
1272
|
+
throw error;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Update media access level. This involves moving the file in Firebase Storage
|
|
1277
|
+
* to a new path reflecting the new access level, and updating its metadata.
|
|
1278
|
+
* @param mediaId - ID of the media to update.
|
|
1279
|
+
* @param newAccessLevel - New access level.
|
|
1280
|
+
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
1281
|
+
*/
|
|
1282
|
+
async updateMediaAccessLevel(mediaId, newAccessLevel) {
|
|
1283
|
+
var _a;
|
|
1284
|
+
console.log(
|
|
1285
|
+
`[MediaService] Attempting to update access level for media ID: ${mediaId} to ${newAccessLevel}`
|
|
1286
|
+
);
|
|
1287
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1288
|
+
if (!metadata) {
|
|
1289
|
+
console.warn(
|
|
1290
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot update access level.`
|
|
1291
|
+
);
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1294
|
+
if (metadata.accessLevel === newAccessLevel) {
|
|
1295
|
+
console.log(
|
|
1296
|
+
`[MediaService] Media ID ${mediaId} already has access level ${newAccessLevel}. Updating timestamp only.`
|
|
1297
|
+
);
|
|
1298
|
+
const metadataDocRef = doc4(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1299
|
+
try {
|
|
1300
|
+
await updateDoc4(metadataDocRef, { updatedAt: Timestamp2.now() });
|
|
1301
|
+
return { ...metadata, updatedAt: Timestamp2.now() };
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
console.error(
|
|
1304
|
+
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
1305
|
+
error
|
|
1306
|
+
);
|
|
1307
|
+
throw error;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
const oldStoragePath = metadata.path;
|
|
1311
|
+
const fileNamePart = `${metadata.id}-${metadata.name}`;
|
|
1312
|
+
const newStoragePath = `media/${newAccessLevel}/${metadata.ownerId}/${metadata.collectionName}/${fileNamePart}`;
|
|
1313
|
+
console.log(
|
|
1314
|
+
`[MediaService] Moving file for ${mediaId} from ${oldStoragePath} to ${newStoragePath}`
|
|
1315
|
+
);
|
|
1316
|
+
const oldStorageFileRef = ref(this.storage, oldStoragePath);
|
|
1317
|
+
const newStorageFileRef = ref(this.storage, newStoragePath);
|
|
1318
|
+
try {
|
|
1319
|
+
console.log(`[MediaService] Downloading bytes from ${oldStoragePath}`);
|
|
1320
|
+
const fileBytes = await getBytes(oldStorageFileRef);
|
|
1321
|
+
console.log(
|
|
1322
|
+
`[MediaService] Successfully downloaded ${fileBytes.byteLength} bytes from ${oldStoragePath}`
|
|
1323
|
+
);
|
|
1324
|
+
console.log(`[MediaService] Uploading bytes to ${newStoragePath}`);
|
|
1325
|
+
await uploadBytes(newStorageFileRef, fileBytes, {
|
|
1326
|
+
contentType: metadata.contentType
|
|
1327
|
+
});
|
|
1328
|
+
console.log(
|
|
1329
|
+
`[MediaService] Successfully uploaded bytes to ${newStoragePath}`
|
|
1330
|
+
);
|
|
1331
|
+
const newDownloadURL = await getDownloadURL(newStorageFileRef);
|
|
1332
|
+
console.log(
|
|
1333
|
+
`[MediaService] Got new download URL for ${newStoragePath}: ${newDownloadURL}`
|
|
1334
|
+
);
|
|
1335
|
+
const updateData = {
|
|
1336
|
+
accessLevel: newAccessLevel,
|
|
1337
|
+
path: newStoragePath,
|
|
1338
|
+
url: newDownloadURL,
|
|
1339
|
+
updatedAt: Timestamp2.now()
|
|
1340
|
+
};
|
|
1341
|
+
const metadataDocRef = doc4(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1342
|
+
console.log(
|
|
1343
|
+
`[MediaService] Updating Firestore metadata for ${mediaId} with new data:`,
|
|
1344
|
+
updateData
|
|
1345
|
+
);
|
|
1346
|
+
await updateDoc4(metadataDocRef, updateData);
|
|
1347
|
+
console.log(
|
|
1348
|
+
`[MediaService] Successfully updated Firestore metadata for ${mediaId}`
|
|
1349
|
+
);
|
|
1350
|
+
try {
|
|
1351
|
+
console.log(`[MediaService] Deleting old file from ${oldStoragePath}`);
|
|
1352
|
+
await deleteObject(oldStorageFileRef);
|
|
1353
|
+
console.log(
|
|
1354
|
+
`[MediaService] Successfully deleted old file from ${oldStoragePath}`
|
|
1355
|
+
);
|
|
1356
|
+
} catch (deleteError) {
|
|
1357
|
+
console.error(
|
|
1358
|
+
`[MediaService] Failed to delete old file from ${oldStoragePath} for media ID ${mediaId}. This file is now orphaned. Error:`,
|
|
1359
|
+
deleteError
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
return { ...metadata, ...updateData };
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
console.error(
|
|
1365
|
+
`[MediaService] Error updating media access level and moving file for ${mediaId}:`,
|
|
1366
|
+
error
|
|
1367
|
+
);
|
|
1368
|
+
if (newStorageFileRef && error.code !== "storage/object-not-found" && ((_a = error.message) == null ? void 0 : _a.includes("uploadBytes"))) {
|
|
1369
|
+
console.warn(
|
|
1370
|
+
`[MediaService] Attempting to delete partially uploaded file at ${newStoragePath} due to error.`
|
|
1371
|
+
);
|
|
1372
|
+
try {
|
|
1373
|
+
await deleteObject(newStorageFileRef);
|
|
1374
|
+
console.warn(
|
|
1375
|
+
`[MediaService] Cleaned up partially uploaded file at ${newStoragePath}.`
|
|
1376
|
+
);
|
|
1377
|
+
} catch (cleanupError) {
|
|
1378
|
+
console.error(
|
|
1379
|
+
`[MediaService] Failed to cleanup partially uploaded file at ${newStoragePath}:`,
|
|
1380
|
+
cleanupError
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
throw error;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* List all media for an owner, optionally filtered by collection and access level.
|
|
1389
|
+
* @param ownerId - ID of the owner.
|
|
1390
|
+
* @param collectionName - Optional: Filter by collection name.
|
|
1391
|
+
* @param accessLevel - Optional: Filter by access level.
|
|
1392
|
+
* @param count - Optional: Number of items to fetch.
|
|
1393
|
+
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
1394
|
+
*/
|
|
1395
|
+
async listMedia(ownerId, collectionName, accessLevel, count, startAfterId) {
|
|
1396
|
+
console.log(`[MediaService] Listing media for owner: ${ownerId}`);
|
|
1397
|
+
let qConstraints = [where4("ownerId", "==", ownerId)];
|
|
1398
|
+
if (collectionName) {
|
|
1399
|
+
qConstraints.push(where4("collectionName", "==", collectionName));
|
|
1400
|
+
}
|
|
1401
|
+
if (accessLevel) {
|
|
1402
|
+
qConstraints.push(where4("accessLevel", "==", accessLevel));
|
|
1403
|
+
}
|
|
1404
|
+
qConstraints.push(orderBy4("createdAt", "desc"));
|
|
1405
|
+
if (count) {
|
|
1406
|
+
qConstraints.push(limit4(count));
|
|
1407
|
+
}
|
|
1408
|
+
if (startAfterId) {
|
|
1409
|
+
const startAfterDoc = await this.getMediaMetadata(startAfterId);
|
|
1410
|
+
if (startAfterDoc) {
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
const finalQuery = query4(
|
|
1414
|
+
collection4(this.db, MEDIA_METADATA_COLLECTION),
|
|
1415
|
+
...qConstraints
|
|
1416
|
+
);
|
|
1417
|
+
try {
|
|
1418
|
+
const querySnapshot = await getDocs4(finalQuery);
|
|
1419
|
+
const mediaList = querySnapshot.docs.map(
|
|
1420
|
+
(doc11) => doc11.data()
|
|
1421
|
+
);
|
|
1422
|
+
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
1423
|
+
return mediaList;
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
console.error("[MediaService] Error listing media:", error);
|
|
1426
|
+
throw error;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Get download URL for media. (Convenience, as URL is in metadata)
|
|
1431
|
+
* @param mediaId - ID of the media.
|
|
1432
|
+
*/
|
|
1433
|
+
async getMediaDownloadUrl(mediaId) {
|
|
1434
|
+
console.log(`[MediaService] Getting download URL for media ID: ${mediaId}`);
|
|
1435
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1436
|
+
if (metadata && metadata.url) {
|
|
1437
|
+
console.log(`[MediaService] URL found: ${metadata.url}`);
|
|
1438
|
+
return metadata.url;
|
|
1439
|
+
}
|
|
1440
|
+
console.log(`[MediaService] URL not found for media ID: ${mediaId}`);
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1151
1444
|
|
|
1152
1445
|
// src/backoffice/services/documentation-template.service.ts
|
|
1153
1446
|
var DocumentationTemplateServiceBackoffice = class {
|
|
@@ -3746,6 +4039,8 @@ export {
|
|
|
3746
4039
|
InvalidTimeframeError,
|
|
3747
4040
|
InvalidTreatmentBenefitError,
|
|
3748
4041
|
ListType,
|
|
4042
|
+
MediaAccessLevel,
|
|
4043
|
+
MediaService,
|
|
3749
4044
|
PRODUCTS_COLLECTION,
|
|
3750
4045
|
PricingMeasure,
|
|
3751
4046
|
ProcedureFamily,
|
package/package.json
CHANGED
|
@@ -6,3 +6,6 @@ export * from "./requirement.service";
|
|
|
6
6
|
export * from "./subcategory.service";
|
|
7
7
|
export * from "./technology.service";
|
|
8
8
|
export * from "./constants.service";
|
|
9
|
+
|
|
10
|
+
// Re-export MediaService from main services for backoffice use
|
|
11
|
+
export { MediaService, MediaAccessLevel, type MediaMetadata, type MediaResource } from "../../services/media/media.service";
|