FSN#38299 Flexkenmerken via de API kunnen bewerken, savepoint bestanden upload/downloaden

svn path=/Website/trunk/; revision=33229
This commit is contained in:
Jos Groot Lipman
2017-03-23 12:22:54 +00:00
parent d1579eb5d8
commit 5f33336720
7 changed files with 173 additions and 68 deletions

View File

@@ -1007,7 +1007,7 @@ api2 = {
return timetable.join(";");
},
// Geef alle velden van een record terug
sql2jsonfields: function _sql2jsonfields(oRs, model)
sql2jsonfields: function _sql2jsonfields(params, oRs, model)
{
var record = {};
for (var fld in model.fields)
@@ -1025,7 +1025,7 @@ api2 = {
record[fld] = val;
}
if ("post_get" in model)
model.post_get(record);
model.post_get(params, record);
return record;
},
sql2json: function _sql2json(params, sql, model)
@@ -1139,7 +1139,7 @@ api2 = {
incmodel.aliasprefix = incmodel.aliasprefix || "";
if (oRs(incmodel.aliasprefix + incmodel.primary).value == null) // Geen record door outer join
continue;
record[incname].push(api2.sql2jsonfields(oRs, incmodel));
record[incname].push(api2.sql2jsonfields(params, oRs, incmodel));
}
else if (model.includes[incname].func) // include via callback functie zoals reservablerooms/occupation
{
@@ -1567,12 +1567,13 @@ function generic_REST_PUT(model, gparams)
var wheres = [model.fields["id"].dbs + " = " + the_key];
var xxxUpd = buildTrackingUpdate(model.table, wheres.join(" AND " ), dbfields, { noValidateToken: true });
// TODO: Generieke tracking?
// TODO: de includes?
var err = Oracle.Execute(xxxUpd.sql, true);
if (err.friendlyMsg)
abort_with_warning(err.friendlyMsg);
if (xxxUpd) // Misschien geen velden opgegeven.
{
var err = Oracle.Execute(xxxUpd.sql, true);
if (err.friendlyMsg)
abort_with_warning(err.friendlyMsg);
}
var inctrack = api2.process_includes(params, this, jsondata, the_key);
if ("disc_params" in model)
@@ -1581,9 +1582,12 @@ function generic_REST_PUT(model, gparams)
var dbfields = api2.update_fields(params, this.disc_params.model, jsondata_dp);
var wheres = [model.disc_params.model.fields[model.disc_params.joinfield].dbs + " = " + the_key];
var xxxUpd = buildTrackingUpdate(model.disc_params.model.table, wheres.join(" AND " ), dbfields, { noValidateToken: true });
var err = Oracle.Execute(xxxUpd.sql, true);
if (err.friendlyMsg)
abort_with_warning(err.friendlyMsg);
if (xxxUpd) // Misschien geen velden opgegeven.
{
var err = Oracle.Execute(xxxUpd.sql, true);
if (err.friendlyMsg)
abort_with_warning(err.friendlyMsg);
}
}
return { key: the_key, warning: "" };

View File

@@ -175,34 +175,41 @@ api2_rest = {
if (/PUT|POST/.test(method)) // Dan is er in de body data meegestuurd
{
switch (format)
if (filter.mode == "attachment" && "custom_fields" in model.includes)
{
case "json":
{
var parsed = RequestJSON();
if (parsed.error)
api2.error(500, "Error parsing input JSON: " + parsed.error);
jsondata = api2_rest.plugin.transform_incoming(requestparams, parsed.json);
if (!jsondata)
api2.error(500, "Error parsing input JSON: Empty");
break;
}
case "xml":
{
var parsed = RequestXML();
if (parsed.error)
api2.error(500, "Error parsing input XML: " + parsed.error);
jsondata = api2_rest.xml2json(parsed.xml);
if (!jsondata)
api2.error(500, "Error parsing input XML: Empty");
break;
}
default:
UNKNOWN_FORMAT_TYPE;
// Body bevat application/octet-stream, dat lezen we later wel uit
}
if (!jsondata || !(model.record_name in jsondata || (model.multi_update && model.records_name in jsondata)))
else
{
api2.error(500, "No '{0}' found in input".format(model.record_name));
switch (format)
{
case "json":
{
var parsed = RequestJSON();
if (parsed.error)
api2.error(500, "Error parsing input JSON: " + parsed.error);
jsondata = api2_rest.plugin.transform_incoming(requestparams, parsed.json);
if (!jsondata)
api2.error(500, "Error parsing input JSON: Empty");
break;
}
case "xml":
{
var parsed = RequestXML();
if (parsed.error)
api2.error(500, "Error parsing input XML: " + parsed.error);
jsondata = api2_rest.xml2json(parsed.xml);
if (!jsondata)
api2.error(500, "Error parsing input XML: Empty");
break;
}
default:
UNKNOWN_FORMAT_TYPE;
}
if (!jsondata || !(model.record_name in jsondata || (model.multi_update && model.records_name in jsondata)))
{
api2.error(500, "No '{0}' found in input".format(model.record_name));
}
}
}
@@ -256,8 +263,8 @@ api2_rest = {
{
var result = model["REST_" + method]( requestparams, key );
}
else if (method == "GET" && filter.mode == "attachment" && "custom_fields" in model.includes)
{
else if (filter.mode == "attachment" && "custom_fields" in model.includes)
{ // https://xxxx.facilitor.nl/trunk/api2/visitors/99685/attachments/1040/testfile.jpg"
if (wasCodePage != 65001)
{
// Door de IIS rewriter is de filenaam in de url utf-8 encoded
@@ -275,12 +282,44 @@ api2_rest = {
requestparams.filter.id = key; // Die kan er maar beter wel zijn!
requestparams.include = ["custom_fields"];
var data = model.REST_GET(requestparams);
if (!data.length) // mogelijk not authorized op hele record
Response.Status = "404 Not Found";
var jsondata = { "custom_fields": [
{
"propertyid": parseInt(filter.subfolder, 10),
"value": filter.filename, // Gaat de database in bij "F"
"attachments": [
{
"name": filter.filename // Zo gaat hij heten op het filesysteem
}
]
}
]
};
if (method == "PUT" || method == "POST")
{
var bytes = Request.TotalBytes;
if (bytes == 0)
{ // TODO
//__DoLog("api_gen_import empty body posted", "#ffff00");
//Response.Write("Error: no data posted for API import");
//Response.End; // Grof maar anders AiAi, dat is nog erger
}
var fileStream = Server.CreateObject("ADODB.Stream");
fileStream.Type = 1; // adTypeBinary eerst nog
fileStream.Open();
fileStream.Write(Request.BinaryRead(bytes));
jsondata["custom_fields"][0]["attachments"][0].datastream = fileStream;
}
var data = model["REST_" + method](requestparams, jsondata, key);
if (method == "GET")
{
if (!data.length) // mogelijk not authorized op hele record
Response.Status = "404 Not Found";
else
model.includes["custom_fields"].model.streamattachment(filter, data[0].custom_fields);
Response.End;
}
else
model.includes["custom_fields"].model.streamattachment(filter, data[0].custom_fields);
Response.End;
result = data;
}
else if (method == "GET")
{

View File

@@ -23,7 +23,7 @@ function model_bez_kenmerk()
this.autfunction = "WEB_PRSSYS";
this.record_title = L("bez_kenmerk");
this.records_title = L("bez_kenmerk_m");
this.module = "BEZ";
this.fields = {
"id": {

View File

@@ -23,6 +23,11 @@
function model_custom_fields(formodel, flexModule, flexParams)
{
if (typeof flexModule != "string")
{
flexModel = flexModule;
flexModule = flexModel.module;
}
flexParams = flexParams || {};
this.module = flexModule;
this.records_name = "customfields";
@@ -84,21 +89,31 @@ function model_custom_fields(formodel, flexModule, flexParams)
// Deze functie wordt na de GET aangeroepen. De bijlagen zijn zo afwijkend
// dat ik dat niet fatsoenlijk in 'fields' verwerkt kreeg
this.post_get = function (record)
this.post_get = function (params, record)
{
if (record.type == 'F' || record.type == 'M')
{
var flexparam = flexProps(flexModule, record.xflexparentkey, String(record.propertyid), flexParams.pNiveau,
{ getFiles: true, api2name: formodel.records_name });
{ getFiles: true, getFileEncoded: params.filter.fileencoding, api2name: formodel.records_name });
record.attachments = [];
for (var f in flexparam.files)
{
var file = flexparam.files[f];
record.attachments.push({ name: file.name,
date: file.date,
size: file.size,
content_url: file.deepurl,
digest: file.digest })
var attachment = { name: file.name,
date: file.date,
size: file.size,
content_url: file.deepurl,
digest: file.digest };
switch (params.filter.fileencoding) // De enige twee encodings die we ondersteunen
{
case "base64":
attachment.content_base64 = file.data;
break;
case "hex":
attachment.content_hex = file.data;
break;
}
record.attachments.push(attachment);
};
}
delete record["xflexparentkey"]; // nu niet meer nodig
@@ -114,7 +129,7 @@ function model_custom_fields(formodel, flexModule, flexParams)
var att = flexfields[fid].attachments[i];
if (att.name.toLowerCase() == filter.filename.toLowerCase()) // Gevonden!!!!
{
params = flexProps(this.module, filter.id, filter.subfolder, flexParams.pNiveau);
var params = flexProps(this.module, filter.id, filter.subfolder, flexParams.pNiveau);
// In de praktijk (b)lijkt IE de ETag niet te sturen voor downloads
// maar wij ondersteunen het in ieder geval wel.
var eTag = '"' + att.digest + '"';
@@ -145,8 +160,36 @@ function model_custom_fields(formodel, flexModule, flexParams)
+ "END;"
Oracle.Execute(sql);
}
this.REST_POST = function (params, jsondata, parent_key) /* add custom_field */
{
// Merk op dat flexProps ook wel het type oplevert. Ik wil echter migreren naar modellen
var kenmerkdata = api2.GET(flexModel, jsondata.propertyid);
// TODO: if (!kenmerkdata) en rechtencontrole
var typ = kenmerkdata.attributetype.id;
if (typ == 'F' || typ == 'M')
{debugger;
var flexparams = flexProps(this.module, params.filter.id, params.filter.subfolder, flexParams.pNiveau);
// TODO: bij type F zorgen dat er <20><>n file overblijft
for (var i = 0; i < jsondata.attachments.length; i++)
{
var attachment = jsondata.attachments[i];
var safefilename = safe.filename(attachment.name);
if (flexparams.isAllowedName(safefilename))
{
CreateFullPath(flexparams.AttachPath);
if ("datastream" in attachment)
attachment.datastream.SaveToFile(flexparams.AttachPath + safefilename, 2); // adSaveCreateOverWrite
// TODO: content_base64 en content_hex encoding ondersteunen
}
else
{
Response.Status = "422 Unprocessable Entity";
Response.End;
}
}
}
var sql = "BEGIN flx.setflex({0}".format(safe.quoted_sql(this.module))
+ " , {0}".format(jsondata.propertyid)
+ " , {0}".format(parent_key)
@@ -157,18 +200,16 @@ function model_custom_fields(formodel, flexModule, flexParams)
}
this.REST_DELETE = function (params, the_key) /* remove custom_field */
{
var sql = "BEGIN flx.deleteflex({0}".format(safe.quoted_sql(this.module))
+ " , {0}".format(the_key)
+ " , {0}".format(params.filter.id)
+ " , {0});".format(flexParams.niveau? safe.quoted_sql(flexParams.niveau): "NULL" )
+ "END;"
Oracle.Execute(sql);
// custom_fields zijn ietwat afwijkend
// 'verwijderen' doe je door de waarde op NULL te zetten (net zoals met vaste velden)
// Anders loop je risico dat bij een update velden die niet in de include=custom_fields
// zitten (omdat je er gewoon geen rechten op had) zo maar verwijderd worden
}
this.list = { columns: ["id", "label", "value"] }
// Merk op: g<><67>n eigen REST_GET
// We kunnen toch alleen via een include van een parent die dan ook
// We werken toch alleen via een include van een parent die dan ook
// vooral alle autorisatiecontrole voor ons kan verzorgen
}

View File

@@ -15,6 +15,9 @@
<!-- #include file="../Shared/discxalg3d.inc"-->
<!-- #include file="../bez/bez.inc" -->
<!-- #include file="./model_custom_fields.inc"-->
<!-- #include file="../mgt/mgt_tools.inc"-->
<!-- #include file="./model_bez_kenmerk.inc"-->
<%
function model_visitors()
{
@@ -38,7 +41,7 @@ function model_visitors()
this.includes= {
"custom_fields" : {
"model": new model_custom_fields(this, "BEZ", { readman: true, readuse: true }),
"model": new model_custom_fields(this, new model_bez_kenmerk(), { readman: true, readuse: true }),
"joinfield": "flexparentkey",
"enable_update": true
}

View File

@@ -383,6 +383,21 @@ function oneFileInfo(fsoFile, result, pModule, pKey, pSubpath, pNiveau, params)
size: fsoFile.Size,
digest: oCrypto.hex_sha1_file(result.AttachPath + fName)
}
if (params.getFileEncoded == "base64" || params.getFileEncoded == "hex")
{
var oStream = Server.CreateObject("ADODB.Stream");
oStream.Open;
oStream.Type = 1; // adTypeBinary
oStream.LoadFromFile(result.AttachPath + fName);
var oXML = new ActiveXObject("Msxml2.DOMDocument.6.0");
var oNode = oXML.createElement("encodeddata");
oNode.dataType = params.getFileEncoded == "base64"?"bin.base64":"bin.hex"; // Zeer snelle oplossing
oNode.nodeTypedValue = oStream.read(oStream.Size);
filedata.data = oNode.text;
oStream.Close();
}
// IIS 7+ geeft 404.11 op een plus-teken in een url. Historisch hebben we daar
// vele bestanden mee en die hernoemen we hier on-the-fly. Er kan nu een
// afwijking ontstaan bij 'F' kenmerken. die in de database zijn opgeslagen

View File

@@ -359,8 +359,7 @@ function buildTrackingUpdate(tabel, where, xfields, params)
var result = _buildFields(fields, params);
var tupels = result.tupels;
// we hebben nooit sequences bij updates?
var sql = "UPDATE "+tabel+" xx SET ";
var first=true;
var updates = [];
var i;
var trackfields = [];
for (i=0; i < tupels.length; i++)
@@ -368,18 +367,18 @@ function buildTrackingUpdate(tabel, where, xfields, params)
var tupel = tupels[i];
if (tupel.field.dbs)
{
if (!first) sql+=", ";
first = false;
sql += "xx." + tupel.field.dbs + "=" + tupel.sql;
updates.push("xx." + tupel.field.dbs + " = " + tupel.sql);
}
if (where && tupel.field.track)
trackfields.push(tupel.field.dbs);
}
var trackarray = [];
var oldjsvals = [];
if (trackfields.length)
if (updates.length && trackfields.length)
{
var sqlt = "SELECT xx." + trackfields.join(", xx.") + " FROM " + tabel + " xx WHERE " + where;
var sqlt = "SELECT xx." + trackfields.join(", xx.")
+ " FROM " + tabel + " xx"
+ " WHERE " + where;
var oRs = Oracle.Execute(sqlt);
for (i in tupels)
{
@@ -432,8 +431,12 @@ function buildTrackingUpdate(tabel, where, xfields, params)
}
oRs.Close();
}
if (!updates.length)
return null;
sql += " WHERE " + (where||"");
sql = "UPDATE " + tabel + " xx"
+ " SET " + updates.join(", ")
+ " WHERE " + (where||"");
return { sql: sql, trackarray: trackarray, oldjsvals: oldjsvals };
}