-
Notifications
You must be signed in to change notification settings - Fork 19
/
workpackageHelper.js
188 lines (180 loc) · 6.69 KB
/
workpackageHelper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import { generateUrl } from '@nextcloud/router'
import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
let cachedStatusColors = {}
let cachedTypeColors = {}
export const workpackageHelper = {
// to allow the unit tests, to clear the cache
clearCache() {
cachedStatusColors = {}
cachedTypeColors = {}
},
async getColorAttributes(path, id) {
const url = generateUrl(path + id)
let response
try {
response = await axios.get(url)
} catch (e) {
response = e.response
}
return (response.status === 200 && response.data?.color)
? response.data.color
: ''
},
replaceHrefToGetId(href) {
// this is a helper method replaces the string like this "/api/v3/types/3" to get id
return href
? href.replace(/.*\//, '')
: null
},
async getAdditionalMetaData(workPackage, linkableWorkpackage = false) {
if (typeof workPackage._links.status.href !== 'string'
|| workPackage._links.status.href === ''
|| typeof workPackage._links.type.href !== 'string'
|| workPackage._links.type.href === ''
|| typeof workPackage.id !== 'number'
|| typeof workPackage.subject !== 'string'
|| workPackage.subject === ''
|| typeof workPackage._links.project.title !== 'string'
|| workPackage._links.project.title === ''
|| typeof workPackage._links.status.title !== 'string'
|| workPackage._links.status.title === ''
|| typeof workPackage._links.type.title !== 'string'
|| workPackage._links.type.title === ''
) {
throw new Error('missing data in workpackage object')
}
if (linkableWorkpackage && typeof workPackage.fileId !== 'number' && workPackage.fileId <= 0) {
throw new Error('missing data in workpackage object')
}
const statusId = this.replaceHrefToGetId(workPackage._links.status.href)
const typeId = this.replaceHrefToGetId(workPackage._links.type.href)
const userId = this.replaceHrefToGetId(workPackage._links.assignee.href)
const projectId = this.replaceHrefToGetId(workPackage._links.project.href)
const userName = workPackage._links.assignee.title
const avatarUrl = generateUrl('/apps/integration_openproject/avatar?')
+ encodeURIComponent('userId')
+ '=' + userId
+ '&' + encodeURIComponent('userName')
+ '=' + userName
let statusColor
if (cachedStatusColors[statusId] === undefined) {
statusColor = await this.getColorAttributes('/apps/integration_openproject/statuses/', statusId)
cachedStatusColors[statusId] = statusColor
} else {
statusColor = cachedStatusColors[statusId]
}
let typeColor
if (cachedTypeColors[typeId] === undefined) {
typeColor = await this.getColorAttributes('/apps/integration_openproject/types/', typeId)
cachedTypeColors[typeId] = typeColor
} else {
typeColor = cachedTypeColors[typeId]
}
return {
id: workPackage.id,
subject: workPackage.subject,
project: workPackage._links.project.title,
projectId,
statusTitle: workPackage._links.status.title,
typeTitle: workPackage._links.type.title,
assignee: userName,
statusCol: statusColor,
typeCol: typeColor,
picture: avatarUrl,
fileId: workPackage.fileId,
}
},
chunkMultipleSelectedFilesInformation(fileInformation) {
// this function chunks 20 files of information in an array and returns an array of it, `20` because Openproject api only allows linking of 20 files per request
const chunkedResult = []
for (let i = 0; i < fileInformation.length; i += 20) {
chunkedResult.push(fileInformation.slice(i, i + 20))
}
return chunkedResult
},
getTotalNoOfFilesInAlreadyChunkedFilesInformation(chunkedFilesInformations) {
let totalNoFiles = 0
for (let i = 0; i < chunkedFilesInformations.length; i++) {
totalNoFiles = totalNoFiles + chunkedFilesInformations[i].length
}
return totalNoFiles
},
// Here the chunkedFilesInformation is the array that contains the array of chunked files information in 20
async linkMultipleFilesToWorkPackageWithChunking(filesInformations, selectedWorkpackage, isRemaining, component) {
const chunkedFilesInformations = []
for (let i = 0; i < filesInformations.length; i += 20) {
chunkedFilesInformations.push(filesInformations.slice(i, i + 20))
}
const chunkingInformation = {
totalNoOfFilesSelected: this.getTotalNoOfFilesInAlreadyChunkedFilesInformation(chunkedFilesInformations),
totalFilesAlreadyLinked: 0,
totalFilesNotLinked: this.getTotalNoOfFilesInAlreadyChunkedFilesInformation(chunkedFilesInformations),
error: false,
remainingFileInformations: [],
selectedWorkPackage: selectedWorkpackage,
}
for (const fileInfoForBody of chunkedFilesInformations) {
try {
let retry = 0
while (retry <= 1) {
try {
await this.makeRequestToLinkFilesToWorkPackage(fileInfoForBody, selectedWorkpackage)
break
} catch (e) {
if (retry === 1) {
throw new Error()
}
}
retry++
}
if (chunkedFilesInformations.indexOf(fileInfoForBody) !== chunkedFilesInformations.length - 1) {
chunkingInformation.totalFilesAlreadyLinked = chunkingInformation.totalFilesAlreadyLinked + 20
} else {
// for the last chunked files information we only count the no of files which are not be 20
chunkingInformation.totalFilesAlreadyLinked = chunkingInformation.totalFilesAlreadyLinked + fileInfoForBody.length
}
chunkingInformation.totalFilesNotLinked = chunkingInformation.totalNoOfFilesSelected - chunkingInformation.totalFilesAlreadyLinked
} catch (e) {
chunkingInformation.error = true
// when error encounters while chunking we compute the information of files for relinking again
for (let i = chunkedFilesInformations.indexOf(fileInfoForBody); i < chunkedFilesInformations.length; i++) {
chunkingInformation.remainingFileInformations.push(...chunkedFilesInformations[i])
}
break
} finally {
if (isRemaining) {
component.setChunkedInformations(chunkingInformation)
} else {
component.$emit('set-chunked-informations', chunkingInformation)
}
}
}
},
async makeRequestToLinkFilesToWorkPackage(fileInfoForBody, selectedWorkpackage) {
const config = {
headers: {
'Content-Type': 'application/json',
},
}
const url = generateUrl('/apps/integration_openproject/work-packages')
const body = {
values: {
workpackageId: selectedWorkpackage.id,
fileinfo: fileInfoForBody,
},
}
await axios.post(url, body, config)
},
async linkFileToWorkPackageWithSingleRequest(fileInfoForBody, selectedWorkpackage, successMessage, component) {
try {
await this.makeRequestToLinkFilesToWorkPackage(fileInfoForBody, selectedWorkpackage)
component.$emit('saved', selectedWorkpackage)
showSuccess(successMessage)
} catch (e) {
showError(
t('integration_openproject', 'Failed to link file to work package'),
)
}
},
}