icfs 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28031e9c5c67e30c2cf4778fbf56a7840117d256e4384e6e044e7cc888958d09
4
- data.tar.gz: 3abea632e084b00bd09ac570710eab52e99a152d073c6f96779a04c23dbc1c21
3
+ metadata.gz: 6ba64d02837a0591aee2cab20c11795beffa59f3ec3dce2014ac7dd0b55e89e5
4
+ data.tar.gz: 1b452562fa4df0cf870eb0ed5bbbf0f686b4ba78579e47e7ce075e84e18b1954
5
5
  SHA512:
6
- metadata.gz: cd28dc30f59e5bec1b272508d5b64ecb950a3e2b6d26d4318156069d19c338093177302ac09207a4b76b7decfa8272f84a8839f3165eeee28fdb9f15ae5c6ef3
7
- data.tar.gz: '08f19a62a3d3c21cdf46c8120bd0b5846107a57409aba71939587affed4e7daf32c4d0bd805919d884baa4d24b520521527f62e8edf66ed6f886cf2237122b27'
6
+ metadata.gz: '02909a341866abc4eb1eaa844317dd02b72ed55c59b0df518f3e54af06a024f6cb4ac2ea8f14a2b64b99e60bdd9dc2bc87ceee421ed591c498db1f0e5c4305c4'
7
+ data.tar.gz: 562c4de6f8605b2ab7b414101642488a93b98fa94157ba4408ed640b6944f8cee33ecb3f710be87570760fd7d0fc6249c2b353163173f64ea53d52624b7b91fe
data/data/icfs.css CHANGED
@@ -200,6 +200,12 @@ div.list-int {
200
200
  }
201
201
 
202
202
 
203
+ div.list-int-sm {
204
+ width: 2em;
205
+ padding: 0 0.15em 0 0.15em;
206
+ }
207
+
208
+
203
209
  div.list-perm {
204
210
  width: 15em;
205
211
  padding: 0 0.15em 0 0.15em;
@@ -238,7 +244,7 @@ div.list-text-m {
238
244
 
239
245
 
240
246
  div.list-time {
241
- width: 12em;
247
+ width: 15em;
242
248
  padding: 0 0.15em 0 0.15em;
243
249
  }
244
250
 
data/data/icfs.js CHANGED
@@ -167,6 +167,23 @@
167
167
 
168
168
  // Entry
169
169
 
170
+ ///////////////////////////////////////////////
171
+ // Enable/disable editing the entry
172
+ function entEnable(){
173
+ var ena = document.getElementById("ent-ena");
174
+ var bdy = document.getElementById("ent-body");
175
+
176
+ var enabled = ena.getAttribute("value");
177
+ if( enabled == "true" ){
178
+ ena.setAttribute("value", "false");
179
+ bdy.setAttribute("class", "ent-body hidden");
180
+ } else {
181
+ ena.setAttribute("value", "true");
182
+ bdy.setAttribute("class", "ent-body");
183
+ }
184
+ }
185
+
186
+
170
187
  ///////////////////////////////////////////////
171
188
  // Add an index
172
189
  function entAddIndex(){
@@ -376,25 +393,6 @@
376
393
 
377
394
  // Action
378
395
 
379
- ///////////////////////////////////////////////
380
- // Enable/disable editing the action
381
- function actEnable(){
382
- var but = document.getElementById("act-task-add");
383
- var ena = document.getElementById("act-ena");
384
- var tsk = document.getElementById("act-tasks");
385
-
386
- var enabled = ena.getAttribute("value");
387
- if( enabled == "true" ){
388
- ena.setAttribute("value", "false");
389
- tsk.setAttribute("class", "sect-right hidden");
390
- but.setAttribute("class", "sect-right invisible");
391
- } else {
392
- ena.setAttribute("value", "true");
393
- tsk.setAttribute("class", "sect-right");
394
- but.setAttribute("class", "sect-right");
395
- }
396
- }
397
-
398
396
 
399
397
  ///////////////////////////////////////////////
400
398
  // Add a row to a task
data/devel/run/base.rb CHANGED
@@ -61,7 +61,8 @@ def get_base
61
61
 
62
62
  # default config
63
63
  defaults = {
64
- 'tz' => '-04:00'
64
+ 'tz' => '-04:00',
65
+ 'rel_time' => true,
65
66
  }
66
67
 
67
68
  # base objects
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Investigative Case File System
4
+ #
5
+ # Copyright 2019 by Graham A. Field
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License version 3.
9
+ #
10
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
11
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+
13
+ # usage: <case-backup> <fs_store_dir> <caseid>
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative 'base'
18
+ require_relative '../../lib/icfs/store_fs'
19
+ require_relative '../../lib/icfs/utils/backup'
20
+
21
+ base = get_base()
22
+ backup = ICFS::Utils::Backup.new(base[:cache], base[:store], base[:log])
23
+ dst = ICFS::StoreFs.new(ARGV[0])
24
+ backup.copy(ARGV[1], dst)
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Investigative Case File System
4
+ #
5
+ # Copyright 2019 by Graham A. Field
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License version 3.
9
+ #
10
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
11
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+
13
+ # usage: <case-restore> <fs_store_dir> <caseid>
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative 'base'
18
+ require_relative '../../lib/icfs/store_fs'
19
+ require_relative '../../lib/utils/backup'
20
+
21
+ base = get_base()
22
+ backup = ICFS::Utils::Backup.new(base[:cache], base[:store], base[:log])
23
+ src = ICFS::StoreFs.new(ARGV[0])
24
+ backup.restore(ARGV[1], src)
data/devel/run/copy-s3.rb CHANGED
@@ -10,6 +10,8 @@
10
10
  # This program is distributed WITHOUT ANY WARRANTY; without even the
11
11
  # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
12
 
13
+ # usage: ./copy-s3.rb <source_dir> <prefix>
14
+
13
15
  # frozen_string_literal: true
14
16
 
15
17
  require 'aws-sdk-s3'
@@ -18,17 +18,6 @@ require 'aws-sdk-s3'
18
18
 
19
19
  require_relative '../../lib/icfs'
20
20
  require_relative '../../lib/icfs/cache_elastic'
21
- require_relative '../../lib/icfs/store_s3'
22
-
23
-
24
- # Minio config
25
- Aws.config.update(
26
- endpoint: 'http://minio:9000',
27
- access_key_id: 'minio_key',
28
- secret_access_key: 'minio_secret',
29
- force_path_style: true,
30
- region: 'us-east-1'
31
- )
32
21
 
33
22
  # default mapping
34
23
  map = {
@@ -42,10 +31,15 @@ map = {
42
31
  }.freeze
43
32
 
44
33
  # base items
45
- s3 = Aws::S3::Client.new
34
+ s3 = Aws::S3::Client.new(
35
+ endpoint: 'http://minio:9000',
36
+ access_key_id: 'minio_key',
37
+ secret_access_key: 'minio_secret',
38
+ force_path_style: true,
39
+ region: 'us-east-1'
40
+ )
46
41
  es = Faraday.new('http://elastic:9200')
47
42
  cache = ICFS::CacheElastic.new(map, es)
48
- store = ICFS::StoreS3.new(s3, 'icfs', 'case/')
49
43
 
50
44
  # create the indexes
51
45
  cache.create(ICFS::CacheElastic::Maps)
@@ -54,27 +48,3 @@ puts "Indexes created"
54
48
  # create a bucket
55
49
  s3.create_bucket(bucket: 'icfs')
56
50
  puts "S3 bucket created"
57
-
58
- api = ICFS::Api.new([], nil, cache, store)
59
-
60
- # add a template
61
- tmpl = {
62
- 'template' => true,
63
- 'status' => true,
64
- 'title' => 'Test template',
65
- 'access' => [
66
- {
67
- 'perm' => '[manage]',
68
- 'grant' => [
69
- 'role2'
70
- ]
71
- }
72
- ]
73
- }
74
- ent = {
75
- 'caseid' => 'test_tmpl',
76
- 'title' => 'Create template',
77
- 'content' => 'To test'
78
- }
79
- api.case_create(ent, tmpl, nil, 'user1')
80
- puts "Create template"
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Investigative Case File System
4
+ #
5
+ # Copyright 2019 by Graham A. Field
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License version 3.
9
+ #
10
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
11
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+
13
+ # usage: ./init-template.sh <template.json> <user>
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative 'base'
18
+
19
+ json = File.read(ARGV[0])
20
+ tmpl = ICFS::Items.parse(json, 'Template', ICFS::Items::ItemCase)
21
+ tmpl.delete('icfs')
22
+ tmpl.delete('log')
23
+
24
+ ent = {
25
+ 'caseid' => tmpl['caseid'],
26
+ 'title' => 'Create case',
27
+ 'content' => 'Added case using manual script',
28
+ }
29
+
30
+ base = get_base()
31
+ api = base[:api]
32
+
33
+ api.case_create(ent, tmpl, nil, ARGV[1])
data/lib/icfs/api.rb CHANGED
@@ -518,6 +518,7 @@ class Api
518
518
  after: Validate::IsIntPos,
519
519
  before: Validate::IsIntPos,
520
520
  user: Items::FieldUsergrp,
521
+ case_edit: Validate::IsBoolean,
521
522
  entry: Validate::IsIntPos,
522
523
  index: Validate::IsIntPos,
523
524
  action: Validate::IsIntPos,
@@ -908,6 +909,13 @@ class Api
908
909
  Items.validate(ent, 'entry', Items::ItemEntryNew)
909
910
  Items.validate(cse, 'case', Items::ItemCaseEdit)
910
911
 
912
+ # get caseid
913
+ cid = ent['caseid']
914
+ cid ||= cse['caseid']
915
+ unless cid
916
+ raise(Error::Values, 'No caseid provided')
917
+ end
918
+
911
919
  # access users/roles/groups are valid, unless manually specifying user
912
920
  unless unam
913
921
  cse["access"].each do |acc|
@@ -953,11 +961,11 @@ class Api
953
961
  # Prep
954
962
 
955
963
  # case
956
- cid = ent['caseid']
957
964
  cse['icfs'] = 1
958
965
  cse['caseid'] = cid
959
966
  cse['log'] = 1
960
967
  cse['tags'] ||= [ ICFS::TagNone ]
968
+ cse['entry'] = 1
961
969
  citem = Items.generate(cse, 'case', Items::ItemCase)
962
970
 
963
971
  # entry
@@ -979,7 +987,10 @@ class Api
979
987
  'entry' => {
980
988
  'num' => 1,
981
989
  },
982
- 'case_hash' => ICFS.hash(citem),
990
+ 'case' => {
991
+ 'set' => true,
992
+ 'hash' => ICFS.hash(citem),
993
+ },
983
994
  }
984
995
  log['files_hash'] = fhash if fhash
985
996
 
@@ -1040,7 +1051,7 @@ class Api
1040
1051
  ###############################################
1041
1052
  # Write items to a case
1042
1053
  #
1043
- # @param ent [Hash] Entry to record, required
1054
+ # @param ent [Hash] Entry to record, optional
1044
1055
  # @param act [Hash, Nilclass] Action to record, optional
1045
1056
  # @param idx [Hash, Nilclass] Index to record, optional
1046
1057
  # @param cse [Hash, Nilclass] Case to record, optional
@@ -1051,22 +1062,36 @@ class Api
1051
1062
  # Sanity checks
1052
1063
 
1053
1064
  # form & content
1054
- if idx || cse
1055
- Items.validate(ent, 'New Entry', Items::ItemEntryNew)
1056
- else
1057
- Items.validate(ent, 'Editable Entry', Items::ItemEntryEdit)
1065
+ if ent
1066
+ if (act || idx || cse)
1067
+ Items.validate(ent, 'New Entry', Items::ItemEntryNew)
1068
+ else
1069
+ Items.validate(ent, 'Editable Entry', Items::ItemEntryEdit)
1070
+ end
1058
1071
  end
1059
1072
  Items.validate(act, 'action', Items::ItemActionEdit) if act
1060
1073
  Items.validate(idx, 'index', Items::ItemIndexEdit) if idx
1061
1074
  Items.validate(cse, 'case', Items::ItemCaseEdit) if cse
1062
1075
 
1063
- # edit index OR case, not both
1064
- if idx && cse
1065
- raise(Error::Value, 'May not edit both case and index at once')
1076
+ # get caseid
1077
+ cid ||= ent['caseid'] if ent
1078
+ cid ||= cse['caseid'] if cse
1079
+ cid ||= act['caseid'] if act
1080
+ cid ||= idx['caseid'] if idx
1081
+ unless cid
1082
+ raise(Error::Values, 'No caseid provided')
1083
+ end
1084
+
1085
+ # no conflicting caseids
1086
+ if( (cse && cse['caseid'] && cse['caseid'] != cid) ||
1087
+ (act && act['caseid'] && act['caseid'] != cid) ||
1088
+ (idx && idx['caseid'] && idx['caseid'] != cid) )
1089
+ raise(Error::Values, 'Conflicting caseids provided')
1066
1090
  end
1067
1091
 
1068
1092
  # no changing the action
1069
- if act && ent['action'] && act['action'] && act['action'] != ent['action']
1093
+ if( act && ent && ent['action'] && act['action'] &&
1094
+ act['action'] != ent['action'] )
1070
1095
  raise(Error::Conflict, 'May not change entry\'s action')
1071
1096
  end
1072
1097
 
@@ -1103,17 +1128,21 @@ class Api
1103
1128
 
1104
1129
  ####################
1105
1130
  # Prep
1106
- cid = ent['caseid']
1107
1131
 
1108
1132
  # entry
1109
- ent['icfs'] = 1
1110
- ent['tags'] ||= [ ]
1111
- ent['user'] = @user
1112
- files, fhash = _pre_files(ent)
1133
+ if ent
1134
+ ent['icfs'] = 1
1135
+ ent['tags'] ||= [ ]
1136
+ ent['user'] = @user
1137
+ ent['caseid'] = cid
1138
+ files, fhash = _pre_files(ent)
1139
+ else
1140
+ files = []
1141
+ end
1113
1142
 
1114
1143
  # action
1115
1144
  if act
1116
- ent['tags'] << ICFS::TagAction
1145
+ ent['tags'] << ICFS::TagAction if ent
1117
1146
  act['icfs'] = 1
1118
1147
  act['caseid'] = cid
1119
1148
  act['tasks'].each do |tk|
@@ -1123,7 +1152,7 @@ class Api
1123
1152
 
1124
1153
  # index
1125
1154
  if idx
1126
- ent['tags'] << ICFS::TagIndex
1155
+ ent['tags'] << ICFS::TagIndex if ent
1127
1156
  idx['icfs'] = 1
1128
1157
  idx['caseid'] = cid
1129
1158
  idx['tags'] ||= [ ICFS::TagNone ]
@@ -1131,7 +1160,7 @@ class Api
1131
1160
 
1132
1161
  # case
1133
1162
  if cse
1134
- ent['tags'] << ICFS::TagCase
1163
+ ent['tags'] << ICFS::TagCase if ent
1135
1164
  cse['icfs'] = 1
1136
1165
  cse['caseid'] = cid
1137
1166
  cse['tags'] ||= [ ICFS::TagNone ]
@@ -1146,7 +1175,7 @@ class Api
1146
1175
  log['files_hash'] = fhash if fhash
1147
1176
 
1148
1177
  # no tags
1149
- ent['tags'] = [ ICFS::TagNone ] if ent['tags'].empty?
1178
+ ent['tags'] = [ ICFS::TagNone ] if ent && ent['tags'].empty?
1150
1179
 
1151
1180
  # current
1152
1181
  nxt = {
@@ -1171,14 +1200,18 @@ class Api
1171
1200
  cur = Items.parse(json, 'current', Items::ItemCurrent)
1172
1201
 
1173
1202
  # entry
1174
- if ent['entry']
1175
- enum = ent['entry']
1176
- json = @cache.entry_read(cid, enum)
1177
- ent_pri = Items.parse(json, 'entry', Items::ItemEntry)
1178
- nxt['entry'] = cur['entry']
1203
+ if ent
1204
+ if ent['entry']
1205
+ enum = ent['entry']
1206
+ json = @cache.entry_read(cid, enum)
1207
+ ent_pri = Items.parse(json, 'entry', Items::ItemEntry)
1208
+ nxt['entry'] = cur['entry']
1209
+ else
1210
+ enum = cur['entry'] + 1
1211
+ nxt['entry'] = enum
1212
+ end
1179
1213
  else
1180
- enum = cur['entry'] + 1
1181
- nxt['entry'] = enum
1214
+ nxt['entry'] = cur['entry']
1182
1215
  end
1183
1216
 
1184
1217
  # action
@@ -1186,7 +1219,7 @@ class Api
1186
1219
  anum = ent_pri['action']
1187
1220
  elsif act && act['action']
1188
1221
  anum = act['action']
1189
- elsif ent['action']
1222
+ elsif ent && ent['action']
1190
1223
  anum = ent['action']
1191
1224
  end
1192
1225
  if anum
@@ -1228,7 +1261,7 @@ class Api
1228
1261
  perms = Set.new
1229
1262
 
1230
1263
  # entry
1231
- perms.merge(ent['perms']) if ent['perms']
1264
+ perms.merge(ent['perms']) if ent && ent['perms']
1232
1265
  if ent_pri
1233
1266
 
1234
1267
  # must have those perms
@@ -1326,7 +1359,7 @@ class Api
1326
1359
 
1327
1360
  # write unless a case or pre-existing action
1328
1361
  unless cse || act_pri
1329
- perms.add( ICFS::PermWrite)
1362
+ perms.add( ICFS::PermWrite )
1330
1363
  end
1331
1364
 
1332
1365
  # permissions
@@ -1341,28 +1374,32 @@ class Api
1341
1374
  # Items
1342
1375
 
1343
1376
  # entry
1344
- ent['entry'] = enum
1345
- ent['log'] = lnum
1346
- ent['time'] ||= now
1347
- ent['action'] = anum if act
1348
- if idx
1349
- if ent['index']
1350
- ent['index'] = ent['index'].push(xnum).uniq.sort
1351
- else
1352
- ent['index'] = [ xnum ]
1377
+ if ent
1378
+ ent['entry'] = enum
1379
+ ent['log'] = lnum
1380
+ ent['time'] ||= now
1381
+ ent['action'] = anum if act
1382
+ if idx
1383
+ if ent['index']
1384
+ ent['index'] << xnum
1385
+ else
1386
+ ent['index'] = [ xnum ]
1387
+ end
1353
1388
  end
1389
+ ent['index'].sort!.uniq! if ent['index']
1390
+ ent['files'].each{|fi| fi['log'] ||= lnum } if ent['files']
1391
+ eitem = Items.generate(ent, 'entry', Items::ItemEntry)
1392
+ log['entry'] = {
1393
+ 'num' => enum,
1394
+ 'hash' => ICFS.hash(eitem)
1395
+ }
1354
1396
  end
1355
- ent['files'].each{|fi| fi['log'] ||= lnum } if ent['files']
1356
- eitem = Items.generate(ent, 'entry', Items::ItemEntry)
1357
- log['entry'] = {
1358
- 'num' => enum,
1359
- 'hash' => ICFS.hash(eitem)
1360
- }
1361
1397
 
1362
1398
  # action
1363
1399
  if act
1364
1400
  act['action'] = anum
1365
1401
  act['log'] = lnum
1402
+ act['entry'] = enum if ent
1366
1403
  aitem = Items.generate(act, 'action', Items::ItemAction)
1367
1404
  log['action'] = {
1368
1405
  'num' => anum,
@@ -1374,6 +1411,7 @@ class Api
1374
1411
  if idx
1375
1412
  idx['index'] = xnum
1376
1413
  idx['log'] = lnum
1414
+ idx['entry'] = enum if ent
1377
1415
  xitem = Items.generate(idx, 'index', Items::ItemIndex)
1378
1416
  log['index'] = {
1379
1417
  'num' => xnum,
@@ -1384,8 +1422,12 @@ class Api
1384
1422
  # case
1385
1423
  if cse
1386
1424
  cse['log'] = lnum
1425
+ cse['entry'] = enum if ent
1387
1426
  citem = Items.generate(cse, 'case', Items::ItemCase)
1388
- log['case_hash'] = ICFS.hash(citem)
1427
+ log['case'] = {
1428
+ 'set' => true,
1429
+ 'hash' => ICFS.hash(citem),
1430
+ }
1389
1431
  end
1390
1432
 
1391
1433
  # log
@@ -1403,8 +1445,10 @@ class Api
1403
1445
  # Write
1404
1446
 
1405
1447
  # entry
1406
- @cache.entry_write(cid, enum, eitem)
1407
- @store.entry_write(cid, enum, lnum, eitem)
1448
+ if ent
1449
+ @cache.entry_write(cid, enum, eitem)
1450
+ @store.entry_write(cid, enum, lnum, eitem)
1451
+ end
1408
1452
 
1409
1453
  # action
1410
1454
  if act
@@ -35,6 +35,7 @@ class CacheElastic < Cache
35
35
  "icfs": { "enabled": false },
36
36
  "caseid": { "type": "keyword" },
37
37
  "log": { "enabled": false },
38
+ "entry": { "enabled": false },
38
39
  "template": { "type": "boolean" },
39
40
  "status": { "type": "boolean" },
40
41
  "title": { "type": "text" },
@@ -66,7 +67,10 @@ class CacheElastic < Cache
66
67
  "num": { "type": "integer" },
67
68
  "hash": { "enabled": false }
68
69
  }},
69
- "case_hash": { "enabled": false },
70
+ "case": { "properties": {
71
+ "set": { "type": "boolean" },
72
+ "hash": { "enabled": false }
73
+ }},
70
74
  "files_hash": { "enabled": false }
71
75
  }}}
72
76
  }',
@@ -104,6 +108,7 @@ class CacheElastic < Cache
104
108
  "caseid": { "type": "keyword" },
105
109
  "action": { "type": "integer" },
106
110
  "log": { "enabled": false },
111
+ "entry": { "enabled": false },
107
112
  "tasks": { "type": "nested","properties": {
108
113
  "assigned": { "type": "keyword" },
109
114
  "title": { "type": "text" },
@@ -121,6 +126,7 @@ class CacheElastic < Cache
121
126
  "caseid": { "type": "keyword" },
122
127
  "index": { "type": "integer" },
123
128
  "log": { "enabled": false },
129
+ "entry": { "enabled": false },
124
130
  "title": {
125
131
  "type": "text",
126
132
  "fields": { "raw": { "type": "keyword" }}
@@ -532,7 +538,7 @@ class CacheElastic < Cache
532
538
  tags: 'tags',
533
539
  perms: ['perms', :empty],
534
540
  action: ['action', :zero],
535
- index: ['index', :size],
541
+ indexes: ['index', :size],
536
542
  files: ['files', :size],
537
543
  stats: ['stats', :size],
538
544
  }.freeze
@@ -792,6 +798,7 @@ class CacheElastic < Cache
792
798
  entry: ['entry', :sub, 'num'].freeze,
793
799
  index: ['index', :sub, 'num'].freeze,
794
800
  action: ['action', :sub, 'num'].freeze,
801
+ case: ['case', :sub, 'set'].freeze,
795
802
  files: ['files_hash', :size].freeze,
796
803
  }.freeze
797
804
 
@@ -806,6 +813,7 @@ class CacheElastic < Cache
806
813
  _query_term('caseid', query[:caseid]),
807
814
  _query_times('times', query[:after], query[:before]),
808
815
  _query_term('user', query[:user]),
816
+ _query_exists('case.set', query[:case_edit]),
809
817
  _query_term('entry.num', query[:entry]),
810
818
  _query_term('index.num', query[:index]),
811
819
  _query_term('action.num', query[:action]),
data/lib/icfs/config.rb CHANGED
@@ -30,9 +30,10 @@ class Config
30
30
  method: :string,
31
31
  valid: /[+\-](0[0-9]|1[0-2]):[0-5][0-9]/.freeze,
32
32
  whitelist: true,
33
- }
34
- }
35
- }
33
+ }.freeze,
34
+ 'rel_time' => Validate::IsBoolean,
35
+ }.freeze
36
+ }.freeze
36
37
 
37
38
  ###############################################
38
39
  # New instance