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

Ook: fields parameter om de opgeleverde velden te beperken
Ook: .tables format om de data in een prettig leesbaar formaat te tonen

svn path=/Website/trunk/; revision=33260
This commit is contained in:
Jos Groot Lipman
2017-03-25 22:08:10 +00:00
parent 113ec00f7d
commit 9f72059a09
8 changed files with 125 additions and 32 deletions

View File

@@ -847,7 +847,7 @@ api2 = {
else if (inckey in existing_includes)
{
__Log("Nu ga ik '{0}' {1} updaten".format(incname, inckey));
incmodel.REST_PUT(params, incdata[j], inckey);
incmodel.REST_PUT(params, incdata[j], inckey, the_key);
existing_includes[inckey].found = true;
}
}
@@ -1007,6 +1007,7 @@ api2 = {
return timetable.join(";");
},
// Geef alle velden van een record terug
// ?? Alleen bij includes in gebruik ??
sql2jsonfields: function _sql2jsonfields(params, oRs, model)
{
var record = {};
@@ -1114,6 +1115,8 @@ api2 = {
var field = model.fields[fld];
if (field.hidden)
continue;
if ("fields" in params.filter && !inArray(fld, params.filter.fields.split(",")))
continue;
var val = api2.sql2jsonval(oRs, fld, model)
//waarom was dit aanwezig?

View File

@@ -264,7 +264,7 @@ api2_rest = {
var result = model["REST_" + method]( requestparams, key );
}
else if (filter.mode == "attachment" && "custom_fields" in model.includes)
{ // https://xxxx.facilitor.nl/trunk/api2/visitors/99685/attachments/1040/testfile.jpg"
{ // GET/PUT/POST 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
@@ -385,7 +385,7 @@ api2_rest = {
Response.End;
}
if (format == "html" || format == "json")
if (format == "html" || format == "json" || format == "table")
{
var result = { };
if (single)
@@ -500,6 +500,20 @@ api2_rest = {
+ Server.HTMLEncode(antwoord)
+ "</pre></body></html>";
break;
case "table":
Response.ContentType = "text/html";
var antwoord = api2_rest.json2htmltable(resultdata[model.records_name], model);
var str_antwoord = "<!DOCTYPE html>"
+ "<html>"
+ "<head>"
+ " <title>{0}</title>".format(single?model.record_name:model.records_name)
+ " <link rel=stylesheet type='text/css' href='../appl/api2/table.css'>"
+ "</head>"
+ "<body>"
+ antwoord
+ "</body>"
+ "</html>";
break;
case "xml":
Response.ContentType = "text/xml";
var xml_antwoord = api2_rest.json2xml(data, model, single);
@@ -551,6 +565,46 @@ api2_rest = {
Response.write(str_antwoord);
},
json2htmltable: function _json2htmltable(data, model, single)
{
var trs = [];
if (data.length) // Header maken
{
var tds = [];
for (var fld in data[0])
tds.push(fld);
trs.push("<th>" + tds.join("</th><th>") + "</th>");
}
for (var i = 0; i < data.length; i++)
{
var rec = data[i];
var tds = [];
for (var fld in rec)
{
var val = rec[fld];
var safeval = Server.HTMLEncode(String(val));
if (val === null)
safeval = '&nbsp;';
if (typeof val == 'object' && val instanceof Date)
safeval = toISODateTimeString(val);
if (val && typeof val == "object" && "id" in val)
{ // dereference
var naam = val.name||"???";
if (typeof naam == 'object' && naam instanceof Date) // Bij appointment
naam = toISODateTimeString(naam);
safeval = val.id + " (" + Server.HTMLEncode(naam) + ")";
}
else if (val && typeof val == "object" && model.includes && fld in model.includes)
{ // dereference
safeval = api2_rest.json2htmltable(val, model.includes[fld].model, single)
}
tds.push(safeval);
}
trs.push("<td>" + tds.join("</td><td>") + "</td>");
}
return "\n<table border='1'>\n<tr>" + trs.join("</tr>\n<tr>") + "</tr></table>";
},
// TODO: Wanneer attributes gebruiken en wanneer (sub)-elements?
// Streven: data == xml2json(json2xml(data))
json2xml: function _json2xml(data, model, single)

View File

@@ -71,7 +71,7 @@ function model_appointments()
this.list = { columns: ["id", "from", "to"] },
this.includes =
{"visitors": { model: model_visitors,
{"visitors": { model: new model_visitors(),
joinfield: "appointment",
enable_update: true
},

View File

@@ -48,6 +48,7 @@ function model_custom_fields(formodel, flexModule, flexParams)
this.fields = {
// De echte unieke waarde "id" is bez_kenmerkwaarde_key.
// We doen echter alles op basis van de samengestelde kenmerk_key + parent_key
// De naam van dat veld weten we hier even niet echter
// en hebben we ook niet nodig
"propertyid": {
@@ -118,6 +119,11 @@ function model_custom_fields(formodel, flexModule, flexParams)
}
delete record["xflexparentkey"]; // nu niet meer nodig
}
// Voor flexbijlagen kennen we een duale interface
// Enerzijds zitten ze gewoon als attachements-object in de JSON
// die een GET van custom_fields oplevert
// Anderzijds zijn ze met GET/PUT/POST/DELETE rechtstreeks te benaderen onder
// /api2/visitors/1234/attachments/1000/test.jpg
this.streamattachment = function(filter, flexfields)
{
for (var fid in flexfields)
@@ -150,26 +156,15 @@ function model_custom_fields(formodel, flexModule, flexParams)
Response.Status = "404 Not Found";
}
this.REST_PUT = function (params, jsondata, the_key) /* update custom_field */
{debugger;
var sql = "BEGIN flx.setflex({0}".format(safe.quoted_sql(this.module))
+ " , {0}".format(jsondata.propertyid)
+ " , {0}".format(params.filter.id)
+ " , {0}".format(safe.quoted_sql(flexParams.niveau))
+ " , {0});".format(safe.quoted_sql(jsondata.value))
+ "END;"
Oracle.Execute(sql);
}
this.REST_POST = function (params, jsondata, parent_key) /* add custom_field */
{
this.REST_PUT = function (params, jsondata, the_key, parent_key) /* update custom_field */
{ // Let op: parameter the_key is de kenmerk_key, niet een een kenmerkwaarde_key
// 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);
{
var flexparams = flexProps(this.module, params.filter.id, the_key, flexParams.pNiveau);
// TODO: bij type F zorgen dat er <20><>n file overblijft
for (var i = 0; i < jsondata.attachments.length; i++)
{
@@ -178,9 +173,17 @@ function model_custom_fields(formodel, flexModule, flexParams)
if (flexparams.isAllowedName(safefilename))
{
CreateFullPath(flexparams.AttachPath);
if ("datastream" in attachment)
if ("datastream" in attachment) // PUT op /api2/visitors/1234/attachments/1000/test.jpg
{
attachment.datastream.SaveToFile(flexparams.AttachPath + safefilename, 2); // adSaveCreateOverWrite
// TODO: content_base64 en content_hex encoding ondersteunen
}
else if ("content_base64" in attachment || "content_hex" in attachment)
{
var fileencoding = "content_base64" in attachment?"bin.base64":"bin.hex";
encodedString2File(flexparams.AttachPath + safefilename,
attachment.content_base64 || attachment.content_hex,
fileencoding);
}
}
else
{
@@ -190,20 +193,30 @@ function model_custom_fields(formodel, flexModule, flexParams)
}
}
if (typ != "M")
{
var sql = "BEGIN flx.setflex({0}".format(safe.quoted_sql(this.module))
+ " , {0}".format(jsondata.propertyid)
+ " , {0}".format(parent_key)
+ " , {0}".format(the_key) // == jsondata.propertyid
+ " , {0}".format(params.filter.id)
+ " , {0}".format(safe.quoted_sql(flexParams.niveau))
+ " , {0});".format(safe.quoted_sql(jsondata.value))
+ "END;"
Oracle.Execute(sql);
}
}
this.REST_POST = function (params, jsondata, parent_key) /* add custom_field */
{ // Voor flexvelden is er geen verschil tusen 'toevoegen' en 'bijwerken'
this.REST_PUT(params, jsondata, jsondata.propertyid, parent_key);
}
this.REST_DELETE = function (params, the_key) /* remove custom_field */
{
// 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
// TODO: flexfiles wel deleten
}
this.list = { columns: ["id", "label", "value"] }

View File

@@ -100,7 +100,9 @@ function model_visitors()
var sql = "SELECT " + query.selects.join(", ")
+ " FROM " + query.tables.join(", ")
+ " WHERE " + query.wheres.join(" AND " )
+ " ORDER BY bez_afspraak_datum, bez_afspraak.bez_afspraak_key";
+ " ORDER BY bez_afspraak.bez_afspraak_key, bez_bezoekers.bez_bezoekers_key";
if (query.orderbys.length)
sql += ", " + query.orderbys.join(", ");
var json = api2.sql2json (params, sql, this );

19
APPL/API2/table.css Normal file
View File

@@ -0,0 +1,19 @@
table {
color: #333; /* Lighten up font color */
font-family: Verdana; /* Nicer font */
font-size: smaller;
border-collapse:
collapse; border-spacing: 0;
}
td, th { border: 1px solid #CCC; height: 1.3em; } /* Make cells a bit taller */
th {
background: #F3F3F3; /* Light grey background */
font-weight: bold; /* Make sure they're bold */
}
td {
background: #FAFAFA; /* Lighter grey background */
text-align: center; /* Center our text */
}

View File

@@ -21,12 +21,12 @@
</rule>
<!-- /api2/buildings/1234.xml?... /default.asp?api2=buildings&format=xml&id=1234&... -->
<rule name="api2SingleRecord" stopProcessing="true">
<match url="^api2/([a-z0-9_]+)/(\d+)\.(xml|json|html|api|doc)/?" />
<match url="^api2/([a-z0-9_]+)/(\d+)\.(xml|json|html|api|doc|table)/?" />
<action type="Rewrite" url="default.asp?api2={R:1}&amp;format={R:3}&amp;id={R:2}" appendQueryString="true" />
</rule>
<!-- /api2/buildings.xml?... /default.asp?api2=buildings&format=xml&... -->
<rule name="api2List" stopProcessing="true">
<match url="^api2/([a-z0-9_]+)\.(xml|json|html|api|doc)/?" />
<match url="^api2/([a-z0-9_]+)\.(xml|json|html|api|doc|table)/?" />
<action type="Rewrite" url="default.asp?api2={R:1}&amp;format={R:2}" appendQueryString="true" />
</rule>
<!-- 2015.1 experimenteel: -->

View File

@@ -385,6 +385,8 @@ function oneFileInfo(fsoFile, result, pModule, pKey, pSubpath, pNiveau, params)
}
if (params.getFileEncoded == "base64" || params.getFileEncoded == "hex")
{
// Verleidelijk om new ActiveXObject("SLNKDWF.Crypto").base64 in te zetten
// Die kan echter alleen text-input aan, niet binary data
var oStream = Server.CreateObject("ADODB.Stream");
oStream.Open;
oStream.Type = 1; // adTypeBinary
@@ -394,7 +396,7 @@ function oneFileInfo(fsoFile, result, pModule, pKey, pSubpath, pNiveau, params)
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;
filedata.data = oNode.text.replace(/\n/g, ""); // Ik wil de newlines er niet in hebben
oStream.Close();
}