Skip to content
Snippets Groups Projects
Commit ce27c274 authored by Rasmus Fuhse's avatar Rasmus Fuhse
Browse files

Resolve "Wiki modernisieren"

Closes #3215

Merge request studip/studip!2180
parent 6722029b
No related branches found
No related tags found
No related merge requests found
Showing
with 1949 additions and 458 deletions
<?php
/**
* wiki.php - wiki controller
*
* @author Jan-Hendrik Willms <tleilax+studip@gmail.com>, Rasmus Fuhse <fuhse@data-quest.de>
* @license GPL2 or any later version
* @since 3.3
*/
class Course_WikiController extends AuthenticatedController
{
protected $allow_nobody = true;
protected $with_session = true;
protected $_autobind = true;
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
object_set_visit_module('wiki');
$this->range = Context::get();
}
public function page_action($page_id = null)
{
if ($page_id === null) {
$page_id = $this->range->getConfiguration()->WIKI_STARTPAGE_ID;
}
Navigation::activateItem('/course/wiki/start');
PageLayout::setTitle(Navigation::getItem('/course/wiki')->getTitle());
$this->page = new WikiPage($page_id);
$sidebar = Sidebar::Get();
if (!$this->page->isReadable()) {
throw new AccessDeniedException();
}
if (!$this->page->isNew()) {
// Table of Contents/QuickLinks
$widget = Sidebar::Get()->addWidget(new ListWidget());
$widget->setTitle(_('QuickLinks'));
$quicklinks = WikiPage::findOneBySQL("`name` = 'toc' AND `range_id` = ?", [$this->range->id]);
$toc_content = $quicklinks ? '<div class="wikitoc" id="00toc">' . wikiReady($quicklinks['content'], true, $this->range->id) . '</div>' : '';
$toc_content_empty = !trim(strip_tags($toc_content));
if (
(!$quicklinks && $GLOBALS['perm']->have_studip_perm($this->range->getConfiguration()->WIKI_CREATE_PERMISSION, $this->range->id))
|| ($quicklinks && $quicklinks->isEditable())
) {
$extra = sprintf(
'<a href="%s">%s</a>',
URLHelper::getLink('dispatch.php/course/wiki/edit_toc'),
$toc_content_empty
? Icon::create('add')->asImg(['title' => _('Erstellen')])
: Icon::create('edit')->asImg(['title' => _('Bearbeiten')])
);
$widget->setExtra($extra);
}
$element = new WidgetElement($toc_content_empty ? _('Keine QuickLinks vorhanden') : $toc_content);
$element->icon = Icon::create('link-intern');
$widget->addElement($element);
}
$this->edit_perms = $this->range->getConfiguration()->WIKI_CREATE_PERMISSION;
if (
$this->edit_perms === 'all'
|| $GLOBALS['perm']->have_studip_perm($this->edit_perms, $this->range->id)
) {
$actions = new ActionsWidget();
$actions->addLink(
_('Neue Wiki-Seite anlegen'),
$this->new_pageURL($this->page->id),
Icon::create('add'),
['data-dialog' => 'width=700']
);
if ($GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) {
$actions->addLink(
_('Wiki verwalten'),
$this->adminURL(),
Icon::create('admin'),
['data-dialog' => 'width=700']
);
}
if ($GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) { //minimum perm tutor necessary
$actions->addLink(
_('Seiten aus Veranstaltung importieren'),
$this->importURL(),
Icon::create('import'),
['data-dialog' => 'width=700']
);
}
$sidebar->addWidget($actions);
}
if (!$this->page->isNew()) {
//then the wiki is not empty
$search = new SearchWidget($this->searchURL());
$search->addNeedle(
_('Im Wiki suchen'),
'search',
true
);
$sidebar->addWidget($search);
$sidebar->addWidget($this->getViewsWidget($this->page, 'read'));
$exports = new ExportWidget();
$exports->addLink(
_('Als PDF exportieren'),
$this->pdfURL($this->page->id),
Icon::create('file-pdf')
);
$sidebar->addWidget($exports);
}
$startPage = WikiPage::find($this->range->getConfiguration()->WIKI_STARTPAGE_ID);
$this->contentbar = ContentBar::get()
->setTOC(CoreWiki::getTOC($this->page->parent && $startPage ? $startPage : $this->page, $this->page['name']))
->setIcon(Icon::create('wiki'))
->setInfo(sprintf(
_('Version %1$s, geändert von %2$s <br> am %3$s'),
$this->page->versionnumber,
sprintf(
'<a href="%s">%s</a>',
URLHelper::getLink('dispatch.php/profile', ['username' => get_username($this->page['user_id'])]),
htmlReady(get_fullname($this->page['user_id']))
),
date('d.m.Y H:i:s', $this->page['chdate'])
));
$action_menu = ActionMenu::get();
if ($this->page->isEditable()) {
$action_menu->addLink(
$this->editURL($this->page),
_('Bearbeiten'),
Icon::create('edit')
);
$action_menu->addLink(
$this->pagesettingsURL($this->page->id),
_('Seiteneinstellungen'),
Icon::create('settings'),
['data-dialog' => 'width=700']
);
$action_menu->addButton(
'delete',
_('Seite löschen'),
Icon::create('trash'),
['data-confirm' => _('Wollen Sie wirklich die komplette Seite löschen?'), 'form' => 'delete_page']
);
}
$action_menu->addLink(
'#',
_('Als Vollbild anzeigen'),
Icon::create('screen-full'),
['class' => 'fullscreen-trigger hidden-medium-down']
);
$this->contentbar->setActionMenu($action_menu);
}
public function pagesettings_action(WikiPage $page)
{
if (!$page->isEditable()) {
throw new AccessDeniedException();
}
$options = [
'' => _('Keine')
];
$descendants_ids = array_map(
function ($d) {
return $d->id;
},
$page->getDescendants()
);
WikiPage::findEachBySQL(
function (WikiPage $p) use ($page, &$options, $descendants_ids) {
if ($p->id !== $page->id && !in_array($p->id, $descendants_ids)) {
$options[$p->id] = $p->name;
}
},
'range_id = ? ORDER BY name',
[$this->range->id]
);
$groups = [
'all' => _('Alle'),
'tutor' => _('Lehrende und Tutoren/Tutorinnen'),
'dozent' => _('Nur Lehrende')
];
Statusgruppen::findEachBySQL(
function (Statusgruppen $group) use (&$groups) {
$groups[$group->id] = $group->name;
},
'`range_id` = ? ORDER BY `name`',
[$this->range->id]
);
$oldname = $page->name;
$this->form = \Studip\Forms\Form::fromSORM(
$page,
[
'legend' => _('Seiteneinstellung'),
'fields' => [
'name' => [
'label' => _('Titel der Seite'),
'required' => true,
'validate' => function ($value, $input) {
$page = $input->getContextObject();
if ($value !== $page->name) {
$page2 = WikiPage::findOneBySQL('`range_id` = :range_id AND `name` = :name', [
'range_id' => $page['range_id'],
'name' => $value
]);
if ($page2) {
return _('Dieser Name ist bereits vergeben.');
}
}
return true;
}
],
'parent_id' => [
'label' => _('Übergeordnete Seite im Inhaltsverzeichnis'),
'type' => 'select',
'options' => $options
],
'read_permission' => [
'label' => _('Lesezugriff für'),
'type' => 'select',
'options' => $groups
],
'write_permission' => [
'label' => _('Schreibzugriff für'),
'type' => 'select',
'options' => $groups
]
]
],
$this->pagesettingsURL($page->id)
)->addStoreCallback(function ($form, $values) use ($oldname) {
if ($values['name'] === $oldname) {
return;
}
$page = $form->getLastPart()->getContextObject();
$other_pages = WikiPage::findBySQL(
"`range_id` = :range_id AND `page_id` != :page_id AND `content` LIKE :search",
[
'page_id' => $page->id,
'range_id' => $page['range_id'],
'search' => '%' . $oldname . '%',
]
);
foreach ($other_pages as $p2) {
$p2['content'] = preg_replace(
"/\[\[\s*" . $oldname . "\b/",
"[[ " . $values['name'],
$p2['content']
);
$p2->store();
}
})->validate();
if (Request::isPost()) {
$this->form->store();
PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.'));
if ($page->isReadable()) {
$this->redirect($this->pageURL($page->id));
} else {
$this->redirect($this->allpagesURL());
}
return;
}
$this->render_form($this->form);
}
public function delete_action(WikiPage $page)
{
if (!Request::isPost() || !CSRFProtection::verifyRequest()) {
throw new AccessDeniedException();
}
$name = $page->name;
$page->delete();
PageLayout::postSuccess(sprintf(_('Die Seite %s wurde gelöscht.'), htmlReady($name)));
$this->redirect($this->allpagesURL());
}
public function allpages_action()
{
Navigation::activateItem('/course/wiki/allpages');
$this->pages = WikiPage::findBySQL(
"`range_id` = ? ORDER BY `name` ASC",
[$this->range->id]
);
if ($GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) {
$actions = new ActionsWidget();
$actions->addLink(
_('Neue Wiki-Seite anlegen'),
$this->new_pageURL(),
Icon::create('add'),
['data-dialog' => 'width=700']
);
$actions->addLink(
_('Wiki verwalten'),
$this->adminURL(),
Icon::create('admin'),
['data-dialog' => 'width=700']
);
Sidebar::Get()->addWidget($actions);
}
$search = new SearchWidget($this->searchURL());
$search->addNeedle(
_('Im Wiki suchen'),
'search',
true
);
Sidebar::Get()->addWidget($search);
$widget = new ExportWidget();
$widget->addLink(
_('Alle Wiki-Seiten als PDF exportieren'),
$this->pdf_allpagesURL(),
Icon::create('file-pdf')
);
Sidebar::Get()->addWidget($widget);
}
public function admin_action()
{
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) {
throw new AccessDeniedException();
}
$this->config = $this->range->getConfiguration();
$this->pages = WikiPage::findBySQL(
'`range_id` = ? ORDER BY `name` ASC',
[$this->range->id]
);
}
public function store_course_config_action()
{
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) {
throw new AccessDeniedException();
}
CSRFProtection::verifyUnsafeRequest();
$this->config = $this->range->getConfiguration();
$this->config->store('WIKI_STARTPAGE_ID', trim(Request::option('wiki_startpage_id')));
if (
$this->config->WIKI_CREATE_PERMISSION === 'all'
|| $GLOBALS['perm']->have_studip_perm($this->config->WIKI_CREATE_PERMISSION, Context::getId())
) {
$this->config->store('WIKI_CREATE_PERMISSION', trim(Request::option('wiki_create_permission')));
}
if (
$this->config->WIKI_RENAME_PERMISSION === 'all'
|| $GLOBALS['perm']->have_studip_perm($this->config->WIKI_RENAME_PERMISSION, $this->range->id)
) {
$this->config->store('WIKI_RENAME_PERMISSION', trim(Request::option('wiki_rename_permission')));
}
PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.'));
if (WikiPage::countBySQL('`range_id` = ? ORDER BY `name` ASC', [$this->range->id]) > 0) {
$this->redirect($this->allpagesURL());
} else {
$this->redirect($this->pageURL());
}
}
public function edit_action(WikiPage $page = null)
{
if ($page->isNew() && Request::get('keyword')) {
$name = trim(Request::get('keyword'));
$page = WikiPage::findOneBySQL('`name` = :name AND `range_id` = :range_id', [
'name' => $name,
'range_id' => Context::getId()
]);
if (!$page) {
$page = WikiPage::create([
'name' => $name,
'range_id' => Context::getId(),
'parent_id' => Request::option('parent_id', $this->range->getConfiguration()->WIKI_STARTPAGE_ID),
]);
}
$this->redirect($this->editURL($page));
return;
}
if (!$page->isEditable()) {
throw new AccessDeniedException();
}
Navigation::activateItem('/course/wiki/start');
$user = User::findCurrent();
WikiOnlineEditingUser::deleteBySQL(
"`page_id` = :page_id AND `chdate` < UNIX_TIMESTAMP() - :threshold",
[
'page_id' => $page->id,
'threshold' => WikiOnlineEditingUser::$threshold
]
);
$pageData = [
'page_id' => $page->id,
'user_id' => $user->id
];
$online_user = WikiOnlineEditingUser::findOneBySQL(
'`page_id` = :page_id AND `user_id` = :user_id',
$pageData
);
if (!$online_user) {
$online_user = WikiOnlineEditingUser::build($pageData);
}
$editingUsers = WikiOnlineEditingUser::countBySQL(
"`page_id` = ? AND `editing` = 1 AND `user_id` != ?",
[$page->id, $user->id]
);
$online_user->editing = $editingUsers === 0 ? 1 : 0;
$online_user->chdate = time();
$online_user->store();
$this->me_online = $online_user;
$this->online_users = WikiOnlineEditingUser::findBySQL(
"JOIN `auth_user_md5` USING (`user_id`)
WHERE `page_id` = ?
ORDER BY Nachname, Vorname",
[$page->id]
);
$startPage = WikiPage::find($this->range->getConfiguration()->WIKI_STARTPAGE_ID);
$this->contentbar = ContentBar::get()
->setTOC(CoreWiki::getTOC($startPage, $page['name']))
->setIcon(Icon::create('wiki'))
->setInfo(_('Zuletzt gespeichert') .': '. '<studip-date-time :timestamp="Math.floor(lastSaveDate / 1000)" :relative="true"></studip-date-time>');
}
public function apply_editing_action(WikiPage $page)
{
if (!$page->isEditable() || !Request::isPost()) {
throw new AccessDeniedException();
}
$user = User::findCurrent();
$pageData = [
'page_id' => $page->id,
'user_id' => $user->id
];
$online_user = WikiOnlineEditingUser::findOneBySQL(
'`page_id` = :page_id AND `user_id` = :user_id',
$pageData
);
if (!$online_user) {
$online_user = WikiOnlineEditingUser::build($pageData);
}
$editingUsers = WikiOnlineEditingUser::countBySQL(
"`page_id` = ? AND `editing` = 1 AND `user_id` != ?",
[$page->id, $user->id]
);
if ($editingUsers > 0) {
$online_user->editing_request = 1;
} else {
$online_user->editing = 1;
}
$online_user->store();
$output = [
'me_online' => $online_user->toArray(),
'users' => $page->getOnlineUsers()
];
$this->render_json($output);
}
public function leave_editing_action(WikiPage $page)
{
if (!$page->isEditable()) {
throw new AccessDeniedException();
}
$user = User::findCurrent();
$pageData = [
'page_id' => $page->id,
'user_id' => $user->id
];
WikiOnlineEditingUser::deleteBySQL(
'`page_id` = :page_id AND `user_id` = :user_id',
$pageData
);
$this->redirect($this->pageURL($page));
}
public function delegate_edit_mode_action(WikiPage $page, $user_id)
{
if (!$page->isEditable() || !Request::isPost()) {
throw new AccessDeniedException();
}
$user = User::findCurrent();
$pageData = [
'page_id' => $page->id,
'user_id' => $user->id
];
$online_user_me = WikiOnlineEditingUser::findOneBySQL(
'`page_id` = :page_id AND `user_id` = :user_id',
$pageData
);
if (!$online_user_me->editing) {
$this->render_json([
'error' => 'not_in_edit_mode'
]);
}
$online_user_them = WikiOnlineEditingUser::findOneBySQL(
'`page_id` = :page_id AND `user_id` = :user_id',
['page_id' => $page->id, 'user_id' => $user_id]
);
if (!$online_user_them || !$online_user_them->editing_request) {
$this->render_json([
'error' => 'user_not_requested_edit_mode'
]);
}
$online_user_me->editing = 0;
$online_user_me->store();
$online_user_them->editing_request = 1; //that will be set to 0 by the user themself
$online_user_them->editing = 1;
$online_user_them->store();
$this->render_json([
'message' => 'edit mode delegated'
]);
}
public function save_action(WikiPage $page)
{
CSRFProtection::verifyUnsafeRequest();
if (!$page->isEditable()) {
throw new AccessDeniedException();
}
$page->content = \Studip\Markup::markAsHtml(trim(Request::get('content')));
$page->store();
PageLayout::postSuccess(_('Die Seite wurde gespeichert.'));
$this->redirect($this->pageURL($page));
}
public function edit_toc_action()
{
$quicklinks = WikiPage::findOneBySQL(
"`name` = 'toc' AND `range_id` = ?",
[$this->range->id]
);
if (!$quicklinks) {
$quicklinks = WikiPage::create([
'range_id' => $this->range->id,
'name' => 'toc'
]);
}
$this->redirect($this->editURL($quicklinks));
}
public function newpages_action()
{
Navigation::activateItem('/course/wiki/listnew');
$statement = DBManager::get()->prepare("
SELECT `wiki_pages`.`page_id` AS `id`,
0 AS `is_version`,
`wiki_pages`.`chdate` AS `timestamp`
FROM `wiki_pages`
WHERE `wiki_pages`.`range_id` = :range_id
UNION
SELECT `wiki_versions`.`version_id` AS `id`,
1 AS `is_version`,
`wiki_versions`.`mkdate` AS `timestamp`
FROM `wiki_versions`
JOIN `wiki_pages` USING (`page_id`)
WHERE `wiki_pages`.`range_id` = :range_id
ORDER BY `timestamp`
");
$statement->execute([
'range_id' => $this->range->id
]);
$this->versions = [];
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
if ($row['is_version']) {
$this->versions[] = WikiVersion::find($row['id']);
} else {
$this->versions[] = WikiPage::find($row['id']);
}
}
}
public function history_action(WikiPage $page)
{
Navigation::activateItem('/course/wiki/start');
Sidebar::Get()->addWidget($this->getViewsWidget($this->page, 'history'));
}
public function version_action(WikiVersion $version)
{
Navigation::activateItem('/course/wiki/start');
Sidebar::Get()->addWidget($this->getViewsWidget($version->page, 'history'));
$startPage = WikiPage::find($this->range->getConfiguration()->WIKI_STARTPAGE_ID);
$this->contentbar = ContentBar::get()
->setTOC(CoreWiki::getTOC($startPage, $version->page['name']))
->setIcon(Icon::create('wiki'))
->setInfo(sprintf(
_('Version %1$s vom %2$s'),
$version->versionnumber,
date('d.m.Y H:i:s', $version['mkdate'])
));
}
public function blame_action(WikiPage $page)
{
Navigation::activateItem('/course/wiki/start');
Sidebar::Get()->addWidget($this->getViewsWidget($page, 'blame'));
$version = WikiVersion::findOneBySQL(
"`page_id` = ? ORDER BY `mkdate` LIMIT 1",
[$page->id]
);
$lines = Studip\Markup::removeHtml($version->content);
$lines = explode("\n", str_replace("\r", '', $lines));
$this->line_versions = array_fill(0, count($lines), $version);
$this->diffarray = WikiDiffer::toDiffLineArray($version->content, $version->user_id);
$differ = new WikiDiffer();
$k = 0;
while ($version && !is_a($version, WikiPage::class)) {
$version = $version->successor;
if ($version) {
$diffarray2 = WikiDiffer::toDiffLineArray($version->content, $version->user_id);
$newarray = $differ->arr_compare('diff', $this->diffarray, $diffarray2);
$this->diffarray = []; //completely rewrite $this->diffarray with newer version
foreach ($newarray as $number => $i) {
if ($i->status['diff'] !== '-') {
$this->diffarray[] = $i;
}
if ($i->status['diff'] === '+') {
$this->line_versions[$number] = $version;
}
}
}
$k++;
if ($k > 100) {
break;
}
}
$this->diffarray[] = null;
}
public function diff_action(WikiPage $page)
{
Navigation::activateItem('/course/wiki/start');
Sidebar::Get()->addWidget($this->getViewsWidget($page, 'diff'));
$this->diffs = [];
$last_version = null;
foreach (array_reverse($page->versions->getArrayCopy()) as $version) {
if ($last_version === null) {
$last_version = $version;
$this->diffs[] = [
'diff' => WikiDiffer::doDiff(
Studip\Markup::removeHtml($version->content),
''
),
'version' => $version
];
continue;
}
$this->diffs[] = [
'diff' => WikiDiffer::doDiff(
Studip\Markup::removeHtml($version->content),
Studip\Markup::removeHtml($last_version->content)
),
'version' => $version
];
$last_version = $version;
}
$this->diffs[] = [
'diff' => WikiDiffer::doDiff(
Studip\Markup::removeHtml($page->content),
$last_version !== null ? Studip\Markup::removeHtml($last_version->content) : ''
),
'version' => $page
];
}
public function versiondiff_action (WikiPage $page, $version_id = null)
{
if ($version_id !== null) {
$this->version = WikiVersion::find($version_id);
}
if (
($this->version && $this->version->page_id != $page->id)
|| !$page->isReadable()
) {
throw new AccessDeniedException();
}
PageLayout::setTitle(_('Änderungen dieser Version'));
$content = $this->version ? $this->version->content : $page->content;
$predecessor = $this->version ? $this->version->predecessor : $page->predecessor;
$this->diff = WikiDiffer::doDiff(
Studip\Markup::removeHtml($content),
Studip\Markup::removeHtml($predecessor ? $predecessor->content : '')
);
if (!$this->version) {
$this->version = $page;
}
}
public function new_page_action($parent_id = null)
{
if (
$this->range->getConfiguration()->WIKI_CREATE_PERMISSION !== 'all'
&& !$GLOBALS['perm']->have_studip_perm($this->range->getConfiguration()->WIKI_CREATE_PERMISSION, $this->range->id)
) {
throw new AccessDeniedException();
}
$page = new WikiPage();
$page->parent_id = $parent_id ?? $this->range->getConfiguration()->WIKI_STARTPAGE_ID;
$parent_id = $parent_id ?? $this->range->getConfiguration()->WIKI_STARTPAGE_ID;
PageLayout::setTitle(_('Neue Wikiseite erstellen'));
$options = [
'-' => _('Keine')
];
WikiPage::findEachBySQL(
function (WikiPage $p) use (&$options) {
$options[$p->id] = $p->name;
},
'range_id = ? ORDER BY name',
[$this->range->id]
);
$this->form = \Studip\Forms\Form::fromSORM(
$page,
[
'legend' => _('Daten'),
'fields' => [
'range_id' => [
'type' => 'no',
'mapper' => function () { return $this->range->id; }
],
'name' => [
'required' => true,
'label' => _('Name der Seite'),
'validate' => function ($value, $input) {
$name_count = WikiPage::countBySql('`name` = :name AND `range_id` = :range_id', [
'name' => $value,
'range_id' => $this->range->id
]);
if ($name_count === 0) {
return true;
} else {
return _('Name existiert schon.');
}
}
],
'parent_id' => [
'label' => _('Übergeordnete Seite im Inhaltsverzeichnis'),
'type' => 'select',
'options' => $options
],
'autocreate_links' => [
'label' => _('Den Seitennamen der neuen Seite automatisch in anderen Wikiseiten verlinken.'),
'type' => 'checkbox',
'permission' => WikiPage::countBySql("`range_id` = ?", [$this->range->id]) > 0
]
]
],
$this->allpagesURL()
)->addStoreCallback(function ($form, $values) {
$page = $form->getLastPart()->getContextObject();
$other_pages = WikiPage::countBySQL(
"`range_id` = :range_id AND `page_id` != :page_id",
[
'page_id' => $page->id,
'range_id' => $page->range_id,
]
);
if ($other_pages == 0) {
$this->range->getConfiguration()->store('WIKI_STARTPAGE_ID', $page->id);
}
if (Request::bool('autocreate_links')) {
$pages = WikiPage::findBySQL(
"`range_id` = :range_id AND `content` LIKE :search",
[
'range_id' => $this->range->id,
'search' => '%' . $values['name'] . '%',
]
);
foreach ($pages as $page) {
$page->content = preg_replace(
"/\b" . $values['name'] . "\b/",
'[[ ' . $values['name'] . ' ]]',
$page->content
);
$page->store();
}
}
}
)->setURL($this->new_pageURL($parent_id))
->validate();
if (Request::isPost()) {
$this->form->store();
$this->redirect($this->editURL($page));
} else {
$this->render_form($this->form);
}
}
public function search_action()
{
Navigation::activateItem('/course/wiki/allpages');
if (Request::get('search')) {
$statement = DBManager::get()->prepare("
SELECT `wiki_pages`.`page_id`,
`wiki_pages`.`name` LIKE :searchterm AS `is_in_name`,
`wiki_pages`.`content` LIKE :searchterm AS `is_in_content`,
`wiki_versions`.`content` LIKE :searchterm AS `is_in_history`,
`wiki_versions`.`name` LIKE :searchterm AS `is_in_old_name`,
`wiki_versions`.`version_id`
FROM `wiki_pages`
LEFT JOIN `statusgruppe_user` ON (`statusgruppe_user`.`statusgruppe_id` = `wiki_pages`.`read_permission`)
LEFT JOIN `wiki_versions` ON (`wiki_versions`.`page_id` = `wiki_pages`.`page_id` AND (`wiki_versions`.`content` LIKE :searchterm OR `wiki_versions`.`name` LIKE :searchterm))
WHERE `wiki_pages`.`range_id` = :range_id
AND (`wiki_pages`.`name` LIKE :searchterm
OR `wiki_pages`.`content` LIKE :searchterm
OR `wiki_versions`.`content` LIKE :searchterm
OR `wiki_versions`.`name` LIKE :searchterm
)
AND (
`wiki_pages`.`read_permission` = 'all'
OR `statusgruppe_user`.`user_id` = :user_id
OR `wiki_pages`.`read_permission` = :perm
OR (`wiki_pages`.`read_permission` = 'tutor' AND :perm = 'dozent')
)
ORDER BY `is_in_name` DESC, `is_in_content` DESC, `is_in_old_name` DESC, `is_in_history` DESC
");
$search = str_replace(['\\', '_', '%'], ['\\\\', '\\_', '\\%'], Request::get('search'));
$perm = $GLOBALS['perm']->get_perm();
if (in_array($perm, ['admin', 'root'])) {
$perm = 'dozent';
}
$statement->execute([
'range_id' => $this->range->id,
'searchterm' => '%' . $search . '%',
'perm' => $perm,
'user_id' => User::findCurrent()->id
]);
$data = $statement->fetchAll(PDO::FETCH_ASSOC);
$this->pages = [];
foreach ($data as $row) {
if (!isset($this->pages[$row['page_id']])) {
$this->pages[$row['page_id']] = [
'page' => WikiPage::find($row['page_id']),
'is_in_name' => $row['is_in_name'],
'is_in_content' => $row['is_in_content'],
'is_in_history' => $row['is_in_history'],
'is_in_old_name' => $row['is_in_old_name'],
'versions' => [$row['version_id']]
];
} else {
$this->pages[$row['page_id']]['versions'][] = $row['version_id'];
$this->pages[$row['page_id']]['is_in_name'] = max($this->pages[$row['page_id']]['is_in_name'], $row['is_in_name']);
$this->pages[$row['page_id']]['is_in_content'] = max($this->pages[$row['page_id']]['is_in_content'], $row['is_in_content']);
$this->pages[$row['page_id']]['is_in_history'] = max($this->pages[$row['page_id']]['is_in_history'], $row['is_in_history']);
$this->pages[$row['page_id']]['is_in_old_name'] = max($this->pages[$row['page_id']]['is_in_old_name'], $row['is_in_old_name']);
}
}
} else {
$this->redirect($this->pageURL());
}
$search = new SearchWidget($this->searchURL());
$search->addNeedle(
_('Im Wiki suchen'),
'search',
true
);
Sidebar::Get()->addWidget($search);
}
public function pdf_action(WikiPage $page)
{
if (!$page->isReadable()) {
throw new AccessDeniedException();
}
$document = new ExportPDF();
$document->SetTitle(_('Wiki: ') . $page->name);
$document->setHeaderTitle(sprintf(_('Wiki von "%s"'), $this->range->name));
$document->setHeaderSubtitle(sprintf(_('Seite: %s'), $page->name));
$document->addPage();
$content = $page->content;
//remove wiki-links:
$content = preg_replace('/\[\[[^|\]]*\|([^]]*)\]\]/', '$1', $content);
$content = preg_replace('/\[\[([^|\]]*)\]\]/', '$1', $content);
$document->writeHTML($content);
$this->render_pdf(
$document,
Context::getHeaderLine() . ' - ' . $page->name . '.pdf',
true
);
}
public function pdf_allpages_action()
{
if (!$GLOBALS['perm']->have_studip_perm('user', Context::getId())) {
throw new AccessDeniedException();
}
$pages = WikiPage::findBySql('`range_id` = ? ORDER BY `name` ASC', [Context::getId()]);
$document = new ExportPDF();
$document->SetTitle(_('Wiki: ') . Context::get()->name);
$document->setHeaderTitle(sprintf(_('Wiki von "%s"'), Context::get()->name));
foreach ($pages as $page) {
if (!$page->isReadable()) {
continue;
}
$document->setHeaderSubtitle(sprintf(_('Seite: %s'), $page->name));
$document->addPage();
// We need the @ in front since TCPDF might throw warning that can lead
// to errors viewing the document
$content = $page->content;
//remove wiki-links:
$content = preg_replace('/\[\[[^|\]]*\|([^]]*)\]\]/', '$1', $content);
$content = preg_replace('/\[\[([^|\]]*)\]\]/', '$1', $content);
//@$document->addContent($content);
@$document->writeHTML($content);
}
$this->render_pdf(
$document,
Context::getHeaderLine() . '.pdf',
true
);
}
protected function getViewsWidget(WikiPage $page, string $action): ViewsWidget
{
$views = new ViewsWidget();
$link = $views->addLink(
_('Lesen'),
$this->pageURL($page)
)->setActive($action === 'read');
$link = $views->addLink(
_('Seiten-Historie'),
$this->historyURL($page)
)->setActive($action === 'history');
$link = $views->addLink(
_('Änderungsliste'),
$this->diffURL($page)
)->setActive($action === 'diff');
$link = $views->addLink(
_('Text mit Autor/-innenzuordnung'),
$this->blameURL($page)
)->setActive($action === 'blame');
return $views;
}
/**
* This action is responsible for importing wiki pages into the wiki
* of a course from another course.
*/
public function import_action()
{
$edit_perms = $this->range->getConfiguration()->WIKI_CREATE_PERMISSION;
if ($edit_perms !== 'dozent') {
$edit_perms = 'tutor';
}
if (!$GLOBALS['perm']->have_studip_perm($edit_perms, $this->range->id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Änderungen an Wiki-Seiten vorzunehmen!'));
}
if (!$this->range) {
PageLayout::postError(
_('Die ausgewählte Veranstaltung wurde nicht gefunden!')
);
}
$this->course_search = new QuickSearch(
'selected_range_id',
new MyCoursesSearch(
'Seminar_id',
$GLOBALS['perm']->get_perm(),
[
'userid' => User::findCurrent()->id,
'exclude' => [$this->range->id],
'institutes' => array_column(Institute::getMyInstitutes(), 'Institut_id')
],
's.`Seminar_id` IN (
SELECT range_id FROM wiki_pages
WHERE range_id = s.`Seminar_id`
)'
)
);
$this->course_search->fireJSFunctionOnSelect(
"function() {jQuery(this).closest('form').submit();}"
);
$this->show_wiki_page_form = false;
$this->bad_course_search = false;
$this->success = false;
//The following steps are identical for the search and the import.
if (Request::submittedSome('selected_range_id', 'import')) {
CSRFProtection::verifyUnsafeRequest();
//Search for wiki pages in the selected course:
$this->selected_range_id = Request::option('selected_range_id');
$this->selected_course = Course::find($this->selected_range_id);
if (!$this->selected_course) {
$this->bad_course_search = true;
return;
}
$this->wiki_pages = WikiPage::findBySQL(
"`range_id` = ? ORDER BY `name`",
[$this->selected_course->id]
);
$this->show_wiki_page_form = true;
}
//The import required additional functionality:
if (Request::submitted('import')) {
CSRFProtection::verifyUnsafeRequest();
$this->selected_wiki_page_ids = Request::getArray('selected_wiki_page_ids');
if (!$this->selected_wiki_page_ids) {
PageLayout::postInfo(_('Es wurden keine Wiki-Seiten ausgewählt!'));
return;
}
$selected_wiki_pages = [];
foreach ($this->selected_wiki_page_ids as $id) {
$wiki_page = WikiPage::find($id);
if ($wiki_page) {
$selected_wiki_pages[] = $wiki_page;
}
}
if (!$selected_wiki_pages) {
PageLayout::postError(_('Es wurden keine Wiki-Seiten gefunden!'));
return;
}
$errors = [];
foreach ($selected_wiki_pages as $selected_page) {
if ($selected_page->isReadable()) {
$count = WikiPage::countBySql(
"`range_id` = :range_id AND `name` = :name",
[
'range_id' => $this->range->id,
'name' => $selected_page['name']
]
);
if ($count === 0) {
$new_page = WikiPage::build([
'range_id' => $this->range->id,
'user_id' => $selected_page->user_id,
'name' => $selected_page->name,
'content' => $selected_page->content,
'chdate' => $selected_page->chdate,
]);
if (!$new_page->store()) {
$errors[] = sprintf(
_('Fehler beim Import der Wiki-Seite %s!'),
htmlReady($new_page->name)
);
}
}
}
}
if ($errors) {
PageLayout::postError(
_('Die folgenden Fehler traten beim Import auf:'),
$errors
);
} else {
$this->show_wiki_page_form = false;
$this->success = true;
PageLayout::postSuccess(
ngettext(
'Die Wiki-Seite wurde importiert! Sie ist unter der Ansicht "Alle Seiten" erreichbar.',
'Die Wiki-Seiten wurden importiert! Sie sind unter der Ansicht "Alle Seiten" erreichbar.',
count($selected_wiki_pages)
)
);
}
}
}
}
......@@ -118,6 +118,8 @@ class JsupdaterController extends AuthenticatedController
'messages' => $this->getMessagesUpdates($pageInfo),
'personalnotifications' => $this->getPersonalNotificationUpdates($pageInfo),
'questionnaire' => $this->getQuestionnaireUpdates($pageInfo),
'wiki_page_content' => $this->getWikiPageContents($pageInfo),
'wiki_editor_status' => $this->getWikiEditorStatus($pageInfo),
];
return array_filter($data);
......@@ -260,6 +262,104 @@ class JsupdaterController extends AuthenticatedController
return $data;
}
private function getWikiPageContents($pageInfo): array
{
$data = [];
if (!empty($pageInfo['wiki_page_content'])) {
foreach ($pageInfo['wiki_page_content'] as $page_id) {
$page = WikiPage::find($page_id);
if ($page && $page->isReadable() && ($page->chdate >= Request::int('server_timestamp'))) {
$data['contents'][$page_id] = wikiReady($page->content, true, $page->range_id, $page->id);
}
}
}
return $data;
}
private function getWikiEditorStatus($pageInfo): array
{
$data = [];
if (!empty($pageInfo['wiki_editor_status'])) {
$user = User::findCurrent();
foreach ((array) $pageInfo['wiki_editor_status']['page_ids'] as $page_id) {
WikiOnlineEditingUser::deleteBySQL(
"`page_id` = :page_id AND `chdate` < UNIX_TIMESTAMP() - :threshold",
[
'page_id' => $page_id,
'threshold' => WikiOnlineEditingUser::$threshold
]
);
$page = WikiPage::find($page_id);
if ($page && $page->isEditable()) {
if (
$pageInfo['wiki_editor_status']['focussed'] == $page_id
&& !empty($pageInfo['wiki_editor_status']['page_content'])
) {
$page->content = \Studip\Markup::markAsHtml(
$pageInfo['wiki_editor_status']['page_content']
);
$page->store();
}
$onlineData = [
'user_id' => $user->id,
'page_id' => $page_id
];
$online = WikiOnlineEditingUser::findOneBySQL(
"`user_id` = :user_id AND `page_id` = :page_id",
$onlineData
);
if (!$online) {
$online = WikiOnlineEditingUser::build($onlineData);
}
$editingUsers = WikiOnlineEditingUser::countBySQL(
"`page_id` = ? AND `editing` = 1 AND `user_id` != ?",
[$page->id, $user->id]
);
if ($editingUsers > 0) {
$online->editing = 0;
} elseif ($online->editing && $online->editing_request) {
// this is the mode that this user requested the editing mode and was granted to get it:
$online->editing_request = 0;
} elseif ($online->editing_request) {
$other_requests = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `editing_request` = 1 AND `user_id` != ?", [
$page->id,
$user->id,
]);
if ($other_requests === 0) {
$online->editing_request = 0;
$online->editing = 1;
}
} else {
if ($pageInfo['wiki_editor_status']['focussed'] == $page_id) {
$online->editing = 1;
} else {
$other_users = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `user_id` != ?", [
$page->id,
$user->id,
]);
if ($other_users === 0) {
// if I'm the only user I don't need to lose the edit mode
$online->editing = 1;
} else {
$online->editing = 0;
}
}
}
$online->chdate = time();
$online->store();
$data['contents'][$page_id] = wikiReady($page->content, true, $page->range_id, $page_id);
$data['wysiwyg_contents'][$page_id] = $page->content;
$data['pages'][$page_id]['editing'] = $online->editing;
} else {
$data['pages'][$page_id]['editing'] = 0;
}
$data['pages'][$page_id]['chdate'] = $page->chdate;
$data['users'][$page_id] = $page->getOnlineUsers();
}
}
return $data;
}
private function getCoursewareClipboardUpdates($pageInfo)
{
$counter = $pageInfo['coursewareclipboard']['counter'] ?? 0;
......
......@@ -170,15 +170,19 @@ class PublicCoursesController extends AuthenticatedController
// Wiki
if (Config::get()->WIKI_ENABLE) {
$query = "SELECT range_id, COUNT(DISTINCT keyword) AS count
FROM wiki
WHERE range_id IN (?)
GROUP BY range_id";
$query = "SELECT `range_id`, COUNT(`wiki_versions`.`version_id`) + 1 AS count
FROM `wiki_pages`
LEFT JOIN `wiki_versions` USING (`page_id`)
WHERE `range_id` IN (?)
GROUP BY `range_id`";
$statement = DBManager::get()->prepare($query);
$statement->execute([$seminar_ids]);
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
if (isset($seminars[$row['range_id']]['navigations']['CoreWiki'])) {
$nav = new Navigation('wiki', 'wiki.php');
$nav = new Navigation(
'wiki',
URLHelper::getURL('dispatch.php/course/wiki/page', ['cid' => $row['range_id']])
);
$nav->setImage(Icon::create('wiki', Icon::ROLE_CLICKABLE, ["title" => sprintf(_('%s WikiSeiten'), $row['count'])]));
$seminars[$row['range_id']]['navigations']['CoreWiki'] = $nav;
}
......
......@@ -585,6 +585,11 @@ abstract class StudipController extends Trails_Controller
);
}
public function render_form(\Studip\Forms\Form $form)
{
$this->render_text($form->render());
}
/**
* relays current request to another controller and returns the response
* the other controller is given all assigned properties, additional parameters are passed
......
<?php
/**
* wiki.php - wiki controller (currently only a helper)
*
* @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
* @license GPL2 or any later version
* @since 3.3
*/
require_once 'lib/wiki.inc.php';
class WikiController extends AuthenticatedController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
$this->keyword = Request::get('keyword');
$this->range_id = Context::getId();
if (Navigation::hasItem('/course/wiki/show')) {
Navigation::activateItem('/course/wiki/show');
}
}
/**
* Display dialog to create a new wiki page.
*/
public function create_action()
{
$this->wiki_page_names = Array();
$wiki_pages = WikiPage::findLatestPages(Context::getId());
$wiki_pages->filter(function ($wikipage) use (&$wiki_page_names) {
$wikipage->keyword === 'WikiWikiWeb' ?: $this->wiki_page_names[] = $wikipage->keyword;
});
natcasesort($this->wiki_page_names);
$wikistartpage = WikiPage::findLatestPage(Context::getId(), 'WikiWikiWeb');
if ($wikistartpage) {
array_unshift($this->wiki_page_names, 'WikiWikiWeb');
}
getShowPageInfobox($this->keyword, true);
}
/**
* change course permissions of wiki pages
*/
public function change_courseperms_action()
{
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range_id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Berechtigungen Wiki-Seiten zu ändern!'));
}
// prevent malformed urls: keyword must be set
if (!$this->keyword) {
throw new InvalidArgumentException(_('Es wurde keine Seite übergeben!'));
}
PageLayout::setTitle(_('Wiki-Einstellungen ändern'));
$this->restricted = CourseConfig::get($this->range_id)->WIKI_COURSE_EDIT_RESTRICTED;
getShowPageInfobox($this->keyword, true);
}
/**
* store course permissions of wiki pages
*/
public function store_courseperms_action()
{
CSRFProtection::verifyUnsafeRequest();
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range_id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Berechtigungen Wiki-Seiten zu ändern!'));
}
// prevent malformed urls: keyword must be set
if (!$this->keyword) {
throw new InvalidArgumentException(_('Es wurde keine Seite übergeben!'));
}
CourseConfig::get($this->range_id)->store(
'WIKI_COURSE_EDIT_RESTRICTED',
Request::int('courseperms')
);
PageLayout::postSuccess(_('Die veranstaltungsbezogenen Berechtigungen auf die Wiki-Seiten wurden geändert!'));
$this->redirect(URLHelper::getURL('wiki.php', ['keyword' => $this->keyword]));
}
/**
* change page permission of a single wiki page
*/
public function change_page_config_action()
{
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range_id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Berechtigungen Wiki-Seiten zu ändern!'));
}
// prevent malformed urls: keyword must be set
if (!$this->keyword) {
throw new InvalidArgumentException(_('Es wurde keine Seite übergeben!'));
}
$page = WikiPage::findLatestPage($this->range_id, $this->keyword);
$this->page = $page;
$this->validKeywords = array_filter(
WikiPage::findLatestPages($this->range_id)->pluck("keyword"),
function ($keyword) use ($page) {
if ($keyword === 'WikiWikiWeb') {
return false;
} else {
return $page->isValidAncestor($keyword);
}
}
);
natcasesort($this->validKeywords);
$wikistartpage = WikiPage::findLatestPage(Context::getId(), 'WikiWikiWeb');
if ($wikistartpage) {
array_unshift($this->validKeywords, 'WikiWikiWeb');
}
PageLayout::setTitle(_('Seiten-Einstellungen ändern'));
$this->config = $page->config;
getShowPageInfobox($this->keyword, true);
}
/**
* store page config of a wiki page
*/
public function store_page_config_action()
{
CSRFProtection::verifyUnsafeRequest();
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->range_id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Berechtigungen von Wiki-Seiten zu ändern!'));
}
// prevent malformed urls: keyword must be set
if (!$this->keyword) {
throw new InvalidArgumentException(_('Es wurde keine Seite übergeben!'));
}
$this->store_pageperms();
$this->store_page_ancestor();
PageLayout::postSuccess(sprintf(
_('Die Einstellungen für Wiki-Seite "%s" wurden geändert!'),
htmlReady($this->keyword)
));
$this->redirect(URLHelper::getURL('wiki.php', ['keyword' => $this->keyword]));
}
/**
* store page permissions of a wiki page
*/
public function store_pageperms()
{
$wiki_page_config = new WikiPageConfig([$this->range_id, $this->keyword]);
$wiki_page_config->read_restricted = Request::int('page_read_perms');
$wiki_page_config->edit_restricted = Request::int('page_edit_perms');
if (Request::int('page_global_perms') || $wiki_page_config->isDefault()) {
WikiPageConfig::deleteBySQL('range_id = ? AND keyword = ?', [$this->range_id, $this->keyword]);
} else {
$wiki_page_config->store();
}
}
/**
* store page ancestor of a wiki page
*/
public function store_page_ancestor()
{
$wikipage = WikiPage::findLatestPage(Context::getId(), $this->keyword);
if ($wikipage) {
if ($wikipage->isEditableBy($GLOBALS['user'])) {
$ancestor = Request::get('ancestor_select') ?: null;
if ($wikipage->isValidAncestor($ancestor)) {
$wikipage->setAncestorForAllVersions($ancestor);
} else {
PageLayout::postInfo(_('Die Vorgängerseite konnte nicht gespeichert werden.'));
}
$wikipage->store();
} else {
PageLayout::postInfo(_('Keine Änderung vorgenommen, da zwischenzeitlich die Editier-Berechtigung entzogen wurde.'));
}
}
}
public function store_action($version)
{
$body = Studip\Markup::purifyHtml(Request::get('body'));
$ancestor = WikiPage::findLatestPage(Context::getId(), $this->keyword)->ancestor;
submitWikiPage($this->keyword, $version, $body, $GLOBALS['user']->id, $this->range_id, $ancestor);
$latest_version = getLatestVersion($this->keyword, $this->range_id);
if (Request::isXhr()) {
$this->render_json([
'version' => $latest_version['version'],
'body' => $latest_version['body'],
'messages' => implode(PageLayout::getMessages()) ?: false,
'zusatz' => getZusatz($latest_version),
]);
} else {
// Yeah, wait for the whole trailification of the wiki...
}
}
public function version_check_action($version)
{
$latest_version = getLatestVersion($this->keyword, $this->range_id);
if (!$latest_version && $version > 1) {
$this->response->add_header('X-Studip-Error', _('Diese Wiki-Seite existiert nicht mehr!'));
$this->render_json(false);
} elseif ($latest_version && $version != $latest_version['version']) {
$error = _('Die von Ihnen bearbeitete Seite ist nicht mehr aktuell.') . ' ';
$error .= _('Falls Sie dennoch speichern, überschreiben Sie die getätigte Änderung und es wird unter Umständen zu Datenverlusten kommen.');
$this->response->add_header('X-Studip-Error', $error);
$this->response->add_header('X-Studip-Confirm', _('Möchten Sie Ihre Version dennoch speichern?'));
$this->render_json(null);
} else {
$this->render_json(true);
}
}
public function info_action()
{
// prevent malformed urls: keyword must be set
if (!$this->keyword) {
throw new InvalidArgumentException(_('Es wurde keine Seite übergeben!'));
}
$this->last_page = WikiPage::findLatestPage($this->range_id, $this->keyword);
$this->last_user = User::find($this->last_page['user_id']);
$this->first_page = getWikiPage($this->keyword, 1);
$this->first_user = User::find($this->first_page['user_id']);
$this->backlinks = getBacklinks($this->keyword);
$page = WikiPage::findLatestPage($this->range_id, $this->keyword);
$this->descendants = $page->children;
PageLayout::setTitle(_('Informationen zur Wikiseite'));
getShowPageInfobox($this->keyword, true);
}
/**
* This action is responsible for importing wiki pages into the wiki
* of a course from another course.
*/
public function import_action($course_id = null)
{
$edit_perms = CourseConfig::get($course_id)->WIKI_COURSE_EDIT_RESTRICTED ? 'tutor' : 'autor';
if (!$GLOBALS['perm']->have_studip_perm($edit_perms, $course_id)) {
throw new AccessDeniedException(_('Sie haben keine Berechtigung, Änderungen an Wikiseiten vorzunehmen!'));
}
$this->course = Course::find($course_id);
if (!$this->course) {
PageLayout::postError(
_('Die ausgewählte Veranstaltung wurde nicht gefunden!')
);
}
$this->course_search = new QuickSearch(
'selected_course_id',
new MyCoursesSearch(
'Seminar_id',
$GLOBALS['perm']->get_perm(),
[
'userid' => $GLOBALS['user']->id,
'exclude' => [$course_id],
'institutes' => array_column(Institute::getMyInstitutes(), 'Institut_id')
],
's.`Seminar_id` IN (
SELECT range_id FROM wiki
WHERE range_id = s.`Seminar_id`
)'
)
);
$this->course_search->fireJSFunctionOnSelect(
"function() {jQuery(this).closest('form').submit();}"
);
$this->show_wiki_page_form = false;
$this->bad_course_search = false;
$this->success = false;
//The following steps are identical for the search and the import.
if (Request::submitted('selected_course_id') || Request::submitted('import')) {
CSRFProtection::verifyUnsafeRequest();
//Search for wiki pages in the selected course:
$this->selected_course_id = Request::option('selected_course_id');
$this->selected_course = Course::find($this->selected_course_id);
if (!$this->selected_course) {
$this->bad_course_search = true;
return;
}
$this->wiki_pages = WikiPage::findLatestPages(
$this->selected_course->id
);
$this->show_wiki_page_form = true;
}
//The import required additional functionality:
if (Request::submitted('import')) {
CSRFProtection::verifyUnsafeRequest();
$this->selected_wiki_page_ids = Request::getArray('selected_wiki_page_ids');
if (!$this->selected_wiki_page_ids) {
PageLayout::postInfo(_('Es wurden keine Wikiseiten ausgewählt!'));
return;
}
$selected_wiki_pages = [];
foreach ($this->selected_wiki_page_ids as $id) {
$wiki_page = WikiPage::find(json_decode($id, true));
if ($wiki_page) {
$selected_wiki_pages[] = $wiki_page;
}
}
if (!$selected_wiki_pages) {
PageLayout::postError(_('Es wurden keine Wikiseiten gefunden!'));
return;
}
$errors = [];
foreach ($selected_wiki_pages as $selected_page) {
$latest_version = WikiPage::findLatestPage(
$this->course->id,
$selected_page->keyword
);
$new_page = new WikiPage();
$new_page->range_id = $this->course->id;
$new_page->user_id = $selected_page->user_id;
$new_page->keyword = $selected_page->keyword;
$new_page->body = $selected_page->body;
$new_page->chdate = $selected_page->chdate;
$new_page->version = $latest_version ? $latest_version->version + 1 : 1;
if (!$new_page->store()) {
$errors[] = sprintf(
_('Fehler beim Import der Wikiseite %s!'),
$new_page->keyword
);
}
}
if ($errors) {
PageLayout::postError(
_('Die folgenden Fehler traten beim Import auf:'),
$errors
);
} else {
$this->show_wiki_page_form = false;
$this->success = true;
PageLayout::postSuccess(
ngettext(
'Die Wikiseite wurde importiert! Sie ist unter dem Navigationspunkt "Alle Seiten" erreichbar.',
'Die Wikiseiten wurden importiert! Sie sind unter dem Navigationspunkt "Alle Seiten" erreichbar.',
count($selected_wiki_pages)
)
);
}
}
}
}
......@@ -6,29 +6,25 @@ namespace RESTAPI\Routes;
* @license GPL 2 or later
* @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0.
*
* @condition course_id ^[0-9a-f]{1,32}$
* @condition range_id ^[0-9a-f]{1,32}$
*/
class Wiki extends \RESTAPI\RouteMap
{
public function before()
{
require_once 'User.php';
require_once 'lib/wiki.inc.php';
}
/**
* Wikiseitenindex einer Veranstaltung
*
* @get /course/:course_id/wiki
* @get /course/:range_id/wiki
*/
public function getCourseWiki($course_id)
public function getCourseWiki($range_id)
{
$pages = \WikiPage::findLatestPages($course_id);
if (!sizeof($pages->findBy('keyword', 'WikiWikWeb'))) {
$pages[] = \WikiPage::getStartPage($course_id);
}
$pages = \WikiPage::findBySQL("`range_id` = ? ORDER BY `name` ASC", [$range_id]);
if (!$pages->first()->isVisibleTo($GLOBALS['user']->id)) {
if (!$pages[0]->isReadable()) {
$this->error(401);
}
......@@ -37,24 +33,24 @@ class Wiki extends \RESTAPI\RouteMap
$linked_pages = [];
foreach ($pages as $page) {
$url = $this->urlf('/course/%s/wiki/%s', [$course_id, htmlReady($page['keyword'])]);
$url = $this->urlf('/course/%s/wiki/%s', [$range_id, htmlReady($page['keyword'])]);
$linked_pages[$url] = $this->wikiPageToJson($page, ["content"]);
}
$this->etag(md5(serialize($linked_pages)));
return $this->paginated($linked_pages, $total, compact('course_id'));
return $this->paginated($linked_pages, $total, compact('range_id'));
}
/**
* Wikiseite auslesen
*
* @get /course/:course_id/wiki/:keyword
* @get /course/:course_id/wiki/:keyword/:version
* @get /course/:range_id/wiki/:keyword
* @get /course/:range_id/wiki/:keyword/:version
*/
public function getCourseWikiKeyword($course_id, $keyword, $version = null)
public function getCourseWikiKeyword($range_id, $keyword, $version = null)
{
$page = $this->requirePage($course_id, $keyword, $version);
$page = $this->requirePage($range_id, $keyword, $version);
$wiki_json = $this->wikiPageToJson($page);
$this->etag(md5(serialize($wiki_json)));
$this->lastmodified($page->chdate);
......@@ -64,33 +60,29 @@ class Wiki extends \RESTAPI\RouteMap
/**
* Wikiseite ändern/hinzufügen
*
* @put /course/:course_id/wiki/:keyword
* @put /course/:range_id/wiki/:keyword
*/
public function putCourseWikiKeyword($course_id, $keyword)
public function putCourseWikiKeyword($range_id, $keyword)
{
if (!isset($this->data['content'])) {
$this->error(400, 'No content provided');
}
$last_version = \WikiPage::findLatestPage($course_id, $keyword);
if (!$last_version) {
$last_version = new \WikiPage([$course_id, $keyword, 0]);
$page =\WikiPage::findOneBySQL("`range_id` = ? AND `name` = ?", [$range_id, $keyword]);
if (!$page) {
$page = new \WikiPage();
$page->range_id = $range_id;
$page->name = $keyword;
}
if (!$last_version->isEditableBy($user_id = $GLOBALS['user']->id)) {
if (!$page->isEditable()) {
$this->error(401);
}
// TODO: rewrite this code and put #submitWikiPage into
// class \WikiPage
if (!\Context::get()) {
\Context::set($course_id);
}
submitWikiPage($keyword, $last_version->version, $this->data['content'], $user_id, $course_id, $last_version->ancestor);
$page->content = $this->data['content'];
$page->store();
$new_version = \WikiPage::findLatestPage($course_id, $keyword);
$url = sprintf('course/%s/wiki/%s/%d', htmlReady($course_id), htmlReady($keyword), $new_version->version);
$url = sprintf('course/%s/wiki/%s/%d', htmlReady($range_id), htmlReady($keyword), count($page->versions) + 1);
$this->redirect($url, 201, 'ok');
}
......@@ -98,37 +90,41 @@ class Wiki extends \RESTAPI\RouteMap
/* PRIVATE HELPER METHODS */
/**************************************************/
private function requirePage($course_id, $keyword, $version)
private function requirePage($range_id, $keyword, $version = null)
{
if ($version) {
$page = \WikiPage::find([$course_id, $keyword, $version]);
} else {
$page = \WikiPage::findLatestPage($course_id, $keyword);
}
$page = \WikiPage::findOneBySQL("`range_id` = ? AND `name` = ?", [$range_id, $keyword]);
if (!$page) {
$this->notFound();
}
if (!$page->isVisibleTo($GLOBALS['user']->id)) {
if (!$page->isReadable($GLOBALS['user']->id)) {
$this->error(401);
}
return $page;
if ($version !== null && $version !== count($page->versions) + 1) {
return $page->versions[count($page->versions) - 1 - $version];
} else {
return $page;
}
}
private function wikiPageToJson($page, $without = [])
{
$json = $page->toArray(words("range_id keyword chdate version"));
$json = [
'range_id' => $page->range_id,
'keyword' => $page->name,
'chdate' => $page->chdate,
'version' => 1
];
// (pre-rendered) content
if (!in_array('content', $without)) {
$json['content'] = $page->body;
$json['content_html'] = wikiReady($page->body);
$json['content'] = $page->content;
$json['content_html'] = wikiReady($page->content, true, $page->range_id, $page->id);
}
if (!in_array('user', $without)) {
if ($page->author) {
$json['user'] = User::getMiniUser($this, $page->author);
$json['user'] = User::getMiniUser($this, $page->user_id);
}
}
......
<?php
/**
* @var WikiPage[] $pages
* @var Course_WikiController $controller
* @var CourseConfig $config
* @var Course|Institute $range
*/
?>
<form class="default" method="post" action="<?= $controller->store_course_config() ?>">
<?= CSRFProtection::tokenTag() ?>
<? if (count($pages) > 0) : ?>
<label>
<?= _('Startseite des Wikis') ?>
<select name="wiki_startpage_id">
<? foreach ($pages as $page) : ?>
<option value="<?= htmlReady($page->id) ?>"
<? if ($config->WIKI_STARTPAGE_ID == $page->id) echo 'selected'; ?>
><?= htmlReady($page->name) ?></option>
<? endforeach ?>
</select>
</label>
<? endif ?>
<? if ($config->WIKI_CREATE_PERMISSION === 'all' || $GLOBALS['perm']->have_studip_perm($config->WIKI_CREATE_PERMISSION, $range->id)) : ?>
<label>
<?= _('Wer darf neue Wiki-Seiten anlegen?') ?>
<select name="wiki_create_permission">
<option value="all"
<? if ($config->WIKI_CREATE_PERMISSION === 'all') echo 'selected'; ?>
><?= _('Alle') ?></option>
<option value="tutor"
<? if ($config->WIKI_CREATE_PERMISSION === 'tutor') echo 'selected'; ?>
><?= _('Tutor/-innen und Lehrende') ?></option>
<option value="dozent"
<?= $GLOBALS['perm']->have_studip_perm('dozent', $range->id) ? '' : 'disabled'?>
<? if ($config->WIKI_CREATE_PERMISSION === 'dozent') echo 'selected'; ?>
><?= _('Nur Lehrende') ?></option>
</select>
</label>
<? else : ?>
<div>
<?= _('Wer darf neue Wiki-Seiten anlegen?') ?>
<div>
<? switch ($config->WIKI_CREATE_PERMISSION) {
case 'all':
echo _('Alle');
break;
case 'tutor':
echo _('Tutor/-innen und Lehrende');
break;
case 'dozent':
echo _('Nur Lehrende');
break;
} ?>
</div>
</div>
<? endif ?>
<? if ($config->WIKI_RENAME_PERMISSION === 'all' || $GLOBALS['perm']->have_studip_perm($config->WIKI_RENAME_PERMISSION, $range->id)) : ?>
<label>
<?= _('Wer darf Wiki-Seiten umbenennen?') ?>
<select name="wiki_rename_permission">
<option value="all"
<? if ($config->WIKI_RENAME_PERMISSION === 'all') echo 'selected'; ?>
><?= _('Alle') ?></option>
<option value="tutor"
<? if ($config->WIKI_RENAME_PERMISSION === 'tutor') echo 'selected'; ?>
><?= _('Tutor/-innen und Lehrende') ?></option>
<option value="dozent"
<?= $GLOBALS['perm']->have_studip_perm('dozent', $range->id) ? '' : 'disabled'?>
<? if ($config->WIKI_RENAME_PERMISSION === 'dozent') echo 'selected'; ?>
><?= _('Nur Lehrende') ?></option>
</select>
</label>
<? else : ?>
<div>
<?= _('Wer darf Wiki-Seiten umbenennen?') ?>
<div>
<? switch ($config->WIKI_RENAME_PERMISSION) {
case 'all':
echo _('Alle');
break;
case 'tutor':
echo _('Tutor/-innen und Lehrende');
break;
case 'dozent':
echo _('Nur Lehrende');
break;
} ?>
</div>
</div>
<? endif ?>
<div data-dialog-button>
<?= \Studip\Button::create(_('Übernehmen')) ?>
</div>
</form>
<?php
/**
* @var WikiPage[] $pages
* @var Course_WikiController $controller
*/
?>
<table class="default sortable-table" data-sortlist="[[0, 0]]">
<caption>
<?= _('Alle Seiten des Wikis') ?>
</caption>
<thead>
<tr>
<th data-sort="text"><?= _('Seitenname') ?></th>
<th data-sort="text"><?= _('Änderungen') ?></th>
<th data-sort="text"><?= _('Letzte Änderung') ?></th>
<th data-sort="text"><?= _('Zuletzt bearbeitet von') ?></th>
</tr>
</thead>
<tbody>
<? foreach ($pages as $page) : ?>
<tr>
<td data-sort-value="<?= htmlReady($page->name) ?>">
<a href="<?= $controller->page($page) ?>">
<?= htmlReady($page->name) ?>
</a>
</td>
<td data-sort-value="<?= count($page->versions) + 1 ?>">
<?= count($page->versions) + 1 ?>
</td>
<td data-sort-value="<?= htmlReady($page->chdate) ?>">
<?= $page->chdate > 0 ? date('d.m.Y H:i:s', $page->chdate) : _('unbekannt') ?>
</td>
<td data-sort-value="<?= htmlReady($page->user ? $page->user->getFullName() : _('unbekannt')) ?>">
<?= Avatar::getAvatar($page->user_id)->getImageTag(Avatar::SMALL) ?>
<?= htmlReady($page->user ? $page->user->getFullName() : _('unbekannt')) ?>
</td>
</tr>
<? endforeach ?>
</tbody>
</table>
<?php
/**
* @var WikiPage $page
* @var array $diffarray
* @var array $line_versions
*/
?>
<h1><?= htmlReady($page->name) . ' - ' . _('Text mit Autor/-innenzuordnung') ?></h1>
<div class="blame_diff">
<?
$last_author = 'None';
$collect = "";
$version = $line_versions[0];
foreach ($diffarray as $number => $line) {
if (!$line || $last_author !== $line->who) {
if (trim($collect) !== '') : ?>
<div class="wiki_line">
<div class="author">
<a href="<?= URLhelper::getLink('dispatch.php/profile', ['username' => get_username($last_author)]) ?>" title="<?= htmlReady(get_fullname($last_author)) ?>">
<?= Avatar::getAvatar($last_author)->getImageTag(Avatar::SMALL) ?>
<div class="author_name"><?= htmlReady(get_fullname($last_author)) ?></div>
</a>
</div>
<a class="difflink"
href="<?= $controller->versiondiff(!$version || is_a($version, WikiPage::class) ? $version : $version->page, is_a($version, WikiVersion::class) ? $version->id : null) ?>"
data-dialog
title="<?= _('Änderungen anzeigen') ?>">
<?= Icon::create('log')->asImg(20, ['class' => 'text-bottom']) ?>
</a>
<div class="content">
<?= wikiReady($collect) ?>
</div>
</div>
<? endif;
$collect = "";
}
if ($line) {
$last_author = $line->who;
$collect .= $line->text;
$version = $line_versions[$number] ?? null;
}
}
?>
</div>
<?php
/**
* @var WikiPage $page
* @var array $diffs
*/
?>
<h1><?= htmlReady($page->name) . ' - ' . _('Änderungsliste') ?></h1>
<div>
<? foreach (array_reverse($diffs) as $diff) : ?>
<?= $this->render_partial('course/wiki/versiondiff', $diff) ?>
<? endforeach ?>
</div>
<?php
/**
* @var WikiPage $page
* @var Course_WikiController $controller
* @var WikiOnlineEditingUser $me_online
*/
?>
<div class="wiki-editor-container"
data-page_id="<?= htmlReady($page->id) ?>"
data-editing="<?= htmlReady($me_online->editing) ?>"
data-content="<?= htmlReady(wikiReady($page->content, true, $page->range_id, $page->id)) ?>"
data-chdate="<?= htmlReady($page->chdate) ?>"
data-users="<?= htmlReady(json_encode($page->getOnlineUsers())) ?>">
<?= $contentbar ?>
<form action="<?= $controller->save($page) ?>" method="post" class="default" v-show="editing">
<?= CSRFProtection::tokenTag() ?>
<textarea class="wiki-editor size-l"
ref="wiki_editor"
data-editor="extraPlugins=WikiLink"
name="content"><?= wysiwygReady($page->content) ?></textarea>
<div></div>
<label>
<input type="checkbox" v-model="autosave">
<?= _('Autosave aktiv') ?>
</label>
<div data-dialog-button="">
<button class="button" :disabled="!isChanged" :title="isChanged ? '<?= _('Speichern Sie den aktuellen Stand.') ?>' : '<?= _('Der aktuelle Stand ist schon gespeichert.') ?>'">
<?= _('Speichern') ?>
</button>
<?= \Studip\LinkButton::create(_('Verlassen'), $controller->leave_editing($page))?>
<button v-for="user in requestingUsers"
:key="user.user_id"
@click.prevent="delegateEditMode(user.user_id)"
class="button">
{{ $gettextInterpolate($gettext('Schreibmodus an %{name} übergeben'), { name: user.fullname }) }}
</button>
</div>
</form>
<div v-if="!editing" class="">
<div v-html="content"></div>
<div data-dialog-button="">
<button class="button"
title="<?= _('Beantragen Sie, dass Sie den Text jetzt bearbeiten wollen.') ?>"
@click.prevent="applyEditing">
<?= _('Bearbeiten beantragen') ?>
</button>
<?= \Studip\LinkButton::create(_('Verlassen'), $controller->leave_editing($page))?>
</div>
</div>
<wiki-editor-online-users :users="users"></wiki-editor-online-users>
</div>
<?php
/**
* @var WikiPage $page
* @var Course_WikiController $controller
*/
?>
<table class="default sortable-table" data-sortlist="[[0, 1]]">
<caption>
<?= sprintf(_('%s - Versionshistorie'), htmlReady($page->name)) ?>
</caption>
<colgroup>
<col style="width: 60px;">
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th data-sort="text"><?= _('Version') ?></th>
<th data-sort="text"><?= _('Autor/in') ?></th>
<th data-sort="text"><?= _('Erstellt am') ?></th>
<th data-sort="false" class="actions"><?= _('Aktion') ?></th>
</tr>
</thead>
<tbody>
<tr>
<td data-sort-value="<?= count($page->versions) + 1 ?>">
<a href="<?= $controller->page($page) ?>">
<?= count($page->versions) + 1 ?>
</a>
</td>
<td data-sort-value="<?= htmlReady($page->user ? $page->user->getFullName() : _('unbekannt')) ?>">
<? if ($page->user) : ?>
<a href="<?= URLhelper::getLink('dispatch.php/profile', ['username' => $page->user->username]) ?>">
<? endif ?>
<?= Avatar::getAvatar($page['user_id'])->getImageTag(Avatar::SMALL) ?>
<?= htmlReady($page->user ? $page->user->getFullName() : _('unbekannt')) ?>
<? if ($page->user) : ?>
</a>
<? endif ?>
</td>
<td data-sort-value="<?= $page->chdate ?>"><?= $page->chdate > 0 ? date('d.m.Y H:i:s', $page->chdate) : _('unbekannt') ?></td>
<td class="actions">
<a href="<?= $controller->versiondiff($page) ?>" data-dialog>
<?= Icon::create('log')->asImg(['class' => 'text-bottom']) ?>
</a>
</td>
</tr>
<? foreach ($page->versions as $i => $version) : ?>
<tr>
<td>
<a href="<?= $controller->version($version) ?>">
<?= count($page->versions) - $i ?>
</a>
</td>
<td>
<? if ($version->user) : ?>
<a href="<?= URLhelper::getLink('dispatch.php/profile', ['username' => $version->user->username]) ?>">
<? endif ?>
<?= Avatar::getAvatar($version['user_id'])->getImageTag(Avatar::SMALL) ?>
<?= htmlReady($version->user ? $version->user->getFullName() : _('unbekannt')) ?>
<? if ($version->user) : ?>
</a>
<? endif ?>
</td>
<td><?= $version->mkdate > 0 ? date('d.m.Y H:i:s', $version->mkdate) : _('unbekannt') ?></td>
<td class="actions">
<a href="<?= $controller->versiondiff($page, $version->id) ?>" data-dialog>
<?= Icon::create('log')->asImg(['class' => 'text-bottom']) ?>
</a>
</td>
</tr>
<? endforeach ?>
</tbody>
</table>
<?php
/**
* @var bool $show_wiki_page_form
* @var Course_WikiController $controller
* @var Range $range
* @var bool $success
* @var bool $bad_course_search
* @var QuickSearch $course_search
* @var Course $selected_course
* @var array $wiki_pages
*/
?>
<form class="default" method="post"
name="wiki_import_form"
data-dialog="size=auto;<?= $show_wiki_page_form ? 'reload-on-close' : '' ?>"
action="<?= $controller->import() ?>">
<?= CSRFProtection::tokenTag() ?>
<? if (!$show_wiki_page_form && !$success): ?>
<fieldset>
<legend><?= _('Suche nach Veranstaltungen') ?></legend>
<label class="with-action">
<? if ($bad_course_search): ?>
<?= _('Meinten Sie eine der folgenden Veranstaltungen?') ?>
<? else: ?>
<?= _('Sie können hier eine Veranstaltung mit zu importierenden Wiki-Seiten suchen.') ?>
<? endif ?>
<?= $course_search->render() ?>
<? if ($bad_course_search): ?>
<a href="<?= $controller->import() ?>"
data-dialog="1">
<?= Icon::create('decline')->asImg([
'class' => 'text-bottom',
'title' => _('Suche zurücksetzen'),
'onclick' => "STUDIP.QuickSearch.reset('wiki_import_form', 'selected_range_id');"
]) ?>
</a>
<? else : ?>
<?= Icon::create('search')->asImg([
'class' => 'text-bottom',
'title' => _('Suche starten'),
'onclick' => "jQuery(this).closest('form').submit();"
]) ?>
<? endif ?>
</label>
<div data-dialog-button>
<? if ($bad_course_search): ?>
<?= Studip\LinkButton::create(
_('Neue Suche'),
$controller->importURL(),
['data-dialog' => 'size=auto']
) ?>
<? endif ?>
<?= Studip\LinkButton::createCancel(
_('Abbrechen'),
$controller->pageURL()
) ?>
</div>
</fieldset>
<? endif ?>
<? if ($show_wiki_page_form): ?>
<input type="hidden" name="selected_range_id"
value="<?= htmlReady($selected_course->id) ?>">
<? if ($wiki_pages): ?>
<table class="default">
<colgroup>
<col style="width: 20px">
<col>
</colgroup>
<caption>
<?= sprintf(
_('%s: Importierbare Wiki-Seiten'),
htmlReady($selected_course->getFullName())
) ?>
</caption>
<thead>
<tr>
<th>
<input type="checkbox"
data-proxyfor=":checkbox[name='selected_wiki_page_ids[]']">
</th>
<th><?= _('Seitenname') ?></th>
</tr>
</thead>
<tbody>
<? foreach ($wiki_pages as $wiki_page): ?>
<? if ($wiki_page->isReadable()) : ?>
<tr>
<td>
<input type="checkbox"
name="selected_wiki_page_ids[]"
value="<?= htmlReady($wiki_page->getId()) ?>">
</td>
<td><?= htmlReady($wiki_page->name) ?></td>
</tr>
<? endif ?>
<? endforeach ?>
</tbody>
</table>
<div data-dialog-button>
<?= Studip\Button::create(_('Importieren'), 'import') ?>
<?= Studip\LinkButton::create(
_('Neue Suche'),
$controller->importURL(),
['data-dialog' => 'size=auto']
) ?>
<?= Studip\LinkButton::createCancel(
_('Abbrechen'),
$controller->pageURL()
) ?>
</div>
<? else: ?>
<?= MessageBox::info(
_('Die gewählte Veranstaltung besitzt keine Wiki-Seiten!')
) ?>
<? endif ?>
<? endif ?>
<? if ($success): ?>
<div data-dialog-button>
<?= Studip\LinkButton::create(
_('Import neu starten'),
$controller->importURL(),
['data-dialog' => 'size=auto']
) ?>
<?= Studip\LinkButton::createCancel(
_('Zurück zum Wiki'),
$controller->pageURL()
) ?>
</div>
<? endif ?>
</form>
<table class="default sortable-table" data-sortlist="[[3, 0]]">
<caption>
<?= _('Letzte Änderungen') ?>
</caption>
<thead>
<tr>
<th data-sort="text"><?= _('Seitenname') ?></th>
<th data-sort="false"><?= _('Text') ?></th>
<th data-sort="text"><?= _('Autor/-in') ?></th>
<th data-sort="text"><?= _('Datum') ?></th>
</tr>
</thead>
<tbody>
<? foreach (array_reverse($versions) as $version) : ?>
<?= $this->render_partial('course/wiki/versioncompare', ['version' => $version]) ?>
<? endforeach ?>
</tbody>
</table>
<?php
/**
* @var WikiPage $page
* @var string $edit_perms
* @var Context $range
* @var Course_WikiController $controller
*/
echo $contentbar;
?>
<? if ($page->isEditable()) : ?>
<form action="<?= $controller->delete($page->id) ?>" method="post" id="delete_page">
<?= CSRFProtection::tokenTag() ?>
</form>
<? endif ?>
<? if ($page->isNew()) : ?>
<section>
<? if ($edit_perms !== 'all' && !$GLOBALS['perm']->have_studip_perm($edit_perms, $range->id)) : ?>
<div class="wiki-empty-background"></div>
<? else : ?>
<a href="<?= $controller->new_page() ?>"
data-dialog
class="wiki-empty-background"
title="<?= _('Dieses Wiki ist noch leer. Erstellen Sie die erste Wiki-Seite.') ?>"></a>
<? endif ?>
<div class="flex">
<? if ($edit_perms !== 'all' && !$GLOBALS['perm']->have_studip_perm($edit_perms, $range->id)) : ?>
<div class="wiki-teaser">
<? else : ?>
<a href="<?= $controller->new_page() ?>"
data-dialog
class="wiki-teaser">
<? endif ?>
<?= _('Mach die Welt ein Stückchen schlauer.') ?>
<? if ($edit_perms !== 'all' && !$GLOBALS['perm']->have_studip_perm($edit_perms, $range->id)) : ?>
</div>
<? else : ?>
</a>
<? endif ?>
</div>
</section>
<? else : ?>
<article class="studip wiki">
<section>
<div class="wiki_page_content wiki_page_content_<?= htmlReady($page->id) ?>"
data-page_id="<?= htmlReady($page->id) ?>">
<?= wikiReady($page->content, true, $range->id, $page->id) ?>
</div>
</section>
<? if ($page->isEditable()) : ?>
<footer id="wikifooter">
<div class="button-group">
<?= \Studip\LinkButton::create(_('Bearbeiten'), $controller->editURL($page)) ?>
</div>
</footer>
<? endif ?>
</article>
<? endif ?>
<?php
/**
* @var WikiPage[] $pages
* @var string $edit_perms
* @var Course_WikiController $controller
*/
?>
<? if (count($pages)) : ?>
<table class="default">
<caption>
<?= sprintf(_('Treffer für Suche nach <em>%s</em> in allen Versionen'), htmlReady(Request::get('search'))) ?>
</caption>
<thead>
<tr>
<th><?= _('Seite') ?></th>
<th><?= _('Treffer') ?></th>
<th><?= _('Datum') ?></th>
</tr>
</thead>
<tbody>
<? foreach ($pages as $page_id => $pagedata) : ?>
<tr>
<td>
<?
sort($pagedata['versions'], SORT_NUMERIC);
$pagedata['versions'] = array_reverse($pagedata['versions']);
if ($pagedata['is_in_content']) {
$content = $pagedata['page']->content;
} else if ($pagedata['is_in_history']) {
$version = WikiVersion::find($pagedata['versions'][0]);
$content = $version->content;
}
?>
<a href="<?= $pagedata['is_in_content'] || $pagedata['is_in_name']
? $controller->page($page_id)
: $controller->version($version) ?>">
<?= htmlReady($pagedata['page']->name) ?>
<? if (!$pagedata['is_in_content'] && !$pagedata['is_in_name']) : ?>
<span><?= _('Nur in alter Version der Seite enthalten.') ?></span>
<? endif ?>
</a>
</td>
<td>
<?
$content = Studip\Markup::removeHtml($content);
$offset = 0;
$output = [];
// find all occurences
while ($offset < mb_strlen($content)) {
$pos = mb_stripos($content, Request::get('search'), $offset);
if ($pos === false) {
break;
}
$offset = $pos + 1;
if (($ignore_next_hits--) > 0) {
// if more than one occurence is found
// in a fragment to be displayed,
// the fragment is only shown once
continue;
}
// show max 80 chars
$fragment = '';
$split_fragment = preg_split('/(' . preg_quote(Request::get('search'), '/') . ')/i', mb_substr($content, max(0, $pos - 40), 80), -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 0; $i < count($split_fragment); ++$i) {
if ($i % 2) {
$fragment .= '<span class="wiki_highlight">';
$fragment .= htmlready($split_fragment[$i], false);
$fragment .= '</span>';
} else {
$fragment .= htmlready($split_fragment[$i], false);
}
}
$found_in_fragment = (count($split_fragment) - 1) / 2; // number of hits in fragment
$ignore_next_hits = ($found_in_fragment > 1) ? $found_in_fragment - 1 : 0;
$output[] = "..." . $fragment . "...";
}
if ($pagedata['is_in_name']) {
$name = str_ireplace(Request::get('search'), '<span class="wiki_highlight">' . htmlReady(Request::get('search')) . '</span>', htmlReady($pagedata['page']->name));
array_unshift($output, sprintf(_('Treffer im Namen: %s'), $name));
} else if ($pagedata['is_in_old_name']) {
$name = str_ireplace(Request::get('search'), '<span class="wiki_highlight">' . htmlReady(Request::get('search')) . '</span>', htmlReady($version->name));
array_unshift($output, sprintf(_('Treffer in alten Namen: %s'), $name));
}
echo implode('<br>', $output);
?>
</td>
<td>
<? if ($pagedata['is_in_content'] || $pagedata['is_in_name']) : ?>
<?= _('Aktuelle Version') . ': ' . ($pagedata['page']->chdate ? date('d.m.Y H:i:s', $pagedata['page']->chdate) : _('unbekannt')) ?>
<? else : ?>
<?= $version->chdate > 0 ? date('d.m.Y H:i:s', $version->chdate) : _('unbekannt') ?>
<? endif ?>
</td>
</tr>
<? endforeach ?>
</tbody>
</table>
<? else : ?>
<?= MessageBox::info(sprintf(_('Ihre Suche nach <em>%s</em> ergab keine Treffer.'), htmlReady(Request::get('search')))) ?>
<? endif ?>
<?= $contentbar ?>
<div class="wiki_page_content">
<?= wikiReady($version['content']) ?>
</div>
<tr>
<td data-sort-value="<?= htmlReady(is_a($version, WikiPage::class) ? $version->name : $version->page->name) ?>">
<a href="<?= is_a($version, WikiPage::class) ? $controller->page($version) : $controller->version($version) ?>">
<?= htmlReady(is_a($version, WikiPage::class) ? $version->name : $version->page->name) ?>
</a>
</td>
<td>
<?
$oldversion = $version->predecessor ? $version->predecessor->content : '';
$oldcontent = strip_tags(wikiReady($oldversion));
$content = strip_tags(wikiReady($version->content));
while ($content && $oldcontent && $content[0] == $oldcontent[0]) {
$content = substr($content, 1);
$oldcontent = substr($oldcontent, 1);
}
while ($content && $oldcontent && $content[strlen($content) - 1] == $oldcontent[strlen($oldcontent) - 1]) {
$content = substr($content, 0, -1);
$oldcontent = substr($oldcontent, 0, -1);
}
if ($content) {
echo nl2br(htmlReady($content));
} elseif ($oldcontent) {
echo _('Gelöscht') . ': ' . nl2br(htmlReady($oldcontent));
} else {
echo nl2br(strip_tags(wikiReady($version->content)));
}
?></td>
<? $user = User::find($version->user_id) ?>
<td data-sort-value="<?= htmlReady($user ? $user->getFullName() : _('unbekannt')) ?>">
<?
if ($user) {
echo Avatar::getAvatar($user->id)->getImageTag(Avatar::SMALL);
echo ' ';
echo htmlReady($user->getFullName());
} else {
echo _('unbekannt');
}
?></td>
<td data-sort-value="<?= htmlReady(is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate) ?>">
<? $chdate = is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate ?>
<?= $chdate > 0 ? date('d.m.Y H:i:s', $chdate) : _('unbekannt') ?>
</td>
</tr>
<?php
/**
* @var WikiPage|WikiVersion $version
* @var Course_WikiController $controller
*/
?>
<h3>
<a href="<?= is_a($version, WikiPage::class) ? $controller->page($version) : $controller->version($version) ?>">
<? $chdate = is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate ?>
<?= sprintf(
_('Version %1$s, geändert von %2$s am %3$s.'),
htmlReady($version->versionnumber),
htmlReady($version->user ? $version->user->getFullName() : _('unbekannt')),
$chdate > 0 ? date('d.m.Y H:i:s', $chdate) : _('unbekannt')) ?>
</a>
</h3>
<div class="wiki_diffs">
<?= $diff ?>
</div>
<?php
/**
* @var WikiController $controller
* @var bool $restricted
* @var string $keyword
*/
?>
<form action="<?= $controller->link_for('wiki/store_courseperms', compact('keyword')) ?>" method="post" class="default">
<?= CSRFProtection::tokenTag() ?>
<fieldset>
<label><?= _('Editierberechtigung') ?></label>
<label>
<input type="radio" name="courseperms" value="0"
<? if (!$restricted) echo 'checked'; ?>>
<?= _('Alle in der Veranstaltung') ?>
</label>
<label>
<input type="radio" name="courseperms" value="1"
<? if ($restricted) echo 'checked'; ?>>
<?= _('Lehrende und Tutor/innen') ?>
</label>
</fieldset>
<footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern')) ?>
<?= Studip\LinkButton::createCancel(
_('Abbrechen'),
URLHelper::getURL('wiki.php', compact('keyword'))
) ?>
</footer>
</form>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment