-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsession.js
More file actions
242 lines (200 loc) · 6.6 KB
/
session.js
File metadata and controls
242 lines (200 loc) · 6.6 KB
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
const base26 = require("./dudk/util/base26.js");
const crypto = require("crypto");
const sheets_lib = require("./dudk/sheets.js");
const backend = require("./dudk/backend");
class Session {
constructor(p = {}) {
this.id = p.id;
this.filename = p.filename;
if ('backendSid' in p) {
this.backendSid = p.backendSid
} else {
this.backendSid = backend.CreateSession();
backend.SessionSetFile(this.backendSid, p.filename);
}
this.fields = p.fields;
this.sheet = p.sheet ?? "";
}
get sheets() {
return backend.SessionGetSheets(this.backendSid)
}
get headerRange() {
return backend.SessionGetHeaderRange(this.backendSid, this.sheet)
}
set headerRange(range) {
const r = range;
if (!r.sheet) {
r.sheet = this.sheet
}
backend.SessionSetHeaderRange(this.backendSid, r)
}
get footerRange() {
return backend.SessionGetFooterRange(this.backendSid, this.sheet)
}
set footerRangeRange(range) {
const r = range;
if (!r.sheet) {
r.sheet = this.sheet
}
backend.SessionSetFooterRange(this.backendSid, r)
}
get mapping() {
return backend.SessionGetMappingRules(this.backendSid)
}
set mapping(rules) {
backend.SessionSetMappingRules(this.backendSid, rules)
}
}
class Range {
constructor(start, end) {
this.start = start
this.end = end
}
}
exports.CreateSession = (config, request) => {
const createResponse = {
id: "",
session: undefined,
error: undefined,
};
const file = request.file;
if (!file) {
createResponse.error = "Please attach a file";
return createResponse;
}
const err = validateUpload(file);
if (err != undefined) {
createResponse.error = err;
return createResponse;
}
createResponse.id = getFilenameHash(file.filename);
createResponse.session = new Session({
id: createResponse.id,
filename: `${config.uploadPath}/${file.filename}`,
fields: config.fields,
});
return createResponse;
};
var getFilenameHash = (filename) => {
const hash = crypto.createHash("md5");
const data = hash.update(filename, "utf-8");
const gen_hash = data.digest("hex");
return gen_hash;
};
var validateUpload = (file) => {
const acceptedMimeTypes = [
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"text/csv",
"application/vnd.oasis.opendocument.spreadsheet",
];
if (!acceptedMimeTypes.includes(file.mimetype)) {
return "Uploaded file was not a supported file type";
}
return undefined;
};
/*
* Returns a header row for display, based on the requested mode and the data
* currently available in the state.
*
* The various display modes are:
* - none - return nothing, no display required
* - index - returns the index of the column in base26.
* - source - returns the header names as they are defined in the source file
* - target - returns the header names as they are in the domain object after mapping
*/
exports.HeaderRowDisplay = (session, displayMode) => {
var mode = displayMode.toLowerCase();
// User has selected 'none' mode, which means we don't return any headers as
// the user does not want to show them. No pre-requisites.
// eslint-disable-next-line no-unused-vars
const noneMode = (_range) => {
return null
}
// Index mode, shows the index as base26 where the values are taken from the range.
// Requires a selected sheet
const indexMode = (range) => {
if (!session.sheet || session.sheet == "") {
console.warn("HeaderRowDisplay: No sheet selected so header display mode is 'none'")
return null
}
const headers = new Array();
for (var i = range.start; i <= range.end; i++) {
headers.push(base26.toBase26(i + 1))
}
return headers
}
// Using the header values selected by the user, use those instead of column indices.
// Requires a selected sheet and a headerRange
const sourceMode = (range) => {
if (!session.sheet) {
console.warn("HeaderRowDisplay: No sheet selected so header display mode is 'none'")
return null
}
const hrange = session.headerRange
if (!hrange) {
console.warn("HeaderRowDisplay: No header range available for source headers")
return null
}
const rows = sheets_lib.GetRows(session.backendSid, session.sheet, session.headerRange.start.row, session.headerRange.end.row + 1)[0];
const headers = new Array();
for (var i = range.start; i <= range.end; i++) {
headers.push(rows[i]?.value ?? "")
}
return headers;
}
// Use the header values from the mapped domain object, so the target column headings and the user's data
// for that column.
// Requires a selected sheet and a mapping
// eslint-disable-next-line no-unused-vars
const targetMode = (_range) => {
if (!session.sheet || session.sheet == "") {
console.warn("HeaderRowDisplay: No sheet selected so header display mode is 'none'")
return null
}
if (!session.mapping) {
console.warn("HeaderRowDisplay: No mapping available so header display mode is 'none'")
return null
}
return noneMode;
}
var range = calculateHeaderRange(session)
// Unless the mode is 'none' then a sheet is required to return headers for display
if (mode != "none" && (!session.sheet || session.sheet == "")) {
console.warn("HeaderRowDisplay: No sheet selected so header display mode is 'none'")
return null
}
switch (mode) {
// Index as base26 name
case "index":
return indexMode(range);
// Header names as selected by user
case "source":
return sourceMode(range);
// Header names as the fieldnames for the domain object
case "target":
return targetMode(range);
}
// If 'none' is specified, or the value provided isn't supported...
return noneMode(range);
}
// Calculate the range, either from the currently selected columns, or from the number
// of items in a row (making the assumption that they're even).
const calculateHeaderRange = (session) => {
const hrange = session.headerRange;
if (hrange) {
return new Range(hrange.start.column, hrange.end.column)
}
if (!session.sheet || session.sheet == "") {
console.warn("HeaderRowDisplay: No sheet selected so finding mode from rows is not possible")
return null
}
// With no specified headers, try and default to the first row. This may already be set
// earlier in the flow, but we add this defensively.
const r = sheets_lib.GetRows(session.backendSid, session.sheet)
if (r) {
return new Range(0, r[0].length)
}
console.warn("HeaderRowDisplay: No rows available when determining number of columns")
return null
}
exports.Session = Session