@web-portal/core-infrastructure 1.0.1 → 1.0.2
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/fesm2022/web-portal-core-infrastructure.mjs +399 -12
- package/fesm2022/web-portal-core-infrastructure.mjs.map +1 -1
- package/lib/services/file-aia-gcs.service.d.ts +21 -0
- package/lib/services/file-gcs.service.d.ts +21 -0
- package/lib/services/file-wap-gcs.service.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1687,6 +1687,9 @@ class FileGCSService {
|
|
|
1687
1687
|
getSignedLink(filePath) {
|
|
1688
1688
|
return this._apiService.post(`${this.baseUrl}/getSignedLink?filePath=${filePath}`);
|
|
1689
1689
|
}
|
|
1690
|
+
getPresignedLink(fileName) {
|
|
1691
|
+
return this._apiService.post(`${this.baseUrl}/getPresignedLink?fileName=${fileName}`);
|
|
1692
|
+
}
|
|
1690
1693
|
attachFile(file) {
|
|
1691
1694
|
const formData = new FormData();
|
|
1692
1695
|
formData.append("file", file);
|
|
@@ -1705,6 +1708,195 @@ class FileGCSService {
|
|
|
1705
1708
|
});
|
|
1706
1709
|
return firstValueFrom(this._http.request(req));
|
|
1707
1710
|
}
|
|
1711
|
+
/**
|
|
1712
|
+
* Build an Error object but keep HTTP-related metadata for callers that need to branch by status.
|
|
1713
|
+
* Note: We intentionally do NOT change business flow; we only enrich the error instance.
|
|
1714
|
+
*/
|
|
1715
|
+
buildHttpError(message, meta) {
|
|
1716
|
+
const err = new Error(message);
|
|
1717
|
+
if (meta?.status !== undefined)
|
|
1718
|
+
err.status = meta.status;
|
|
1719
|
+
if (meta?.statusText !== undefined)
|
|
1720
|
+
err.statusText = meta.statusText;
|
|
1721
|
+
if (meta?.url !== undefined)
|
|
1722
|
+
err.url = meta.url;
|
|
1723
|
+
if (meta?.cause !== undefined)
|
|
1724
|
+
err.cause = meta.cause;
|
|
1725
|
+
return err;
|
|
1726
|
+
}
|
|
1727
|
+
uploadFile(file) {
|
|
1728
|
+
return new Observable((observer) => {
|
|
1729
|
+
let xhr = null;
|
|
1730
|
+
// Tạo tên file unique để tránh trùng tên khi upload nhiều lần
|
|
1731
|
+
const uniqueFileName = this.generateUniqueFileName(file.name);
|
|
1732
|
+
firstValueFrom(this.getPresignedLink(uniqueFileName))
|
|
1733
|
+
.then((presignedData) => {
|
|
1734
|
+
if (!presignedData) {
|
|
1735
|
+
throw new Error("Không nhận được presigned link từ server");
|
|
1736
|
+
}
|
|
1737
|
+
const presignedURL = presignedData.PreSignedURL ||
|
|
1738
|
+
presignedData.preSignedURL ||
|
|
1739
|
+
presignedData.url;
|
|
1740
|
+
const filePath = presignedData.FilePath || presignedData.filePath;
|
|
1741
|
+
const absoluteURL = presignedData.AbsoluteURL || presignedData.absoluteURL;
|
|
1742
|
+
if (!presignedURL) {
|
|
1743
|
+
throw new Error("Presigned URL không hợp lệ");
|
|
1744
|
+
}
|
|
1745
|
+
const contentType = presignedData.ContentType ||
|
|
1746
|
+
presignedData.contentType ||
|
|
1747
|
+
file.type ||
|
|
1748
|
+
"application/octet-stream";
|
|
1749
|
+
xhr = new XMLHttpRequest();
|
|
1750
|
+
const cleanup = () => {
|
|
1751
|
+
if (xhr) {
|
|
1752
|
+
xhr.upload.removeEventListener("progress", progressHandler);
|
|
1753
|
+
xhr.removeEventListener("load", loadHandler);
|
|
1754
|
+
xhr.removeEventListener("error", errorHandler);
|
|
1755
|
+
xhr.removeEventListener("timeout", timeoutHandler);
|
|
1756
|
+
xhr.abort();
|
|
1757
|
+
xhr = null;
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
const progressHandler = (_event) => {
|
|
1761
|
+
// No-op: progress not consumed by current callers
|
|
1762
|
+
};
|
|
1763
|
+
const loadHandler = async () => {
|
|
1764
|
+
if (xhr && xhr.status === 200) {
|
|
1765
|
+
try {
|
|
1766
|
+
const finalUrl = absoluteURL || presignedURL;
|
|
1767
|
+
const result = this.buildResult(file, filePath, finalUrl);
|
|
1768
|
+
cleanup();
|
|
1769
|
+
observer.next(result);
|
|
1770
|
+
observer.complete();
|
|
1771
|
+
}
|
|
1772
|
+
catch (err) {
|
|
1773
|
+
cleanup();
|
|
1774
|
+
const msg = err?.message ||
|
|
1775
|
+
"Upload thất bại. Vui lòng thử lại.";
|
|
1776
|
+
observer.error(this.buildHttpError(msg, {
|
|
1777
|
+
status: xhr?.status,
|
|
1778
|
+
statusText: xhr?.statusText,
|
|
1779
|
+
url: presignedURL,
|
|
1780
|
+
cause: err,
|
|
1781
|
+
}));
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
else if (xhr) {
|
|
1785
|
+
const errorMessage = `Upload file thất bại: ${xhr.statusText} (${xhr.status})`;
|
|
1786
|
+
cleanup();
|
|
1787
|
+
observer.error(this.buildHttpError(errorMessage, {
|
|
1788
|
+
status: xhr.status,
|
|
1789
|
+
statusText: xhr.statusText,
|
|
1790
|
+
url: presignedURL,
|
|
1791
|
+
}));
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
const errorHandler = () => {
|
|
1795
|
+
if (!xhr)
|
|
1796
|
+
return;
|
|
1797
|
+
let userMessage = "Upload file thất bại";
|
|
1798
|
+
if (xhr.status === 0) {
|
|
1799
|
+
userMessage =
|
|
1800
|
+
"Không thể kết nối đến máy chủ lưu trữ. Máy chủ không phản hồi.";
|
|
1801
|
+
}
|
|
1802
|
+
else if (xhr.status >= 500) {
|
|
1803
|
+
userMessage = "Lỗi máy chủ. Vui lòng thử lại sau.";
|
|
1804
|
+
}
|
|
1805
|
+
else if (xhr.status >= 400) {
|
|
1806
|
+
userMessage = `Lỗi yêu cầu: ${xhr.statusText}`;
|
|
1807
|
+
}
|
|
1808
|
+
cleanup();
|
|
1809
|
+
observer.error(this.buildHttpError(userMessage, {
|
|
1810
|
+
status: xhr.status,
|
|
1811
|
+
statusText: xhr.statusText,
|
|
1812
|
+
url: presignedURL,
|
|
1813
|
+
}));
|
|
1814
|
+
};
|
|
1815
|
+
const timeoutHandler = () => {
|
|
1816
|
+
cleanup();
|
|
1817
|
+
observer.error(this.buildHttpError("Kết nối đến máy chủ hết thời gian. Vui lòng thử lại.", {
|
|
1818
|
+
status: xhr?.status,
|
|
1819
|
+
statusText: xhr?.statusText,
|
|
1820
|
+
url: presignedURL,
|
|
1821
|
+
}));
|
|
1822
|
+
};
|
|
1823
|
+
xhr.upload.addEventListener("progress", progressHandler);
|
|
1824
|
+
xhr.addEventListener("load", loadHandler);
|
|
1825
|
+
xhr.addEventListener("error", errorHandler);
|
|
1826
|
+
xhr.addEventListener("timeout", timeoutHandler);
|
|
1827
|
+
xhr.timeout = 60000 * 5;
|
|
1828
|
+
xhr.open("PUT", presignedURL, true);
|
|
1829
|
+
xhr.setRequestHeader("Content-Type", contentType);
|
|
1830
|
+
xhr.send(file);
|
|
1831
|
+
})
|
|
1832
|
+
.catch((error) => {
|
|
1833
|
+
if (xhr) {
|
|
1834
|
+
xhr.abort();
|
|
1835
|
+
xhr = null;
|
|
1836
|
+
}
|
|
1837
|
+
let userMessage = "Upload file thất bại";
|
|
1838
|
+
if (error.errorMessage) {
|
|
1839
|
+
userMessage = error.errorMessage;
|
|
1840
|
+
}
|
|
1841
|
+
else if (error.code === "ECONNABORTED" ||
|
|
1842
|
+
error.message?.includes("timeout")) {
|
|
1843
|
+
userMessage =
|
|
1844
|
+
"Kết nối đến máy chủ hết thời gian. Vui lòng thử lại.";
|
|
1845
|
+
}
|
|
1846
|
+
else if (error.message?.includes("failed to respond") ||
|
|
1847
|
+
error.message?.includes("Network Error")) {
|
|
1848
|
+
userMessage =
|
|
1849
|
+
"Không thể kết nối đến máy chủ lưu trữ. Máy chủ không phản hồi.";
|
|
1850
|
+
}
|
|
1851
|
+
else if (error.message) {
|
|
1852
|
+
userMessage = `Lỗi kết nối: ${error.message}`;
|
|
1853
|
+
}
|
|
1854
|
+
else if (error.error?.message) {
|
|
1855
|
+
userMessage = error.error.message;
|
|
1856
|
+
}
|
|
1857
|
+
observer.error(this.buildHttpError(userMessage, {
|
|
1858
|
+
status: error?.status,
|
|
1859
|
+
statusText: error?.statusText,
|
|
1860
|
+
url: error?.url,
|
|
1861
|
+
cause: error,
|
|
1862
|
+
}));
|
|
1863
|
+
});
|
|
1864
|
+
return () => {
|
|
1865
|
+
if (xhr) {
|
|
1866
|
+
xhr.abort();
|
|
1867
|
+
xhr = null;
|
|
1868
|
+
}
|
|
1869
|
+
};
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Tạo tên file unique bằng cách thêm timestamp và random string
|
|
1874
|
+
* Format: originalname-timestamp-random.ext
|
|
1875
|
+
*/
|
|
1876
|
+
generateUniqueFileName(originalFileName) {
|
|
1877
|
+
const timestamp = Date.now();
|
|
1878
|
+
const randomString = Math.random().toString(36).substring(2, 9);
|
|
1879
|
+
// Tách tên file và extension
|
|
1880
|
+
const lastDotIndex = originalFileName.lastIndexOf(".");
|
|
1881
|
+
if (lastDotIndex === -1) {
|
|
1882
|
+
// Không có extension
|
|
1883
|
+
return `${originalFileName}-${timestamp}-${randomString}`;
|
|
1884
|
+
}
|
|
1885
|
+
const nameWithoutExt = originalFileName.substring(0, lastDotIndex);
|
|
1886
|
+
const extension = originalFileName.substring(lastDotIndex);
|
|
1887
|
+
return `${nameWithoutExt}-${timestamp}-${randomString}${extension}`;
|
|
1888
|
+
}
|
|
1889
|
+
extractFileName(filePath) {
|
|
1890
|
+
return filePath.split("/").pop() || "";
|
|
1891
|
+
}
|
|
1892
|
+
buildResult(file, filePath, url) {
|
|
1893
|
+
return {
|
|
1894
|
+
url,
|
|
1895
|
+
filePath,
|
|
1896
|
+
fileName: this.extractFileName(filePath) || file.name,
|
|
1897
|
+
originalName: file.name,
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1708
1900
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FileGCSService, deps: [{ token: i1$2.HttpClient }, { token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1709
1901
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FileGCSService, providedIn: "root" }); }
|
|
1710
1902
|
}
|
|
@@ -1722,6 +1914,9 @@ class FileAIA_GCSService {
|
|
|
1722
1914
|
getSignedLink(filePath) {
|
|
1723
1915
|
return this._apiService.post(`${this.baseUrl}/getSignedLink?filePath=${filePath}`);
|
|
1724
1916
|
}
|
|
1917
|
+
getPresignedLink(fileName) {
|
|
1918
|
+
return this._apiService.post(`${this.baseUrl}/getPresignedLink?fileName=${fileName}`);
|
|
1919
|
+
}
|
|
1725
1920
|
attachFile(file) {
|
|
1726
1921
|
const formData = new FormData();
|
|
1727
1922
|
formData.append("file", file);
|
|
@@ -1740,6 +1935,195 @@ class FileAIA_GCSService {
|
|
|
1740
1935
|
});
|
|
1741
1936
|
return firstValueFrom(this._http.request(req));
|
|
1742
1937
|
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Build an Error object but keep HTTP-related metadata for callers that need to branch by status.
|
|
1940
|
+
* Note: We intentionally do NOT change business flow; we only enrich the error instance.
|
|
1941
|
+
*/
|
|
1942
|
+
buildHttpError(message, meta) {
|
|
1943
|
+
const err = new Error(message);
|
|
1944
|
+
if (meta?.status !== undefined)
|
|
1945
|
+
err.status = meta.status;
|
|
1946
|
+
if (meta?.statusText !== undefined)
|
|
1947
|
+
err.statusText = meta.statusText;
|
|
1948
|
+
if (meta?.url !== undefined)
|
|
1949
|
+
err.url = meta.url;
|
|
1950
|
+
if (meta?.cause !== undefined)
|
|
1951
|
+
err.cause = meta.cause;
|
|
1952
|
+
return err;
|
|
1953
|
+
}
|
|
1954
|
+
uploadFile(file) {
|
|
1955
|
+
return new Observable((observer) => {
|
|
1956
|
+
let xhr = null;
|
|
1957
|
+
// Tạo tên file unique để tránh trùng tên khi upload nhiều lần
|
|
1958
|
+
const uniqueFileName = this.generateUniqueFileName(file.name);
|
|
1959
|
+
firstValueFrom(this.getPresignedLink(uniqueFileName))
|
|
1960
|
+
.then((presignedData) => {
|
|
1961
|
+
if (!presignedData) {
|
|
1962
|
+
throw new Error("Không nhận được presigned link từ server");
|
|
1963
|
+
}
|
|
1964
|
+
const presignedURL = presignedData.PreSignedURL ||
|
|
1965
|
+
presignedData.preSignedURL ||
|
|
1966
|
+
presignedData.url;
|
|
1967
|
+
const filePath = presignedData.FilePath || presignedData.filePath;
|
|
1968
|
+
const absoluteURL = presignedData.AbsoluteURL || presignedData.absoluteURL;
|
|
1969
|
+
if (!presignedURL) {
|
|
1970
|
+
throw new Error("Presigned URL không hợp lệ");
|
|
1971
|
+
}
|
|
1972
|
+
const contentType = presignedData.ContentType ||
|
|
1973
|
+
presignedData.contentType ||
|
|
1974
|
+
file.type ||
|
|
1975
|
+
"application/octet-stream";
|
|
1976
|
+
xhr = new XMLHttpRequest();
|
|
1977
|
+
const cleanup = () => {
|
|
1978
|
+
if (xhr) {
|
|
1979
|
+
xhr.upload.removeEventListener("progress", progressHandler);
|
|
1980
|
+
xhr.removeEventListener("load", loadHandler);
|
|
1981
|
+
xhr.removeEventListener("error", errorHandler);
|
|
1982
|
+
xhr.removeEventListener("timeout", timeoutHandler);
|
|
1983
|
+
xhr.abort();
|
|
1984
|
+
xhr = null;
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
const progressHandler = (_event) => {
|
|
1988
|
+
// No-op: progress not consumed by current callers
|
|
1989
|
+
};
|
|
1990
|
+
const loadHandler = async () => {
|
|
1991
|
+
if (xhr && xhr.status === 200) {
|
|
1992
|
+
try {
|
|
1993
|
+
const finalUrl = absoluteURL || presignedURL;
|
|
1994
|
+
const result = this.buildResult(file, filePath, finalUrl);
|
|
1995
|
+
cleanup();
|
|
1996
|
+
observer.next(result);
|
|
1997
|
+
observer.complete();
|
|
1998
|
+
}
|
|
1999
|
+
catch (err) {
|
|
2000
|
+
cleanup();
|
|
2001
|
+
const msg = err?.message ||
|
|
2002
|
+
"Upload thất bại. Vui lòng thử lại.";
|
|
2003
|
+
observer.error(this.buildHttpError(msg, {
|
|
2004
|
+
status: xhr?.status,
|
|
2005
|
+
statusText: xhr?.statusText,
|
|
2006
|
+
url: presignedURL,
|
|
2007
|
+
cause: err,
|
|
2008
|
+
}));
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
else if (xhr) {
|
|
2012
|
+
const errorMessage = `Upload file thất bại: ${xhr.statusText} (${xhr.status})`;
|
|
2013
|
+
cleanup();
|
|
2014
|
+
observer.error(this.buildHttpError(errorMessage, {
|
|
2015
|
+
status: xhr.status,
|
|
2016
|
+
statusText: xhr.statusText,
|
|
2017
|
+
url: presignedURL,
|
|
2018
|
+
}));
|
|
2019
|
+
}
|
|
2020
|
+
};
|
|
2021
|
+
const errorHandler = () => {
|
|
2022
|
+
if (!xhr)
|
|
2023
|
+
return;
|
|
2024
|
+
let userMessage = "Upload file thất bại";
|
|
2025
|
+
if (xhr.status === 0) {
|
|
2026
|
+
userMessage =
|
|
2027
|
+
"Không thể kết nối đến máy chủ lưu trữ. Máy chủ không phản hồi.";
|
|
2028
|
+
}
|
|
2029
|
+
else if (xhr.status >= 500) {
|
|
2030
|
+
userMessage = "Lỗi máy chủ. Vui lòng thử lại sau.";
|
|
2031
|
+
}
|
|
2032
|
+
else if (xhr.status >= 400) {
|
|
2033
|
+
userMessage = `Lỗi yêu cầu: ${xhr.statusText}`;
|
|
2034
|
+
}
|
|
2035
|
+
cleanup();
|
|
2036
|
+
observer.error(this.buildHttpError(userMessage, {
|
|
2037
|
+
status: xhr.status,
|
|
2038
|
+
statusText: xhr.statusText,
|
|
2039
|
+
url: presignedURL,
|
|
2040
|
+
}));
|
|
2041
|
+
};
|
|
2042
|
+
const timeoutHandler = () => {
|
|
2043
|
+
cleanup();
|
|
2044
|
+
observer.error(this.buildHttpError("Kết nối đến máy chủ hết thời gian. Vui lòng thử lại.", {
|
|
2045
|
+
status: xhr?.status,
|
|
2046
|
+
statusText: xhr?.statusText,
|
|
2047
|
+
url: presignedURL,
|
|
2048
|
+
}));
|
|
2049
|
+
};
|
|
2050
|
+
xhr.upload.addEventListener("progress", progressHandler);
|
|
2051
|
+
xhr.addEventListener("load", loadHandler);
|
|
2052
|
+
xhr.addEventListener("error", errorHandler);
|
|
2053
|
+
xhr.addEventListener("timeout", timeoutHandler);
|
|
2054
|
+
xhr.timeout = 60000 * 5;
|
|
2055
|
+
xhr.open("PUT", presignedURL, true);
|
|
2056
|
+
xhr.setRequestHeader("Content-Type", contentType);
|
|
2057
|
+
xhr.send(file);
|
|
2058
|
+
})
|
|
2059
|
+
.catch((error) => {
|
|
2060
|
+
if (xhr) {
|
|
2061
|
+
xhr.abort();
|
|
2062
|
+
xhr = null;
|
|
2063
|
+
}
|
|
2064
|
+
let userMessage = "Upload file thất bại";
|
|
2065
|
+
if (error.errorMessage) {
|
|
2066
|
+
userMessage = error.errorMessage;
|
|
2067
|
+
}
|
|
2068
|
+
else if (error.code === "ECONNABORTED" ||
|
|
2069
|
+
error.message?.includes("timeout")) {
|
|
2070
|
+
userMessage =
|
|
2071
|
+
"Kết nối đến máy chủ hết thời gian. Vui lòng thử lại.";
|
|
2072
|
+
}
|
|
2073
|
+
else if (error.message?.includes("failed to respond") ||
|
|
2074
|
+
error.message?.includes("Network Error")) {
|
|
2075
|
+
userMessage =
|
|
2076
|
+
"Không thể kết nối đến máy chủ lưu trữ. Máy chủ không phản hồi.";
|
|
2077
|
+
}
|
|
2078
|
+
else if (error.message) {
|
|
2079
|
+
userMessage = `Lỗi kết nối: ${error.message}`;
|
|
2080
|
+
}
|
|
2081
|
+
else if (error.error?.message) {
|
|
2082
|
+
userMessage = error.error.message;
|
|
2083
|
+
}
|
|
2084
|
+
observer.error(this.buildHttpError(userMessage, {
|
|
2085
|
+
status: error?.status,
|
|
2086
|
+
statusText: error?.statusText,
|
|
2087
|
+
url: error?.url,
|
|
2088
|
+
cause: error,
|
|
2089
|
+
}));
|
|
2090
|
+
});
|
|
2091
|
+
return () => {
|
|
2092
|
+
if (xhr) {
|
|
2093
|
+
xhr.abort();
|
|
2094
|
+
xhr = null;
|
|
2095
|
+
}
|
|
2096
|
+
};
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Tạo tên file unique bằng cách thêm timestamp và random string
|
|
2101
|
+
* Format: originalname-timestamp-random.ext
|
|
2102
|
+
*/
|
|
2103
|
+
generateUniqueFileName(originalFileName) {
|
|
2104
|
+
const timestamp = Date.now();
|
|
2105
|
+
const randomString = Math.random().toString(36).substring(2, 9);
|
|
2106
|
+
// Tách tên file và extension
|
|
2107
|
+
const lastDotIndex = originalFileName.lastIndexOf(".");
|
|
2108
|
+
if (lastDotIndex === -1) {
|
|
2109
|
+
// Không có extension
|
|
2110
|
+
return `${originalFileName}-${timestamp}-${randomString}`;
|
|
2111
|
+
}
|
|
2112
|
+
const nameWithoutExt = originalFileName.substring(0, lastDotIndex);
|
|
2113
|
+
const extension = originalFileName.substring(lastDotIndex);
|
|
2114
|
+
return `${nameWithoutExt}-${timestamp}-${randomString}${extension}`;
|
|
2115
|
+
}
|
|
2116
|
+
extractFileName(filePath) {
|
|
2117
|
+
return filePath.split("/").pop() || "";
|
|
2118
|
+
}
|
|
2119
|
+
buildResult(file, filePath, url) {
|
|
2120
|
+
return {
|
|
2121
|
+
url,
|
|
2122
|
+
filePath,
|
|
2123
|
+
fileName: this.extractFileName(filePath) || file.name,
|
|
2124
|
+
originalName: file.name,
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
1743
2127
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FileAIA_GCSService, deps: [{ token: i1$2.HttpClient }, { token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1744
2128
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FileAIA_GCSService, providedIn: "root" }); }
|
|
1745
2129
|
}
|
|
@@ -1784,7 +2168,7 @@ class FileWAPGCSService {
|
|
|
1784
2168
|
formData.append("file", file);
|
|
1785
2169
|
const req = new HttpRequest("POST", `${this.baseUrl}/attachFile`, formData, {
|
|
1786
2170
|
reportProgress: true,
|
|
1787
|
-
responseType: "json"
|
|
2171
|
+
responseType: "json",
|
|
1788
2172
|
});
|
|
1789
2173
|
return this._http.request(req);
|
|
1790
2174
|
}
|
|
@@ -1793,17 +2177,17 @@ class FileWAPGCSService {
|
|
|
1793
2177
|
formData.append("file", file);
|
|
1794
2178
|
const req = new HttpRequest("POST", `${this.baseUrl}/attachFile`, formData, {
|
|
1795
2179
|
reportProgress: true,
|
|
1796
|
-
responseType: "json"
|
|
2180
|
+
responseType: "json",
|
|
1797
2181
|
});
|
|
1798
2182
|
return firstValueFrom(this._http.request(req));
|
|
1799
2183
|
}
|
|
1800
2184
|
uploadFile(file) {
|
|
1801
|
-
return new Observable(observer => {
|
|
2185
|
+
return new Observable((observer) => {
|
|
1802
2186
|
let xhr = null;
|
|
1803
2187
|
// Tạo tên file unique để tránh trùng tên khi upload nhiều lần
|
|
1804
2188
|
const uniqueFileName = this.generateUniqueFileName(file.name);
|
|
1805
2189
|
firstValueFrom(this.getPresignedLink(uniqueFileName))
|
|
1806
|
-
.then(presignedData => {
|
|
2190
|
+
.then((presignedData) => {
|
|
1807
2191
|
if (!presignedData) {
|
|
1808
2192
|
throw new Error("Không nhận được presigned link từ server");
|
|
1809
2193
|
}
|
|
@@ -1815,7 +2199,10 @@ class FileWAPGCSService {
|
|
|
1815
2199
|
if (!presignedURL) {
|
|
1816
2200
|
throw new Error("Presigned URL không hợp lệ");
|
|
1817
2201
|
}
|
|
1818
|
-
const contentType =
|
|
2202
|
+
const contentType = presignedData.ContentType ||
|
|
2203
|
+
presignedData.contentType ||
|
|
2204
|
+
file.type ||
|
|
2205
|
+
"application/octet-stream";
|
|
1819
2206
|
xhr = new XMLHttpRequest();
|
|
1820
2207
|
const cleanup = () => {
|
|
1821
2208
|
if (xhr) {
|
|
@@ -1853,7 +2240,7 @@ class FileWAPGCSService {
|
|
|
1853
2240
|
status: xhr?.status,
|
|
1854
2241
|
statusText: xhr?.statusText,
|
|
1855
2242
|
url: presignedURL,
|
|
1856
|
-
cause: err
|
|
2243
|
+
cause: err,
|
|
1857
2244
|
}));
|
|
1858
2245
|
}
|
|
1859
2246
|
}
|
|
@@ -1863,7 +2250,7 @@ class FileWAPGCSService {
|
|
|
1863
2250
|
observer.error(this.buildHttpError(errorMessage, {
|
|
1864
2251
|
status: xhr.status,
|
|
1865
2252
|
statusText: xhr.statusText,
|
|
1866
|
-
url: presignedURL
|
|
2253
|
+
url: presignedURL,
|
|
1867
2254
|
}));
|
|
1868
2255
|
}
|
|
1869
2256
|
};
|
|
@@ -1885,7 +2272,7 @@ class FileWAPGCSService {
|
|
|
1885
2272
|
observer.error(this.buildHttpError(userMessage, {
|
|
1886
2273
|
status: xhr.status,
|
|
1887
2274
|
statusText: xhr.statusText,
|
|
1888
|
-
url: presignedURL
|
|
2275
|
+
url: presignedURL,
|
|
1889
2276
|
}));
|
|
1890
2277
|
};
|
|
1891
2278
|
const timeoutHandler = () => {
|
|
@@ -1893,7 +2280,7 @@ class FileWAPGCSService {
|
|
|
1893
2280
|
observer.error(this.buildHttpError("Kết nối đến máy chủ hết thời gian. Vui lòng thử lại.", {
|
|
1894
2281
|
status: xhr?.status,
|
|
1895
2282
|
statusText: xhr?.statusText,
|
|
1896
|
-
url: presignedURL
|
|
2283
|
+
url: presignedURL,
|
|
1897
2284
|
}));
|
|
1898
2285
|
};
|
|
1899
2286
|
xhr.upload.addEventListener("progress", progressHandler);
|
|
@@ -1905,7 +2292,7 @@ class FileWAPGCSService {
|
|
|
1905
2292
|
xhr.setRequestHeader("Content-Type", contentType);
|
|
1906
2293
|
xhr.send(file);
|
|
1907
2294
|
})
|
|
1908
|
-
.catch(error => {
|
|
2295
|
+
.catch((error) => {
|
|
1909
2296
|
if (xhr) {
|
|
1910
2297
|
xhr.abort();
|
|
1911
2298
|
xhr = null;
|
|
@@ -1935,7 +2322,7 @@ class FileWAPGCSService {
|
|
|
1935
2322
|
status: error?.status,
|
|
1936
2323
|
statusText: error?.statusText,
|
|
1937
2324
|
url: error?.url,
|
|
1938
|
-
cause: error
|
|
2325
|
+
cause: error,
|
|
1939
2326
|
}));
|
|
1940
2327
|
});
|
|
1941
2328
|
return () => {
|
|
@@ -1971,7 +2358,7 @@ class FileWAPGCSService {
|
|
|
1971
2358
|
url,
|
|
1972
2359
|
filePath,
|
|
1973
2360
|
fileName: this.extractFileName(filePath) || file.name,
|
|
1974
|
-
originalName: file.name
|
|
2361
|
+
originalName: file.name,
|
|
1975
2362
|
};
|
|
1976
2363
|
}
|
|
1977
2364
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FileWAPGCSService, deps: [{ token: i1$2.HttpClient }, { token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|