1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
5 * Think about how to handle the nav stuff...
6 * -> all urls need to respond to direct requests.
7 * -> the direct request is always an ajax
13 // Browse.php - only for rendering the body..
14 // Tree.php - the actually tree..
16 require_once 'MTrackWeb.php';
18 class MTrackWeb_Browse extends MTrackWeb
29 var $elements = array();
31 var $showCreate = false; // show create repo.
32 var $canEditRepo = false;
35 var $canDeleteFork = false;
54 $this->pi = $pi . (strlen($pi) ? $this->bootLoader->ext : '');
56 if (!isset($_REQUEST['ajax_body'])) {
57 $this->title = "Browse: " . $this->pi;
60 $this->masterTemplate = 'tree.html';
61 //DB_DataObject::debugLevel(1);
66 $this->repo = DB_DataObject::factory('mtrack_repos');
67 $file = $this->repo->loadFromPath($this->pi);
68 if (!$this->repo->id) {
75 if (isset($_GET['jump']) && strlen($_GET['jump'])) {
76 list($this->object, $this->ident) = explode(':', $_GET['jump'], 2);
80 if (!$this->projectPerm($this->repo->project_id, 'MTrack.Repos', 'S')) {
81 return HTML_FlexyFramework::run('Noperm'); // noperm = loggedin -> need more perms / not.. try loggin in..
84 $this->bdata = $this->getBrowseData($this->repo, $file, $this->object, $this->ident);
85 if (isset($this->bdata->err) ) {
86 throw new Exception($this->bdata->err);
88 require_once 'MTrack/Wiki/Item.php';
89 //make sure we can render..
90 MTrack_Wiki_Item::$repo = $this->repo->impl();
92 //$this->repo = (count($crumbs) > 2) ? MTrackSCM::factory($this->pi) : null ;
99 //$this->bdata = mtrack_cache(
100 // array($this,'getBrowseData'),
101 // array($this->repo, $this->pi, $this->object, $this->ident)
104 $this->basename = basename($file);
106 $crumbs = !strlen($file) || dirname($file) == '.' || !strlen(dirname($file)) ? array() :
107 explode('/', dirname($file));
110 $this->crumbs = array();
116 foreach($crumbs as $path)
121 $location .= strlen($location) ? '/' : '';
122 $location .= strlen($path) ? urlencode($path) : '';
123 $c->location = $location;
124 $this->crumbs[] = $c;
126 // echo '<PRE>';print_R($this->crumbs);
128 if ($this->bdata && count($this->bdata->jumps)) {
129 require_once 'HTML/Template/Flexy/Element.php';
130 $this->elements['jump'] = new HTML_Template_Flexy_Element('select');
131 // print_r($bdata->jumps);
132 $this->elements['jump']->setOptions($this->bdata->jumps);
139 if (MTrackACL::hasAllRights('Browser', 'create')) {
140 some users may have rights to create repos that belong to projects.
141 * Determine that list of projects here, because we need it for both
142 * the fork and new repo cases */
144 $owners = array("user:{$this->authUser->userid}" => $this->authUser->userid);
145 $q = MTrackDB::q( 'select projid, shortname, name from projects order by ordinal') ;
146 foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $row) {
147 if (MTrackACL::hasAllRights("project:". $row['projid'], 'modify')) {
148 $owners["project:". $row['shortname']] = $row['shortname'];
151 $this->showCreate = count($owners) > 1 ? true : false;
152 require_once 'HTML/Template/Flexy/Element.php';
153 $this->elements['repo:parent'] = new HTML_Template_Flexy_Element('select');
154 $this->elements['repo:parent']->setOptions($owners);
159 MTrackACL::requireAllRights("repo:{$this->repo->id}", 'read');
161 // this looks buggy..
163 if ( $this->repo->canFork() &&
164 MTrackACL::hasAllRights('Browser', 'fork') &&
165 MTrackConfig::get('repos', 'allow_user_repo_creation')
168 $this->canFork = true;
169 $this->forkname = $this->repo->shortname;
171 if ("{$this->authUser->userid}/{$this->repo->shortname}" == $this->repo->getBrowseRootName()) {
172 // if this is mine already, make a "more unique" name for my new fork
173 $this->forkname = $this->repo->shortname . '2';
177 if ( $this->repo->parent &&
178 MTrackACL::hasAllRights("repo:{$this->repo->id}", "delete")
181 $this->canDeleteFork = true;
184 if (MTrackACL::hasAllRights("repo:{$this->repo->id}", "modify")) {
185 $this->canEditRepo = true;
187 // watch UI is different in this version..
188 // MTrackWatch::renderWatchUI('repo', $repo->id);
192 /// non repo options..
196 $this->dirname = $this->repo ? $this->repo->displayName() : '';
199 $this->dirname .= '/'. $file;
201 $this->up = strlen($file) ? dirname($this->dirname) : '';
202 $this->jump = isset($_GET['jump']) ? $_GET['jump'] : '';
205 return $this->noRepo(explode('/', $pi));
208 //print_r($this); exit;
213 function noRepo($crumbs)
216 /*if ( MTrackACL::hasAllRights('Browser', 'fork')
217 && MTrackConfig::get('repos', 'allow_user_repo_creation')
220 $repotypes = array();
222 foreach (MTrack_Repo::getAvailableSCMs() as $t => $r) {
223 $d = $r->getSCMMetaData();
224 $repotypes[$t] = $d['name'];
226 require_once 'HTML/Template/Flexy/Element.php';
227 $this->elements['repo:type'] = new HTML_Template_Flexy_Element('select');
228 $this->elements['repo:type']->setOptions($repotypes);
231 // DB_DataObject::debugLevel(1);
232 $mine = $this->authUser ? "user:{$this->authUser->id}" : '';
234 $do = DB_DataObject::factory('mtrack_repos');
237 $crumbs[0] = empty($crumbs[0]) ? 'default' : $crumbs[0] ;
239 if (count($crumbs) == 1 && $crumbs[0] != 'default') {
241 $do->whereAdd("parent like('%:". $do->escape($crumbs[0]). "')"); // subset
243 } else if (count($crumbs) == 1 && $crumbs[0] == 'default') {
245 $do->whereAdd(" parent = ''"); // top level..
247 /* looking for top level items */
250 /* have my own repos bubble up */
251 if ($this->authUser) {
252 $do->orderBy("CASE WHEN parent = '" . $do->escape('user:' . $this->authUser->id) . "' THEN 0 ELSE 1 END, shortname ASC");
254 $do->orderBy("shortname ASC");
256 // FIXME -> permissions on repositories goes here..
257 //$do->ensurePerm($this->authUser);
260 $this->repos= array();
261 while ($do->fetch()) {
263 if (!$this->projectPerm($do->project_id, 'MTrack.Repos', 'S')) {
267 $this->repos[]= clone($do);
279 function getBrowseData($repo, $pi, $object, $ident, $hashes = false)
281 $data = new StdClass;
282 $data->dirs = array();
283 $data->files = array();
284 $data->jumps = array();
289 $branches = $repo->getBranches();
290 $tags = $repo->getTags();
291 if (count($branches) + count($tags)) {
292 $jumps = array("" => "- Select Branch / Tag - ");
293 if (is_array($branches)) {
294 foreach ($branches as $name => $notcare) {
295 $jumps["branch:$name"] = "Branch: $name";
298 if (is_array($tags)) {
299 foreach ($tags as $name => $notcare) {
300 $jumps["tag:$name"] = "Tag: $name";
303 $data->jumps = $jumps;
311 $ents = $repo->readdir($pi, $object, $ident);
312 if ($hashes == false) {
313 $ents = $this->cachedChangeEvent($ents);
315 $ents = $this->cachedChangeEventFill($ents, $hashes);
319 foreach ($ents as $file) {
320 if (!is_a($file, 'MTrackEvent')) {
321 $needLog[] = $file->hash;
324 $basename = basename($file->name);
326 $dirs[$basename] = $file;
328 $files[$basename] = $file;
332 uksort($files, 'strnatcmp');
333 uksort($dirs, 'strnatcmp');
336 $data->dirs = array_values($dirs);
337 $data->files = array_values($files);
339 $this->repopath = $this->repo->displayName();
340 $this->needLog = $needLog;
346 * New version of Directory listing
347 * - 1st run through -> fetch all the change events that we have
348 * for ones we do not have, fetch them later..
351 function cachedChangeEvent($ar)
353 // fetch a list of hashes...
357 $e->basename = basename($e->name);
361 $q = DB_DataObject::factory('mtrack_clcache');
362 $q->whereAddIn('rev', array_keys($map), 'string');
363 $q->repo_id = $this->repo->id;
364 $revs = $q->fetchAll('rev', 'sobject');
365 $impl = $this->repo->impl();
367 foreach($revs as $hash => $sobject) {
368 $event = $impl->commitLogToEvent($sobject);
370 $event->basename = $map[$hash]->basename;
371 $map[$hash] = $event; // this was previous only done for directories??? why???
373 return array_values($map);
376 function cachedChangeEventFill($ar,$hashes)
380 if (!in_array($e->hash,$hashes)) {
383 $ent = $this->repo->history($this->name, 1, 'rev', $this->rev);
389 $q = DB_DataObject::factory('mtrack_clcache');
391 $q->repo_id = $this->repo->id;
392 $q->sobject = $ent[0]->commit;
394 // only copy a few essentials from ent, as we will send it back via json.
396 $add->changelog = $ent[0]->changelogOneToHtml($this->link)
397 $add->basename = basename($e->name);
398 $add->changeby = $ent[0]->changeby;
400 $map[$e->hash] = $add;
411 $this->pi = $pi . (strlen($pi) ? $this->bootLoader->ext : '');
415 $this->repo = DB_DataObject::factory('mtrack_repos');
416 $file = $this->repo->loadFromPath($this->pi);
417 if (!$this->repo->id) {
418 $this->jerr("INVALID URL");
421 $this->object = null;
424 if (isset($_GET['jump']) && strlen($_GET['jump'])) {
425 list($this->object, $this->ident) = explode(':', $_GET['jump'], 2);
429 $this->jerr("INVALID URL");
431 if (!$this->projectPerm($this->repo->project_id, 'MTrack.Repos', 'S')) {
432 $this->jerr("INVALID URL");
434 if (empty($_POST['hashes'])) {
435 $this->jerr("INVALID URL");
438 $ar = $this->getBrowseData($this->repo, $file, $this->object, $this->ident, explode(',', $_POST['hashes']));