Merge branch 'development'
This commit is contained in:
commit
e73b51880f
18 changed files with 474 additions and 5503 deletions
|
|
@ -211,6 +211,7 @@ const file = ref<File | undefined>()
|
|||
label="กดปุ่มEnterเพื่อเพิ่ม"
|
||||
use-input
|
||||
use-chips
|
||||
hide-dropdown-icon
|
||||
multiple
|
||||
input-debounce="0"
|
||||
@new-value="createCategory"
|
||||
|
|
@ -220,11 +221,6 @@ const file = ref<File | undefined>()
|
|||
@update:model-value="(v) => $emit('update:category', v)"
|
||||
data-testid="filterDataCategory"
|
||||
>
|
||||
<template v-slot:no-option>
|
||||
<q-item>
|
||||
<q-item-section class="text-grey"> No results </q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import type { QTableProps } from 'quasar'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import io from 'socket.io-client'
|
||||
|
||||
import { useSearchDataStore } from '@/stores/searched-data'
|
||||
import { useFileInfoStore } from '@/stores/file-info-data'
|
||||
|
|
@ -22,7 +23,7 @@ const props = withDefaults(
|
|||
action: false,
|
||||
},
|
||||
)
|
||||
const { foundFile, isActFoundFile } = storeToRefs(useSearchDataStore())
|
||||
const { foundFile } = storeToRefs(useSearchDataStore())
|
||||
const { getFileInfo, getSize, getType } = useFileInfoStore()
|
||||
|
||||
const storageStore = useStorage()
|
||||
|
|
@ -75,6 +76,29 @@ const columns: QTableProps['columns'] = [
|
|||
style: 'width: 20px',
|
||||
},
|
||||
]
|
||||
const socket = io(import.meta.env.VITE_API_HOST)
|
||||
|
||||
socket.on('FileUpload', (data: StorageFile) => {
|
||||
replaceSearchItem(data.pathname, data)
|
||||
})
|
||||
socket.on('FileMove', (data: { from: StorageFile; to: StorageFile }) => {
|
||||
replaceSearchItem(data.from.pathname, data.to)
|
||||
})
|
||||
socket.on('FileDelete', (data: { pathname: string }) => {
|
||||
removeSearchItem(data.pathname)
|
||||
})
|
||||
|
||||
function removeSearchItem(pathname: string) {
|
||||
const idx = foundFile.value.findIndex((v) => v.pathname === pathname)
|
||||
if (idx !== -1) foundFile.value.splice(idx, 1)
|
||||
filterSearch()
|
||||
}
|
||||
|
||||
function replaceSearchItem(pathname: string, data: StorageFile) {
|
||||
const idx = foundFile.value.findIndex((v) => v.pathname === pathname)
|
||||
if (idx !== -1) foundFile.value[idx] = data
|
||||
filterSearch()
|
||||
}
|
||||
|
||||
function triggerFileDelete(pathname: string) {
|
||||
deleteFormType.value = 'deleteFile'
|
||||
|
|
@ -85,10 +109,6 @@ function triggerFileDelete(pathname: string) {
|
|||
function confirmDelete() {
|
||||
if (deleteFormType) {
|
||||
deleteFile(deleteFormPath.value)
|
||||
|
||||
setTimeout(() => {
|
||||
isActFoundFile.value = true
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +182,9 @@ onMounted(() => {
|
|||
</div>
|
||||
|
||||
<div v-if="props.viewMode === 'view_list' && foundFile.length > 0">
|
||||
<span class="text-body text-grey">จำนวน {{ filterFoundFile?.length }} รายการ</span>
|
||||
<span class="text-body text-grey"
|
||||
>จำนวน {{ filterFoundFile?.length }} รายการ</span
|
||||
>
|
||||
<div class="grid q-mt-md">
|
||||
<div v-for="(value, index) in filterFoundFile" :key="value.title">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ async function downloadSubmit(path: string | undefined) {
|
|||
|
||||
const arr = path.split('/')
|
||||
|
||||
if (arr.length < 3 || arr.length > 4) return
|
||||
if (arr.length < 4 || arr.length > 5) return
|
||||
|
||||
const file = arr.pop()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { ref, watch } from 'vue'
|
|||
import { storeToRefs } from 'pinia'
|
||||
import axiosClient from '@/services/HttpService'
|
||||
import mime from 'mime'
|
||||
import io from 'socket.io-client'
|
||||
|
||||
import type { StorageFile } from '@/stores/storage'
|
||||
import { useSearchDataStore } from '@/stores/searched-data'
|
||||
|
|
@ -15,11 +14,9 @@ import AdvancedSearch from '@/modules/01_user/components/AdvancedSearch.vue'
|
|||
const loaderStore = useLoader()
|
||||
const { isFilePreview } = storeToRefs(useFileInfoStore())
|
||||
const {
|
||||
foundFile,
|
||||
isExact,
|
||||
isSearch,
|
||||
isAdvSearchCall,
|
||||
isActFoundFile,
|
||||
searchData,
|
||||
advSearchDataField,
|
||||
advSearchDataRow,
|
||||
|
|
@ -41,20 +38,6 @@ const submitSearchData = ref<{
|
|||
const props = defineProps<{
|
||||
mode: 'admin' | 'user'
|
||||
}>()
|
||||
const socket = io(import.meta.env.VITE_API_HOST)
|
||||
|
||||
socket.on('FileUpload', (data: StorageFile) => {
|
||||
replaceSearchItem(data.pathname, data)
|
||||
})
|
||||
socket.on('FileMove', (data: { from: StorageFile; to: StorageFile }) => {
|
||||
replaceSearchItem(data.from.pathname, data.to)
|
||||
})
|
||||
|
||||
function replaceSearchItem(pathname: string, data: StorageFile) {
|
||||
const idx = foundFile.value.findIndex((v) => v.pathname === pathname)
|
||||
|
||||
if (idx !== -1) foundFile.value[idx] = data
|
||||
}
|
||||
|
||||
async function submitSearch() {
|
||||
isFilePreview.value = false
|
||||
|
|
@ -136,18 +119,6 @@ async function submitSearch() {
|
|||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isActFoundFile.value,
|
||||
(edited) => {
|
||||
if (edited === true) {
|
||||
submitSearch()
|
||||
setTimeout(() => {
|
||||
isActFoundFile.value = false
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => searchData.value.value,
|
||||
(search) => {
|
||||
|
|
@ -165,7 +136,7 @@ watch(
|
|||
outlined
|
||||
dense
|
||||
label="ค้นหา"
|
||||
debounce="500"
|
||||
debounce="300"
|
||||
bg-color="white"
|
||||
v-model="searchData.value"
|
||||
id="inputSearch"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export const useSearchDataStore = defineStore('searched', () => {
|
|||
const isAdvSearchCall = ref<boolean>(false)
|
||||
const isSearch = ref<Boolean>(false)
|
||||
const isExact = ref<boolean>(false)
|
||||
const isActFoundFile = ref<Boolean>(false)
|
||||
const searchData = ref<Search>({
|
||||
field: 'title',
|
||||
value: '',
|
||||
|
|
@ -51,7 +50,6 @@ export const useSearchDataStore = defineStore('searched', () => {
|
|||
isSearch,
|
||||
isExact,
|
||||
isAdvSearchCall,
|
||||
isActFoundFile,
|
||||
searchData,
|
||||
advSearchDataRow,
|
||||
advSearchDataField,
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ test.afterAll(async () => {
|
|||
})
|
||||
|
||||
test('Login', async () => {
|
||||
await page.goto('http://localhost:3010/admin')
|
||||
await page.goto('https://edm.frappet.synology.me/admin')
|
||||
await expect(page).toHaveTitle('Sign in to EDM')
|
||||
await page.fill("input[name='username']", 'oom')
|
||||
await page.fill("input[name='password']", 'oom')
|
||||
await page.fill("input[name='username']", 'net')
|
||||
await page.fill("input[name='password']", 'P@ssw0rd')
|
||||
await page.click("input[name='login']")
|
||||
|
||||
await page.waitForTimeout(2000)
|
||||
|
|
@ -31,18 +31,13 @@ test('Login', async () => {
|
|||
test('Create Cabinet', async () => {
|
||||
await page.waitForTimeout(2000)
|
||||
await page.click("//div[@id='triggerFolderCreateFileItem']")
|
||||
|
||||
await page.fill(
|
||||
"//input[@placeholder='กรอกชื่อ']",
|
||||
cabinet,
|
||||
)
|
||||
|
||||
await page.fill("//input[@placeholder='กรอกชื่อ']", cabinet)
|
||||
await page.click("//button[@type='submit']")
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(cabinet)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(cabinet)
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
})
|
||||
|
|
@ -53,74 +48,159 @@ test('Go to Cabinet', async () => {
|
|||
|
||||
test('Create drawer', async () => {
|
||||
await page.click("//div[@id='triggerFolderCreateFileItem']")
|
||||
await page.fill(
|
||||
"//input[@placeholder='กรอกชื่อ']",
|
||||
drawer,
|
||||
)
|
||||
await page.fill("//input[@placeholder='กรอกชื่อ']", drawer)
|
||||
await page.click("//button[@type='submit']")
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(drawer)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(drawer)
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
})
|
||||
|
||||
test('Go into drawer', async () => {
|
||||
await page.click(`(//div[text()='${drawer}'])[2]`)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(drawer)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(drawer)
|
||||
})
|
||||
|
||||
test('Create Folder', async () => {
|
||||
await page.click("//div[@id='triggerFolderCreateFileItem']")
|
||||
await page.fill(
|
||||
"//input[@placeholder='กรอกชื่อ']",
|
||||
folder,
|
||||
)
|
||||
await page.fill("//input[@placeholder='กรอกชื่อ']", folder)
|
||||
await page.click("//button[@type='submit']")
|
||||
await page.waitForTimeout(300)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(folder)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(folder)
|
||||
})
|
||||
|
||||
test('Go into Folder', async () => {
|
||||
await page.click(`(//div[text()='${folder}'])[2]`)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(folder)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(folder)
|
||||
})
|
||||
|
||||
test('Create Subfolder', async () => {
|
||||
await page.click("//div[@id='triggerFolderCreateFileItem']")
|
||||
await page.fill(
|
||||
"//input[@placeholder='กรอกชื่อ']",
|
||||
await page.fill("//input[@placeholder='กรอกชื่อ']", subfolder)
|
||||
await page.click("//button[@type='submit']")
|
||||
await page.waitForTimeout(300)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
subfolder,
|
||||
)
|
||||
await page.click("(//button[@type='submit'])[3]")
|
||||
await page.waitForTimeout(300)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(subfolder)
|
||||
})
|
||||
|
||||
test('Go into Subfolder', async () => {
|
||||
|
||||
await page.click(`//div[text()='${subfolder}']`)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(folder)
|
||||
await page.click(`(//div[text()='${subfolder}'])[2]`)
|
||||
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(folder)
|
||||
})
|
||||
|
||||
test('Upload File in SubFolder Level', async () => {
|
||||
await page.click("//span[text()='สร้างเอกสาร']")
|
||||
await page
|
||||
.locator("//input[@type='file']")
|
||||
.setInputFiles('tests/searchtest.txt')
|
||||
await page.fill("//input[@placeholder='กรอกชื่อเรื่อง']", 'testtext')
|
||||
await page.click("(//button[@type='submit'])[1]")
|
||||
await page.waitForTimeout(2500)
|
||||
await page.click('button#getFolder')
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Go into Text File', async () => {
|
||||
await page.click("//div[text()='testtext']")
|
||||
})
|
||||
|
||||
test('Download File Text', async () => {
|
||||
await page.click("//span[text()='ดาวน์โหลด']")
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
||||
test('Go back to SubFolder Level Again', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
})
|
||||
|
||||
test('Delete file Cancel', async () => {
|
||||
await page.click(
|
||||
`//button[@data-testid='action${cabinet}/${drawer}/${folder}/${subfolder}/searchtest.txt']`,
|
||||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Delete file Confirm', async () => {
|
||||
await page.click(
|
||||
`//button[@data-testid='action${cabinet}/${drawer}/${folder}/${subfolder}/searchtest.txt']`,
|
||||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Back to Folder', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(subfolder)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
subfolder,
|
||||
)
|
||||
})
|
||||
|
||||
test('Upload File in Folder Level', async () => {
|
||||
await page.click("//span[text()='สร้างเอกสาร']")
|
||||
await page
|
||||
.locator("//input[@type='file']")
|
||||
.setInputFiles('tests/searchtest.txt')
|
||||
await page.fill("//input[@placeholder='กรอกชื่อเรื่อง']", 'testtext')
|
||||
await page.click("(//button[@type='submit'])[1]")
|
||||
await page.waitForTimeout(2500)
|
||||
await page.click('button#getFolder')
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Go into Text File in Folder', async () => {
|
||||
await page.click("//div[text()='testtext']")
|
||||
})
|
||||
|
||||
test('Download File Text in Folder', async () => {
|
||||
await page.click("//span[text()='ดาวน์โหลด']")
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
||||
test('Go back to Folder Level Again', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
})
|
||||
|
||||
test('Delete file Cancel in Folder', async () => {
|
||||
await page.click(
|
||||
`//button[@data-testid='action${cabinet}/${drawer}/${folder}/searchtest.txt']`,
|
||||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Delete file Confirm in Folder', async () => {
|
||||
await page.click(
|
||||
`//button[@data-testid='action${cabinet}/${drawer}/${folder}/searchtest.txt']`,
|
||||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(
|
||||
'testtext',
|
||||
)
|
||||
})
|
||||
|
||||
test('Edit Subfolder', async () => {
|
||||
|
|
@ -130,9 +210,7 @@ test('Edit Subfolder', async () => {
|
|||
await page.click("(//div[@role='listitem'])[1]")
|
||||
await page.fill("(//input[@placeholder='กรอกชื่อ'])[1]", newName)
|
||||
await page.click("(//button[@id='FoldeSubmit'])[1]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Subfolder Cancel', async () => {
|
||||
|
|
@ -141,9 +219,7 @@ test('Delete Subfolder Cancel', async () => {
|
|||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Subfolder Confirm', async () => {
|
||||
|
|
@ -154,16 +230,12 @@ test('Delete Subfolder Confirm', async () => {
|
|||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(newName)
|
||||
})
|
||||
|
||||
test('Back to drawer', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(folder)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(folder)
|
||||
})
|
||||
|
||||
test('Edit Folder', async () => {
|
||||
|
|
@ -173,9 +245,7 @@ test('Edit Folder', async () => {
|
|||
await page.click("(//div[@role='listitem'])[1]")
|
||||
await page.fill("(//input[@placeholder='กรอกชื่อ'])[1]", newName)
|
||||
await page.click("(//button[@id='FoldeSubmit'])[1]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Folder Cancel', async () => {
|
||||
|
|
@ -184,9 +254,7 @@ test('Delete Folder Cancel', async () => {
|
|||
)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Folder Confirm', async () => {
|
||||
|
|
@ -197,16 +265,12 @@ test('Delete Folder Confirm', async () => {
|
|||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(newName)
|
||||
})
|
||||
|
||||
test('Back to Cabinet', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(drawer)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(drawer)
|
||||
})
|
||||
|
||||
test('Edit drawer', async () => {
|
||||
|
|
@ -214,18 +278,14 @@ test('Edit drawer', async () => {
|
|||
await page.click("(//div[@role='listitem'])[1]")
|
||||
await page.fill("(//input[@placeholder='กรอกชื่อ'])[1]", newName)
|
||||
await page.click("(//button[@id='FoldeSubmit'])[1]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Drawer Cancel', async () => {
|
||||
await page.click(`//button[@data-testid='action${cabinet}/${newName}/']`)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Drawer Confirm', async () => {
|
||||
|
|
@ -234,35 +294,30 @@ test('Delete Drawer Confirm', async () => {
|
|||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(newName)
|
||||
})
|
||||
|
||||
test('Back to Home', async () => {
|
||||
await page.click("//i[text()='arrow_back']")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(cabinet)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(cabinet)
|
||||
})
|
||||
|
||||
test('Edit Cabinet', async () => {
|
||||
await page.click(`//button[@data-testid='action${cabinet}/']`)
|
||||
await page.click("(//div[@role='listitem'])[1]")
|
||||
await page.fill("(//input[@placeholder='กรอกชื่อ'])[1]", newName)
|
||||
await page.click("(//button[@id='FoldeSubmit'])[1]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
console.log(cabinet)
|
||||
|
||||
await page.click(`"//button[@data-testid='action${cabinet}/']"`)
|
||||
//button[@data-testid='actionI0Xc50SHxGe4kYehU4t2B/']
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.fill("(//input[@placeholder='กรอกชื่อ'])2]", newName)
|
||||
await page.click("(//button[@id='FoldeSubmit'])[2]")
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Cabinet Cancel', async () => {
|
||||
await page.click(`//button[@data-testid='action${newName}/']`)
|
||||
await page.click("(//div[@role='listitem'])[2]")
|
||||
await page.click("(//div[@class='q-space']/following-sibling::button)[2]")
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).toContainText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).toContainText(newName)
|
||||
})
|
||||
|
||||
test('Delete Cabinet Confirm', async () => {
|
||||
|
|
@ -271,7 +326,5 @@ test('Delete Cabinet Confirm', async () => {
|
|||
await page.click(
|
||||
"(//div[contains(@class,'q-card__actions justify-end')]//button)[2]",
|
||||
)
|
||||
await expect(
|
||||
page.locator("(//div[contains(@class,'bg-white rounded-borders')])[2]"),
|
||||
).not.toHaveText(newName)
|
||||
await expect(page.locator("(//div[@class='col'])[3]")).not.toHaveText(newName)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,218 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("cabinet")
|
||||
export class CabinetController extends Controller {
|
||||
@Get("/")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการตู้เอกสารได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/",
|
||||
name: "ตู้เอกสาร 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 2/",
|
||||
name: "ตู้เอกสาร 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listCabinet(): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list)
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการตู้เอกสารได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
@Post("/")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createCabinet(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ตู้เอกสาร 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
) {
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Put("/{cabinetName}")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editCabinet(
|
||||
@Path() cabinetName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ตู้เอกสารใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
const path = `${cabinetName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", { from: `${cabinetName}/`, to: `${replaceIllegalChars(body.name)}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Delete("/{cabinetName}")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteCabinet(@Path() cabinetName: string) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET!, `${cabinetName}/`, true);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", { pathname: `${cabinetName}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Get("/{cabinetName}/size")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(@Path() cabinetName: string) {
|
||||
const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/`, true).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer")
|
||||
export class DrawerController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการลิ้นชักได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/",
|
||||
name: "ลิ้นชัก 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 2/",
|
||||
name: "ลิ้นชัก 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listDrawer(@Path() cabinetName: string): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!, `${cabinetName}/`).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list)
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการลิ้นชักได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบลิ้นชัก")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createDrawer(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ลิ้นชัก 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
) {
|
||||
const basePath = `${cabinetName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Put("/{drawerName}")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editDrawer(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ลิ้นชักใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
const path = `${cabinetName}/${drawerName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/`,
|
||||
to: `${cabinetName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Delete("/{drawerName}")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteDrawer(@Path() cabinetName: string, @Path() drawerName: string) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", {
|
||||
pathname: `${cabinetName}/${drawerName}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Get("/{drawerName}/size")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(@Path() cabinetName: string, @Path() drawerName: string) {
|
||||
const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/${drawerName}/`, true).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,438 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
Post,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
} from "tsoa";
|
||||
|
||||
import esClient from "../elasticsearch";
|
||||
import minioClient from "../minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/file")
|
||||
export class FileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
): Promise<StorageFile[]> {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
path: `${cabinetName}/${drawerName}/${folderName}/`,
|
||||
},
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
|
||||
const records = search.hits.hits
|
||||
.map((v) => {
|
||||
if (v._source) {
|
||||
const { attachment, ...rest } = v._source;
|
||||
return rest satisfies StorageFile;
|
||||
}
|
||||
})
|
||||
.filter((v: StorageFile | undefined): v is StorageFile => !!v);
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
if (body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
// pathname is unique and should not have multiple record with same path
|
||||
if (result && result.hits.hits.length > 0 && result.hits.hits[0]._source) {
|
||||
await esClient
|
||||
.delete({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: result.hits.hits[0]._id,
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
|
||||
const rec = result && result.hits.hits.length > 0 ? result.hits.hits[0]._source : false;
|
||||
|
||||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
|
||||
await esClient.index({
|
||||
index: DEFAULT_INDEX!,
|
||||
document: metadata,
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUploadRequest", metadata);
|
||||
|
||||
return {
|
||||
...body,
|
||||
createdAt: metadata.createdAt,
|
||||
createdBy: metadata.createdBy,
|
||||
updatedAt: metadata.updatedAt,
|
||||
updatedBy: metadata.updatedBy,
|
||||
upload: await minioClient.presignedPutObject(DEFAULT_BUCKET!, pathname),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@Response(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async updateFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
): Promise<void | { upload: string }> {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const pathname = `${basePath}${fileName}`;
|
||||
|
||||
if (
|
||||
!Boolean(
|
||||
await minioClient.statObject(DEFAULT_BUCKET!, `${pathname}`).catch((e) => {
|
||||
if (e.code === "NotFound") return false;
|
||||
throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
}),
|
||||
)
|
||||
) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์");
|
||||
}
|
||||
|
||||
const { file, ...metadata } = body;
|
||||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (file) {
|
||||
const destination = `${basePath}${replaceIllegalChars(file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
if (copy) {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient
|
||||
.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
.then(() => minioClient.removeObject(DEFAULT_BUCKET!, pathname));
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdateMove", {
|
||||
from: search.hits.hits[0]._source,
|
||||
to: {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, pathname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient.update({
|
||||
index,
|
||||
id,
|
||||
doc: { ...metadata, ...meta },
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const updated: StorageFile = {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
...meta,
|
||||
};
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdate", updated);
|
||||
}
|
||||
}
|
||||
|
||||
return body.file
|
||||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async deleteFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
|
||||
);
|
||||
await esClient.deleteByQuery({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: { pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}` },
|
||||
},
|
||||
});
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async downloadFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: { pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}` },
|
||||
},
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
const { attachment, ...rest } = search.hits.hits[0]._source!;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
download: await minioClient.presignedGetObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder")
|
||||
export class FolderController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1",
|
||||
name: "แฟ้ม 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2",
|
||||
name: "แฟ้ม 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!, `${cabinetName}/${drawerName}`).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createFolder(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้ม 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
) {
|
||||
const basePath = `${cabinetName}/${drawerName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Put("/{folderName}")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editFolder(
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้มใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
const path = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${drawerName}/${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/${folderName}/`,
|
||||
to: `${cabinetName}/${drawerName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Delete("/{folderName}")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", { pathname: `${cabinetName}/${drawerName}/${folderName}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/{folderName}/size")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
const list = await listItem(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/`,
|
||||
true,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified."
|
|||
@Route("/search")
|
||||
export class SearchController extends Controller {
|
||||
@Post("/")
|
||||
@Tags("ค้นหา")
|
||||
@Tags("Search")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async searchFile(@Body() search: Search): Promise<StorageFile[]> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
Post,
|
||||
Put,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
|
|
@ -114,6 +115,10 @@ interface DownloadFileBody {
|
|||
file: string;
|
||||
}
|
||||
|
||||
function stripLeadingSlash(str: string) {
|
||||
return str.replace(/^\//, "");
|
||||
}
|
||||
|
||||
async function folderSize(path: string[]) {
|
||||
const size = await new Promise<number>((resolve, reject) => {
|
||||
const stream = minioClient.listObjectsV2(
|
||||
|
|
@ -138,7 +143,7 @@ async function listFolder(path: string[], hidden: boolean = false) {
|
|||
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET,
|
||||
path.length === 0 ? "" : path.join("/") + "/",
|
||||
stripLeadingSlash(`${path.join("/")}/`),
|
||||
);
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.prefix)
|
||||
|
|
@ -182,7 +187,7 @@ async function listFile(path: string[], hidden: boolean = false) {
|
|||
sort: [{ pathname: "asc" }],
|
||||
query: {
|
||||
bool: {
|
||||
must: { match: { path: path.join("/") + "/" } },
|
||||
must: { match: { path: stripLeadingSlash(`${path.join("/")}/`) } },
|
||||
must_not: !hidden ? { match: { hidden: true } } : undefined,
|
||||
},
|
||||
},
|
||||
|
|
@ -202,14 +207,14 @@ async function listFile(path: string[], hidden: boolean = false) {
|
|||
return records;
|
||||
}
|
||||
|
||||
async function checkPathExist(bucket: string, path: string) {
|
||||
if (path.split("/").filter(Boolean).length === 0) return true; // root does not contain any mark
|
||||
return await checkFileExist(bucket, `${path}/.keep`);
|
||||
async function checkPathExist(bucket: string, path: string[]) {
|
||||
if (path.filter(Boolean).length === 0) return true; // root does not contain any mark
|
||||
return await checkFileExist(bucket, `${path.filter(Boolean).join("/")}/.keep`);
|
||||
}
|
||||
|
||||
async function checkFileExist(bucket: string, pathname: string) {
|
||||
return Boolean(
|
||||
await minioClient.statObject(bucket, pathname).catch((e) => {
|
||||
await minioClient.statObject(bucket, stripLeadingSlash(pathname)).catch((e) => {
|
||||
if (e.code === "NotFound") return false;
|
||||
console.error(`Storage Error: ${e}`);
|
||||
throw new Error(MINIO_ERROR_MESSAGE);
|
||||
|
|
@ -219,16 +224,21 @@ async function checkFileExist(bucket: string, pathname: string) {
|
|||
|
||||
@Route("storage")
|
||||
export class StorageController extends Controller {
|
||||
/**
|
||||
* @summary แสดงรายการแฟ้มหรือไฟล์
|
||||
*/
|
||||
@Post("list")
|
||||
@Tags("Storage Folder", "Storage File")
|
||||
@Security("bearerAuth")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
name: "แฟ้ม 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2/",
|
||||
name: "แฟ้ม 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
|
|
@ -243,6 +253,7 @@ export class StorageController extends Controller {
|
|||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
|
|
@ -252,15 +263,21 @@ export class StorageController extends Controller {
|
|||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
@Tags("Storage Folder", "Storage File")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async getList(@Body() body: ListRequestBody) {
|
||||
const path = body.path.filter(Boolean);
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
if (body.operation === "folder") return await listFolder(path, body.hidden);
|
||||
if (body.operation === "file") return await listFile(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary สร้างแฟ้ม
|
||||
*/
|
||||
@Post("folder")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
|
|
@ -271,7 +288,7 @@ export class StorageController extends Controller {
|
|||
) {
|
||||
const { path, name } = body;
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +300,7 @@ export class StorageController extends Controller {
|
|||
const created = await minioClient
|
||||
.putObject(
|
||||
DEFAULT_BUCKET,
|
||||
`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/.keep`,
|
||||
stripLeadingSlash(`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/.keep`),
|
||||
"",
|
||||
0,
|
||||
meta,
|
||||
|
|
@ -293,7 +310,9 @@ export class StorageController extends Controller {
|
|||
if (!created) throw new Error(MINIO_ERROR_MESSAGE);
|
||||
|
||||
io.getInstance()?.emit("FolderCreate", {
|
||||
pathname: `${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/`,
|
||||
pathname: stripLeadingSlash(
|
||||
`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/`,
|
||||
),
|
||||
name: name.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
...meta,
|
||||
});
|
||||
|
|
@ -302,23 +321,26 @@ export class StorageController extends Controller {
|
|||
}
|
||||
|
||||
/**
|
||||
* ยา้ย Folder ภายใต้ Folder (Path) หนึ่ง ไปภายใน Folder (Path) หนึ่งและสามารถเปลี่ยนชื่อได้
|
||||
* ยา้ยแฟ้มภายในตำแหน่งหนึ่งไปภายในอีกแฟ้มหนึ่ง
|
||||
* หรือเปลี่ยนชื่อได้
|
||||
*
|
||||
* @summary ยา้ยแฟ้ม
|
||||
*/
|
||||
@Put("folder")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async moveFolder(@Body() body: PutFolderBody) {
|
||||
const src = `${body.from.path.join("/")}/${body.from.name}`;
|
||||
const dst = `${body.to.path.join("/")}/${body.to.name}`;
|
||||
const src = stripLeadingSlash(`${body.from.path.join("/")}/${body.from.name}`);
|
||||
const dst = stripLeadingSlash(`${body.to.path.join("/")}/${body.to.name}`);
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, src))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, src.split("/")))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
if (await checkPathExist(DEFAULT_BUCKET, dst)) {
|
||||
if (await checkPathExist(DEFAULT_BUCKET, dst.split("/"))) {
|
||||
throw new HttpError(HttpStatusCode.CONFLICT, PATH_ALREADY_EXIST);
|
||||
}
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path))) {
|
||||
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +358,7 @@ export class StorageController extends Controller {
|
|||
await Promise.all(
|
||||
list.map(async (v) => {
|
||||
const from = `/${DEFAULT_BUCKET}/${v.pathname}`;
|
||||
const to = `${dst}/${v.pathname.slice(`${src}/`.length)}`;
|
||||
const to = stripLeadingSlash(`${dst}/${v.pathname.slice(`${src}/`.length)}`);
|
||||
|
||||
const result = await minioClient
|
||||
.copyObject(DEFAULT_BUCKET, to, from, copyCond)
|
||||
|
|
@ -376,7 +398,7 @@ export class StorageController extends Controller {
|
|||
id: data._id,
|
||||
doc: {
|
||||
pathname: to,
|
||||
path: to.split("/").slice(0, -1).join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.split("/").slice(0, -1).join("/")}/`),
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
|
|
@ -390,8 +412,8 @@ export class StorageController extends Controller {
|
|||
);
|
||||
|
||||
io.getInstance()?.emit("FolderMove", {
|
||||
from: `${src}/`,
|
||||
to: `${dst}/`,
|
||||
from: stripLeadingSlash(`${src}/`),
|
||||
to: stripLeadingSlash(`${dst}/`),
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
|
|
@ -400,6 +422,10 @@ export class StorageController extends Controller {
|
|||
@Post("folder/size")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
size: 10240,
|
||||
})
|
||||
public async folderSize(@Body() body: FolderBody) {
|
||||
return { size: await folderSize([...body.path, body.name]) };
|
||||
}
|
||||
|
|
@ -412,9 +438,17 @@ export class StorageController extends Controller {
|
|||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteStorage(@Body() body: DeleteFolderBody) {
|
||||
if (body.path.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ไม่สามารถลบได้");
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET, body.path.join("/") + "/", true);
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.path.join("/")}/`),
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => v && v.name && objects.push(v.name));
|
||||
stream.on("close", async () => {
|
||||
|
|
@ -435,30 +469,53 @@ export class StorageController extends Controller {
|
|||
@Tags("Storage File")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
uploadUrl: "s3.storage.upload",
|
||||
})
|
||||
public async postFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body() body: FileBody,
|
||||
) {
|
||||
const { path, file } = body;
|
||||
const validFileName = file.replace(/[/\\?%*:|"<>#]/g, "-").trim();
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: path.join("/") + "/" } },
|
||||
query: {
|
||||
match: {
|
||||
pathname: stripLeadingSlash(`${path.join("/")}/${validFileName}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||
|
||||
const metadata: StorageFile = {
|
||||
path: path.join("/") + "/",
|
||||
pathname: path.join("/") + "/" + file.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
fileName: file.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
path: stripLeadingSlash(`${path.join("/")}/`),
|
||||
pathname: stripLeadingSlash(`${path.join("/")}/${validFileName}`),
|
||||
fileName: validFileName,
|
||||
fileSize: 0, // Will be get by minio object storage after file is uploaded
|
||||
fileType: "", // Will be determined by minio object storage after file is uploaded
|
||||
title: body.title ?? file.replace(/[/\\?%*:|"<>#]/g, "-").trim(), // default to same as filename
|
||||
title: body.title ?? validFileName, // default to same as filename
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
|
|
@ -504,6 +561,8 @@ export class StorageController extends Controller {
|
|||
@Tags("Storage File")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Response(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
@Example({ uploadUrl: "s3.storage.upload" })
|
||||
public async moveFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body() body: PutFileBody,
|
||||
|
|
@ -512,7 +571,9 @@ export class StorageController extends Controller {
|
|||
.search<StorageFile & { attachment: Record<string, any> }>({
|
||||
index: DEFAULT_INDEX,
|
||||
query: {
|
||||
match: { pathname: body.from.path.join("/") + `/${body.from.file}` },
|
||||
match: {
|
||||
pathname: stripLeadingSlash(`${body.from.path.join("/")}/${body.from.file}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||
|
|
@ -523,7 +584,12 @@ export class StorageController extends Controller {
|
|||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์ดังกล่าว");
|
||||
}
|
||||
if (!(await checkFileExist(DEFAULT_BUCKET, body.from.path.join("/") + `/${body.from.file}`))) {
|
||||
if (
|
||||
!(await checkFileExist(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.from.path.join("/")}/${body.from.file}`),
|
||||
))
|
||||
) {
|
||||
await esClient.delete({
|
||||
index: DEFAULT_INDEX,
|
||||
id: search.hits.hits[0]._id,
|
||||
|
|
@ -531,10 +597,15 @@ export class StorageController extends Controller {
|
|||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์ดังกล่าว");
|
||||
}
|
||||
if (body.to && JSON.stringify(body.from) !== JSON.stringify(body.to)) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path))) {
|
||||
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||
}
|
||||
if (await checkFileExist(DEFAULT_BUCKET, body.to.path.join("/") + `/${body.to.file}`)) {
|
||||
if (
|
||||
await checkFileExist(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.to.path.join("/")}/${body.to.file}`),
|
||||
)
|
||||
) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.PRECONDITION_FAILED,
|
||||
"พบไฟล์ในต้ำแหน่งปลายทาง ไม่สามารถย้ายได้",
|
||||
|
|
@ -563,7 +634,7 @@ export class StorageController extends Controller {
|
|||
|
||||
if (from && to && JSON.stringify(from) !== JSON.stringify(to)) {
|
||||
const src = [DEFAULT_BUCKET, ...from.path, ""].join("/") + from.file;
|
||||
const dst = to.path.join("/") + `/${to.file}`;
|
||||
const dst = stripLeadingSlash(`${to.path.join("/")}/${to.file}`);
|
||||
|
||||
const result = await minioClient.copyObject(DEFAULT_BUCKET, dst, src, copyCond).catch((e) => {
|
||||
console.error(`MinIO Error: ${e}`);
|
||||
|
|
@ -577,7 +648,7 @@ export class StorageController extends Controller {
|
|||
id: id,
|
||||
doc: {
|
||||
...metadata,
|
||||
path: to.path.join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.path.join("/")}/`),
|
||||
pathname: dst,
|
||||
fileName: to.file,
|
||||
...dateMeta,
|
||||
|
|
@ -586,7 +657,10 @@ export class StorageController extends Controller {
|
|||
})
|
||||
.then(
|
||||
async () =>
|
||||
await minioClient.removeObject(DEFAULT_BUCKET, from.path.join("/") + `/${from.file}`),
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${from.path.join("/")}/${from.file}`),
|
||||
),
|
||||
)
|
||||
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||
|
||||
|
|
@ -595,7 +669,7 @@ export class StorageController extends Controller {
|
|||
to: {
|
||||
...source,
|
||||
...metadata,
|
||||
path: to.path.join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.path.join("/")}/`),
|
||||
pathname: dst,
|
||||
fileName: to.file,
|
||||
...dateMeta,
|
||||
|
|
@ -633,7 +707,7 @@ export class StorageController extends Controller {
|
|||
});
|
||||
|
||||
if (upload) {
|
||||
const src = from.path.join("/") + `/${from.file}`;
|
||||
const src = stripLeadingSlash(`${from.path.join("/")}/${from.file}`);
|
||||
const presignedUrl = await minioClient.presignedPutObject(DEFAULT_BUCKET, src);
|
||||
return { uploadUrl: presignedUrl };
|
||||
}
|
||||
|
|
@ -650,7 +724,7 @@ export class StorageController extends Controller {
|
|||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFile(@Body() body: DeleteFileBody) {
|
||||
const pathname = body.path.join("/") + `/${body.file}`;
|
||||
const pathname = stripLeadingSlash(`${body.path.join("/")}/${body.file}`);
|
||||
|
||||
await minioClient
|
||||
.removeObject(DEFAULT_BUCKET, pathname)
|
||||
|
|
@ -671,8 +745,26 @@ export class StorageController extends Controller {
|
|||
@Tags("Download")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
downloadUrl: "s3.storage.download",
|
||||
})
|
||||
public async downloadFile(@Body() body: DownloadFileBody) {
|
||||
const pathname = body.path.join("/") + `/${body.file}`;
|
||||
const pathname = stripLeadingSlash(`${body.path.join("/")}/${body.file}`);
|
||||
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX,
|
||||
|
|
|
|||
|
|
@ -1,270 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder")
|
||||
export class SubFolderController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1",
|
||||
name: "แฟ้มย่อย 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 2",
|
||||
name: "แฟ้มย่อย 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}`,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบของแฟ้ม")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createFolder(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body() body: { name: string },
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Put("/{subFolderName}")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editFolder(
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้มใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
const path = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(
|
||||
body.name,
|
||||
)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
to: `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Delete("/{subFolderName}")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Get("/{subFolderName}/size")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
const list = await listItem(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}`,
|
||||
true,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
Post,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
} from "tsoa";
|
||||
|
||||
import esClient from "../elasticsearch";
|
||||
import minioClient from "../minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route(
|
||||
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder/{subFolderName}/file",
|
||||
)
|
||||
export class SubFolderFileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
): Promise<StorageFile[]> {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
path: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
},
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
|
||||
const records = search.hits.hits
|
||||
.map((v) => {
|
||||
if (v._source) {
|
||||
const { attachment, ...rest } = v._source;
|
||||
return rest satisfies StorageFile;
|
||||
}
|
||||
})
|
||||
.filter((v: StorageFile | undefined): v is StorageFile => !!v);
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
// pathname is unique and should not have multiple record with same path
|
||||
if (result && result.hits.hits.length > 0 && result.hits.hits[0]._source) {
|
||||
await esClient
|
||||
.delete({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: result.hits.hits[0]._id,
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
|
||||
const rec = result && result.hits.hits.length > 0 ? result.hits.hits[0]._source : false;
|
||||
|
||||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
|
||||
await esClient.index({
|
||||
index: DEFAULT_INDEX!,
|
||||
document: metadata,
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUploadRequest", metadata);
|
||||
|
||||
return {
|
||||
...body,
|
||||
createdAt: metadata.createdAt,
|
||||
createdBy: metadata.createdBy,
|
||||
updatedAt: metadata.updatedAt,
|
||||
updatedBy: metadata.updatedBy,
|
||||
upload: await minioClient.presignedPutObject(DEFAULT_BUCKET!, pathname),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async updateFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
) {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const pathname = `${basePath}${fileName}`;
|
||||
|
||||
if (
|
||||
!Boolean(
|
||||
await minioClient.statObject(DEFAULT_BUCKET!, `${pathname}`).catch((e) => {
|
||||
if (e.code === "NotFound") return false;
|
||||
throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
}),
|
||||
)
|
||||
) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์");
|
||||
}
|
||||
|
||||
const { file, ...metadata } = body;
|
||||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (file) {
|
||||
const destination = `${basePath}${replaceIllegalChars(file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
if (copy) {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
await esClient
|
||||
.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
.then(() => minioClient.removeObject(DEFAULT_BUCKET!, pathname));
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdateMove", {
|
||||
from: search.hits.hits[0]._source,
|
||||
to: {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, pathname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
const updated: StorageFile = {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
...meta,
|
||||
};
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdate", updated);
|
||||
}
|
||||
}
|
||||
|
||||
return body.file
|
||||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async deleteFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
);
|
||||
await esClient.deleteByQuery({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example folderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK)
|
||||
public async downloadFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
const { attachment, ...rest } = search.hits.hits[0]._source!;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
download: await minioClient.presignedGetObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ async function handleNotFoundRecord(
|
|||
buffer: Buffer,
|
||||
stat: { size: number; type: string },
|
||||
) {
|
||||
const path = pathname.split("/").slice(0, -1).join("/") + "/";
|
||||
const path = stripLeadingSlash(pathname.split("/").slice(0, -1).join("/") + "/");
|
||||
const filename = pathname.split("/").at(-1);
|
||||
const base64 = Buffer.from(buffer).toString("base64");
|
||||
|
||||
|
|
@ -175,3 +175,7 @@ async function handleFoundRecord(
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
function stripLeadingSlash(str: string) {
|
||||
return str.replace(/^\//, "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,10 @@
|
|||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { Controller, ValidationService, FieldErrors, ValidateError, TsoaRoute, HttpStatusCodeLiteral, TsoaResponse, fetchMiddlewares } from '@tsoa/runtime';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { CabinetController } from './controllers/cabinetController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { DrawerController } from './controllers/drawerController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { FileController } from './controllers/fileController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { FolderController } from './controllers/folderController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SearchController } from './controllers/searchController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { StorageController } from './controllers/storageController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderController } from './controllers/subFolderController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderFileController } from './controllers/subFolderFileController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { VersionController } from './controllers/versionController';
|
||||
import { expressAuthentication } from './utils/auth';
|
||||
// @ts-ignore - no great way to install types from subpackage
|
||||
|
|
@ -28,17 +16,6 @@ import type { RequestHandler, Router } from 'express';
|
|||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
const models: TsoaRoute.Models = {
|
||||
"StorageFolder": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"pathname": {"dataType":"string","required":true},
|
||||
"name": {"dataType":"string","required":true},
|
||||
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
"createdBy": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
},
|
||||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"StorageFile": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
|
|
@ -71,6 +48,17 @@ const models: TsoaRoute.Models = {
|
|||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"StorageFolder": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"pathname": {"dataType":"string","required":true},
|
||||
"name": {"dataType":"string","required":true},
|
||||
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
"createdBy": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
},
|
||||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"ListRequestBody": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
|
|
@ -124,11 +112,11 @@ const models: TsoaRoute.Models = {
|
|||
"PutFileBody": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"hidden": {"dataType":"boolean"},
|
||||
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"title": {"dataType":"string"},
|
||||
"description": {"dataType":"string"},
|
||||
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"hidden": {"dataType":"boolean"},
|
||||
"from": {"dataType":"nestedObjectLiteral","nestedProperties":{"file":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}},"required":true},
|
||||
"to": {"dataType":"nestedObjectLiteral","nestedProperties":{"file":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}}},
|
||||
"upload": {"dataType":"boolean"},
|
||||
|
|
@ -164,561 +152,6 @@ export function RegisterRoutes(app: Router) {
|
|||
// NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look
|
||||
// Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
|
||||
// ###########################################################################################################
|
||||
app.get('/cabinet',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.listCabinet)),
|
||||
|
||||
function CabinetController_listCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.listCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.createCabinet)),
|
||||
|
||||
function CabinetController_createCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.createCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.editCabinet)),
|
||||
|
||||
function CabinetController_editCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.editCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.deleteCabinet)),
|
||||
|
||||
function CabinetController_deleteCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.deleteCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.calc)),
|
||||
|
||||
function CabinetController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.listDrawer)),
|
||||
|
||||
function DrawerController_listDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.listDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.createDrawer)),
|
||||
|
||||
function DrawerController_createDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.createDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.editDrawer)),
|
||||
|
||||
function DrawerController_editDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.editDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.deleteDrawer)),
|
||||
|
||||
function DrawerController_deleteDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.deleteDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.calc)),
|
||||
|
||||
function DrawerController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.getFile)),
|
||||
|
||||
function FileController_getFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.getFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.uploadFile)),
|
||||
|
||||
function FileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.uploadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.patch('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.updateFile)),
|
||||
|
||||
function FileController_updateFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.updateFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.deleteFile)),
|
||||
|
||||
function FileController_deleteFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.deleteFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.downloadFile)),
|
||||
|
||||
function FileController_downloadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.listFolder)),
|
||||
|
||||
function FolderController_listFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.listFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.createFolder)),
|
||||
|
||||
function FolderController_createFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.createFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.editFolder)),
|
||||
|
||||
function FolderController_editFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.editFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.deleteFolder)),
|
||||
|
||||
function FolderController_deleteFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.deleteFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.calc)),
|
||||
|
||||
function FolderController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/search',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SearchController)),
|
||||
|
|
@ -765,7 +198,7 @@ export function RegisterRoutes(app: Router) {
|
|||
|
||||
|
||||
const promise = controller.getList.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, undefined, next);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
|
@ -844,7 +277,7 @@ export function RegisterRoutes(app: Router) {
|
|||
|
||||
|
||||
const promise = controller.folderSize.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, undefined, next);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
|
@ -975,304 +408,6 @@ export function RegisterRoutes(app: Router) {
|
|||
const controller = new StorageController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.listFolder)),
|
||||
|
||||
function SubFolderController_listFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.listFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.createFolder)),
|
||||
|
||||
function SubFolderController_createFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.createFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.editFolder)),
|
||||
|
||||
function SubFolderController_editFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.editFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.deleteFolder)),
|
||||
|
||||
function SubFolderController_deleteFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.deleteFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.calc)),
|
||||
|
||||
function SubFolderController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.getFile)),
|
||||
|
||||
function SubFolderFileController_getFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.getFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.uploadFile)),
|
||||
|
||||
function SubFolderFileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.uploadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.patch('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.updateFile)),
|
||||
|
||||
function SubFolderFileController_updateFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.updateFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.deleteFile)),
|
||||
|
||||
function SubFolderFileController_deleteFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.deleteFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.downloadFile)),
|
||||
|
||||
function SubFolderFileController_downloadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,16 +25,7 @@
|
|||
"description": "Keycloak Bearer Token",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{ "name": "ตู้เอกสาร" },
|
||||
{ "name": "ลิ้นชัก" },
|
||||
{ "name": "แฟ้ม" },
|
||||
{ "name": "แฟ้มย่อย" },
|
||||
{ "name": "ไฟล์" },
|
||||
{ "name": "ดาวน์โหลด" },
|
||||
{ "name": "ค้นหา" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"routes": {
|
||||
"routesDir": "src",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue