EGroupware /
egroupware
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Filemanager - document merge |
||
| 4 | * |
||
| 5 | * @link http://www.egroupware.org |
||
| 6 | * @author Nathan Gray |
||
| 7 | * @package filemanager |
||
| 8 | * @copyright 2012 Nathan Gray |
||
| 9 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||
| 10 | * @version $Id$ |
||
| 11 | */ |
||
| 12 | |||
| 13 | use EGroupware\Api; |
||
| 14 | use EGroupware\Api\Link; |
||
| 15 | use EGroupware\Api\Vfs; |
||
| 16 | |||
| 17 | /** |
||
| 18 | * Filemanager - document merge object |
||
| 19 | * Only merges information about the files, not the files themselves |
||
| 20 | */ |
||
| 21 | class filemanager_merge extends Api\Storage\Merge |
||
| 22 | { |
||
| 23 | /** |
||
| 24 | * Functions that can be called via menuaction |
||
| 25 | * |
||
| 26 | * @var array |
||
| 27 | */ |
||
| 28 | var $public_functions = array( |
||
| 29 | 'show_replacements' => true, |
||
| 30 | ); |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Fields that are numeric, for special numeric handling |
||
| 34 | */ |
||
| 35 | protected $numeric_fields = array( |
||
| 36 | ); |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Fields that are dates or timestamps |
||
| 40 | */ |
||
| 41 | public $date_fields = array( |
||
| 42 | 'mtime', 'ctime' |
||
| 43 | ); |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Business object to pull records from |
||
| 47 | */ |
||
| 48 | protected $bo = null; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * Current directory - affects how files are named |
||
| 52 | */ |
||
| 53 | protected $dir = ''; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * Constructor |
||
| 57 | * |
||
| 58 | */ |
||
| 59 | function __construct($_dir = '') |
||
| 60 | { |
||
| 61 | parent::__construct(); |
||
| 62 | |||
| 63 | if($_dir) |
||
| 64 | { |
||
| 65 | $this->dir = $_dir; |
||
| 66 | } |
||
| 67 | |||
| 68 | // switch off handling of html formated content, if html is not used |
||
| 69 | $this->parse_html_styles = Api\Storage\Customfields::use_html('filemanager'); |
||
| 70 | } |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Get replacements |
||
| 74 | * |
||
| 75 | * @param int $id id of entry |
||
| 76 | * @param string &$content=null content to create some replacements only if they are use |
||
| 77 | * @return array|boolean |
||
| 78 | */ |
||
| 79 | protected function get_replacements($id,&$content=null) |
||
| 80 | { |
||
| 81 | if (!($replacements = $this->filemanager_replacements($id, '', $content))) |
||
| 82 | { |
||
| 83 | return false; |
||
| 84 | } |
||
| 85 | return $replacements; |
||
| 86 | } |
||
| 87 | |||
| 88 | /** |
||
| 89 | * Get filemanager replacements |
||
| 90 | * |
||
| 91 | * @param int $id id (vfs path) of entry |
||
| 92 | * @param string $prefix='' prefix like eg. 'erole' |
||
| 93 | * @return array|boolean |
||
| 94 | */ |
||
| 95 | public function filemanager_replacements($id,$prefix='', &$content = null) |
||
| 96 | { |
||
| 97 | $info = array(); |
||
| 98 | $file = Vfs::lstat($id,true); |
||
| 99 | |||
| 100 | $file['mtime'] = Api\DateTime::to($file['mtime']); |
||
| 101 | $file['ctime'] = Api\DateTime::to($file['ctime']); |
||
| 102 | |||
| 103 | $file['name'] = Vfs::basename($id); |
||
| 104 | $file['dir'] = ($dir = Vfs::dirname($id)) ? Vfs::decodePath($dir) : ''; |
||
| 105 | $dirlist = explode('/',$file['dir']); |
||
| 106 | $file['folder'] = array_pop($dirlist); |
||
| 107 | $file['folder_file'] = $file['folder'] . '/'.$file['name']; |
||
| 108 | $file['path'] = $id; |
||
| 109 | $file['rel_path'] = str_replace($this->dir.'/', '', $id); |
||
| 110 | $file['hsize'] = Vfs::hsize($file['size']); |
||
| 111 | $file['mime'] = Vfs::mime_content_type($id); |
||
| 112 | $file['gid'] *= -1; // our widgets use negative gid's |
||
| 113 | if (($props = Vfs::propfind($id))) |
||
| 114 | { |
||
| 115 | foreach($props as $prop) |
||
| 116 | { |
||
| 117 | $file[$prop['name']] = $prop['val']; |
||
| 118 | } |
||
| 119 | } |
||
| 120 | if (($file['is_link'] = Vfs::is_link($id))) |
||
| 121 | { |
||
| 122 | $file['symlink'] = Vfs::readlink($id); |
||
| 123 | } |
||
| 124 | // Custom fields |
||
| 125 | if($content && strpos($content, '#') !== 0) |
||
| 126 | { |
||
| 127 | // Expand link-to custom fields |
||
| 128 | $this->cf_link_to_expand($file, $content, $info); |
||
| 129 | |||
| 130 | foreach(Api\Storage\Customfields::get('filemanager') as $name => $field) |
||
| 131 | { |
||
| 132 | // Set any missing custom fields, or the marker will stay |
||
| 133 | if(!$file['#'.$name]) |
||
| 134 | { |
||
| 135 | $file['#'.$name] = ''; |
||
| 136 | continue; |
||
| 137 | } |
||
| 138 | |||
| 139 | // Format date cfs per user Api\Preferences |
||
| 140 | if($field['type'] == 'date' || $field['type'] == 'date-time') |
||
| 141 | { |
||
| 142 | $this->date_fields[] = '#'.$name; |
||
| 143 | $file['#'.$name] = Api\DateTime::to($file['#'.$name], $field['type'] == 'date' ? true : ''); |
||
| 144 | } |
||
| 145 | } |
||
| 146 | } |
||
| 147 | |||
| 148 | // If in apps folder, try for app-specific placeholders |
||
| 149 | if($dirlist[1] == 'apps' && count($dirlist) > 1) |
||
| 150 | { |
||
| 151 | // Try this first - a normal path /apps/appname/id/file |
||
| 152 | list($app, $app_id) = explode('/', substr($file['path'], strpos($file['path'], 'apps/')+5)); |
||
| 153 | // Symlink? |
||
| 154 | if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps'])) { |
||
| 155 | // Try resolving just app + ID - /apps/App Name/Record Title/file |
||
| 156 | $resolved = Vfs::resolve_url_symlinks(implode('/',array_slice(explode('/',$file['dir']),0,4))); |
||
| 157 | list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/')+5)); |
||
| 158 | |||
| 159 | if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps'])) { |
||
| 160 | // Get rid of any virtual folders (eg: All$) and symlinks |
||
| 161 | $resolved = Vfs::resolve_url_symlinks($file['path']); |
||
| 162 | list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/')+5)); |
||
| 163 | } |
||
| 164 | } |
||
| 165 | if($app && $app_id) |
||
| 166 | { |
||
| 167 | if($app && $GLOBALS['egw_info']['user']['apps'][$app]) |
||
| 168 | { |
||
| 169 | $app_merge = null; |
||
|
0 ignored issues
–
show
Unused Code
introduced
by
Loading history...
|
|||
| 170 | try |
||
| 171 | { |
||
| 172 | $classname = $app .'_merge'; |
||
| 173 | if(class_exists($classname)) |
||
| 174 | { |
||
| 175 | $app_merge = new $classname(); |
||
| 176 | if($app_merge && method_exists($app_merge, 'get_replacements')) |
||
| 177 | { |
||
| 178 | $app_placeholders = $app_merge->get_replacements($app_id, $content); |
||
| 179 | } |
||
| 180 | } |
||
| 181 | } |
||
| 182 | // Silently discard & continue |
||
| 183 | catch(Exception $e) { |
||
| 184 | unset($e); // not used |
||
| 185 | } |
||
| 186 | } |
||
| 187 | } |
||
| 188 | } |
||
| 189 | $link = Link::mime_open($file['url'], $file['mime']); |
||
| 190 | if(is_array($link)) |
||
| 191 | { |
||
| 192 | // Directories have their internal protocol in path here |
||
| 193 | if($link['path'] && strpos($link['path'], '://') !== false) $link['path'] = $file['path']; |
||
| 194 | $link = Api\Session::link('/index.php', $link); |
||
| 195 | } |
||
| 196 | else |
||
| 197 | { |
||
| 198 | // Regular files |
||
| 199 | $link = Api\Session::link($link); |
||
| 200 | } |
||
| 201 | |||
| 202 | // Prepend site, if missing |
||
| 203 | if ($link[0] == '/') $link = Api\Framework::getUrl($link); |
||
| 204 | |||
| 205 | $file['link'] = Api\Html::a_href(Api\Html::htmlspecialchars($file['name']), $link); |
||
| 206 | $file['webdav_url'] = Api\Session::link(Vfs::download_url($file['url'])); |
||
| 207 | $file['url'] = $link; |
||
| 208 | |||
| 209 | // Add markers |
||
| 210 | foreach($file as $key => &$value) |
||
| 211 | { |
||
| 212 | if(!$value) $value = ''; |
||
| 213 | $info['$$'.($prefix ? $prefix.'/':'').$key.'$$'] = $value; |
||
| 214 | } |
||
| 215 | if($app_placeholders) |
||
| 216 | { |
||
| 217 | $info = array_merge($app_placeholders, $info); |
||
| 218 | } |
||
| 219 | return $info; |
||
| 220 | } |
||
| 221 | |||
| 222 | /** |
||
| 223 | * Create a share for an entry |
||
| 224 | * |
||
| 225 | * @param string $app |
||
| 226 | * @param string $id |
||
| 227 | * @param string $path |
||
| 228 | * @param type $content |
||
| 229 | * @return type |
||
| 230 | */ |
||
| 231 | protected function create_share($app, $id, &$content) |
||
| 232 | { |
||
| 233 | // Check if some other process created the share (with custom options) |
||
| 234 | // and put it in the session cache for us |
||
| 235 | $path = $id; |
||
| 236 | $session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, $path); |
||
| 237 | if($session && $session['share_path'] == $path) |
||
| 238 | { |
||
| 239 | return $session; |
||
| 240 | } |
||
| 241 | else if (($session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, "$app::$id")) && |
||
| 242 | substr($session['share_path'], -strlen($path)) === $path) |
||
| 243 | { |
||
| 244 | return $session; |
||
| 245 | } |
||
| 246 | // Need to create the share here. |
||
| 247 | // No way to know here if it should be writable, or who it's going to |
||
| 248 | $mode = /* ? ? Sharing::WRITABLE :*/ Api\Sharing::READONLY; |
||
| 249 | $recipients = array(); |
||
| 250 | $extra = array(); |
||
| 251 | |||
| 252 | return \EGroupware\Api\Vfs\Sharing::create($path, $mode, NULL, $recipients, $extra); |
||
| 253 | } |
||
| 254 | |||
| 255 | /** |
||
| 256 | * Generate table with replacements for the Api\Preferences |
||
| 257 | * |
||
| 258 | */ |
||
| 259 | public function show_replacements() |
||
| 260 | { |
||
| 261 | $GLOBALS['egw_info']['flags']['app_header'] = lang('filemanager').' - '.lang('Replacements for inserting entries into documents'); |
||
| 262 | $GLOBALS['egw_info']['flags']['nonavbar'] = false; |
||
| 263 | echo $GLOBALS['egw']->framework->header(); |
||
| 264 | |||
| 265 | echo "<table width='90%' align='center'>\n"; |
||
| 266 | echo '<tr><td colspan="4"><h3>'.lang('Filemanager fields:')."</h3></td></tr>"; |
||
| 267 | |||
| 268 | $n = 0; |
||
| 269 | $fields = array( |
||
| 270 | 'name' => 'name', |
||
| 271 | 'path' => 'Absolute path', |
||
| 272 | 'rel_path' => 'Path relative to current directory', |
||
| 273 | 'folder' => 'Containing folder', |
||
| 274 | 'folder_file' => 'Containing folder and file name', |
||
| 275 | 'url' => 'url', |
||
| 276 | 'webdav_url' => 'External path using webdav', |
||
| 277 | 'link' => 'Clickable link to file', |
||
| 278 | 'comment' => 'comment', |
||
| 279 | 'mtime' => 'modified', |
||
| 280 | 'ctime' => 'created', |
||
| 281 | 'mime' => 'Type', |
||
| 282 | 'hsize' => 'Size', |
||
| 283 | 'size' => 'Size (in bytes)', |
||
| 284 | ); |
||
| 285 | foreach($fields as $name => $label) |
||
| 286 | { |
||
| 287 | if (!($n&1)) echo '<tr>'; |
||
| 288 | echo '<td>{{'.$name.'}}</td><td>'.lang($label).'</td>'; |
||
| 289 | if ($n&1) echo "</tr>\n"; |
||
| 290 | $n++; |
||
| 291 | } |
||
| 292 | |||
| 293 | echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>"; |
||
| 294 | foreach(Api\Storage\Customfields::get('filemanager') as $name => $field) |
||
| 295 | { |
||
| 296 | echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n"; |
||
| 297 | } |
||
| 298 | |||
| 299 | echo '<tr><td colspan="4"><h3>'.lang('Application fields').":</h3></td></tr>"; |
||
| 300 | echo '<tr><td colspan="4">'.lang('For files linked to an application entry (inside /apps/appname/id/) the placeholders for that application are also available. See the specific application for a list of available placeholders.').'</td></tr>'; |
||
| 301 | |||
| 302 | echo '<tr><td colspan="4"><h3>'.lang('General fields:')."</h3></td></tr>"; |
||
| 303 | foreach(array( |
||
| 304 | 'date' => lang('Date'), |
||
| 305 | 'user/n_fn' => lang('Name of current user, all other contact fields are valid too'), |
||
| 306 | 'user/account_lid' => lang('Username'), |
||
| 307 | 'pagerepeat' => lang('For serial letter use this tag. Put the content, you want to repeat between two Tags.'), |
||
| 308 | 'label' => lang('Use this tag for addresslabels. Put the content, you want to repeat, between two tags.'), |
||
| 309 | 'labelplacement' => lang('Tag to mark positions for address labels'), |
||
| 310 | 'IF fieldname' => lang('Example {{IF n_prefix~Mr~Hello Mr.~Hello Ms.}} - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms.'), |
||
| 311 | 'NELF' => lang('Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role'), |
||
| 312 | 'NENVLF' => lang('Example {{NENVLF role}} - if field role is not empty, set a LF without any value of the field'), |
||
| 313 | 'LETTERPREFIX' => lang('Example {{LETTERPREFIX}} - Gives a letter prefix without double spaces, if the title is empty for example'), |
||
| 314 | 'LETTERPREFIXCUSTOM' => lang('Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller'), |
||
| 315 | ) as $name => $label) |
||
| 316 | { |
||
| 317 | echo '<tr><td>{{'.$name.'}}</td><td colspan="3">'.$label."</td></tr>\n"; |
||
| 318 | } |
||
| 319 | |||
| 320 | echo "</table>\n"; |
||
| 321 | |||
| 322 | echo $GLOBALS['egw']->framework->footer(); |
||
| 323 | } |
||
| 324 | } |
||
| 325 |