From 636a529f5fdab080d6562fd2ebecc4604c256a8a Mon Sep 17 00:00:00 2001 From: root Date: Thu, 4 May 2017 15:22:50 +0200 Subject: [PATCH 01/29] Make charts resizable --- httpsdocs/js/widget/block/Chart.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index f9df1690..545c0960 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -66,6 +66,7 @@ Ext.define('CB.widget.block.Chart', { width: '100%' ,store: this.chartDataStore ,colors: App.colors + ,resizable: true ,axes: [ { type: 'numeric' @@ -108,6 +109,7 @@ Ext.define('CB.widget.block.Chart', { width: '100%' ,store: this.chartDataStore ,colors: App.colors + ,resizable: true ,axes: [{ type: 'numeric' ,position: 'left' @@ -145,6 +147,7 @@ Ext.define('CB.widget.block.Chart', { } ,'pie': { width: '100%' + ,resizable: true ,store: this.chartDataStore ,series: [{ type: 'pie', From a32eba92ef05dbb30676ed0ab376d654723b8a62 Mon Sep 17 00:00:00 2001 From: habbes Date: Mon, 8 May 2017 11:34:00 +0200 Subject: [PATCH 02/29] Pin chart resizers so they are always visible --- httpsdocs/js/widget/block/Chart.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 545c0960..66b05f09 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -66,7 +66,10 @@ Ext.define('CB.widget.block.Chart', { width: '100%' ,store: this.chartDataStore ,colors: App.colors - ,resizable: true + ,resizable: { + pinned: true, + handles: 'all' + } ,axes: [ { type: 'numeric' @@ -109,7 +112,10 @@ Ext.define('CB.widget.block.Chart', { width: '100%' ,store: this.chartDataStore ,colors: App.colors - ,resizable: true + ,resizable: { + pinned: true, + handles: 'all' + } ,axes: [{ type: 'numeric' ,position: 'left' @@ -147,7 +153,10 @@ Ext.define('CB.widget.block.Chart', { } ,'pie': { width: '100%' - ,resizable: true + ,resizable: { + pinned: true, + handles: 'all' + } ,store: this.chartDataStore ,series: [{ type: 'pie', From 3a0c88c778d1fe63bfead22edf27e399bf000119 Mon Sep 17 00:00:00 2001 From: habbes Date: Tue, 9 May 2017 07:31:08 +0200 Subject: [PATCH 03/29] Hide pie chart labels for small sections --- httpsdocs/js/widget/block/Chart.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 66b05f09..4463049f 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -158,6 +158,7 @@ Ext.define('CB.widget.block.Chart', { handles: 'all' } ,store: this.chartDataStore + ,interactions: ['rotate'] ,series: [{ type: 'pie', donut: 0, @@ -165,7 +166,13 @@ Ext.define('CB.widget.block.Chart', { label: { field: 'shortname', display: 'outside', - calloutLine: true + calloutLine: true, + renderer: function (value, sprite, config, renderData, index) { + var angle = Math.abs(renderData.endAngle - renderData.startAngle); + console.log('value', value, 'angle', angle); + if (angle > 400) return value; + return '' ; + } }, showInLegend: true ,highlight: true @@ -264,6 +271,7 @@ Ext.define('CB.widget.block.Chart', { this.removeAll(true); var cfg = Ext.clone(this.chartConfigs[charts[0]]); + var chartClass = 'Ext.chart.Chart'; if(!Ext.isEmpty(cfg)) { // cfg.height = Math.max(cfg.store.getCount() * 25, 300); From 4ce01c6cd66d732541732b942dd027b1d397b9ed Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 11 May 2017 13:54:41 +0200 Subject: [PATCH 04/29] Add comments in pie chart renderer function --- httpsdocs/js/widget/block/Chart.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 4463049f..5b6aa6db 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -168,10 +168,19 @@ Ext.define('CB.widget.block.Chart', { display: 'outside', calloutLine: true, renderer: function (value, sprite, config, renderData, index) { + /* + * update in task_#392 + * hide labels where sections are too small to avoid labels + * overlapping and making the chart unreable + */ var angle = Math.abs(renderData.endAngle - renderData.startAngle); - console.log('value', value, 'angle', angle); - if (angle > 400) return value; - return '' ; + /* + * the threshold selected here is arbitrary and seemed to work + * well for the charts I tested with. + */ + var threshold = 400; + if (angle > threshold) return value; + return ''; } }, showInLegend: true From 1d14c71b3051efbc90028ea313f496e594579442 Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 18 May 2017 11:17:59 +0200 Subject: [PATCH 05/29] test method for updating object translations --- bin/import_objects_translations.php | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 bin/import_objects_translations.php diff --git a/bin/import_objects_translations.php b/bin/import_objects_translations.php new file mode 100644 index 00000000..d74f82f7 --- /dev/null +++ b/bin/import_objects_translations.php @@ -0,0 +1,62 @@ +#!/usr/bin/php + "পুরুষ ", + "my"=> "အမျိုးသား "]; //male +$id = 1467; + +echo "translating\n"; +updateObjectTranslations($id, $trans); + +/** + * updates language translations of the object + * with the specified id + * @param number $id + * @param array $translations associative array mapping + * language codes and the corresponding text translations + * for this object, e.g. ["en"=>"Cheeze","fr"=>"Fromage"] + */ +function updateObjectTranslations ($id, $translations) { + $obj = Objects::getCustomClassByObjectId($id); + $obj->load(); + $data = $obj->getData(); + foreach($translations as $lg=>$text) { + $data['data']['title_'.$lg] = $text; + } + $obj->update($data); +} \ No newline at end of file From 06cb4693e5fea857fbfe3937681fd011310b2adb Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 18 May 2017 11:54:36 +0200 Subject: [PATCH 06/29] Add functions to read csv file in translations import script --- bin/import_objects_translations.php | 70 ++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/bin/import_objects_translations.php b/bin/import_objects_translations.php index d74f82f7..3ffc1887 100644 --- a/bin/import_objects_translations.php +++ b/bin/import_objects_translations.php @@ -34,14 +34,24 @@ \CB\Config::setFlag('disableActivityLog', true); -// TESTING -$trans = [ - "bn"=> "পুরুষ ", - "my"=> "အမျိုးသား "]; //male -$id = 1467; +/** + * reads the speficied csv file handle + * and imports translations for each row into the DB + * for the object specified at that row + * the csv file should have column header as the first line, + * the first column should be for the object id and the remaining + * columns for the languages to translate, each language should + * be specifed by its language code in the header + * @param handle $file + */ +function importTranslationsFromFile ($file) { + $langs = parseHeader($file); + while (!feof($file)) { + $row = parseNextTranslations($file, $langs); + updateObjectTranslations($row['id'], $row['translations']); + } +} -echo "translating\n"; -updateObjectTranslations($id, $trans); /** * updates language translations of the object @@ -59,4 +69,50 @@ function updateObjectTranslations ($id, $translations) { $data['data']['title_'.$lg] = $text; } $obj->update($data); +} + +/** + * reads the next line of the specified csv + * file handle in an attempt to get the languages + * in the translation, this should be used to + * read the first line of the file, before other + * reads are done + * @param handle $file + * @return array array of language codes from the csv + * header row + */ +function parseHeader ($file) { + $header = fgetcsv($file); + $langs = array_slice($header, 1); + return $langs +} + +/** + * reads the next line of the specified csv file + * handle and maps languages to translations of + * the object at that row + * the first column of the row is considered the object + * id and the remaining columns as translations + * the number of columns should therefore be 1 + the + * size of the $langs array + * @param handle $file + * @param array $langs array of language codes + * @return array associative array with keys id and + * translations, where translations is an associative + * array mapping languages to translations for the given object id + */ +function parseNextTranslations ($file, $langs) { + $row = fgetcsv($file); + $id = $row[0]; + // clean id if it starts with # character + if($id[0] == '#') { + $id = substr($id, 1); + } + $id = (int) $id; + $values = array_slice($row, 1); + $trans = array_combine($langs, $values); + return [ + "id" => $id, + "translations" => $trans + ]; } \ No newline at end of file From 61c7095f4d4760bbbee68a8fe915eb8f98fd3c52 Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 18 May 2017 14:22:03 +0200 Subject: [PATCH 07/29] Complete objects translations import script --- bin/import_objects_translations.php | 68 +++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/bin/import_objects_translations.php b/bin/import_objects_translations.php index 3ffc1887..8bc5f445 100644 --- a/bin/import_objects_translations.php +++ b/bin/import_objects_translations.php @@ -21,6 +21,9 @@ ini_set('max_execution_time', 0); +// include cron init script +// sets up the environment and also +// the DB based on the selected core $cronPath = realpath( dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . @@ -34,6 +37,37 @@ \CB\Config::setFlag('disableActivityLog', true); +// run the script +run(); + + +/** + * runs the import script based on cmd option + */ +function run () { + $options = getopt('c:f:'); + // the `c` (core) param is already checked by the cron init script + if(!array_key_exists('f', $options)) { + printLine("Error: please specify filename"); + printUsage(); + return; + } + $filename = $options['f']; + printLine("Opening $filename..."); + $file = fopen($filename, 'r'); + if(!$file) { + printLine("Error: could not open file"); + return; + } + + printLine("Importing translations..."); + importTranslationsFromFile($file); + + fclose($file); + printLine("Done!"); +} + + /** * reads the speficied csv file handle * and imports translations for each row into the DB @@ -48,6 +82,7 @@ function importTranslationsFromFile ($file) { $langs = parseHeader($file); while (!feof($file)) { $row = parseNextTranslations($file, $langs); + if(!$row) continue; // skip empty lines updateObjectTranslations($row['id'], $row['translations']); } } @@ -63,6 +98,12 @@ function importTranslationsFromFile ($file) { */ function updateObjectTranslations ($id, $translations) { $obj = Objects::getCustomClassByObjectId($id); + if(!$obj) { + printLine("Object #".$id." not found"); + return; + } + // load data from DB first in order not to overwrite/lose + // existing data that's not part of the update $obj->load(); $data = $obj->getData(); foreach($translations as $lg=>$text) { @@ -83,8 +124,8 @@ function updateObjectTranslations ($id, $translations) { */ function parseHeader ($file) { $header = fgetcsv($file); - $langs = array_slice($header, 1); - return $langs + $langs = array_map(trim, array_slice($header, 1)); + return $langs; } /** @@ -97,12 +138,17 @@ function parseHeader ($file) { * size of the $langs array * @param handle $file * @param array $langs array of language codes - * @return array associative array with keys id and + * @return array|null associative array with keys id and * translations, where translations is an associative * array mapping languages to translations for the given object id + * returns null if the line is empty */ function parseNextTranslations ($file, $langs) { $row = fgetcsv($file); + if (empty($row)) { + // return null on empty lines + return null; + } $id = $row[0]; // clean id if it starts with # character if($id[0] == '#') { @@ -115,4 +161,20 @@ function parseNextTranslations ($file, $langs) { "id" => $id, "translations" => $trans ]; +} + +/** + * helper to echo logs + * @param string $str + */ +function printLine ($str) { + echo $str."\n"; +} + +/** + * prints usage example and instructions + */ +function printUsage () { + printLine("USAGE:"); + printLine("php import_objects_translations -c corename -f filename"); } \ No newline at end of file From 1202d0cb7418a52e53d35a30bc8f16dd3749504e Mon Sep 17 00:00:00 2001 From: habbes Date: Mon, 12 Jun 2017 13:35:58 +0200 Subject: [PATCH 08/29] Allow option to not skipping security when loading objects for field --- httpsdocs/classes/CB/Browser.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/httpsdocs/classes/CB/Browser.php b/httpsdocs/classes/CB/Browser.php index 30bbdac5..9b39f965 100644 --- a/httpsdocs/classes/CB/Browser.php +++ b/httpsdocs/classes/CB/Browser.php @@ -610,9 +610,12 @@ public function getObjectsForField($p) $search = new Search(); - // temporary: Don't use permissions for Objects fields - // it can be later reinforced per field in config - $p['skipSecurity'] = true; + + if (!isset($p['skipSecurity'])) { + // temporary: Don't use permissions for Objects fields + // it can be later reinforced per field in config + $p['skipSecurity'] = true; + } $rez = $search->query($p); $this->setCustomIcons($rez['data']); From afac58f3d376d012dcbba6fcaa8c7f823c6e5b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= Date: Fri, 16 Jun 2017 11:42:11 +0300 Subject: [PATCH 09/29] Fix undefined constant warning. --- bin/import_objects_translations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/import_objects_translations.php b/bin/import_objects_translations.php index 8bc5f445..034b088f 100644 --- a/bin/import_objects_translations.php +++ b/bin/import_objects_translations.php @@ -124,7 +124,7 @@ function updateObjectTranslations ($id, $translations) { */ function parseHeader ($file) { $header = fgetcsv($file); - $langs = array_map(trim, array_slice($header, 1)); + $langs = array_map('trim', array_slice($header, 1)); return $langs; } @@ -177,4 +177,4 @@ function printLine ($str) { function printUsage () { printLine("USAGE:"); printLine("php import_objects_translations -c corename -f filename"); -} \ No newline at end of file +} From 90b19da4fccb369ccc37696973580fa7f089284c Mon Sep 17 00:00:00 2001 From: Andres Vergara Date: Fri, 16 Jun 2017 23:50:40 +0200 Subject: [PATCH 10/29] add sys/solr_configsets/default_config/ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 04a50094..231c1c29 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ backup/ sys/solr_configsets/default_config/*.unloaded +sys/solr_configsets/default_config/ +!sys/solr_configsets/default_config/conf ssl/ From 886fa9af67113e77b5763ca62412376ee86e5fb0 Mon Sep 17 00:00:00 2001 From: Andres Vergara Date: Tue, 20 Jun 2017 01:10:02 +0200 Subject: [PATCH 11/29] add DM\Tree::getOwner method and implemented --- httpsdocs/classes/CB/DataModel/Tree.php | 29 ++++++++++++++++++++++++- httpsdocs/classes/CB/Objects/Object.php | 7 +++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/httpsdocs/classes/CB/DataModel/Tree.php b/httpsdocs/classes/CB/DataModel/Tree.php index 9077a26c..7e0ea9e2 100644 --- a/httpsdocs/classes/CB/DataModel/Tree.php +++ b/httpsdocs/classes/CB/DataModel/Tree.php @@ -214,7 +214,7 @@ public static function getCaseId($id) } /** - * Update owner for ginev ids + * Update owner for given ids * @param int $ids * @param int $ownerId * @return void @@ -239,6 +239,33 @@ public static function updateOwner($ids, $ownerId) } } + /** + * Get owner for given id + * @param int $id + * @return int + */ + public static function getOwner($id) + { + $rez = null; + + $res = DB\dbQuery( + 'SELECT oid + FROM tree + WHERE id = $1', + array( + $id + ) + ); + + if ($r = $res->fetch_assoc()) + $rez = $r['oid']; + + $res->close(); + // var_dump($rez); + + return $rez; + } + public static function getRootId() { $rez = null; diff --git a/httpsdocs/classes/CB/Objects/Object.php b/httpsdocs/classes/CB/Objects/Object.php index 83d62ae1..e12eed60 100644 --- a/httpsdocs/classes/CB/Objects/Object.php +++ b/httpsdocs/classes/CB/Objects/Object.php @@ -195,7 +195,12 @@ protected function collectModelData() $p['cid'] = User::getId(); } if (empty($p['oid'])) { - $p['oid'] = $p['cid']; + $oid = DM\Tree::getOwner($p['id']); + + if (empty($oid)) + $p['oid'] = $p['cid']; + else + $p['oid'] = $oid; } if (empty($p['cdate'])) { From 3dd42337fef9202867473b3991c2a9e63ec7386d Mon Sep 17 00:00:00 2001 From: habbes Date: Tue, 27 Jun 2017 11:21:52 +0200 Subject: [PATCH 12/29] Do not truncate tooltips on charts --- httpsdocs/js/widget/block/Chart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 5b6aa6db..da401688 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -55,7 +55,7 @@ Ext.define('CB.widget.block.Chart', { trackMouse: true ,style: 'background: #FFF; overflow: visible' ,height: 20 - ,width: 200 + ,width: 'auto' ,renderer: function(storeItem, item) { this.setTitle(storeItem.get('name') + ': ' + storeItem.get('count')); } From 65bf0e710504fb9b17c65607c97a82673066be39 Mon Sep 17 00:00:00 2001 From: Eric Wamugu Date: Wed, 5 Jul 2017 12:43:40 +0300 Subject: [PATCH 13/29] Add export feature for charts as a PNG image --- httpsdocs/js/widget/block/Chart.js | 12 ++++++++++++ logs/.gitignore | 0 2 files changed, 12 insertions(+) mode change 100644 => 100755 logs/.gitignore diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index da401688..909dce15 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -27,6 +27,18 @@ Ext.define('CB.widget.block.Chart', { scope: this ,afterrender: this.onAfterRender } + ,dockedItems: [{ + xtype: 'toolbar', + items: [{ + xtype: 'button', + text: 'Download Chart as PNG Image', + handler: function(btn, e, eOpts) { + btn.up('CBWidgetBlockChart').down("chart").save({ + type: "image/png" + }) + } + }] + }] }); this.callParent(arguments); diff --git a/logs/.gitignore b/logs/.gitignore old mode 100644 new mode 100755 From 4e0cf4357d643c6c5928af0845eb9d03a03c3f94 Mon Sep 17 00:00:00 2001 From: Eric Wamugu Date: Wed, 5 Jul 2017 12:51:57 +0300 Subject: [PATCH 14/29] Add export feature for charts to a PNG image --- httpsdocs/js/widget/block/Chart.js | 1 - 1 file changed, 1 deletion(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 909dce15..2a6ff97d 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -22,7 +22,6 @@ Ext.define('CB.widget.block.Chart', { type: 'vbox' ,pack: 'top' } - ,listeners: { scope: this ,afterrender: this.onAfterRender From 38b1dd2608db95c0f251d4155709d3200a3bdfe8 Mon Sep 17 00:00:00 2001 From: Eric Wamugu Date: Wed, 5 Jul 2017 13:02:27 +0300 Subject: [PATCH 15/29] Fix for PHP 7 in how it resolves variables strictly from left to right --- httpsdocs/classes/CB/Browser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpsdocs/classes/CB/Browser.php b/httpsdocs/classes/CB/Browser.php index 9b39f965..43f5cf0f 100644 --- a/httpsdocs/classes/CB/Browser.php +++ b/httpsdocs/classes/CB/Browser.php @@ -393,7 +393,7 @@ public function getObjectsForField($p) if (!empty($fieldConfig['source']['fn'])) { $method = explode('.', $fieldConfig['source']['fn']); $class = new $method[0](); - $rez = $class->$method[1]($p); + $rez = $class->{$method[1]}($p); // if custom source returned any result then return it right there // otherwise custom source can add some filtering params and we go further processing @@ -610,7 +610,7 @@ public function getObjectsForField($p) $search = new Search(); - + if (!isset($p['skipSecurity'])) { // temporary: Don't use permissions for Objects fields // it can be later reinforced per field in config From b98219cedb4076fe9f697907afff8d5a40bc3e1d Mon Sep 17 00:00:00 2001 From: Andres Vergara Date: Thu, 6 Jul 2017 09:19:54 +0200 Subject: [PATCH 16/29] add int option in switch sentence --- httpsdocs/js/app.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/httpsdocs/js/app.js b/httpsdocs/js/app.js index 9426fe9e..a0ad76ad 100644 --- a/httpsdocs/js/app.js +++ b/httpsdocs/js/app.js @@ -981,6 +981,26 @@ function initApp() { } break; + case 'int': + ed = new Ext.form.Int({ + data: objData + + ,plugins: [{ + ptype: 'CBPluginFieldDropDownList' + ,commands: [ + { + prefix: ' ' + ,regex: /^([\w\d_\.]+)/i + + ,insertField: 'info' + + ,handler: CB.plugin.field.DropDownList.prototype.onAtCommand + } + ] + }] + }); + break; + case 'text': ed = new Ext.form.Text({ data: objData From 46fbbd88c93e8cd00824d2295ad26448fabe922b Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 6 Jul 2017 13:46:28 +0200 Subject: [PATCH 17/29] Create script to update object field names --- bin/update_fields.php | 173 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 bin/update_fields.php diff --git a/bin/update_fields.php b/bin/update_fields.php new file mode 100644 index 00000000..8e02e799 --- /dev/null +++ b/bin/update_fields.php @@ -0,0 +1,173 @@ +#!/usr/bin/php +updateObjects(); + println('Done'); +} + + +class FieldUpdater { + + private $templateId; + private $fields; + + function __construct ($fs, $ts=null) { + $this->templateIds = $ts; + $this->fields = $fs; + } + + private function fetchObjectIds () { + $q = $this->buildQuery(); + return DB\dbQuery($q); + } + + private function buildQuery () { + $q = "SELECT o.id + FROM objects o"; + if (!empty($this->templateIds)) { + $ids = implode(',', $this->templateIds); + $q .= " JOIN tree t on o.id=t.id AND t.template_id in (".$ids.")"; + } + return $q; + } + + public function updateObjects () { + $res = $this->fetchObjectIds(); + while ($row = $res->fetch_assoc()) { + $this->updateObject($row['id']); + } + } + + public function updateObject ($id) { + $o = Objects::getCustomClassById($id); + $o->load(); + $data = $o->getData(); + foreach ($this->fields as $old=>$new) { + if (isset($data['data'][$old])) { + $data['data'][$new] = $data[$old]; + unset($data['data'][$old]); + } + } + $o->update($data); + } +} + +/** + * parses the templates string arg and returns + * an array of template ids + * @param string $t comma separated list of template + * ids: id1,id2,id3 + * @return array + */ +function parseTemplates ($t) { + return explode(',', $t); +} + +/** + * parses the fields string arg and returns + * an array mapping old fields to new fields + * @param string $f string-encoded list old to new fields + * mapping in the form oldName1:newName1,oldName2:newName2 + * @return array associative array mapping old field names + * to new names + */ +function parseFields ($f) { + $pairs = explode(',', $f); + return array_reduce($pairs, function($res, $item) { + $oldNew = explode(':', $item); + $res[$oldNew[0]] = $oldNew[1]; + return $res; + }, []); +} + +function printUsage() { + println('php update_fields.php -c -f -t '); + println('Options:'); + println('-c : the Casebox core name without the cb_ prefix'); + println('-f : list of fields to updated in the form oldName1:newName1,oldName2:newName2'); + println('-t (optional): comma-separated list of template ids'); + println('Note: If option -t is provided, only objects from those templates will be updated,' + .' otherwise ALL objects will be updated.'); + println(); + println("Example:"); + println("php update_fields.php -c demo -f age:victim_age,sex:gender -t 3849,1234"); +} + +function println ($s='') { + echo "$s\n"; +} From 8fcb8c4e7f61dc8c897e05c228d601992725bb11 Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 6 Jul 2017 13:54:14 +0200 Subject: [PATCH 18/29] Add comments to update_fields script --- bin/update_fields.php | 64 ++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/bin/update_fields.php b/bin/update_fields.php index 8e02e799..97b539d0 100644 --- a/bin/update_fields.php +++ b/bin/update_fields.php @@ -22,6 +22,8 @@ php update_fields.php -c mycore -t 1123,230 -f age:victim_age,sex:gender php update_fields.php -c mycore -f name:first_name + + After running this script, you should update the solr prepared date and reindex the solr core. */ @@ -78,34 +80,29 @@ function run () { // $updater = new FieldUpdater($fs, $ts); // $updater->updateObjects(); println('Done'); + println("Now update solr prepared data and reindex the solr core"); } class FieldUpdater { - private $templateId; + private $templateIds; private $fields; + /** + * @param array $fs mapping of old field names to new names + * @param array $ts list of template ids + */ function __construct ($fs, $ts=null) { $this->templateIds = $ts; $this->fields = $fs; } - private function fetchObjectIds () { - $q = $this->buildQuery(); - return DB\dbQuery($q); - } - - private function buildQuery () { - $q = "SELECT o.id - FROM objects o"; - if (!empty($this->templateIds)) { - $ids = implode(',', $this->templateIds); - $q .= " JOIN tree t on o.id=t.id AND t.template_id in (".$ids.")"; - } - return $q; - } - + /** + * Fetches and updates objects + * based on the set template ids and field + * names to udpate + */ public function updateObjects () { $res = $this->fetchObjectIds(); while ($row = $res->fetch_assoc()) { @@ -113,6 +110,10 @@ public function updateObjects () { } } + /** + * update the object with the specified id + * @param mixed $id + */ public function updateObject ($id) { $o = Objects::getCustomClassById($id); $o->load(); @@ -125,6 +126,30 @@ public function updateObject ($id) { } $o->update($data); } + + /** + * fetch object ids from the db + * @return resource the db cursor + */ + private function fetchObjectIds () { + $q = $this->buildQuery(); + return DB\dbQuery($q); + } + + /** + * builds sql query to use for fetching + * objects based on the specified templates + * @return string + */ + private function buildQuery () { + $q = "SELECT o.id + FROM objects o"; + if (!empty($this->templateIds)) { + $ids = implode(',', $this->templateIds); + $q .= " JOIN tree t on o.id=t.id AND t.template_id in (".$ids.")"; + } + return $q; + } } /** @@ -155,6 +180,9 @@ function parseFields ($f) { }, []); } +/** + * prints helpful usage info + */ function printUsage() { println('php update_fields.php -c -f -t '); println('Options:'); @@ -168,6 +196,10 @@ function printUsage() { println("php update_fields.php -c demo -f age:victim_age,sex:gender -t 3849,1234"); } +/** + * ouputs the specified string followed by a new line + * @param string $s + */ function println ($s='') { echo "$s\n"; } From 75c30f4477e1847f3204b2006a2bfac1e8028dce Mon Sep 17 00:00:00 2001 From: habbes Date: Thu, 6 Jul 2017 13:55:55 +0200 Subject: [PATCH 19/29] Enable object fields update code --- bin/update_fields.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/update_fields.php b/bin/update_fields.php index 97b539d0..55d556b1 100644 --- a/bin/update_fields.php +++ b/bin/update_fields.php @@ -1,6 +1,6 @@ #!/usr/bin/php updateObjects(); + $updater = new FieldUpdater($fs, $ts); + $updater->updateObjects(); println('Done'); println("Now update solr prepared data and reindex the solr core"); } From 3c7d16add4f882309b53eae45231b6a6fa48d59f Mon Sep 17 00:00:00 2001 From: Andres Vergara Date: Thu, 6 Jul 2017 17:39:37 +0200 Subject: [PATCH 20/29] fix git ignore [ssl] folder --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 231c1c29..4e28ce48 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ sys/solr_configsets/default_config/*.unloaded sys/solr_configsets/default_config/ !sys/solr_configsets/default_config/conf -ssl/ +\[ssl\]/ # ignore custom import scripts install/import/ From cf72d4adbdd2f00dbd4fa31434c1bb052cdf2631 Mon Sep 17 00:00:00 2001 From: Andres Vergara Date: Thu, 6 Jul 2017 17:50:22 +0200 Subject: [PATCH 21/29] display error in DB settings on installation script --- httpsdocs/lib/install_functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpsdocs/lib/install_functions.php b/httpsdocs/lib/install_functions.php index e5db7ff1..b0e4607c 100644 --- a/httpsdocs/lib/install_functions.php +++ b/httpsdocs/lib/install_functions.php @@ -407,7 +407,7 @@ function verifyDBConfig(&$cfg) $success = true; try { - @new \mysqli( + new \mysqli( $cfg['db_host'], $cfg['su_db_user'], (isset($cfg['su_db_pass']) ? $cfg['su_db_pass'] : null), From 697df163dfc147f02fcce4ee6c36edf0dad84116 Mon Sep 17 00:00:00 2001 From: habbes Date: Fri, 7 Jul 2017 11:00:37 +0200 Subject: [PATCH 22/29] Fix bugs in update_fields script --- bin/update_fields.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/update_fields.php b/bin/update_fields.php index 55d556b1..426a0259 100644 --- a/bin/update_fields.php +++ b/bin/update_fields.php @@ -50,9 +50,9 @@ run(); function run () { - $opts = getopt('c:f:t:h', ['help']); + $opts = getopt('c:f:t:h'); var_dump($opts); - if (isset($opts['h']) || isset($opts['help'])) { + if (isset($opts['h'])) { printUsage(); return; } @@ -113,12 +113,12 @@ public function updateObjects () { * @param mixed $id */ public function updateObject ($id) { - $o = Objects::getCustomClassById($id); + $o = Objects::getCustomClassByObjectId($id); $o->load(); $data = $o->getData(); foreach ($this->fields as $old=>$new) { - if (isset($data['data'][$old])) { - $data['data'][$new] = $data[$old]; + if (array_key_exists($old, $data['data'])) { + $data['data'][$new] = $data['data'][$old]; unset($data['data'][$old]); } } From af61135cc1172a0cc4ae51a98d60557c030c931f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faber=20Andr=C3=A9s=20Vergara=20Holgu=C3=ADn?= Date: Fri, 7 Jul 2017 07:01:08 -0500 Subject: [PATCH 23/29] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4e28ce48..30b18a91 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ sys/solr_configsets/default_config/*.unloaded sys/solr_configsets/default_config/ !sys/solr_configsets/default_config/conf +ssl/ \[ssl\]/ # ignore custom import scripts From 980d3c0339843bacc768e664c38394772976ae01 Mon Sep 17 00:00:00 2001 From: habbes Date: Mon, 10 Jul 2017 09:30:33 +0200 Subject: [PATCH 24/29] Fix errors in update_fields script --- bin/update_fields.php | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/bin/update_fields.php b/bin/update_fields.php index 426a0259..0ee653d4 100644 --- a/bin/update_fields.php +++ b/bin/update_fields.php @@ -104,7 +104,7 @@ function __construct ($fs, $ts=null) { public function updateObjects () { $res = $this->fetchObjectIds(); while ($row = $res->fetch_assoc()) { - $this->updateObject($row['id']); + $this->updateObject($row); } } @@ -112,17 +112,15 @@ public function updateObjects () { * update the object with the specified id * @param mixed $id */ - public function updateObject ($id) { - $o = Objects::getCustomClassByObjectId($id); - $o->load(); - $data = $o->getData(); + public function updateObject ($row) { + $data = json_decode($row['data'], true); foreach ($this->fields as $old=>$new) { - if (array_key_exists($old, $data['data'])) { - $data['data'][$new] = $data['data'][$old]; - unset($data['data'][$old]); + if (array_key_exists($old, $data)) { + $data[$new] = $data[$old]; + unset($data[$old]); } } - $o->update($data); + $this->saveToDb($row['id'], $data); } /** @@ -140,7 +138,7 @@ private function fetchObjectIds () { * @return string */ private function buildQuery () { - $q = "SELECT o.id + $q = "SELECT o.id, o.data FROM objects o"; if (!empty($this->templateIds)) { $ids = implode(',', $this->templateIds); @@ -148,6 +146,18 @@ private function buildQuery () { } return $q; } + + /** + * persists object data in db + * @param mixed $id id of the object to update + * @param array $data + */ + private function saveToDb ($id, $data) { + $data = json_encode($data); + $q = "UPDATE objects SET data=$2 + WHERE id=$1"; + DB\dbQuery($q, [$id, $data]); + } } /** From 099bac62243bdaab1735c607bf436b54432ea24e Mon Sep 17 00:00:00 2001 From: habbes Date: Mon, 10 Jul 2017 12:13:32 +0200 Subject: [PATCH 25/29] Update debug statements for update_fields.php script --- bin/update_fields.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/update_fields.php b/bin/update_fields.php index 0ee653d4..82f4e007 100644 --- a/bin/update_fields.php +++ b/bin/update_fields.php @@ -51,7 +51,6 @@ function run () { $opts = getopt('c:f:t:h'); - var_dump($opts); if (isset($opts['h'])) { printUsage(); return; @@ -110,10 +109,14 @@ public function updateObjects () { /** * update the object with the specified id - * @param mixed $id + * @param array $row db row with id and data fields */ public function updateObject ($row) { $data = json_decode($row['data'], true); + if (empty($data)) { + println("Empty data for object ".$row['id']); + return; + } foreach ($this->fields as $old=>$new) { if (array_key_exists($old, $data)) { $data[$new] = $data[$old]; From cf92685daaf1645317661c962be24cf7e54e02b3 Mon Sep 17 00:00:00 2001 From: habbes Date: Mon, 10 Jul 2017 13:26:48 +0200 Subject: [PATCH 26/29] Use different colors for bars in bar and column charts --- httpsdocs/js/widget/block/Chart.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/httpsdocs/js/widget/block/Chart.js b/httpsdocs/js/widget/block/Chart.js index 2a6ff97d..62071beb 100644 --- a/httpsdocs/js/widget/block/Chart.js +++ b/httpsdocs/js/widget/block/Chart.js @@ -70,7 +70,7 @@ Ext.define('CB.widget.block.Chart', { ,renderer: function(storeItem, item) { this.setTitle(storeItem.get('name') + ': ' + storeItem.get('count')); } - }; + };console.log('colors', App.colors); this.chartConfigs = { 'bar': { @@ -117,6 +117,12 @@ Ext.define('CB.widget.block.Chart', { scope: this ,itemclick: this.onChartItemClick } + ,renderer: function (sprite, record, attr, index, store) { + var colorChoice = index % App.colors.length; + return Ext.apply(attr, { + fill: App.colors[colorChoice] + }); + } }] } ,'column': { @@ -160,6 +166,12 @@ Ext.define('CB.widget.block.Chart', { scope: this ,itemclick: this.onChartItemClick } + ,renderer: function (sprite, record, attr, index, store) { + var colorChoice = index % App.colors.length; + return Ext.apply(attr, { + fill: App.colors[colorChoice] + }); + } }] } ,'pie': { From 4cb34b6f9d168441b6fbbc0298ce09257be8fa34 Mon Sep 17 00:00:00 2001 From: Bert Verstappen Date: Mon, 6 Nov 2017 12:50:00 +0100 Subject: [PATCH 27/29] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e3b9fbb7..ab9763f7 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,9 @@ Casebox Casebox is a Content Management Platform for record, file and task management. -Full documentation can be found on the website: -http://docs.casebox.org/en/latest/ +Casebox was developed jointly by HURIDOCS and KETSE.com. -Made at Ketse & HURIDOCS -------------------------- - -Casebox is being developed by [Ketse](https://www.ketse.com/) & [HURIDOCS](https://www.huridocs.org/). +Starting in 2017, HURIDOCS manages its own version of the Casebox codebase for human rights organisations and KETSE.com continues to support the original code. If your request is not related to human rights work and you are not a non-profit, then please contact Ketse at info@ketse.com for more information on the commercial services they can provide. Code status From e4f99cc95fd6de537a05d723872e4a720ca07788 Mon Sep 17 00:00:00 2001 From: Bert Verstappen Date: Mon, 6 Nov 2017 13:53:14 +0100 Subject: [PATCH 28/29] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab9763f7..656d4e91 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,11 @@ Casebox is a Content Management Platform for record, file and task management. Casebox was developed jointly by HURIDOCS and KETSE.com. -Starting in 2017, HURIDOCS manages its own version of the Casebox codebase for human rights organisations and KETSE.com continues to support the original code. If your request is not related to human rights work and you are not a non-profit, then please contact Ketse at info@ketse.com for more information on the commercial services they can provide. +Starting in 2017, HURIDOCS manages its own version of the Casebox codebase for human rights organisations and KETSE.com continues to support the original code. + +If you are working with a human rights organisation, contact casebox at huridocs.org + +If your request is not related to human rights work and you are not a non-profit, then please contact Ketse at info at ketse.com for more information on the commercial services they can provide. Code status From 596ef38c5b8d3a69372a887d560f8a1bf7ec46ef Mon Sep 17 00:00:00 2001 From: Eric Wamugu Date: Thu, 30 Aug 2018 10:17:08 +0000 Subject: [PATCH 29/29] fix typo on invite email and add extra details of the person invited --- install/mysql/_casebox.sql | 2 +- sys/templates/email_invite.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/mysql/_casebox.sql b/install/mysql/_casebox.sql index e91c25f1..cc0806e9 100644 --- a/install/mysql/_casebox.sql +++ b/install/mysql/_casebox.sql @@ -60870,7 +60870,7 @@ insert into `translations`(`id`,`pid`,`name`,`en`,`es`,`ge`,`fr`,`hy`,`pt`,`ro` (3089,NULL,'ErrorCreatingPreview','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file','Preview not available at this moment, please download the file',1,NULL,0), -(3090,NULL,'MailInviteSubject','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) ivited you to {projectTitle}',1,NULL,0), +(3090,NULL,'MailInviteSubject','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}','[Casebox] {creatorFullName} ({creatorEmail}) invited you {username} ({userEmail}) to {projectTitle}',1,NULL,0), (3091,NULL,'FollowText','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email','Follow get notified in app & email',2,NULL,0), diff --git a/sys/templates/email_invite.html b/sys/templates/email_invite.html index bb323d7d..9a30f2e8 100644 --- a/sys/templates/email_invite.html +++ b/sys/templates/email_invite.html @@ -103,7 +103,7 @@

- {creatorFullName} ({creatorEmail}) has invited you to {projectTitle}. + {creatorFullName} ({creatorEmail}) has invited you {username} ({userEmail}) to {projectTitle}.