FSN#38299 Flexkenmerken via de API kunnen bewerken, savepoint bestanden upload/downloaden
svn path=/Website/trunk/; revision=33229
This commit is contained in:
@@ -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: "" };
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user