class ICFS::Web::Client

Web Client

Constants

DivAction

Action div

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

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

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

Home Link

DivHomeUr

Home user/role

DivIndex

Index div

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

DivNav

navbar div

DivNavTab

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(js) click to toggle source

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

call(env) click to toggle source

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

_a_action(env, cid, anum, lnum, txt) click to toggle source

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
_a_action_edit(env, cid, anum, txt) click to toggle source

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
_a_action_tags(env, query, txt) click to toggle source

Link to action tags

# File lib/icfs/web/client.rb, line 4381
def _a_action_tags(env, query, txt)
  '<a href="%s/action_tags%s">%s</a>' % [
    env['SCRIPT_NAME'],
    _util_query(query),
    Rack::Utils.escape_html(txt)
  ]
end
_a_case(env, cid, lnum, txt) click to toggle source

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
_a_case_create(env, tid, txt) click to toggle source

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
_a_case_edit(env, cid, txt) click to toggle source

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
_a_case_tags(env, query, txt) click to toggle source

Link to case tags

# File lib/icfs/web/client.rb, line 4358
def _a_case_tags(env, query, txt)
  '<a href="%s/case_tags%s">%s</a>' % [
    env['SCRIPT_NAME'],
    _util_query(query),
    Rack::Utils.escape_html(txt)
  ]
end
_a_config_edit(env, txt) click to toggle source

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
_a_entry(env, cid, enum, lnum, txt) click to toggle source

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
_a_entry_edit(env, cid, enum, anum, txt) click to toggle source

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
_a_entry_search(env, query, txt) click to toggle source

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
_a_entry_tags(env, query, txt) click to toggle source

Link to entry tags

# File lib/icfs/web/client.rb, line 4370
def _a_entry_tags(env, query, txt)
  '<a href="%s/entry_tags/%s">%s</a>' % [
    env['SCRIPT_NAME'],
    _util_query(query),
    Rack::Utils.escape_html(txt),
  ]
end
_a_file(env, cid, enum, lnum, fnum, fname, txt) click to toggle source

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
_a_home(env, txt) click to toggle source

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
_a_index(env, cid, xnum, lnum, txt) click to toggle source

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
_a_index_edit(env, cid, xnum, txt) click to toggle source

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
_a_index_tags(env, query, txt) click to toggle source

Link to action tags

# File lib/icfs/web/client.rb, line 4392
def _a_index_tags(env, query, txt)
  '<a href="%s/index_tags/%s">%s</a>' % [
    env['SCRIPT_NAME'],
    _util_query(query),
    Rack::Utils.escape_html(txt)
  ]
end
_a_info(env, txt) click to toggle source

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
_a_log(env, cid, lnum, txt) click to toggle source

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
_a_stats(env, query, txt) click to toggle source

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
_call_action(env) click to toggle source

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
_call_action_edit(env) click to toggle source

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
_call_case(env) click to toggle source

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
_call_case_create(env) click to toggle source

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
_call_case_edit(env) click to toggle source

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
_call_config_edit(env) click to toggle source

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
_call_entry(env) click to toggle source

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
_call_entry_edit(env) click to toggle source

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
_call_file(env) click to toggle source

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
_call_home(env) click to toggle source

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
_call_index(env) click to toggle source

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
_call_index_edit(env) click to toggle source

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
_call_index_lookup(env) click to toggle source

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
_call_info(env) click to toggle source

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
_call_log(env) click to toggle source

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
_div_action(env, act) click to toggle source

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
_div_case(env, cse) click to toggle source

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
_div_config(env) click to toggle source

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
_div_desc(head, body) click to toggle source

Page description div

# File lib/icfs/web/client.rb, line 1598
def _div_desc(head, body)
  DivDesc % [ head, body ]
end
_div_entry(env, ent) click to toggle source

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
_div_form(env, path, cid, parts, button) click to toggle source

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
_div_home(env) click to toggle source

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
_div_index(env, idx) click to toggle source

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
_div_info(env) click to toggle source

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
_div_list(env, resp, list) click to toggle source

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, '&mdash;'])
      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
_div_log(env, log) click to toggle source

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
_div_msg(env, msg) click to toggle source

Message div

# File lib/icfs/web/client.rb, line 1158
def _div_msg(env, msg)
  DivMsg % msg
end
_div_nav(env) click to toggle source

Navbar div

# File lib/icfs/web/client.rb, line 1072
def _div_nav(env)

  unam = env['icfs'].user
  cid = env['icfs.cid']

  # with case
  if cid
    tc = _a_case(env, cid, 0, cid)
    tabs = [
      _a_entry_search(env, {
          caseid: cid,
          purpose: 'Case Entries',
        }, 'Entries'),
      _a_index_search(env, {
          caseid: cid,
          purpose: 'Case Indexes',
        }, 'Indexes'),
      _a_stats(env, {
          caseid: cid,
          purpose: 'Case Stats',
        }, 'Stats'),
      _a_entry_tags(env, {
          caseid: cid,
          purpose: 'Entry Tags',
        }, 'Entry Tags'),
      _a_index_tags(env, {
          caseid: cid,
          purpose: 'Index Tags',
        }, 'Index Tags'),
      _a_entry_edit(env, cid, 0, 0, 'New Entry'),
      _a_index_edit(env, cid, 0, 'New Index'),
    ]

  # no case
  else
    tc = ''
    tabs = [
      _a_action_search(env, {
          assigned: unam,
          status: true,
          flag: true,
          purpose: 'Flagged Actions',
        }, 'Actions'),
      _a_case_search(env, {
          grantee: unam,
          status: true,
          template: false,
          purpose: 'Open Cases',
        }, 'Cases'),
      _a_stats(env, {
          credit: unam,
          after: Time.now.to_i - 60*60*24*30,
          purpose: 'User Stats - Last 30 days',
        }, 'Stats'),
      _a_config_edit(env, 'Config'),
      _a_info(env, 'Info'),
    ]
  end

  # tab divs
  tabs = tabs.map{|aa| DivNavTab % aa}.join('')

  return DivNav % [
    _a_home(env, 'ICFS'),
    tc,
    tabs
  ]
end
_div_page(resp, pr=nil) { |query, page| ... } click to toggle source

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
_div_query(env, type, sup, query, disp=false) click to toggle source

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 = ' &ndash; ' + list.join(', ')
  end

  # enable value
  value = disp ? 'true' : 'false'

  return _div_desc(purp, DivQuery % [ type, paras, value ])
end
_form_action(env, cid, act = nil) click to toggle source

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
_form_case(env, cse) click to toggle source

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
_form_config(env) click to toggle source

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
_form_create(env) click to toggle source

Case Create Form

# File lib/icfs/web/client.rb, line 1831
def _form_create(env)
  [ FormCaseCreate, '' ]
end
_form_entry(env, cid, ent=nil, opts={}) click to toggle source

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
_form_index(env, cid, idx=nil) click to toggle source

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
_form_query(env, sup, query, act, disp=false) click to toggle source

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
_post_action(env, para) click to toggle source

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
_post_case(env, para) click to toggle source

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
_post_config(env, para) click to toggle source

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
_post_entry(env, para, opts={}) click to toggle source

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
_post_index(env, para) click to toggle source

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
_resp(env, res, body) click to toggle source

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
_resp_badreq(env, msg) click to toggle source

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
_resp_conflict(env, msg) click to toggle source

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
_resp_forbidden(env, msg) click to toggle source

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
_resp_notfound(env, msg) click to toggle source

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
_resp_success(env, body) click to toggle source

Success

# File lib/icfs/web/client.rb, line 4757
def _resp_success(env, body)
  return _resp(env, 200, body)
end
_util_case(env) click to toggle source

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
_util_config(cfg, key, val) click to toggle source

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
_util_get_query(env, sup) click to toggle source

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
_util_num(env, loc) click to toggle source

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
_util_post(env) click to toggle source

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
_util_query(query) click to toggle source

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('&amp;')
  else
    return ''
  end
end
_util_time_parse(env, str) click to toggle source

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
_verb_get(env) click to toggle source

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
_verb_getpost(env) click to toggle source

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