1<?php
2/**
3 * DokuWiki Plugin farmsync (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Michael Große <dokuwiki@cosmocode.de>
7 */
8
9if (!defined('DOKU_INC')) die();
10
11use dokuwiki\Form\Form;
12use dokuwiki\plugin\farmsync\meta\FarmSyncUtil;
13
14class action_plugin_farmsync_ajax extends DokuWiki_Action_Plugin {
15
16    /**
17     * Registers a callback function for a given event
18     *
19     * @param Doku_Event_Handler $controller DokuWiki's event controller object
20     * @return void
21     */
22    public function register(Doku_Event_Handler $controller) {
23        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax');
24    }
25
26    private $farm_util;
27
28    function __construct() {
29        $this->farm_util = new FarmSyncUtil();
30    }
31
32    /**
33     * Pass Ajax call to a type
34     *
35     * @param Doku_Event $event event object by reference
36     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
37     *                           handler was registered]
38     */
39    public function handle_ajax(Doku_Event $event, $param) {
40        if ($event->data != 'plugin_farmsync') return;
41        $event->preventDefault();
42        $event->stopPropagation();
43
44        global $INPUT;
45
46        $sectok = $INPUT->str('sectok');
47        if (!checkSecurityToken($sectok)) {
48            $this->sendResponse(403, "Security-Token invalid!");
49            return;
50        }
51
52
53
54        $target = $INPUT->str('farmsync-animal');
55        $page = $INPUT->str('farmsync-page');
56        $source = $INPUT->str('farmsync-source');
57        $action = $INPUT->str('farmsync-action');
58
59        if ($INPUT->has('farmsync-getstruct')) {
60            $schemas = $this->farm_util->getAllStructSchemasList($source);
61            $form = new Form();
62            $form->addTagOpen('div')->addClass('structsync');
63            foreach ($schemas as $schema) {
64                $form->addTagOpen('div')->addClass('lineradio');
65                $form->addHTML("<label>$schema</label>");
66                $form->addTagOpen('div')->addClass('container');
67                $form->addCheckbox("farmsync_struct[schema_$schema]", "Schema");
68                $form->addCheckbox("farmsync_struct[assign_$schema]", "Replace assignments");
69                $form->addTagClose('div');
70                $form->addTagClose('div');
71            }
72            $form->addTagClose('div');
73            $this->sendResponse(200, $form->toHTML());
74            return;
75        }
76
77        if ($action == 'diff') {
78            $targetText = $this->farm_util->readRemotePage($target, $page, false);
79            $sourceText = $this->farm_util->readRemotePage($source, $page, false);
80            $diff = new \Diff(explode("\n", $targetText), explode("\n", $sourceText));
81            $diffformatter = new \TableDiffFormatter();
82            $result = '<table class="diff">';
83            $result .= '<tr>';
84            $result .= '<th colspan="2">' . $this->getLang('diff:animal') . '</th>';
85            $result .= '<th colspan="2">' . $this->getLang('diff:source') . '</th>';
86            $result .= '</tr>';
87            $result .= $diffformatter->format($diff);
88            $result .= '</table>';
89            $this->sendResponse(200, $result);
90            return;
91        }
92
93        if ($action == 'overwrite') {
94            $type = $INPUT->str('farmsync-type');
95            if (!$INPUT->has('farmsync-content')) {
96                if ($type == 'media') {
97                    $this->farm_util->saveRemoteMedia($source, $target, $page);
98                } elseif ($type == 'page') {
99                    $this->overwriteRemotePage($source, $target, $page);
100                } elseif ($type == 'struct') {
101                    $json = $this->farm_util->getAnimalStructSchemasJSON($source, array($page));
102                    $this->farm_util->importAnimalStructSchema($target, $page, $json[$page]);
103                } else {
104                    $targetFN = $this->farm_util->getRemoteFilename($target, $page, null, false);
105                    $sourceFN = $this->farm_util->getRemoteFilename($source, $page, null, false);
106
107                    $this->farm_util->replaceRemoteFile($targetFN, io_readFile($sourceFN), filemtime($sourceFN));
108                }
109                $this->farm_util->clearAnimalCache($target);
110                $this->sendResponse(200, "");
111                return;
112            }
113
114            if ($INPUT->has('farmsync-content')) {
115                $content = $INPUT->str('farmsync-content');
116                $this->writeManualMerge($source, $target, $page, $content);
117                $this->farm_util->clearAnimalCache($target);
118                $this->sendResponse(200, "");
119                return;
120            }
121        }
122        $this->sendResponse(400, "malformed request");
123    }
124
125    /**
126     * @param int $code
127     * @param string $msg
128     */
129    private function sendResponse($code, $msg) {
130        header('Content-Type: application/json');
131        http_status($code);
132        $json = new JSON;
133        echo $json->encode($msg);
134    }
135
136    public function overwriteRemotePage($source, $target, $page) {
137        $sourceModTime = $this->farm_util->getRemoteFilemtime($source, $page);
138        $this->farm_util->saveRemotePage($target, $page, $this->farm_util->readRemotePage($source, $page), $sourceModTime);
139    }
140
141    public function writeManualMerge($source, $target, $page, $content) {
142        global $INPUT;
143        $sourceModTime = $this->farm_util->getRemoteFilemtime($source, $page);
144        $targetArchiveFileName = $this->farm_util->getRemoteFilename($target, $page, $sourceModTime);
145        $changelogline = join("\t", array($sourceModTime, clientIP(true), DOKU_CHANGE_TYPE_MINOR_EDIT, $page, $INPUT->server->str('REMOTE_USER'), "Revision inserted due to manual merge"));
146        $this->farm_util->addRemotePageChangelogRevision($target, $page, $changelogline, false);
147        $this->farm_util->replaceRemoteFile($targetArchiveFileName, $this->farm_util->readRemotePage($source, $page));
148        $this->farm_util->saveRemotePage($target, $page, $content);
149    }
150}
151