import
[web.mtrack] / inc / wiki-item.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 class MTrackWikiItem {
5   public $pagename = null;
6   public $filename = null;
7   public $version = null;
8   public $file = null;
9   static $wc = null;
10
11   function __get($name) {
12     if ($name == 'content') {
13       $this->content = stream_get_contents($this->file->cat());
14       return $this->content;
15     }
16   }
17
18   static function commitNow() {
19     /* force any delayed push to invoke right now */
20     self::$wc = null;
21     putenv("MTRACK_WIKI_COMMIT=");
22   }
23
24   static function loadByPageName($name) {
25     $w = new MTrackWikiItem($name);
26     if ($w->file) {
27       return $w;
28     }
29     return null;
30   }
31
32   static function getWC() {
33     if (self::$wc === null) {
34       self::getRepoAndRoot($repo);
35       self::$wc = $repo->getWorkingCopy();
36     }
37     return self::$wc;
38   }
39
40   static function getRepoAndRoot(&$repo) {
41     $repo = MTrackRepo::loadByName('default/wiki');
42     return $repo->getDefaultRoot();
43   }
44
45   function __construct($name, $version = null) {
46     $this->pagename = $name;
47     $this->filename = self::getRepoAndRoot($repo) . $name;
48     $suf = MTrackConfig::get('core', 'wikifilenamesuffix');
49     if ($suf) {
50       $this->filename .= $suf;
51     }
52
53     if ($version !== null) {
54       $this->file = $repo->file($this->filename, 'rev', $version);
55     } else {
56       $this->file = $repo->file($this->filename);
57     }
58     if ($this->file && $repo->history($this->filename, 1)) {
59       $this->version = $this->file->rev;
60     } else {
61       $this->file = null;
62     }
63   }
64
65   function save(MTrackChangeset $changeset) {
66     $wc = self::getWC();
67     $lfilename = $this->pagename;
68     $suf = MTrackConfig::get('core', 'wikifilenamesuffix');
69     if ($suf) {
70       $lfilename .= $suf;
71     }
72
73     if (!strlen(trim($this->content))) {
74       if ($wc->file_exists($lfilename)) {
75         // removing
76         $wc->delFile($lfilename);
77       }
78     } else {
79       if (!$wc->file_exists($lfilename)) {
80         // handle dirs
81         $elements = explode('/', $lfilename);
82         $accum = array();
83         while (count($elements) > 1) {
84           $ent = array_shift($elements);
85           $accum[] = $ent;
86           $base = join(DIRECTORY_SEPARATOR, $accum);
87           if (!$wc->file_exists($base)) {
88             if (!mkdir($wc->getDir() . DIRECTORY_SEPARATOR . $base)) {
89               throw new Exception(
90                   "unable to mkdir(" . $wc->getDir() .
91                   DIRECTORY_SEPARATOR . "$base)");
92             }
93             $wc->addFile($base);
94           } else if (!is_dir($wc->getDir() . DIRECTORY_SEPARATOR . $base)) {
95             throw new Exception("$base is not a dir; cannot create $lfilename");
96           }
97         }
98         file_put_contents($wc->getDir() . DIRECTORY_SEPARATOR . $lfilename,
99             $this->content);
100         $wc->addFile($lfilename);
101       } else {
102         file_put_contents($wc->getDir() . DIRECTORY_SEPARATOR . $lfilename,
103             $this->content);
104       }
105     }
106     /* use an env var to signal to the commit hook that it does not
107      * need to make a changeset for this commit */
108     putenv("MTRACK_WIKI_COMMIT=1");
109     $wc->commit($changeset);
110   }
111
112   static function index_item($object)
113   {
114     list($ignore, $ident) = explode(':', $object, 2);
115     $w = MTrackWikiItem::loadByPageName($ident);
116
117     MTrackSearchDB::add("wiki:$w->pagename", array(
118       'wiki' => $w->content,
119       'who' => $w->who,
120       ), true);
121   }
122   static function _get_parent_for_acl($objectid) {
123     if (preg_match("/^(wiki:.*)\/([^\/]+)$/", $objectid, $M)) {
124       return $M[1];
125     }
126     if (preg_match("/^wiki:.*$/", $objectid, $M)) {
127       return 'Wiki';
128     }
129     return null;
130   }
131 }
132
133 class MTrackWikiCommitListener implements IMTrackCommitListener {
134   function vetoCommit($msg, $files, $actions) {
135     return true;
136   }
137
138   function postCommit($msg, $files, $actions) {
139     /* is this affecting the wiki? */
140     $wiki = array();
141     $suf = MTrackConfig::get('core', 'wikifilenamesuffix');
142     foreach ($files as $name) {
143       list($repo, $fname) = explode('/', $name, 2);
144       if ($repo == 'wiki') {
145         if ($suf && substr($fname, -strlen($suf)) == $suf) {
146           $fname = substr($fname, 0, -strlen($suf));
147         }
148         $wiki[] = $fname;
149       }
150     }
151     /* MTRACK_WIKI_COMMIT is set by MTrackWikiItem when it commits,
152      * so we check for the absence of it to determine if mtrack has
153      * recorded a changeset record */
154     if (count($wiki) && getenv("MTRACK_WIKI_COMMIT") != "1") {
155       /* wiki being changed outside of the MTrackWikiItem class, so
156        * let's create a changeset record for the search engine to
157        * pick up and index this change */
158       foreach ($wiki as $name) {
159         $CS = MTrackChangeset::begin("wiki:$name", $msg);
160         $CS->commit();
161       }
162     }
163     return true;
164   }
165
166   static function register() {
167     $l = new MTrackWikiCommitListener;
168     MTrackCommitChecker::registerListener($l);
169   }
170
171 };
172
173 MTrackSearchDB::register_indexer('wiki', array('MTrackWikiItem', 'index_item'));
174 MTrackWikiCommitListener::register();
175 MTrackACL::registerAncestry('wiki', array('MTrackWikiItem', '_get_parent_for_acl'));
176