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