1<?php
2
3use dokuwiki\Extension\ActionPlugin;
4use dokuwiki\Extension\EventHandler;
5use dokuwiki\Extension\Event;
6use dokuwiki\Form\Form;
7use dokuwiki\plugin\structpublish\meta\Constants;
8use dokuwiki\plugin\structpublish\meta\Revision;
9
10/**
11 * Action component responsible for the publish banner
12 * attached to struct data of a page
13 */
14class action_plugin_structpublish_banner extends ActionPlugin
15{
16    /** @var \helper_plugin_structpublish_db */
17    protected $dbHelper;
18
19    /** @var bool */
20    protected $compactView;
21
22    /** @inheritDoc */
23    public function register(EventHandler $controller)
24    {
25        $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, 'renderBanner');
26    }
27
28    /**
29     * Add banner to pages under structpublish control
30     */
31    public function renderBanner(Event $event)
32    {
33        global $ID;
34        global $INFO;
35        global $REV;
36
37        if ($event->data !== 'show') {
38            return;
39        }
40
41        $this->dbHelper = plugin_load('helper', 'structpublish_db');
42
43        if (!$this->dbHelper->isPublishable()) {
44            return;
45        }
46
47        $this->compactView = (bool)$this->getConf('compact_view');
48
49        // get the possible revisions needed in the banner
50        $newestRevision = new Revision($ID, $INFO['currentrev']);
51        if ($REV) {
52            $shownRevision = new Revision($ID, $REV);
53        } else {
54            $shownRevision = $newestRevision;
55        }
56        $latestpubRevision = $newestRevision->getLatestPublishedRevision();
57        $prevpubRevision = $shownRevision->getLatestPublishedRevision($REV ?:  $INFO['currentrev']);
58
59        $compactClass = $this->compactView ? ' compact' : '';
60        $banner = '<div class="plugin-structpublish-banner ' . $shownRevision->getStatus() . $compactClass . '">';
61
62        // status of the shown revision
63        $banner .= '<span class="icon">' .
64            inlineSVG(__DIR__ . '/../ico/' . $shownRevision->getStatus() . '.svg') .
65            '</span>';
66        $banner .= $this->getBannerText('status_' . $shownRevision->getStatus(), $shownRevision);
67
68        // link to previous or newest published version
69        if ($latestpubRevision !== null && $shownRevision->getRev() < $latestpubRevision->getRev()) {
70            $banner .= $this->getBannerText('latest_publish', $latestpubRevision, $shownRevision->getRev());
71        } else {
72            $banner .= $this->getBannerText('previous_publish', $prevpubRevision, $shownRevision->getRev());
73        }
74
75        // link to newest draft, if exists, is not shown already and user has a role
76        if (
77            $newestRevision->getRev() != $shownRevision->getRev() &&
78            $newestRevision->getStatus() != Constants::STATUS_PUBLISHED &&
79            $this->dbHelper->checkAccess($ID)
80        ) {
81            $banner .= $this->getBannerText('latest_draft', $newestRevision, $shownRevision->getRev());
82        }
83
84        // action buttons
85        if ($shownRevision->getRev() == $newestRevision->getRev()) {
86            $banner .= $this->actionButtons(
87                $shownRevision->getStatus(),
88                $latestpubRevision ? $this->increaseVersion($latestpubRevision->getVersion()) : '1'
89            );
90        }
91
92        $banner .= '</div>';
93        echo $banner;
94    }
95
96    /**
97     * Fills place holder texts with data from the given Revision
98     *
99     * @param string $name
100     * @param Revision $rev
101     * @return string
102     */
103    protected function getBannerText($name, $rev, $diff = '')
104    {
105        if ($rev === null) {
106            return '';
107        }
108
109        $replace = [
110            '{user}' => userlink($rev->getUser()),
111            '{revision}' => $this->makeLink($rev->getId(), $rev->getRev(), dformat($rev->getRev())),
112            '{datetime}' => $this->makeLink($rev->getId(), $rev->getRev(), dformat($rev->getTimestamp())),
113            '{version}' => hsc($rev->getVersion()),
114        ];
115
116        $text = $this->getLang($this->compactView ? "compact_banner_$name" : "banner_$name");
117
118        $text = strtr($text, $replace);
119
120        // add link to diff view
121        if ($diff && $diff !== $rev->getRev()) {
122            $link = wl($rev->getId(), ['do' => 'diff', 'rev2[0]' => $rev->getRev(), 'rev2[1]' => $diff]);
123            $icon = inlineSVG(__DIR__ . '/../ico/diff.svg');
124            $text .= ' <a href="' . $link . '" title="' . $this->getLang('diff') . '">' . $icon . '</a>';
125        }
126
127        $tag = $this->compactView ? 'span' : 'p';
128
129        return "<$tag class='$name'>$text</$tag>";
130    }
131
132    /**
133     * Create a HTML link to a specific revision
134     *
135     * @param string $id page id
136     * @param int $rev revision to link to
137     * @param int $text the link text to use
138     * @return string
139     */
140    protected function makeLink($id, $rev, $text)
141    {
142        $url = wl($id, ['rev' => $rev]);
143        return '<a href="' . $url . '">' . hsc($text) . '</a>';
144    }
145
146    /**
147     * Create the form for approval and publishing
148     *
149     * @param string $status current status
150     * @param string $newVersion suggested new Version
151     * @return string
152     */
153    protected function actionButtons($status, $newVersion)
154    {
155        global $ID;
156        if ($status === Constants::STATUS_PUBLISHED) {
157            return '';
158        }
159
160        $form = new Form();
161
162        if (
163            $status !== Constants::STATUS_APPROVED &&
164            $this->dbHelper->checkAccess($ID, [Constants::ACTION_APPROVE])
165        ) {
166            $form->addButton(
167                'structpublish[' . Constants::ACTION_APPROVE . ']',
168                $this->getLang('action_' . Constants::ACTION_APPROVE)
169            )->attr('type', 'submit');
170        }
171
172        if ($this->dbHelper->checkAccess($ID, [Constants::ACTION_PUBLISH])) {
173            $form->addTextInput('version', $this->getLang('newversion'))->val($newVersion);
174            $form->addButton(
175                'structpublish[' . Constants::ACTION_PUBLISH . ']',
176                $this->getLang('action_' . Constants::ACTION_PUBLISH)
177            )->attr('type', 'submit');
178        }
179
180        return $form->toHTML();
181    }
182
183    /**
184     * Tries to increase a given version
185     *
186     * @param string $version
187     * @return string
188     */
189    protected function increaseVersion($version)
190    {
191        $parts = explode('.', $version);
192        $last = array_pop($parts);
193
194        if (is_numeric($last)) {
195            $last++;
196        }
197        $parts[] = $last;
198
199        return implode('.', $parts);
200    }
201}
202