From c5dd013f188f9a9157d3730006359e4914eebb84 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 10 Mar 2004 00:58:18 +0000 Subject: [PATCH] first version of xmlrpc support for infolog --- infolog/inc/class.boinfolog.inc.php | 242 ++++++++++++++++++++++++++-- infolog/inc/class.soinfolog.inc.php | 107 ++++++------ infolog/inc/class.uiinfolog.inc.php | 16 +- 3 files changed, 289 insertions(+), 76 deletions(-) diff --git a/infolog/inc/class.boinfolog.inc.php b/infolog/inc/class.boinfolog.inc.php index 39f6ffc9fe..48e3ebc916 100644 --- a/infolog/inc/class.boinfolog.inc.php +++ b/infolog/inc/class.boinfolog.inc.php @@ -37,6 +37,30 @@ var $valid_pathes = array(); var $send_file_ips = array(); + var $xmlrpc_methods = array(); + var $soap_functions = array( + 'read' => array( + 'in' => array('int'), + 'out' => array('array') + ), + 'search' => array( + 'in' => array('array'), + 'out' => array('array') + ), + 'write' => array( + 'in' => array('array'), + 'out' => array() + ), + 'delete' => array( + 'in' => array('int'), + 'out' => array() + ), + 'categories' => array( + 'in' => array('bool'), + 'out' => array('array') + ), + ); + function boinfolog( $info_id = 0) { $this->enums = $this->stock_enums = array( @@ -108,6 +132,9 @@ $this->tz_offset = $GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset']; $this->tz_offset_sec = 60*60*$this->tz_offset; + // are we called via xmlrpc? + $this->xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method; + $this->read( $info_id); } @@ -178,7 +205,27 @@ function read($info_id) { - $err = $this->so->read($info_id) === False; + if (is_array($info_id)) + { + $info_id = (int)$info_id['info_id']; + } + + if ($this->so->read($info_id) === False) + { + if ($this->xmlrpc) + { + $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['not_exist'],$GLOBALS['xmlrpcstr']['not_exist']); + } + return False; + } + if (!$this->check_access($info_id,PHPGW_ACL_READ)) // check behind read, to prevent a double read + { + if ($this->xmlrpc) + { + $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']); + } + return False; + } $data = &$this->so->data; if ($data['info_subject'] == $this->subject_from_des($data['info_des'])) @@ -187,11 +234,30 @@ } $this->link_id2from($data); - return $err ? False : $data; + if ($this->xmlrpc) + { + $data = $this->data2xmlrpc($data); + } + return $data; } - function delete($info_id,$delete_children,$new_parent) + function delete($info_id,$delete_children=False,$new_parent=False) { + if (is_array($info_id)) + { + $delete_children = $info_id['delete_children']; + $new_parent = $info_id['new_parent']; + $info_id = $info_id['info_id']; + } + if (!$this->check_access($info_id,PHPGW_ACL_DELETE)) + { + if ($this->xmlrpc) + { + $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']); + } + return False; + } + $this->link->unlink(0,'infolog',$info_id); $this->so->delete($info_id,$delete_children,$new_parent); @@ -199,7 +265,20 @@ function write($values,$check_defaults=True,$touch_modified=True) { - while (list($key,$val) = each($values)) + if ($values['info_id'] && !$this->check_access($values['info_id'],PHPGW_ACL_EDIT) || + !$values['info_id'] && $values['info_id_parent'] && !$this->check_access($values['info_id_parent'],PHPGW_ACL_ADD)) + { + if ($this->xmlrpc) + { + $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']); + } + return False; + } + if ($this->xmlrpc) + { + $values = $this->xmlrpc2data($values); + } + foreach($values as $key => $val) { if ($key[0] != '#' && substr($key,0,5) != 'info_') { @@ -247,9 +326,32 @@ return $this->so->anzSubs( $info_id ); } - function search($order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,&$start,&$total,$col_filter=False) + /*! + @function search + @abstract searches InfoLog for a certain pattern in $query + @syntax search( $query ) + @param $query[order] column-name to sort after + @param $query[sort] sort-order DESC or ASC + @param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or '' + @param $query[cat_id] category to use or 0 or unset + @param $query[search] pattern to search, search is done in info_from, info_subject and info_des + @param $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used + @param &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries + @param $query[col_filter] array with column-name - data pairs, data == '' means no filter (!) + @returns array with id's as key of the matching log-entries + */ + function search(&$query) { - return $this->so->search($order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,$start,$total,$col_filter); + $ret = $this->so->search($query); + if ($this->xmlrpc && is_array($ret)) + { + foreach($ret as $id => $data) + { + $ret[$id] = $this->data2xmlrpc($data); + } + } + //echo "

boinfolog::search(".print_r($query,True).")=

".print_r($ret,True)."
\n"; + return $ret; } /*! @@ -280,12 +382,18 @@ */ function link_query( $pattern ) { - $start = $total = 0; - $ids = $this->search('','','','',$pattern,'','','',&$start,&$total); + $query = array( + 'search' => $pattern, + 'start' => 0, + ); + $ids = $this->search($query); $content = array(); - while (is_array($ids) && list( $id,$info ) = each( $ids )) + if (is_array($ids)) { - $content[$id] = $this->link_title($id); + foreach($ids as $id => $info ) + { + $content[$id] = $this->link_title($id); + } } return $content; } @@ -315,11 +423,15 @@ $GLOBALS['phpgw']->translation->add_app('infolog'); $do_events = $args['location'] == 'calendar_include_events'; - $start = 0; $to_include = array(); $date_wanted = sprintf('%04d/%02d/%02d',$args['year'],$args['month'],$args['day']); - while ($infos = $this->search('info_startdate'.($do_events?'':' DESC'),'', - "user$user".($do_events?'date':'opentoday').$date_wanted,'','','','','',$start,$total)) + $query = array( + 'order' => 'info_startdate', + 'sort' => $do_events ? 'ASC' : 'DESC', + 'filter'=> "user$user".($do_events ? 'date' : 'opentoday').$date_wanted, + 'start' => 0, + ); + while ($infos = $this->search($query)) { foreach($infos as $info) { @@ -352,7 +464,7 @@ 'content' => $content ); } - if ($total <= ($start+=count($infos))) + if ($query['total'] <= ($query['start']+=count($infos))) { break; // no more availible } @@ -360,4 +472,106 @@ //echo "boinfolog::cal_to_include("; print_r($args); echo ")
"; print_r($to_include); echo "
\n"; return $to_include; } + + function list_methods($_type='xmlrpc') + { + /* + ** This handles introspection or discovery by the logged in client, + ** in which case the input might be an array. The server always calls + ** this function to fill the server dispatch map using a string. + */ + + if (is_array($_type)) + { + $_type = $_type['type'] ? $_type['type'] : $_type[0]; + } + + switch($_type) + { + case 'xmlrpc': + $xml_functions = array( + 'read' => array( + 'function' => 'read', + 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), + 'docstring' => lang('Read one record by passing its id.') + ), + 'search' => array( + 'function' => 'search', + 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), + 'docstring' => lang('Returns a list / search for records.') + ), + 'write' => array( + 'function' => 'write', + 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), + 'docstring' => lang('Write (add or update) a record by passing its fields.') + ), + 'delete' => array( + 'function' => 'delete', + 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), + 'docstring' => lang('Delete one record by passing its id.') + ), + 'categories' => array( + 'function' => 'categories', + 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), + 'docstring' => lang('List all categories.') + ), + 'list_methods' => array( + 'function' => 'list_methods', + 'signature' => array(array(xmlrpcStruct,xmlrpcString)), + 'docstring' => lang('Read this list of methods.') + ) + ); + return $xml_functions; + break; + case 'soap': + return $this->soap_functions; + break; + default: + return array(); + break; + } + } + + function data2xmlrpc($data) + { + // translate timestamps + foreach(array('info_startdate','info_enddate','info_datemodified') as $name) + { + if (isset($data[$name])) + { + $data[$name] = $GLOBALS['server']->date2iso8601($data[$name]); + } + } + // translate cat_id + if (isset($data['cat_id'])) + { + $data['cat_id'] = $GLOBALS['server']->cats2xmlrpc(array($data['cat_id'])); + } + return $data; + } + + function xmlrpc2data($data) + { + // translate timestamps + foreach(array('info_startdate','info_enddate','info_datemodified') as $name) + { + if (isset($data[$name])) + { + $data[$name] = $GLOBALS['server']->iso86012date($data[$name],True); + } + } + // translate cat_id + if (isset($data['cat_id'])) + { + $cats = $GLOBALS['server']->xmlrpc2cats($data['cat_id']); + $data['cat_id'] = (int)$cats[0]; + } + return $data; + } + + // return array with all infolog categories (for xmlrpc) + function categories($complete = False) + { + return $GLOBALS['server']->categories($complete); + } } diff --git a/infolog/inc/class.soinfolog.inc.php b/infolog/inc/class.soinfolog.inc.php index adf9c338fc..86f62ec6ae 100644 --- a/infolog/inc/class.soinfolog.inc.php +++ b/infolog/inc/class.soinfolog.inc.php @@ -18,7 +18,7 @@ @abstract storage object / db-layer for InfoLog @author Ralf Becker @copyright GPL - GNU General Public License - @note all values passed to this class are run either through intval or addslashes to prevent query-inserting + @note all values passed to this class are run either through intval or addslashes to prevent query-insertion and for pgSql 7.3 compatibility */ class soinfolog // DB-Layer @@ -72,17 +72,17 @@ } $owner = $info['info_owner']; - $access_ok = $owner == $this->user || // user has all rights - // ACL only on public entrys || $owner granted _PRIVATE - (!!($this->grants[$owner] & $required_rights) || - // implicite read-rights for responsible user !!! - $info['info_responsible'] == $this->user && $required_rights == PHPGW_ACL_READ) && - ($info['info_access'] == 'public' || - !!($this->grants[$owner] & PHPGW_ACL_PRIVATE)); - + $access_ok = $owner == $this->user || // user has all rights + // ACL only on public entrys || $owner granted _PRIVATE + (!!($this->grants[$owner] & $required_rights) || + // implicite read-rights for responsible user !!! + $info['info_responsible'] == $this->user && $required_rights == PHPGW_ACL_READ) && + ($info['info_access'] == 'public' || + !!($this->grants[$owner] & PHPGW_ACL_PRIVATE)); + // echo "check_access(info_id=$info_id (owner=$owner, user=$user),required_rights=$required_rights): access".($access_ok?"Ok":"Denied"); - - return $access_ok; + + return $access_ok; } /*! @@ -104,7 +104,7 @@ } if (is_array($this->grants)) { - while (list($user,$grant) = each($this->grants)) + foreach($this->grants as $user => $grant) { // echo "

grants: user=$user, grant=$grant

"; if ($grant & (PHPGW_ACL_READ|PHPGW_ACL_EDIT)) @@ -180,7 +180,8 @@ @syntax dateFilter($filter = '') @param $filter upcoming = startdate is in the future
today startdate < tomorrow
- overdue enddate < tomorrow + overdue enddate < tomorrow
+ limitYYYY/MM/DD not older or open @returns the necesary sql */ function dateFilter($filter = '') @@ -212,6 +213,8 @@ return ''; } return " AND ($today <= info_startdate AND info_startdate < $tomorrow)"; + case 'limit': + return " AND (info_modified >= '$today' OR NOT (info_status IN ('done','billed')))"; } return ''; } @@ -223,12 +226,12 @@ */ function init() { - $this->data = array( + $this->data = array( 'info_owner' => $this->user, - 'info_pri' => 'normal' + 'info_pri' => 'normal' ); - } - + } + /*! @function db2data @abstract copy data after a query into $data @@ -454,53 +457,51 @@ /*! @function search @abstract searches InfoLog for a certain pattern in $query - @syntax search( $order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,&$start,&$total ) - @param $order comma-separated list of columns to order the result (no 'ORDER BY'), eg. 'info_subject DESC' - @param $sort comma-separated list of columns to to sort by (incl. 'SORT BY') or '' - @param $filter string with combination of acl-, date- and status-filters, eg. 'own-open-today' or '' - @param $cat_id category to use or 0 - @param $query pattern to search, search is done in info_from, info_subject and info_des - @param $action / $action_id if only entries linked to a specified app/entry show be used - @param &$start, &$total nextmatch-parameters will be used and set if query returns less entries - @param $col_filter array with column-name - data pairs, data == '' means no filter (!) + @syntax search( $query ) + @param $query[order] column-name to sort after + @param $query[sort] sort-order DESC or ASC + @param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or '' + @param $query[cat_id] category to use or 0 or unset + @param $query[search] pattern to search, search is done in info_from, info_subject and info_des + @param $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used + @param &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries + @param $query[col_filter] array with column-name - data pairs, data == '' means no filter (!) @returns array with id's as key of the matching log-entries */ - function search($order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,&$start,&$total,$col_filter=False) + function search(&$query) { - //echo "

soinfolog.search(order='$order',,filter='$filter',,query='$query',action='$action/$action_id')

\n"; + //echo "

soinfolog.search(".print_r($query,True).")

\n"; $action2app = array( 'addr' => 'addressbook', 'proj' => 'projects', 'event' => 'calendar' ); - if (isset($action2app[$action])) - { - $action = $action2app[$action]; - } + $action = isset($action2app[$query['action']]) ? $action2app[$query['action']] : $query['action']; + if ($action != '') { - $links = $this->links->get_links($action=='sp'?'infolog':$action,$action_id,'infolog'); - + $links = $this->links->get_links($action=='sp'?'infolog':$action,$query['action_id'],'infolog'); + if (count($links)) { $link_extra = ($action == 'sp' ? 'OR' : 'AND').' phpgw_infolog.info_id IN ('.implode(',',$links).')'; } } - if ($order) + if ($query['order']) { - $ordermethod = 'ORDER BY ' . $this->db->db_addslashes($order) . ' ' . $this->db->db_addslashes($sort); + $ordermethod = 'ORDER BY ' . $this->db->db_addslashes($query['order']) . ' ' . $this->db->db_addslashes($query['sort']); } else { $ordermethod = 'ORDER BY info_datemodified DESC'; // newest first } - $filtermethod = $this->aclFilter($filter); - $filtermethod .= $this->statusFilter($filter); - $filtermethod .= $this->dateFilter($filter); + $filtermethod = $this->aclFilter($query['filter']); + $filtermethod .= $this->statusFilter($query['filter']); + $filtermethod .= $this->dateFilter($query['filter']); - if (is_array($col_filter)) + if (is_array($query['col_filter'])) { - foreach($col_filter as $col => $data) + foreach($query['col_filter'] as $col => $data) { $data = $this->db->db_addslashes($data); if (!empty($data)) @@ -511,19 +512,19 @@ } //echo "

filtermethod='$filtermethod'

"; - if (intval($cat_id)) + if (intval($query['cat_id'])) { - $filtermethod .= ' AND info_cat='.intval($cat_id).' '; + $filtermethod .= ' AND info_cat='.intval($query['cat_id']).' '; } $join = ''; - if ($query) // we search in _from, _subject, _des and _extra_value for $query + if ($query['search']) // we search in _from, _subject, _des and _extra_value for $query { - $query = $this->db->db_addslashes($query); + $query['search'] = $this->db->db_addslashes($query['query']); $sql_query = "AND (info_from like '%$query%' OR info_subject ". "LIKE '%$query%' OR info_des LIKE '%$query%' OR info_extra_value LIKE '%$query%') "; $join = 'LEFT JOIN phpgw_infolog_extra ON phpgw_infolog.info_id=phpgw_infolog_extra.info_id'; } - $pid = 'AND info_id_parent='.($action == 'sp' ? $action_id : 0); + $pid = 'AND info_id_parent='.($action == 'sp' ? $query['action_id'] : 0); if (!$GLOBALS['phpgw_info']['user']['preferences']['infolog']['listNoSubs'] && $action != 'sp') @@ -533,15 +534,15 @@ $ids = array( ); if ($action == '' || $action == 'sp' || count($links)) { - $query = "FROM phpgw_infolog $join WHERE ($filtermethod $pid $sql_query) $link_extra"; - $this->db->query($sql='SELECT DISTINCT phpgw_infolog.info_id '.$query,__LINE__,__FILE__); - $total = $this->db->num_rows(); + $sql_query = "FROM phpgw_infolog $join WHERE ($filtermethod $pid $sql_query) $link_extra"; + $this->db->query($sql='SELECT DISTINCT phpgw_infolog.info_id '.$sql_query,__LINE__,__FILE__); + $query['total'] = $this->db->num_rows(); - if (!$start || $start > $total) + if (!$query['start'] || $query['start'] > $query['total']) { - $start = 0; + $query['start'] = 0; } - $this->db->limit_query($sql="SELECT DISTINCT phpgw_infolog.* $query $ordermethod",$start,__LINE__,__FILE__); + $this->db->limit_query($sql="SELECT DISTINCT phpgw_infolog.* $sql_query $ordermethod",$query['start'],__LINE__,__FILE__); //echo "

sql='$sql'

\n"; while ($this->db->next_record()) { @@ -551,7 +552,7 @@ } else { - $start = $total = 0; + $query['start'] = $query['total'] = 0; } return $ids; } diff --git a/infolog/inc/class.uiinfolog.inc.php b/infolog/inc/class.uiinfolog.inc.php index d4d9ff8133..ebbe6a7fb2 100644 --- a/infolog/inc/class.uiinfolog.inc.php +++ b/infolog/inc/class.uiinfolog.inc.php @@ -159,24 +159,23 @@ //echo "

uiinfolog.get_rows(start=$query[start],search='$query[search]',filter='$query[filter]',cat_id=$query[cat_id],action='$query[action]/$query[action_id]',col_filter=".print_r($query['col_filter'],True).")

\n"; $this->save_sessiondata($query); - $ids = $this->bo->search($query['order'],$query['sort'],$query['filter'],$query['cat_id'], - $query['search'],$query['action'],$query['action_id'],$query['ordermethod'], - $query['start'],$total,$query['col_filter']); + $ids = $this->bo->search($query); if (!is_array($ids)) { $ids = array( ); } - $rows = array( $total ); + $rows = array( $query['total'] ); $readonlys = array(); foreach($ids as $id => $info) { $rows[] = $this->get_info($info,$readonlys,$query['action'],$query['action_id']); } //echo "

readonlys = "; _debug_array($readonlys); + //echo "rows=

".print_r($rows,True)."
\n"; reset($rows); - return $total; + return $query['total']; } function index($values = 0,$action='',$action_id='',$referer=0,$extra_app_header=False,$return_html=False) @@ -253,7 +252,7 @@ $action_id = 0; break; } - $values['main'][1] = $this->get_info($action_id,&$readonlys['main']); + $values['main'][1] = $this->get_info($action_id,$readonlys['main']); break; } $readonlys['cancel'] = $action != 'sp'; @@ -298,7 +297,7 @@ return $referer ? $this->tmpl->location($referer) : $this->index(); } $readonlys = $values = array(); - $values['main'][1] = $this->get_info($info_id,&$readonlys['main']); + $values['main'][1] = $this->get_info($info_id,$readonlys['main']); $this->tmpl->read('infolog.delete'); @@ -659,8 +658,7 @@ $extra = $this->messages + $this->filters; $enums = $this->bo->enums + $this->bo->status; unset($enums['defaults']); - reset($enums); - while (list($key,$msg_arr) = each($enums)) + foreach($enums as $key => $msg_arr) { $extra += $msg_arr; }