<% /* $Revision$ $Id$ File: model_custom_fields.inc Description: Flexkenmerken model Context: Er is géén eigen api_custom_fields We kunnen alleen via een include van een parent die dan ook vooral alle autorisatiecontrole voor ons kan verzorgen Notes: Voor de GET gebruiken we getSqlFlex uit resultset_flex Lekker gemakkelijk hoewel hij niet 100% de volgnummer beperkingen volgt Voor de PUT/POST/DELETE gebruiken we de functies van PACKAGE flx */ %> <% function model_custom_fields(formodel, flexModule, flexParams) { var flexModel = null; // alleen nog niet bij issues if (typeof flexModule != "string") { flexModel = flexModule; flexModule = flexModel.module; } flexParams = flexParams || {}; this.module = flexModule; this.records_name = "custom_fields"; this.record_name = "custom_field"; this.table = "flex"; this.primary = "kenmerk_key"; this.records_title = L("custom_field_m"); this.record_title = L("custom_field"); this.keyfield = "propertyid"; // api2/process_includes werkt nu iets anders // getSqlFlex heeft bij multi-language 'user' al nodig voor de lcl's // daarom hieronder een indirecte/ delayed fntablesql this.fntablesql = function _fntablesql() { var theSqlFlex = getSqlFlex(flexModule, formodel.primary, flexParams); return "(" + theSqlFlex + ") flex"; } 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": { "dbs": "kenmerk_key", "label": L("lcl_key"), "typ": "key" }, "value": { "dbs": "waarde", "label": L("lcl_fac_value"), "typ": "varchar" }, "type": { "dbs": "kenmerktype", "label": L("mgt_srtkenmerk_kenmerktype"), "typ": "varchar" }, "sequence": { "dbs": "volgnummer", "label": L("mgt_kenmerk_volgnummer"), "typ": "number" }, "label": { "dbs": "omschrijving", "label": L("mgt_srtkenmerk_label"), "typ": "varchar" }, "flexparentkey": { "dbs": "flexparentkey", "typ": "key" }, // TODO: record.flexparentid wordt er uitgestript vanwege niet teruglinken naar de parent // we hebben hem echter wel nodig. Dit moet beter.... "xflexparentkey": { "dbs": "flexparentkey", "typ": "key", "sql": "flexparentkey" } }; // 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 (params, record) { if (record.type == 'F' || record.type == 'M') { var flexparam = flexProps(flexModule, record.xflexparentkey, String(record.propertyid), flexParams.pNiveau, { getFiles: true, getFileEncoded: params.filter.fileencoding, api2name: formodel.records_name }); record.attachments = []; for (var f in flexparam.files) { var file = flexparam.files[f]; 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 } // 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) { if (flexfields[fid].propertyid == filter.subfolder && flexfields[fid].attachments) { for (var i = 0; i < flexfields[fid].attachments.length; i++) { var att = flexfields[fid].attachments[i]; if (att.name.toLowerCase() == filter.filename.toLowerCase()) // Gevonden!!!! { 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 + '"'; Response.AddHeader("ETag", eTag); if (Request.ServerVariables("HTTP_IF_NONE_MATCH") == eTag) { // We hebben een match! Response.Clear(); Response.Status = "304 Not modified"; Response.End; } StreamFile(params.AttachPath, att.name, "application/octet-stream"); } } } } __Log(filter); Response.Status = "404 Not Found"; } if (flexModel) // nog even niet voor MLD 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') { var flexparams = flexProps(this.module, parent_key, the_key, flexParams.pNiveau); // TODO: bij type F zorgen dat er éé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) // PUT op /api2/visitors/1234/attachments/1000/test.jpg { attachment.datastream.SaveToFile(flexparams.AttachPath + safefilename, 2); // adSaveCreateOverWrite } 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 { Response.Status = "422 Unprocessable Entity"; Response.End; } } } if (typ != "M") { var sql = "BEGIN flx.setflex({0}".format(safe.quoted_sql(this.module)) + " , {0}".format(the_key) // == jsondata.propertyid + " , {0}".format(parent_key) + " , {0}".format(safe.quoted_sql(flexParams.pNiveau)) + " , {0});".format(safe.quoted_sql(jsondata.value)) + "END;" Oracle.Execute(sql); } } if (flexModel) // nog even niet voor MLD 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 kunnen deleten } this.list = { columns: ["id", "label", "value"] } // Merk op: géén eigen REST_GET // We werken toch alleen via een include van een parent die dan ook // vooral alle autorisatiecontrole voor ons kan verzorgen } function set_custom_field(jsondata, kenmerk_key, val, typ) { if (!("custom_fields" in jsondata)) jsondata.custom_fields = []; for (var i=0; i< jsondata.custom_fields.length; i++) { if (jsondata.custom_fields[i].propertyid == kenmerk_key) { jsondata.custom_fields[i].value = val; return; // direct klaar } } // JGL: is het volgende wel nodig? Opdrachten gingen via saveFlexKenmerken maar dat is achterhaald? if (!typ) abort_with_warning("Cannot set_custom_field key '{0}' without type".format(kenmerk_key)); jsondata.custom_fields.push({ propertyid: kenmerk_key, value: val, type: typ }); } function get_custom_field(jsondata, kenmerk_key) { if (!("custom_fields" in jsondata)) return null; for (var i=0; i< jsondata.custom_fields.length; i++) { if (jsondata.custom_fields[i].propertyid == kenmerk_key) { return jsondata.custom_fields[i].value; // direct klaar } } return null; } %>