Всем привет!
Подскажите, пожалуйста, знает ли кто-нибудь способ в серверном скрипте получить содержимое не-текстового вложения? Например, в какой-нибудь ArrayBuffer-объект запихнуть.
Тот же вопрос касается и добавления не-текстового содержимого в качестве вложения.
Хочу обработать docx-файл, а тут для SimpleAttachment не помогут ни метод getContent() для получения содержимого, ни метод write() - для записи (там везде - String)…
В клиентском скрипте, насколько понял, можно fetch использовать для получения содержимого через URL вложения. А как обстоят дела с серверным скриптом?
Можно воспользоваться методом readBase64()
Получим файл, закодированный в base64. Далее надо будет его преобразовать из base64 в blob. Но использовать предоставляемую функцию API base64Decode() нельзя. он вернет только символы. Надо написать свою функцию. DeepSeek в помощь.
Спасибо за наводку! Попробую…
Тем временем, пока удалось только через клиентскую часть docx обработать…
Ещё раз большое спасибо!
У меня, наконец, получилось хотя бы с клиентской частью. Только в этом случае мне помог не readBase64(), а writeBase64(). Хоть и знал про этот метод, но, честно говоря, не думал, что его можно для бинарного содержимого использовать. В итоге, клиентская часть готовит нужный docx-файл - на выходе там ArrayBuffer, который кодирую в base64 на клиентской стороне (гугл помог), а на серверной принимаю это и как есть скармливаю в writeBase64(). Пока так…
Всем привет!
Вдруг кому-то пригодится. Представляю пару функций. Первая - берёт на входе base64-строку, а выдаёт бинарное содержимое ArrayBuffer:
function myatob (base64) {
const b64Translation = {
"A": 0, "B": 1, "C": 2, "D": 3, "E": 4, "F": 5, "G": 6, "H": 7, "I": 8, "J": 9, "K": 10, "L": 11, "M": 12,
"N": 13, "O": 14, "P": 15, "Q": 16, "R": 17, "S": 18, "T": 19, "U": 20, "V": 21, "W": 22, "X": 23, "Y": 24, "Z": 25,
"a": 26, "b": 27, "c": 28, "d": 29, "e": 30, "f": 31, "g": 32, "h": 33, "i": 34, "j": 35, "k": 36, "l": 37, "m": 38,
"n": 39, "o": 40, "p": 41, "q": 42, "r": 43, "s": 44, "t": 45, "u": 46, "v": 47, "w": 48, "x": 49, "y": 50, "z": 51,
"0": 52, "1": 53, "2": 54, "3": 55, "4": 56, "5": 57, "6": 58, "7": 59, "8": 60, "9": 61, "+": 62, "/": 63, "=": "-"
}
let result = [];
for (let i = 0; i < base64.length; i+=4) {
const bCode = [];
for (let j = 0; j < 4; j++) {
const symbol = base64[i+j];
bCode[j] = b64Translation[symbol];
}
result.push ((bCode[0]<<2) | (bCode[1]>>4));
bCode[2]!="-" && result.push (((bCode[1]&15)<<4) | (bCode[2]>>2));
bCode[3]!="-" && result.push (((bCode[2]&3)<<6) | bCode[3]);
}
let buffer = new ArrayBuffer(result.length);
let view = new Uint8Array(buffer);
let idx = 0;
for (let b of result) {
view[idx++] = b;
}
return buffer;
}
И вторая - наоборот, из ArrayBuffer делает base64:
function mybtoa (input) {
const symbols = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"
];
const uint8Array = new Uint8Array(input);
let result = '';
for (let i = 0; i < uint8Array.length; i+=3) {
const bCode = [];
for (let j = 0; j < 3; j++) {
if ((i+j) < uint8Array.length) {
bCode[j] = uint8Array[i+j];
} else {
bCode[j] = null;
}
}
result += symbols[bCode[0]>>2];
if (bCode[1] != null) {
result += symbols[((bCode[0]&3)<<4) | (bCode[1]>>4)];
if (bCode[2] != null) {
result += symbols[((bCode[1]&15)<<2) | (bCode[2]>>6)];
result += symbols[bCode[2]&63];
} else {
result += symbols[((bCode[1]&15)<<4)];
result += "=";
}
} else {
result += symbols[((bCode[0]&3)<<4)];
result += "==";
}
}
return result;
}
P.S. Профессиональные программисты, не ругайте, пожалуйста уж как смог…
Ну вот, оказалось, что платформа S1 не имеет ни atob(), ни btoa(). Поэтому пришлось своё писать.
Да, хорошо получилось
Спасибо!
Правда, свою задачу я так и не смог выполнить на серверной стороне… ) скрипт обработки не стал работать на S1… не понравилась ему платформа… поэтому всё равно пришлось клиентскую часть задействовать (но уже в меньшей степени)…
Ну давай решим твою задачу на серверной стороне.
Какая полная постановка? Что значит приготовить или обработать docx-файл?
Напомню, что есть такой вариант манипуляции с бинарностью на серверной стороне
const simpleInstanceUri = ss.getProperty('simple.instance.uri');
const URL_BASE = (simpleInstanceUri.startsWith('https://')) ? simpleInstanceUri : `https://${simpleInstanceUri}`;
const request = sws.restRequestV1();
request.setRequestUrl('https://s3-home.simpleone.ru/public-attachment/4/9f/istzt33ycijsiym7rv7ax92yd76l2arr?response-content-disposition=inline%3B%20filename%3D%22spacer24.gif%22&response-content-type=image%2Fgif%3B'); //the URL from which the file is downloaded
const downloadResponse = request.execute();
request.setRequestUrl(`${URL_BASE}/v1/attachments/upload/user/${ss.getUserId()}`); // the URL on which the file is uploaded
request.setRequestHeader('Authorization', `Bearer ${new SimpleUser().getAccessToken()}`);
request.addFileContent(downloadResponse.getContentBase64(), 'files', 'spacer24.gif');
const uploadResponse = request.execute();
Полная постановка следующая:
Есть файл-шаблон в формате docx, прикреплённый к одному из системных свойств. Это - форма заявления на отпуск. При согласовании отпуска нужно сформировать заполненную форму и присоединить её к отправляемому (в отдел кадров, например) письму. Файл-шаблон подготовлен так, чтобы с помощью модуля docx-templates можно было его заполнить (ФИО, даты и т.п.). Скрипт взят отсюда: https://unpkg.com/docx-templates/lib/browser.js
Из скрипта вычерrнут export и основная функция переименована в createReport (строка export-а подсказала, какую функцию нужно переименовать - там pe было; больше ничего переименовывать не потребовалось).
Через виджет пробовал использовать этот скрипт на клиентской стороне - прекрасно работает. Принцип примерно такой:
- на серверной стороне использую readBase64() и передаю полученное на клиентскую сторону;
- дополнительно на серверной стороне вытягиваю скрипт для docx-templates (из includes) - тоже передаю на клиентскую сторону;
- на клиентской стороне из полученной base64-строки получаю бинарное содержимое (теперь уже даже моим скриптом);
- бинарник скармливаю функции createReport из модуля docx-templates - получаю другой бинарник, который перевожу в base64-строку, отправляемую на серверную часть;
- на серверной части использую writeBase64() для записи полученного вложения (это уже заполненная форма на отпуск).
На серверной стороне createReport модуля docx-templates просто “тихо” отрабатывает, не выдавая ни ошибок, ни результата (на выходе - undefined)… Упоминание console там было только одно (console.error) - его заменил, но, в принципе, это было необязательно, поскольку выполняется оно только после проверки, что console имеет место быть. Ещё там есть обращения к таким вещам как document, documentElement, но тут уж не знаю, что с этим поделать - просто была надежда, что эти куски на серверной стороне просто не выполняются…
Спасибо за подсказку про REST, но там всё та же проблема. Нет там никакой бинарности на выходе. Там на выходе - объект SimpleRestResponse, у которого так же нет методов для получения бинарного потока содержимого (пробовал getBody() - выдаёт строку, длина которой не совпадает с размером файла, что логично для такой “строки”).
Для бинарника можно использовать лишь метод getContentBase64(), который даёт всё ту же base64-строку, как и предложенный выше метод readBase64(). И записать через REST можно тоже только base64-строку. Так что, не вижу никакого смысла использовать REST…