class ICFS::Web::Client
Constants
- DivAction
Action div
- DivActionLink
Action link
- DivActionTag
Action Tag
- DivActionTask
Action task
- DivCase
Case div
- DivCaseAccess
Case div each access
- DivCaseActions
Case div action links
- DivCaseGrant
Case div each grant
- DivCaseLink
Case div links
- DivCaseStatEach
Case div each stat
- DivCaseStats
Case div stats section
- DivCaseTag
Case div each tag
- DivConfig
The config settings div
- DivConfigItem
each config setting
- DivDesc
Div description
- DivEntry
entry div
- DivEntryAction
entry action
- DivEntryFileEach
entry each file
- DivEntryFiles
entry files
- DivEntryIndex
entry index
- DivEntryIndexEach
entry index each
- DivEntryLink
entry link each
- DivEntryPermEach
entry perm each
- DivEntryPerms
entry perms
- DivEntryStatEach
entry each stat
- DivEntryStats
entry stats
- DivEntryTag
entry tag each
- DivForm
Form
- DivHome
Home div
- DivHomeLink
Home Link
- DivHomeUr
Home user/role
- DivIndex
Index div
- DivIndexLink
Index Links
- DivIndexTag
Index tags
- DivInfo
info div
- DivInfoList
List items in the info div
- DivList
Search results list
- DivListHead
Search results header
- DivListHeadItems
Search results header items
- DivListItem
search results item
- DivListItemTitle
search results item with title
- DivListRow
Search results row
- DivLog
log div
- DivLogAction
log action
- DivLogCase
log case
- DivLogEntry
log entry
- DivLogFileEach
log file
- DivLogFiles
log file
- DivLogIndex
log index
- DivMsg
message div
navbar div
navbar tab
- DivPage
Pageing div
- DivQuery
Query div
- FormAction
action edit form
- FormActionFlagEd
action flag editable
- FormActionFlagRo
action flag read-only
- FormActionStatusEd
action open editable
- FormActionStatusRo
action open readonly
- FormActionTagButton
action tag button
- FormActionTagEd
action tag editable
- FormActionTagRo
action tag read-only
- FormActionTask
action task
- FormActionTaskedEd
action tasked editable
- FormActionTaskedRo
action tasked read only
- FormActionTimeEd
action time editable
- FormActionTimeRo
action time read-only
- FormActionTitleEd
action title editable
- FormActionTitleRo
action title read only
- FormCase
Case form
- FormCaseAccess
Case form Access each
- FormCaseCreate
Form to create a new case
- FormCaseGrant
Case form Grant each
- FormCaseStat
Case form Stat each
- FormCaseTag
Case form Tag each
- FormConfig
Config
form- FormConfigItem
Item on the config form
- FormEntry
entry edit form
- FormEntryClaim
Entry form Stat Claim
- FormEntryEnable
entry toggle button
- FormEntryFileEach
Entry form file each
- FormEntryIndex
Entry form for indexes
- FormEntryIndexEach
Entry form index each
- FormEntryPermEach
Entry form Perm each
- FormEntryPermOpt
Entry form Perm option
- FormEntryStatEach
Entry form Stat each
- FormEntryStatOpt
Entry form Stat option
- FormEntryStatSel
Entry form Stat select
- FormEntryTagEach
Entry form tag each
- FormIndex
Index form
- FormIndexTagEach
Index form tag
- FormQuery
Query Form
- FormQueryItem
Query form item
- ListAction
Task list options
- ListActionTags
Action Tags list
- ListCase
List case search
- ListCaseTags
Case Tags list
- ListColClass
Column classes by symbol
- ListEntry
Entry query display
- ListEntryTags
Entry Tags list
- ListIndex
Task list options
- ListIndexTags
Index tags list
- ListLog
Log query display
- ListStats
Stats list options
- Page
HTML page
- QueryAction
Task query options
- QueryActionTags
Action Tag query
- QueryCase
Case query options
- QueryCaseTags
Query for case tags
- QueryEntry
Entry query options
- QueryEntryTags
Entry tags query options
- QueryIndex
Index query options
- QueryIndexTags
Index tags query
- QueryLog
Log query options
- QueryStats
Stats query options
Public Class Methods
New instance
@param js [String] the URL for the javascript
# File lib/icfs/web/client.rb, line 33 def initialize(js) @js = js.freeze end
Public Instance Methods
A Rack call
@param env [Hash] the Rack environment
# File lib/icfs/web/client.rb, line 43 def call(env) # grab the path components path = env['PATH_INFO'] if path.empty? cmps = [''] else cmps = path.split('/', -1) cmps.shift if cmps[0].empty? cmps = [''] if cmps.empty? end env['icfs.cmps'] = cmps # reset env['icfs'].reset case cmps[0] # search when 'case_search' return _call_search(env, 'Case Search', 'Case Search', QueryCase, ListCase, :case_search, Proc.new{|qu, txt| _a_case_search(env, qu, txt) } ) when 'entry_search' return _call_search(env, 'Entry Search', 'Entry Search', QueryEntry, ListEntry, :entry_search, Proc.new{|qu, txt| _a_entry_search(env, qu, txt) } ) when 'log_search' return _call_search(env, 'Log Search', 'Log Search', QueryLog, ListLog, :log_search, Proc.new{|qu, txt| _a_log_search(env, qu, txt) } ) when 'action_search' return _call_search(env, 'Action Search', 'Action Search', QueryAction, ListAction, :action_search, Proc.new{|qu, txt| _a_action_search(env, qu, txt) } ) when 'index_search' return _call_search(env, 'Index Search', 'Index Search', QueryIndex, ListIndex, :index_search, Proc.new{|qu, txt| _a_index_search(env, qu, txt) } ) when 'index_lookup'; return _call_index_lookup(env) # aggregations when 'stats' return _call_search(env, 'Stats Search', 'Stats Search', QueryStats, ListStats, :stats, nil ) when 'case_tags' return _call_search(env, 'Case Tags', 'Case Tags Search', QueryCaseTags, ListCaseTags, :case_tags, nil ) when 'entry_tags' return _call_search(env, 'Entry Tags', 'Entry Tag Search', QueryEntryTags, ListEntryTags, :entry_tags, nil ) when 'action_tags' return _call_search(env, 'Action Tags', 'Action Tag Search', QueryActionTags, ListActionTags, :action_tags, nil ) when 'index_tags' return _call_search(env, 'Index Tags', 'Index Tag Search', QueryIndexTags, ListIndexTags, :index_tags, nil ) # forms when 'case_create'; return _call_case_create(env) when 'case_edit'; return _call_case_edit(env) when 'entry_edit'; return _call_entry_edit(env) when 'index_edit'; return _call_index_edit(env) when 'action_edit'; return _call_action_edit(env) when 'config_edit'; return _call_config_edit(env) # view when 'home', ''; return _call_home(env) when 'case'; return _call_case(env) when 'entry'; return _call_entry(env) when 'log'; return _call_log(env) when 'action'; return _call_action(env) when 'index'; return _call_index(env) when 'file'; return _call_file(env) # info page when 'info'; return _call_info(env) # not supported path else env['icfs.page'] = 'Invalid' raise(Error::NotFound, 'Invalid request') end rescue Error::NotFound => e return _resp_notfound( env, 'Not found: %s' % Rack::Utils.escape_html(e.message) ) rescue Error::Perms => e return _resp_forbidden( env, 'Forbidden: %s' % Rack::Utils.escape_html(e.message) ) rescue Error::Conflict => e return _resp_conflict( env, 'Conflict: %s' % Rack::Utils.escape_html(e.message) ) rescue Error::Value => e return _resp_badreq( env, 'Invalid values: %s' % Rack::Utils.escape_html(e.message) ) rescue Error::Interface => e return _resp_badreq(env, Rack::Utils.escape_html(e.message)) end
Private Instance Methods
Link to an Action
# File lib/icfs/web/client.rb, line 4528 def _a_action(env, cid, anum, lnum, txt) '<a href="%s/action/%s/%d/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), anum, lnum, Rack::Utils.escape_html(txt) ] end
Link to Action edit
# File lib/icfs/web/client.rb, line 4454 def _a_action_edit(env, cid, anum, txt) '<a href="%s/action_edit/%s/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), anum, Rack::Utils.escape_html(txt) ] end
Link to Action search
# File lib/icfs/web/client.rb, line 4323 def _a_action_search(env, query, txt) '<a href="%s/action_search%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Link to Case
# File lib/icfs/web/client.rb, line 4489 def _a_case(env, cid, lnum, txt) '<a href="%s/case/%s/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), lnum, Rack::Utils.escape_html(txt) ] end
Link to create a case
# File lib/icfs/web/client.rb, line 4404 def _a_case_create(env, tid, txt) '<a href="%s/case_create/%s">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(tid), Rack::Utils.escape_html(txt), ] end
Link to Case edit
# File lib/icfs/web/client.rb, line 4416 def _a_case_edit(env, cid, txt) '<a href="%s/case_edit/%s">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), Rack::Utils.escape_html(txt) ] end
Link to Case search
# File lib/icfs/web/client.rb, line 4287 def _a_case_search(env, query, txt) '<a href="%s/case_search%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Link to Config
edit
# File lib/icfs/web/client.rb, line 4467 def _a_config_edit(env, txt) '<a href="%s/config_edit">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape_html(txt) ] end
Link to an entry
# File lib/icfs/web/client.rb, line 4501 def _a_entry(env, cid, enum, lnum, txt) '<a href="%s/entry/%s/%d/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), enum, lnum, Rack::Utils.escape_html(txt) ] end
Link to Entry edit
# File lib/icfs/web/client.rb, line 4428 def _a_entry_edit(env, cid, enum, anum, txt) '<a href="%s/entry_edit/%s/%d/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), enum, anum, Rack::Utils.escape_html(txt) ] end
Link to Entry search
# File lib/icfs/web/client.rb, line 4299 def _a_entry_search(env, query, txt) '<a href="%s/entry_search%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Link to a File
# File lib/icfs/web/client.rb, line 4556 def _a_file(env, cid, enum, lnum, fnum, fname, txt) '<a href="%s/file/%s/%d-%d-%d-%s">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), enum, lnum, fnum, Rack::Utils.escape(fname), Rack::Utils.escape_html(txt) ] end
Link to Home
# File lib/icfs/web/client.rb, line 4478 def _a_home(env, txt) '<a href="%s/home">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape_html(txt) ] end
Link to an Index
# File lib/icfs/web/client.rb, line 4542 def _a_index(env, cid, xnum, lnum, txt) '<a href="%s/index/%s/%d/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), xnum, lnum, Rack::Utils.escape_html(txt) ] end
Link to Index edit
# File lib/icfs/web/client.rb, line 4441 def _a_index_edit(env, cid, xnum, txt) '<a href="%s/index_edit/%s/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), xnum, Rack::Utils.escape_html(txt) ] end
Link to Index search
# File lib/icfs/web/client.rb, line 4335 def _a_index_search(env, query, txt) '<a href="%s/index_search%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Link to info page
# File lib/icfs/web/client.rb, line 4277 def _a_info(env, txt) '<a href="%s/info">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape_html(txt) ] end
Link to a Log
# File lib/icfs/web/client.rb, line 4515 def _a_log(env, cid, lnum, txt) '<a href="%s/log/%s/%d">%s</a>' % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), lnum, Rack::Utils.escape_html(txt) ] end
Link to Log search
# File lib/icfs/web/client.rb, line 4311 def _a_log_search(env, query, txt) '<a href="%s/log_search%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Link to stats search
# File lib/icfs/web/client.rb, line 4347 def _a_stats(env, query, txt) '<a href="%s/stats%s">%s</a>' % [ env['SCRIPT_NAME'], _util_query(query), Rack::Utils.escape_html(txt) ] end
Display an Action
# File lib/icfs/web/client.rb, line 933 def _call_action(env) env['icfs.page'] = 'Action View' api = env['icfs'] _verb_get(env) cid = _util_case(env) anum = _util_num(env, 2) lnum = _util_num(env, 3) raise(Error::Interface, 'No Action requested') if anum == 0 act = api.action_read(cid, anum, lnum) ent = api.entry_read(cid, act['entry']) if act['entry'] ent_div = _div_entry(env, ent) if ent # historical if lnum != 0 msg = 'This is a historical version of this Action' list_div = '' # current else msg = '' query = { caseid: cid, action: anum, purpose: 'Action Entries', } resp = api.entry_search(query) list_div = _div_list(env, resp, ListEntry) + _div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)} end # display body = [ _div_nav(env), _div_desc('View Action', msg), _div_action(env, act), ent_div, list_div ] return _resp_success(env, body.join('')) end
Edit an Action
# File lib/icfs/web/client.rb, line 754 def _call_action_edit(env) env['icfs.page'] = 'Action Edit' api = env['icfs'] _verb_getpost(env) cid = _util_case(env) # get the form if env['REQUEST_METHOD'] == 'GET' anum = _util_num(env, 2) # see if editing is possible unless( api.access_list(cid).include?(ICFS::PermAction) || ((anum != 0) && api.tasked?(cid, anum)) ) raise(Error::Perms, 'Not able to edit this action.') end act = api.action_read(cid, anum) if anum != 0 opts = {enable: false} opts[:action] = anum if act parts = [ _form_action(env, cid, act), _form_entry(env, cid, nil, opts), ] desc = act ? 'Edit Action' : 'New Action' body = [ _div_nav(env), _div_desc(desc, ''), _div_form(env, '/action_edit/', cid, parts, 'Record Action'), ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) # process ent = _post_entry(env, para) act = _post_action(env, para) act['caseid'] = cid api.record(ent, act, nil, nil) # display the index body = [ _div_nav(env), _div_action(env, act), ] body << _div_entry(env, ent) if ent return _resp_success(env, body.join('')) end end
Display a Case
# File lib/icfs/web/client.rb, line 865 def _call_case(env) env['icfs.page'] = 'Case View' api = env['icfs'] _verb_get(env) cid = _util_case(env) lnum = _util_num(env, 2) cse = api.case_read(cid, lnum) ent = api.entry_read(cid, cse['entry']) if cse['entry'] msg = (lnum != 0) ? 'This is a historical version of this Case' : '' body = [ _div_nav(env), _div_desc('Case Information', msg), _div_case(env, cse), ] body << _div_entry(env, ent) if ent return _resp_success(env, body.join('')) end
Create a new case
# File lib/icfs/web/client.rb, line 537 def _call_case_create(env) env['icfs.page'] = 'Case Create' api = env['icfs'] tid = _util_case(env) _verb_getpost(env) # get the form if env['REQUEST_METHOD'] == 'GET' tpl = api.case_read(tid) tpl['title'] = '' parts = [ _form_create(env), _form_case(env, tpl), _form_entry(env, tid, nil, {no_index: true}), ] body = [ _div_nav(env), _div_desc( 'Create New Case', '<i>template:</i> %s' % Rack::Utils.escape_html(tid), ), _div_form(env, '/case_create/', tid, parts, 'Create Case') ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) # process cse = _post_case(env, para) cid = para['create_cid'] cse['template'] = (para['create_tmpl'] == 'true') ? true : false # process entry ent = _post_entry(env, para, {no_index: true}) Items.validate(tid, 'Template ID', Items::FieldCaseid) ent['caseid'] = cid # create api.case_create(ent, cse, tid) # display the new case env['icfs.cid'] = cid body = _div_nav(env) + _div_case(env, cse) return _resp_success(env, body) end end
Edit a case
# File lib/icfs/web/client.rb, line 590 def _call_case_edit(env) env['icfs.page'] = 'Case Edit' cid = _util_case(env) api = env['icfs'] _verb_getpost(env) # get the form if env['REQUEST_METHOD'] == 'GET' cse = api.case_read(cid) parts = [ _form_case(env, cse), _form_entry(env, cid, nil, {enable: false}), ] body = [ _div_nav(env), _div_desc('Edit Case', ''), _div_form(env, '/case_edit/', cid, parts, 'Record Case'), ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) # process cse = _post_case(env, para) ent = _post_entry(env, para) cse['caseid'] = cid cse_old = api.case_read(cid) cse['template'] = cse_old['template'] api.record(ent, nil, nil, cse) # display the case body = [ _div_nav(env), _div_case(env, cse), ] body << _div_entry(env, ent) if ent return _resp_success(env, body.join('')) end end
Edit configuration
# File lib/icfs/web/client.rb, line 811 def _call_config_edit(env) env['icfs.page'] = 'Config Edit' api = env['icfs'] cfg = api.config _verb_getpost(env) # get the form if env['REQUEST_METHOD'] == 'GET' parts = [ _form_config(env) ] body = [ _div_nav(env), _div_desc('Edit Configuration', ''), _div_form(env, '/config_edit/', nil, parts, 'Save Config'), ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) vals = _post_config(env, para) cfg.clear vals.each{|key, val| cfg.set(key,val) } cfg.save api.user_flush() # display the index body = [ _div_nav(env), _div_desc('Edit Configuration', 'Settings saved'), _div_config(env), ].join('') return _resp_success(env, body) end end
Display an Entry
# File lib/icfs/web/client.rb, line 887 def _call_entry(env) env['icfs.page'] = 'Entry View' api = env['icfs'] _verb_get(env) cid = _util_case(env) enum = _util_num(env, 2) lnum = _util_num(env, 3) raise(Error::Interface, 'No Entry requested') if enum == 0 ent = api.entry_read(cid, enum, lnum) if lnum != 0 msg = 'This is a historical version of this Entry' else msg = '' end body = [ _div_nav(env), _div_desc('View Entry', msg), _div_entry(env, ent), ].join('') return _resp_success(env, body) end
Edit an entry
# File lib/icfs/web/client.rb, line 636 def _call_entry_edit(env) env['icfs.page'] = 'Entry Edit' api = env['icfs'] _verb_getpost(env) cid = _util_case(env) # get the form if env['REQUEST_METHOD'] == 'GET' enum = _util_num(env, 2) anum = _util_num(env, 3) # entry or action specified if enum != 0 desc = 'Edit Entry' ent = api.entry_read(cid, enum) elsif anum != 0 desc = 'New Entry in Action' act = api.action_read(cid, anum) else desc = 'New Entry' end # see if editing is possible unless( api.access_list(cid).include?(ICFS::PermWrite) || ( (anum != 0) && api.tasked?(cid, anum))) raise(Error::Perms, 'Not able to edit this entry.') end # build form opts = {} opts[:enable] = true if enum == 0 opts[:action] = anum if anum parts = [ _form_entry(env, cid, ent, opts) ] body = [ _div_nav(env), _div_desc(desc, ''), _div_form(env, '/entry_edit/', cid, parts, 'Record Entry'), ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) # process ent = _post_entry(env, para) raise(Error::Values, 'Entry form not enabled') unless ent ent['caseid'] = cid api.record(ent, nil, nil, nil) # display the entry body = [ _div_nav(env), _div_entry(env, ent) ] return _resp_success(env, body.join('')) end end
Get a file
# File lib/icfs/web/client.rb, line 1024 def _call_file(env) env['icfs.page'] = 'File Download' api = env['icfs'] _verb_get(env) cid = _util_case(env) # get filename cmps = env['icfs.cmps'] if cmps.size < 3 || cmps[2].empty? raise(Error::Interface, 'No file specified in the URL') end fnam = Rack::Utils.unescape(cmps[2]) ma = /^(\d+)-(\d+)-(\d+)-(.+)$/.match fnam if !ma raise(Error::Interface, 'File not properly specified in URL') end enum = ma[1].to_i lnum = ma[2].to_i fnum = ma[3].to_i ext = ma[4].rpartition('.')[2] # get MIME-type by extension if ext.empty? mime = 'application/octet-stream' else mime = Rack::Mime.mime_type('.' + ext) end # return the file file = api.file_read(cid, enum, lnum, fnum) fr = Web::FileResp.new(file) headers = { 'Content-Length' => file.size.to_s, 'Content-Type' => mime, 'Content-Disposition' => 'attachment', } return [200, headers, fr] end
User Home page
# File lib/icfs/web/client.rb, line 850 def _call_home(env) env['icfs.page'] = 'Home' _verb_get(env) body = [ _div_nav(env), _div_desc('User Home', ''), _div_home(env), ].join('') return _resp_success(env, body) end
Display an Index
# File lib/icfs/web/client.rb, line 979 def _call_index(env) env['icfs.page'] = 'Index View' api = env['icfs'] _verb_get(env) cid = _util_case(env) xnum = _util_num(env, 2) lnum = _util_num(env, 3) raise(Error::Interface, 'No Index requested') if xnum == 0 idx = api.index_read(cid, xnum, lnum) ent = api.entry_read(cid, idx['entry']) if idx['entry'] ent_div = ent ? _div_entry(env, ent) : '' # historical index if lnum != 0 msg = 'This is a historical version of this Index' list_div = '' # current index else msg = '' query = { caseid: cid, index: xnum } resp = api.entry_search(query) list_div = _div_list(env, resp, ListEntry) + _div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)} end # display body = [ _div_nav(env), _div_desc('View Index', msg), _div_index(env, idx), ent_div, list_div ] return _resp_success(env, body.join('')) end
Edit an Index
# File lib/icfs/web/client.rb, line 700 def _call_index_edit(env) env['icfs.page'] = 'Index Edit' api = env['icfs'] _verb_getpost(env) cid = _util_case(env) # get the form if env['REQUEST_METHOD'] == 'GET' # see if editing is possible unless api.access_list(cid).include?(ICFS::PermWrite) raise(Error::Perms, 'Not able to edit this index.') end xnum = _util_num(env, 2) idx = api.index_read(cid, xnum) if xnum != 0 parts = [ _form_index(env, cid, idx), _form_entry(env, cid, nil, {enable: false}), ] desc = idx ? 'Edit Index' : 'New Index' body = [ _div_nav(env), _div_desc(desc, ''), _div_form(env, '/index_edit/', cid, parts, 'Record Index'), ].join('') return _resp_success(env, body) # post the form elsif env['REQUEST_METHOD'] == 'POST' para = _util_post(env) # process ent = _post_entry(env, para) idx = _post_index(env, para) idx['caseid'] = cid api.record(ent, nil, idx, nil) # display the index body = [ _div_nav(env), _div_index(env, idx), ] body << _div_entry(env, ent) if ent return _resp_success(env, body.join('')) end end
Do an index lookup
# File lib/icfs/web/client.rb, line 396 def _call_index_lookup(env) env['icfs.page'] = 'Index Lookup' api = env['icfs'] _verb_get(env) # query required if env['QUERY_STRING'].empty? raise(Error::Interface, 'Query string required') end # do the query query = _util_get_query(env, QueryIndex) resp = api.index_search(query) first = resp[:list][0] # raw rack return if first body = { 'index' => first[:object][:index], 'title' => first[:object][:title], } else body = { 'index' => nil } end body = JSON.generate(body) head = { 'Content-Type' => 'application/json', 'Content-Length' => body.bytesize.to_s } return [200, head, [body]] end
Info page
# File lib/icfs/web/client.rb, line 221 def _call_info(env) env['icfs.page'] = 'Info' api = env['icfs'] _verb_get(env) body = [ _div_nav(env), _div_desc('User Info', ''), _div_info(env), _div_desc('Config Info', ''), _div_config(env), ].join('') return _resp_success(env, body) end
Display a Log
# File lib/icfs/web/client.rb, line 913 def _call_log(env) env['icfs.page'] = 'Log View' api = env['icfs'] _verb_get(env) cid = _util_case(env) lnum = _util_num(env, 2) raise(Error::Interface, 'No log requested') if lnum == 0 log = api.log_read(cid, lnum) body = [ _div_nav(env), _div_desc('View Log', ''), _div_log(env, log) ].join('') return _resp_success(env, body) end
Common search, tags, stats code
# File lib/icfs/web/client.rb, line 239 def _call_search(env, page, type, query_get, list, api_meth, page_proc) env['icfs.page'] = page api = env['icfs'] _verb_get(env) act = '%s/%s' % [env['SCRIPT_NAME'], env['icfs.cmps'][0]] # form if env['QUERY_STRING'].empty? body = [ _div_nav(env), _div_desc(type, ''), _form_query(env, query_get, {}, act, true) ] # do the query else query = _util_get_query(env, query_get) resp = api.send(api_meth, query) if query[:caseid] env['icfs.cid' ] = query[:caseid] end body = [ _div_nav(env), _div_query(env, type, query_get, resp[:query]), _form_query(env, query_get, resp[:query], act), _div_list(env, resp, list), ] if page_proc body << _div_page(resp, page_proc) end end return _resp_success(env, body.join('')) end
Action div
# File lib/icfs/web/client.rb, line 2472 def _div_action(env, act) api = env['icfs'] cid = act['caseid'] # get perms & user/roles al = api.access_list(act['caseid']) perm_act = al.include?(ICFS::PermAction) ur = Set.new ur.add api.user ur.merge api.roles links = [] anum = act['action'] links << _a_action_edit(env, cid, anum, 'Edit this Action') lnum = act['log'] links << _a_log_search(env, { 'caseid' => cid, 'action' => anum, 'purpose' => 'Action History', }, 'History of Action') links << _a_entry_edit(env, cid, 0, anum, 'New Entry in Action') # each task tasks = [] ta = act['tasks'] ta.each_index do |ixr| ix = ixr + 1 tk = ta[ixr] # if we can edit edit = (ixr == 0) ? perm_act : ur.include?(tk['assigned']) # tags tags = tk['tags'].map do |tg| qu = { assigned: tk['assigned'], tags: tg, } qu[:caseid] = cid if tk['assigned'] == ICFS::UserCase DivActionTag % _a_action_search(env, qu, tg) end tasks << DivActionTask % [ edit ? 'task-ed' : 'task-ro', Rack::Utils.escape_html(tk['assigned']), Rack::Utils.escape_html(tk['title']), tk['status'] ? 'Open' : 'Closed', tk['flag'] ? 'Raised' : 'Normal', ICFS.time_weekday(tk['time'], api.config), tags.join(''), ] end return DivAction % [ _a_case(env, cid, 0, cid), _a_action(env, cid, anum, 0, anum.to_s), _a_log(env, cid, lnum, lnum.to_s), links.map{|lk| DivActionLink % lk }.join(''), tasks.join('') ] end
Case div
# File lib/icfs/web/client.rb, line 1897 def _div_case(env, cse) api = env['icfs'] urg = api.urg cid = cse['caseid'] al = api.access_list(cid) status = cse['status'] ? 'Open' : 'Closed' template = cse['template'] ? 'Yes' : 'No' # case links links = [ _a_log_search(env, {caseid: cid, case_edit: true}, 'History of Case'), _a_log_search(env, {caseid: cid}, 'All Logs'), ] if al.include?(ICFS::PermManage) links << _a_case_edit(env, cid, 'Edit This Case') if cse['template'] links << _a_case_create(env, cid, 'Create New Case') end end links.map!{|aa| DivCaseLink % aa} # action section if al.include?(ICFS::PermAction) now = Time.now.to_i actions = [ _a_action_edit(env, cid, 0, 'New Action'), _a_action_search(env, { caseid: cid, assigned: ICFS::UserCase, status: true, flag: true, purpose: 'Flagged Actions', }, 'List flagged'), _a_action_search(env, { caseid: cid, assigned: ICFS::UserCase, status: true, before: now, sort: 'time_asc', purpose: 'Actions - Past Date', }, 'List past'), _a_action_search(env, { caseid: cid, assigned: ICFS::UserCase, status: true, after: now, sort: 'time_desc', purpose: 'Actions - Future Date', }, 'List future'), _a_action_search(env, { caseid: cid, assigned: ICFS::UserCase, status: true, purpose: 'Open Actions', }, 'List open'), _a_action_tags(env, { caseid: cid, assigned: ICFS::UserCase, status: true, purpose: 'Open Action Tags', }, 'Action tags'), ].map{|lk| DivCaseLink % lk} actions = DivCaseActions % actions.join('') else actions = '' end # tags tags = cse['tags'].map do |tg| DivCaseTag % _a_case_search(env, {tags: tg}, Rack::Utils.escape_html(tg) ) end # access control acc = cse['access'].map do |ac| pm = Rack::Utils.escape_html(ac['perm']) ugl = ac['grant'].map do |ug| DivCaseGrant % Rack::Utils.escape_html(ug) end DivCaseAccess % [ pm, ugl.join('') ] end # stats if cse['stats'] stats = cse['stats'].map do |st| DivCaseStatEach % _a_entry_search(env, { caseid: cid, stat: st, purpose: 'Entries with Stat' }, Rack::Utils.escape_html(st) ) end stats = DivCaseStats % stats.join('') else stats = '' end return DivCase % [ Rack::Utils.escape_html(cid), _a_log(env, cid, cse['log'], cse['log'].to_s), status, template, links.join(''), Rack::Utils.escape_html(cse['title']), acc.join(''), tags.join(''), stats, actions, ] end
Config
div
# File lib/icfs/web/client.rb, line 1171 def _div_config(env) api = env['icfs'] cfg = api.config items = cfg.setup.map do |key, opt| DivConfigItem % [ opt[:name], opt[:display], _util_config(cfg, key, cfg.get(key)) ] end return DivConfig % items.join('') end
Page
description div
# File lib/icfs/web/client.rb, line 1598 def _div_desc(head, body) DivDesc % [ head, body ] end
Entry div
# File lib/icfs/web/client.rb, line 2097 def _div_entry(env, ent) api = env['icfs'] cid = ent['caseid'] links = [] enum = ent['entry'] links << _a_entry_edit(env, cid, enum, 0, 'Edit This Entry') lnum = ent['log'] links << _a_log_search(env, { 'caseid' => cid, 'entry' => enum, 'purpose' => 'History of Entry', }, 'History of Entry') if ent['action'] anum = ent['action'] action = DivEntryAction % _a_action(env, cid, anum, 0, anum.to_s) links << _a_entry_edit(env, cid, 0, anum, 'New Entry in Action') else action = '' end if ent['index'] indexes = ent['index'].map do |xnum| idx = api.index_read(cid, xnum) DivEntryIndexEach % _a_index(env, cid, xnum, 0, idx['title']) end index = DivEntryIndex % indexes.join('') else index = '' end tags = ent['tags'].map do |tag| DivEntryTag % _a_entry_search(env, { 'caseid' => cid, 'tags' => tag, 'purpose' => 'Tag Entries', }, tag) end if ent['perms'] pa = ent['perms'].map do |pm| DivEntryPermEach % Rack::Utils.escape_html(pm) end perms = DivEntryPerms % pa.join("\n") else perms = '' end if ent['stats'] sa = ent['stats'].map do |st| ca = st['credit'].map do |ug| Rack::Utils.escape_html(ug) end DivEntryStatEach % [ Rack::Utils.escape_html(st['name']), st['value'], ca.join(', ') ] end stats = DivEntryStats % sa.join("\n") else stats = '' end if ent['files'] fa = ent['files'].map do |fd| DivEntryFileEach % _a_file(env, cid, enum, fd['log'], fd['num'], fd['name'], fd['name']) end files = DivEntryFiles % fa.join("\n") else files = '' end return DivEntry % [ _a_case(env, cid, 0, cid), _a_entry(env, cid, enum, 0, enum.to_s), _a_log(env, cid, lnum, lnum.to_s), Rack::Utils.escape_html(ent['user']), action, links.map{|lk| DivEntryLink % lk }.join(''), Rack::Utils.escape_html(ent['title']), ICFS.time_weekday(ent['time'], api.config), Rack::Utils.escape_html(ent['content']), tags.join("\n"), index, perms, stats, files ] end
Form div
@param env [Hash] Rack environment @param path [String] the path to submit @param cid [String, NilClass] case ID @param parts [Array<String>] the form sections @param button [String] the submit button text
# File lib/icfs/web/client.rb, line 1874 def _div_form(env, path, cid, parts, button) spath = env['SCRIPT_NAME'] + path spath += Rack::Utils.escape(cid) if cid return DivForm % [ spath, parts.join(''), button, ] end
Home div
# File lib/icfs/web/client.rb, line 1697 def _div_home(env) api = env['icfs'] # get the user & roles ur = [ api.user ] ur.concat api.roles now = Time.now.to_i # actions useract = ur.map do |ug| cl = [ _a_case_search(env, { grantee: ug, status: true, template: false, purpose: 'Open Cases' }, 'open'), _a_case_search(env, { grantee: ug, status: false, template: false, purpose: 'Closed Cases' }, 'closed'), _a_case_search(env, { grantee: ug, perm: ICFS::PermAction, status: true, template: false, purpose: 'Action Manager Cases' }, 'action mgr'), _a_case_tags(env, { grantee: ug, status: true, template: false, purpose: 'Open Case Tags' }, 'tags'), ].map{|lk| DivHomeLink % lk }.join('') al = [ _a_action_search(env, { assigned: ug, status: true, flag: true, purpose: 'Flagged Actions' }, 'flagged'), _a_action_search(env, { assigned: ug, status: true, before: now, sort: 'time_asc', purpose: 'Actions - Past Date', }, 'past'), _a_action_search(env, { assigned: ug, status: true, after: now, sort: 'time_desc', purpose: 'Actions - Future Date', }, 'future'), _a_action_search(env, { assigned: ug, status: true, purpose: 'Open Actions' }, 'all open'), _a_action_tags(env, { assigned: ug, status: true, purpose: 'Open Action Tags' }, 'tags'), ].map{|lk| DivHomeLink % lk }.join('') ol = [ _a_case_search(env, { grantee: ug, perm: ICFS::PermManage, status: true, template: false, purpose: 'Managed Cases', }, 'managed'), _a_case_search(env, { grantee: ug, perm: ICFS::PermManage, status: true, template: true, purpose: 'Templates', }, 'templates'), _a_stats(env, { credit: ug, after: Time.now.to_i - 60*60*24*30, purpose: 'User/Role Stats - 30 days', }, '30-day stats'), ].map{|lk| DivHomeLink % lk }.join('') DivHomeUr % [Rack::Utils.escape_html(ug), al, cl, ol ] end DivHome % useract.join('') end
Index div
# File lib/icfs/web/client.rb, line 2611 def _div_index(env, idx) cid = idx['caseid'] links = [] xnum = idx['index'] links << _a_index_edit(env, cid, xnum, 'Edit This Index') lnum = idx['log'] links << _a_log_search(env, { 'caseid' => cid, 'index' => xnum, 'purpose' => 'Index History', }, 'History of Index') tags = idx['tags'].map do |tg| DivIndexTag % _a_index_search(env, { 'caseid' => cid, 'tags' => tg, 'purpose' => 'Index Entries', }, tg) end return DivIndex % [ _a_case(env, cid, 0, cid), _a_index(env, cid, xnum, 0, xnum.to_s), _a_log(env, cid, lnum, lnum.to_s), links.map{|lk| DivIndexLink % lk }.join(''), Rack::Utils.escape_html(idx['title']), Rack::Utils.escape_html(idx['content']), tags.join(''), ] end
Info div
# File lib/icfs/web/client.rb, line 1205 def _div_info(env) api = env['icfs'] tz = api.config.get('tz') # roles/groups/perms roles = api.roles.map{|rol| DivInfoList % Rack::Utils.escape_html(rol)} grps = api.groups.map{|grp| DivInfoList % Rack::Utils.escape_html(grp)} perms = api.perms.map{|pm| DivInfoList % Rack::Utils.escape_html(pm)} # global stats gstats = api.gstats.map{|st| DivInfoList % Rack::Utils.escape_html(st)} return DivInfo % [ Rack::Utils.escape_html(api.user), roles.join(''), grps.join(''), perms.join(''), gstats.join(''), ] end
Search results list div
@param env [Hash] Rack environment @param resp [Hash] Search response @param list [Array] List of object items to display and how
# File lib/icfs/web/client.rb, line 1293 def _div_list(env, resp, list) return _div_msg(env, 'No results found') if resp[:list].size == 0 # did we query with caseid? qcid = resp[:query].key?(:caseid) # copy the query qu = resp[:query].dup # header row hcols = list.map do |sym, opt| if sym == :caseid && qcid '' else DivListHeadItems[sym] end end head = DivListHead % hcols.join('') # do we do relative times? cfg = env['icfs'].config rel_time = cfg.get('rel_time') # search results into rows rows = resp[:list].map do |sr| obj = sr[:object] cid = obj[:caseid] cols = list.map do |sym, opt| it = obj[sym] cc = ListColClass[sym] ct = nil # snippets are special non-column, not in the object itself if sym == :snippet if sr[:snippet] next( DivListItem % ['list-snip', sr[:snippet]]) else next('') end # redacted result elsif it.nil? next( DivListItem % [cc, '—']) end # normal result case sym # snippets - a special non-column, not in the object itself when :snippet if sr[:snippet] cd = sr[:snippet] else cd = nil end # entry when :entry case opt when :current cd = _a_entry(env, cid, it, 0, it.to_s) when :log cd = (it != 0) ? _a_entry(env, cid, it, obj[:log], it.to_s) : '' else cd = it.to_s end # action when :action case opt when :current cd = (it == 0) ? '' : _a_action(env, cid, it, 0, it.to_s) when :log cd = (it != 0) ? _a_action(env, cid, it, obj[:log], it.to_s) : '' else cd = it == 0 ? '' : it.to_s end # index when :index case opt when :current cd = _a_index(env, cid, it, 0, it.to_s) when :log if it != 0 cd = _a_index(env, cid, it, obj[:log], it.to_s) else cd = '' end else cd = it.to_s end # case when :case case opt when :log cd = (it != 0) ? _a_case(env, cid, obj[:log], 'Y') : '' else cd = '' end # indexes when :indexes cd = (it == 0) ? '' : it.to_s # log when :log case opt when :link cd = _a_log(env, cid, it, it.to_s) else cd = it.to_s end # tags when :tags if it.size == 1 && it[0] == ICFS::TagNone cd = '' else cd = it.size.to_s end # tag - the result of a tags aggregation when :tag qu[:tags] = it case opt when :entry qu[:purpose] = 'Entry Tag Search' cd = _a_entry_search(env, qu, it) when :index qu[:purpose] = 'Index Tag Search' cd = _a_index_search(env, qu, it) when :case qu[:purpose] = 'Case Tag Search' cd = _a_case_search(env, qu, it) when :action qu[:purpose] = 'Action Tag Search' cd = _a_action_search(env, qu, it) end # time when :time if rel_time tme = ICFS.time_relative(it) ct = ICFS.time_weekday(it, cfg) else tme = ICFS.time_weekday(it, cfg) end case opt when :entry cd = _a_entry(env, cid, obj[:entry], 0, tme) when :log cd = _a_log(env, cid, obj[:log], tme) else cd = tme end # title when :title case opt when :entry cd = _a_entry(env, cid, obj[:entry], 0, it) when :action cd = _a_action(env, cid, obj[:action], 0, it) when :case cd = _a_case(env, cid, 0, it) when :index cd = _a_index(env, cid, obj[:index], 0, it) when :action cd = _a_action(env, cid, obj[:action], 0, it) else cd = Rack::Utils.escape_html(it) end # caseid when :caseid case opt when :current cd = _a_case(env, it, 0, it) when :mixed cd = qcid ? nil : _a_case(env, it, 0, it) else cd = Rack::Utils.escape_html(cid) end # stat - only on stats aggregation when :stat qu[:stat] = it qu[:purpose] = 'Entry Stat Search' cd = _a_entry_search(env, qu, it) # sum - only on stats aggregation when :sum cd = it.to_s # count - only on stats aggregation when :count cd = it.to_s # files when :files cd = it == 0 ? '' : it.to_s # user when :user cd = Rack::Utils.escape_html(it) # stats when :stats cd = it == 0 ? '' : it.to_s # huh? else raise NotImplementedError, sym.to_s end if cd if ct DivListItemTitle % [cc, ct, cd] else DivListItem % [cc, cd] end else '' end end DivListRow % cols.join('') end return DivList % [head, rows.join('')] end
Log div
# File lib/icfs/web/client.rb, line 2309 def _div_log(env, log) cid = log['caseid'] lnum = log['log'] navp = (lnum == 1) ? 'prev' : _a_log(env, cid, lnum-1, 'prev') navn = _a_log(env, cid, lnum + 1, 'next') if log['case'] chash = DivLogCase % _a_case(env, cid, lnum, log['case']['hash']) else chash = '' end if log['entry'] enum = log['entry']['num'] entry = DivLogEntry % [ _a_entry(env, cid, enum, lnum, log['entry']['hash']), enum ] else entry = '' end if log['action'] action = DivLogAction % [ _a_action(env, cid, log['action']['num'], lnum, log['action']['hash']), log['action']['num'], ] else action = '' end if log['index'] index = DivLogIndex % [ _a_index(env, cid, log['index']['num'], lnum, log['index']['hash']), log['index']['num'], ] else index = '' end if log['files_hash'] ha = log['files_hash'] fa = [] ha.each_index do |ix| fa << DivLogFileEach % [ _a_file(env, cid, enum, lnum, ix, 'file.bin', ha[ix]), ix ] end files = DivLogFiles % fa.join("\n") else files = '' end return DivLog % [ Rack::Utils.escape_html(cid), log['log'], navp, navn, ICFS.time_weekday(log['time'], env['icfs'].config), Rack::Utils.escape_html(log['user']), log['prev'], entry, chash, action, index, files ] end
Message div
# File lib/icfs/web/client.rb, line 1158 def _div_msg(env, msg) DivMsg % msg end
Page
navigation div
@param resp [Array<Hash>] search results @param pr [Proc] A Proc which is called instead of yield @yield [query, disp] the query to run and what to display @yieldparam query [Hash] the query to execute @yieldparam disp [String] what to display in the link @yieldreturn [String] the HTML link for the query page @return [String] a HTML div for page nav
# File lib/icfs/web/client.rb, line 1621 def _div_page(resp, pr=nil) hits = resp[:hits] page_size = resp[:size] tot_pages = ((hits - 1) / page_size) + 1 disp_pages = (tot_pages > 10) ? 10 : tot_pages query = resp[:query].dup if query.key?(:page) cur = query[:page].to_i else cur = 1 end if cur > disp_pages cur = disp_pages end # numeric links ary = [] disp_pages.times do |pg| page = pg + 1 if page == cur ary << '<b>%d</b>' % page else query[:page] = page if pr val = pr.call(query, page.to_s) else val = yield(query, page.to_s) end ary << val end end # previous if cur == 1 prev_page = '' else query[:page] = cur - 1 if pr prev_page = pr.call(query, '(Prev)') else prev_page = yield(query, '(Prev)') end end # next if cur == disp_pages next_page = '' else query[:page] = cur + 1 if pr next_page = pr.call(query, '(Next)') else next_page = yield(query, '(Next)') end end return DivPage % [ prev_page, ary.join(' '), next_page, hits, tot_pages ] end
Description div for queries
# File lib/icfs/web/client.rb, line 2691 def _div_query(env, type, sup, query, disp=false) cfg = env['icfs'].config # query purpose if query[:purpose] purp = Rack::Utils.escape_html(query[:purpose]) else purp = type end # display the query parameters list = [] sup.each do |txt, sym, pr| next if !query.key?(sym) || (sym == :purpose) || (sym == :page) val = query[sym] case pr when :string para = Rack::Utils.escape_html(val) when :boolean para = val ? 'true' : 'false' when :integer para = val.to_s when :time para = ICFS.time_local(val, cfg) else raise NotImplementedError, pr.to_s end list << '<i>%s:</i> %s' % [sym, para] end if list.empty? paras = '' else paras = ' – ' + list.join(', ') end # enable value value = disp ? 'true' : 'false' return _div_desc(purp, DivQuery % [ type, paras, value ]) end
Action form
# File lib/icfs/web/client.rb, line 3494 def _form_action(env, cid, act = nil) api = env['icfs'] cfg = api.config # new action if !act ta = [{ 'assigned' => ICFS::UserCase, 'title' => '', 'status' => true, 'flag' => true, 'time' => nil, 'tags' => [ ICFS::TagNone ], }] else ta = act['tasks'] end # get perms al = api.access_list(cid) perm_act = al.include?(ICFS::PermAction) if !perm_act && !act raise(Error::Perms, 'Missing perm: %s' % ICFS::PermAction) end # get user/group list ur = Set.new ur.add api.user ur.merge api.roles # each task tasks = [] ta.each_index do |ixr| ix = ixr + 1 tk = ta[ixr] # figure out if we can edit if ixr == 0 edit = perm_act else edit = ur.include?(tk['assigned']) end # never edit the tasked esc = Rack::Utils.escape_html(tk['assigned']) ug = FormActionTaskedRo % [ ix, esc, esc ] # can edit it if edit title = FormActionTitleEd % [ ix, Rack::Utils.escape_html(tk['title']) ] status = FormActionStatusEd % [ ix, tk['status'] ? ' checked' : '' ] flag = FormActionFlagEd % [ ix, tk['flag'] ? ' checked' : '' ] if tk['time'] time = FormActionTimeEd % [ ix, ICFS.time_local(tk['time'], cfg) ] else time = FormActionTimeEd % [ix, ''] end if tk['tags'][0] == ICFS::TagNone tags_cnt = 1 tags = FormActionTagEd % [ix, 1, ''] else tags_cnt = 0 tags = tk['tags'].map do |tg| tags_cnt = tags_cnt + 1 FormActionTagEd % [ ix, tags_cnt, Rack::Utils.escape_html(tg) ] end tags = tags.join('') end tag_list = 'act-%d-tag-list' % ix tag_add = FormActionTagButton % tag_list # can't edit else esc = Rack::Utils.escape_html(tk['title']) title = FormActionTitleRo % [ ix, esc, esc ] status = FormActionStatusRo % [ ix, tk['status'] ? 'true' : 'false', tk['status'] ? 'Open' : 'Closed', ] if tk['flag'] flag = FormActionFlagRo % ix else flag = FormActionFlagEd % [ ix, '' ] end esc = ICFS.time_local(tk['time'], cfg) time = FormActionTimeRo % [ ix, esc, esc ] tags_cnt = 0 if tk['tags'][0] != ICFS::TagNone tags = tk['tags'].map do |tg| tags_cnt = tags_cnt + 1 esc = Rack::Utils.escape_html(tg) FormActionTagRo % [ ix, tags_cnt, esc, esc ] end tags = tags.join('') else tags = '' end tag_add = '' end tasks << FormActionTask % [ edit ? 'ed' : 'ro', ug, title, status, flag, time, ix, ix, tags_cnt, tags, tag_add ] end return FormAction % [ act ? act['action'] : 0, tasks.size, act ? act['action'] : 0, tasks.join('') ] end
Case form
# File lib/icfs/web/client.rb, line 2914 def _form_case(env, cse) status = ' checked' if cse['status'] # tags tags_cnt = 0 if cse['tags'][0] != ICFS::TagNone tags_list = cse['tags'].map do |tg| tags_cnt = tags_cnt + 1 FormCaseTag % [ tags_cnt, Rack::Utils.escape_html(tg) ] end tags = tags_list.join('') else tags = '' end # stats stats_cnt = 0 if cse['stats'] stats_list = cse['stats'].map do |st| stats_cnt += 1 FormCaseStat % [stats_cnt, Rack::Utils.escape_html(st)] end stats = stats_list.join('') else stats = '' end # access acc_cnt = 0 acc_list = cse['access'].map do |ad| acc_cnt = acc_cnt + 1 grant_cnt = 0 grants = ad['grant'].map do |ug| grant_cnt = grant_cnt + 1 FormCaseGrant % [ acc_cnt, grant_cnt, Rack::Utils.escape_html(ug) ] end FormCaseAccess % [ acc_cnt, grant_cnt, acc_cnt, Rack::Utils.escape_html(ad['perm']), grants.join(''), ] end return FormCase % [ Rack::Utils.escape_html(cse['title']), status, tags_cnt, tags, acc_cnt, acc_list.join(''), stats_cnt, stats, ] end
Config
Form
# File lib/icfs/web/client.rb, line 3864 def _form_config(env) cfg = env['icfs'].config items = cfg.setup.map do |key, opt| input = opt[:input] input_string = case input[0] when :text '<input class="%s" name="%s" type="text" value="%s">' % [ input[1], opt[:label], cfg.set?(key) ? Rack::Utils.escape_html(cfg.get(key)) : '' ] when :boolean '<input class="form-boolean" name="%s" type="text" value="%s">' % [ opt[:label], cfg.set?(key) ? (cfg.get(key) ? 'true' : 'false') : '' ] when :select items = [ '<option value=""></option>' ] cur = cfg.set?(key) ? cfg.get(key) : false input[3].each do |it| sel = (it[0] == cur) ? ' selected' : '' items << '<option value="%s"%s>%s</option>' % [it[0], sel, it[1]] end '<select class="%s" name="%s">%s</select>' % [ input[1], input[2], items.join('') ] else raise(ArgumentError, 'Invalid Config setup') end FormConfigItem % [ opt[:name], input_string, opt[:tip], _util_config(cfg, key, cfg.default(key)) ] end return FormConfig % items.join('') end
Case Create Form
# File lib/icfs/web/client.rb, line 1831 def _form_create(env) [ FormCaseCreate, '' ] end
New entry form
@param env [Hash] Rack enviornment @param cid [String] caseid @param ent [Hash] the Entry @param opts [Hash] options @option opts [Integer] The action num @option opts [Boolean] :no_index Does not display indexe
# File lib/icfs/web/client.rb, line 3102 def _form_entry(env, cid, ent=nil, opts={}) api = env['icfs'] # title if ent && ent['title'] title = Rack::Utils.escape_html(ent['title']) else title = '' end # time if ent && ent['time'] time = ICFS.time_local(ent['time'], api.config) else time = '' end # action if opts[:action] anum = opts[:action] elsif ent && ent['action'] anum = ent['action'] else anum = 0 end # content if ent && ent['content'] content = Rack::Utils.escape_html(ent['content']) else content = '' end # files files_cnt = 0 files_list = [] if ent && ent['files'] ent['files'].each do |fd| files_cnt = files_cnt + 1 files_list << FormEntryFileEach % [ files_cnt, Rack::Utils.escape_html(fd['name']), files_cnt, files_cnt, fd['num'], fd['log'] ] end files = files_list.join("\n") else files = '' end # tags tags_cnt = 0 if ent && ent['tags'][0] != ICFS::TagNone tags_list = ent['tags'].map do |tg| tags_cnt = tags_cnt + 1 FormEntryTagEach % [tags_cnt, Rack::Utils.escape_html(tg)] end tags = tags_list.join('') else tags = '' end # indexes index_cnt = 0 if opts[:no_index] index = '' elsif ent && ent['index'] idx_list = ent['index'].map do |xnum| index_cnt += 1 idx = api.index_read(cid, xnum, 0) FormEntryIndexEach % [ index_cnt, xnum, Rack::Utils.escape_html(idx['title']) ] end index = idx_list.join('') else index = '' end # stats select stats_sel = api.stats_list(cid).to_a.sort.map do |stat| esc = Rack::Utils.escape_html(stat) FormEntryStatOpt % [esc, esc] end stats_sel = FormEntryStatSel % stats_sel.join('') # stats count & list stats_cnt = 0 stats_list = [] if ent && ent['stats'] stats_list = ent['stats'].map do |st| stats_cnt = stats_cnt + 1 claim_cnt = 0 claims = st['credit'].map do |ug| claim_cnt = claim_cnt + 1 FormEntryClaim % [stats_cnt, claim_cnt, Rack::Utils.escape_html(ug)] end esc = Rack::Utils.escape_html(st['name']) FormEntryStatEach % [ stats_cnt, claim_cnt, stats_cnt, esc, esc, stats_cnt, st['value'].to_s, claims.join('') ] end stats = stats_list.join('') else stats = '' end # perms select al = env['icfs'].access_list(cid) perms_sel = al.sort.map do |pm| esc = Rack::Utils.escape_html(pm) FormEntryPermOpt % [esc, esc] end perms_sel = perms_sel.join('') # perms count & list perms_cnt = 0 if ent && ent['perms'] perms_list = ent['perms'].map do |pm| perms_cnt = perms_cnt + 1 esc = Rack::Utils.escape_html(pm) FormEntryPermEach % [esc, perms_cnt, esc] end perms = perms_list.join('') else perms = '' end # do index if opts[:no_index] index = '' else index = FormEntryIndex % [ env['SCRIPT_NAME'], Rack::Utils.escape(cid), index_cnt, index, ] end return FormEntry % [ opts[:enable] ? 'true' : 'false', ent ? ent['entry'] : 0, anum, opts[:enable] ? '' : FormEntryEnable, opts[:enable] ? '' : ' hidden', title, time, content, tags_cnt, tags, files_cnt, files, index, stats_sel, stats_cnt, stats, perms_sel, perms_cnt, perms ] end
Index form
# File lib/icfs/web/client.rb, line 3772 def _form_index(env, cid, idx=nil) # title if idx && idx['title'] title = Rack::Utils.escape_html(idx['title']) else title = '' end # content if idx && idx['content'] content = Rack::Utils.escape_html(idx['content']) else content = '' end # tags tags_cnt = 0 if idx && idx['tags'][0] != ICFS::TagNone tags_list = idx['tags'].map do |tg| tags_cnt += 1 FormIndexTagEach % [tags_cnt, Rack::Utils.escape_html(tg)] end tags = tags_list.join('') else tags = '' end return FormIndex % [ idx ? idx['index'] : 0, title, content, tags_cnt, tags ] end
Query form
# File lib/icfs/web/client.rb, line 2756 def _form_query(env, sup, query, act, disp=false) cfg = env['icfs'].config # supported params inputs = sup.map do |txt, sym, pr| case sym when :caseid ilabel = 'Case ID' iclass = 'form-caseid' ihint = 'Filter for a specific case.' when :title ilabel = 'Title' iclass = 'form-title' ihint = 'Text search within the title.' when :prefix ilabel = 'Prefix' iclass = 'form-title' ihint = 'Filter for titles starting with fixed text.' when :content ilabel = 'Content' iclass = 'form-content' ihint = 'Text search within the content.' when :tags ilabel = 'Tag' iclass = 'form-tag' ihint = 'Filter for only a specific tag.' when :action ilabel = 'Action' iclass = 'form-int' ihint = 'Filter for a specific action (by number).' when :before ilabel = 'Before' iclass = 'form-time' ihint = 'Filter for items occuring before this date and time.' when :after ilabel = 'After' iclass = 'form-time' ihint = 'Filter for items occuring after this date and time.' when :credit ilabel = 'Credit' iclass = 'form-usergrp' ihint = 'Filter for stats crediting this user or role.' when :size ilabel = 'Size' iclass = 'form-int' ihint = 'Number of results to be returned per page.' when :page next when :sort ilabel = 'Sort' iclass = 'form-sort' ihint = 'How to sort the results.' when :purpose next when :user ilabel = 'User' iclass = 'form-usergrp' ihint = 'Filter for logs authored by this user.' when :grantee ilabel = 'Grantee' iclass = 'form-usergrp' ihint = 'Filter for cases granting this user or role a permission.' when :perm ilabel = 'Permission' iclass = 'form-perm' ihint = 'Filter for cases granting this permission.' when :case_edit ilabel = 'Case edited' iclass = 'form-boolean' ihint = 'Filter for logs recoding a case.' when :entry ilabel = 'Entry' iclass = 'form-int' ihint = 'Filter for logs recording specified entry (by number).' when :index ilabel = 'Index' iclass = 'form-int' ihint = 'Filter for specified index (by number).' when :assigned ilabel = 'Assigned' iclass = 'form-usergrp' ihint = 'Filter for tasks assigned to specified user or role.' when :status ilabel = 'Status' iclass = 'form-boolean' ihint = 'Filter for open items. Use true or false.' when :flag ilabel = 'Flag' iclass = 'form-boolean' ihint = 'Filter for flagged tasks. Use true or false.' when :template ilabel = 'Template' iclass = 'form-boolean' ihint = 'Filter for template cases. Use true or false.' when :stat ilabel = 'Stat' iclass = 'form-boolean' ihint = 'Filter for stats by name. Use true or false.' else raise NotImplementedError, sym.to_s end case pr when :string itype = 'text' ivalue = query[sym] || '' when :boolean itype = 'text' if query[sym].nil? ivalue = '' else ivalue = query[sym] ? 'true' : 'false' end when :integer itype = 'text' ivalue = query[sym] ? query[sym].to_s : '' when :time itype = 'text' ivalue = query[sym] ? ICFS.time_local(query[sym], cfg) : '' else raise NotImplementedError, pr.to_s end FormQueryItem % [ilabel, txt, iclass, itype, ivalue, ihint] end # display the form formClass = disp ? '' : ' hidden' return FormQuery % [ formClass, act, inputs.join('') ] end
Action edit
# File lib/icfs/web/client.rb, line 4160 def _post_action(env, para) act = {} # action anum = para['act-num'].to_i act['action'] = anum if anum != 0 # tasks tasks = [] acnt = para['act-cnt'].to_i raise(Error::Interface, 'Too many tasks') if(acnt > 100) acnt.times do |ix| tx = 'act-%d' % [ix + 1] ug = para[tx + '-task'] next if ug.nil? || ug.empty? title = para[tx + '-title'] status = (para[tx + '-status'] == 'true') ? true : false flag = (para[tx + '-flag'] == 'true') ? true : false tstr = para[tx + '-time'] time = _util_time_parse(env, tstr) tags = [] tcnt = para[tx + '-tag'].to_i raise(Error::Interface, 'Too many tags') if (tcnt > 100) tcnt.times do |gx| tag = para[tx + '-tag-%d' % [gx + 1]] next if !tag || tag.empty? tags << tag end if tags.empty? tags = [ ICFS::TagNone ] else tags = tags.uniq.sort end tk = { 'assigned' => ug, 'title' => title, 'time' => time, 'status' => status, 'flag' => flag, 'tags' => tags } tasks << tk end act['tasks'] = tasks return act end
Case edit
# File lib/icfs/web/client.rb, line 3942 def _post_case(env, para) # case object cse = {} # title cse['title'] = para['cse-title'] # status cse['status'] = (para['cse-status'] == 'true') ? true : false # tags tags = [] tcnt = para['cse-tag'].to_i if tcnt > 100 raise(Error::Interface, 'Tag count too large') end tcnt.times do |ix| tx = 'cse-tag-%d' % [ix + 1] tag = para[tx] next if !tag || tag.empty? tags << tag end if tags.empty? cse['tags'] = [ ICFS::TagNone ] else cse['tags'] = tags.uniq.sort end # access acc = [] acnt = para['cse-acc-cnt'].to_i if acnt > 100 raise(Error::Interface, 'Access count too large') end acnt.times do |ix| ixr = ix + 1 pnam = para['cse-acc-%d-perm' % ixr] gcnt = para['cse-acc-%d' % ixr].to_i next if gcnt == 0 || !pnam || pnam.empty? grant = [] if gcnt > 100 raise(Error::Interface, 'Grant count too large') end gcnt.times do |gx| sug = para['cse-acc-%d-%d' % [ixr, gx+1]] next if !sug || sug.empty? grant << sug end next if grant.empty? acc << { 'perm' => pnam, 'grant' => grant } end cse['access'] = acc # stats stats = [] scnt = para['cse-stat'].to_i if scnt > 100 raise(Error::Interface, 'Stat count too large') end scnt.times do |ix| sx = 'cse-stat-%d' % [ix + 1] stat = para[sx] next if !stat || stat.empty? stats << stat end cse['stats'] = stats unless stats.empty? return cse end
Config
edit
# File lib/icfs/web/client.rb, line 4247 def _post_config(env, para) api = env['icfs'] cfg = api.config vals = {} cfg.setup.each do |key, opt| val = para[opt[:label]] next if val.nil? || val.empty? case opt[:parse] when :text vals[key] = val when :boolean vals[key] = (val.downcase == 'true') ? true : false else raise(ArgumentError, 'Invalid config parser') end end return vals end
Entry edit
# File lib/icfs/web/client.rb, line 4023 def _post_entry(env, para, opts={}) return nil unless para['ent-ena'] == 'true' api = env['icfs'] # entry object ent = {} # entry enum = para['ent-num'].to_i ent['entry'] = enum if enum != 0 # action anum = para['ent-act'].to_i ent['action'] = anum if anum != 0 # time tstr = para['ent-time'] time = _util_time_parse(env, tstr) ent['time'] = time if time # title & content ent['title'] = para['ent-title'] ent['content'] = para['ent-content'] # tags tags = [] tcnt = para['ent-tag'].to_i raise(Error::Interface, 'too many tags') if(tcnt > 100) tcnt.times do |ix| tx = 'ent-tag-%d' % [ix + 1] tag = para[tx] tags << tag unless( !tag || tag.empty? ) end ent['tags'] = tags.uniq.sort unless tags.empty? # indexes unless opts[:no_index] index = [] icnt = para['ent-idx-cnt'].to_i raise(Error::Interface, 'Too many indexes') if(icnt > 100) icnt.times do |ix| tx = 'ent-idx-%d' % (ix + 1) xnum = para[tx].to_i index << xnum unless xnum == 0 end ent['index'] = index.uniq.sort unless index.empty? end # perms perms = [] pcnt = para['ent-perm-cnt'].to_i raise(Error::Interface, 'Too many perms') if(pcnt > 100) pcnt.times do |ix| px = 'ent-perm-%d' % [ix + 1] pm = para[px] next if !pm || pm.empty? perms << pm end ent['perms'] = perms unless perms.empty? # stats stats = [] scnt = para['ent-stats-cnt'].to_i raise(Error::Interface, 'Too many stats') if(scnt > 100) scnt.times do |ix| ixr = ix + 1 sname = para['ent-stat-%d-name' % ixr] sval = para['ent-stat-%d-value' % ixr] next if !sname || !sval || sname.empty? || sval.empty? sval = sval.to_f scred = para['ent-stat-%d' % ixr].to_i sugs = [] raise(Error::Interface, 'Too many credits') if(scred > 100) scred.times do |cx| sug = para['ent-stat-%d-%d' % [ixr, cx + 1]] next if !sug || sug.empty? sugs << sug end next if sugs.empty? stats << { 'name' => sname, 'value' => sval, 'credit' => sugs } end ent['stats'] = stats unless stats.empty? # files files = [] fcnt = para['ent-file-cnt'].to_i raise(Error::Interface, 'Too many files') if(fcnt > 100) fcnt.times do |ix| ixr = ix + 1 fnam = para['ent-file-%d-name' % ixr] fupl = para['ent-file-%d-file' % ixr] fnum = para['ent-file-%d-num' % ixr] if fnum fnum, flog = fnum.split('-').map do |xx| y = xx.to_i (y == 0) ? nil : y end else fnum = nil flog = nil end if fupl && !fupl.empty? ftmp = api.tempfile IO::copy_stream(fupl[:tempfile], ftmp) fnam = fupl[:filename] if fnam.empty? fupl[:tempfile].close! files << { 'temp' => ftmp, 'name' => fnam } elsif fnam && !fnam.empty? && fnum && flog files << { 'num' => fnum, 'log' => flog, 'name' => fnam } end end ent['files'] = files unless files.empty? return ent end
Index edit
# File lib/icfs/web/client.rb, line 4216 def _post_index(env, para) # index object idx = {} # number xnum = para['idx-num'].to_i idx['index'] = xnum if xnum != 0 # title & content idx['title'] = para['idx-title'] idx['content'] = para['idx-content'] # tags tags = [] tcnt = para['idx-tag'].to_i raise(Error::Interface, 'Too many tags') if(tcnt > 100) tcnt.times do |ix| tx = 'idx-tag-%d' % [ix + 1] tag = para[tx] tags << tag unless( !tag | tag.empty? ) end idx['tags'] = tags.uniq.sort unless tags.empty? return idx end
A Rack HTTP response
@param env [Hash] Rack environment @param res [Integer] the HTTP result @param body [Sting] the HTML page body
# File lib/icfs/web/client.rb, line 4726 def _resp(env, res, body) html = Page % [ env['icfs.page'], env['icfs'].config.get('css'), @js, body ] head = { 'Content-Type' => 'text/html; charset=utf-8', 'Content-Length' => html.bytesize.to_s } return [res, head, [html]] end
Bad Request
# File lib/icfs/web/client.rb, line 4765 def _resp_badreq(env, msg) body = _div_nav(env) + _div_msg(env, msg) return _resp(env, 400, body) end
Conflict
# File lib/icfs/web/client.rb, line 4774 def _resp_conflict(env, msg) body = _div_nav(env) + _div_msg(env, msg) return _resp(env, 409, body) end
Forbidden
# File lib/icfs/web/client.rb, line 4792 def _resp_forbidden(env, msg) body = _div_nav(env) + _div_msg(env, msg) return _resp(env, 403, body) end
Not Found
# File lib/icfs/web/client.rb, line 4783 def _resp_notfound(env, msg) body = _div_nav(env) + _div_msg(env, msg) return _resp(env, 404, body) end
Success
# File lib/icfs/web/client.rb, line 4757 def _resp_success(env, body) return _resp(env, 200, body) end
Get the case
# File lib/icfs/web/client.rb, line 4628 def _util_case(env) cmps = env['icfs.cmps'] if cmps.size < 2 || cmps[1].empty? raise(Error::NotFound, 'No case specified in the URL') end cid = Rack::Utils.unescape(cmps[1]) Items.validate(cid, 'case', Items::FieldCaseid) env['icfs.cid'] = cid return cid end
Display the config value
# File lib/icfs/web/client.rb, line 4595 def _util_config(cfg, key, val) opt = cfg.setup(key) case opt[:input][0] when :text return val when :boolean return val ? 'true' : 'false' when :select opt[:input][3].each{|ary| return ary[1] if ary[0] == val } return 'Invalid select option' else raise(ArgumentError, 'Unsupported config display type') end end
Parse a query string
# File lib/icfs/web/client.rb, line 4677 def _util_get_query(env, sup) rck = Rack::Request.new(env) para = rck.GET query = {} # supported parameters sup.each do |txt, sym, proc| val = para[txt] next if !val || val.empty? case proc when :string query[sym] = val when :array query[sym] = val.split(',').map{|aa| aa.strip} when :boolean if val.downcase == 'true' query[sym] = true elsif val == 'false' query[sym] = false end when :integer query[sym] = val.to_i when :time if /^\s*\d+\s*$/.match(val) time = val.to_i else time = _util_time_parse(env, val) end query[sym] = time else raise NotImplementedError end end return query end
Get a number from the URL
# File lib/icfs/web/client.rb, line 4643 def _util_num(env, loc) cmps = env['icfs.cmps'] (cmps.size < (loc+1) || cmps[loc].empty?) ? 0 : cmps[loc].to_i end
Process the POST
# File lib/icfs/web/client.rb, line 4615 def _util_post(env) rck = Rack::Request.new(env) para = rck.POST para.each do |key, val| val.force_encoding('utf-8') if val.is_a?(String) end return para end
Generate query string
# File lib/icfs/web/client.rb, line 4662 def _util_query(query) if query qa = query.map do |key, val| '%s=%s' % [Rack::Utils.escape(key), Rack::Utils.escape(val)] end return '?' + qa.join('&') else return '' end end
Parse a provided time string
# File lib/icfs/web/client.rb, line 4652 def _util_time_parse(env, str) cfg = env['icfs'].config time = ICFS.time_parse(str, cfg) raise(Error::Value, 'Invalid time string') if !time return time end
Require a GET HTTP method
# File lib/icfs/web/client.rb, line 4574 def _verb_get(env) if env['REQUEST_METHOD'] != 'GET' raise(Error::Interface, 'Only GET method allowed') end end
Require a GET or POST method
# File lib/icfs/web/client.rb, line 4584 def _verb_getpost(env) if env['REQUEST_METHOD'] != 'GET' && env['REQUEST_METHOD'] != 'POST' raise(Error::Interface, 'Only GET or POST method allowed') end end