Skip to content

Commit

Permalink
Merge pull request #47 from YesWiki/feature/fanzine
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Parisot authored Sep 6, 2021
2 parents b1fb210 + 1e08b3e commit e77c90e
Show file tree
Hide file tree
Showing 33 changed files with 2,434 additions and 663 deletions.
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Extension YesWiki publication

> Extension [YesWiki] qui génère des publications au format PDF à partir d'une sélection de [fiches Bazar][Bazar] et/ou de [pages de contenu][yeswiki-page].
> Une extension [YesWiki] pour créer des documents imprimables (format PDF) à partir d'une sélection de [fiches Bazar][Bazar] et/ou de [pages de contenu][yeswiki-page].
La mise en page est effectuée par [Paged.js](https://www.pagedjs.org/)
([documentation](https://www.pagedjs.org/documentation/)), et la capture PDF par un [navigateur dit "headless"][headless-browser] (par défaut [chromium](#pré-requis)).

Les publications générées sont de type [ebook](#pour-générer-des-ebooks-téléchargeables) ou [newsletter](#pour-générer-des-newsletters).
Les publications générées sont de type [livres/livrets](#pour-générer-des-livrets-téléchargeables), [fanzines](#pour-générer-des-livrets-téléchargeables) ou [newsletter](#pour-générer-des-newsletters).


<table>
Expand Down Expand Up @@ -33,12 +33,23 @@ Les publications générées sont de type [ebook](#pour-générer-des-ebooks-té
<th scope="col">Une page "publication", avec actions de téléchargement et prévisualisation (auteur·ices et admin)</th>
<th scope="col">Bouton d'export à ajouter (<a href="#action-bazar2publication">action <code>{{bazar2publication}}</code></a>)</th>
</tr>
<tr>
<td>
<img src="presentation/fanzine-layouts/single-page.svg" alt="">
</td>
<td>
</td>
</tr>
<tr>
<th scope="col">Exemple de pliage de fanzine</th>
<th scope="col"></th>
</tr>
</table>

## Pré-requis technique

Avoir installé [Chromium](https://www.chromium.org/Home) **sur
le serveur** et connaitre le chemin d'accès vers l'exécutable.
le serveur**. Éventuellement, connaître le chemin d'accès vers l'exécutable s'il est différent de `/usr/bin/chromium`.

Pour installer Chrome sous Ubuntu/Debian :

Expand All @@ -59,11 +70,11 @@ L'action `{{publicationgenerator}}` prend en charge les étapes 1, 2 et 3.

Le handler `/pdf` prend en charge l'étape 4.

### Pour générer des ebooks téléchargeables
### Pour générer des livrets téléchargeables

Utiliser l'action `{{publicationgenerator}}`. Aucun paramètre n'est obligatoire.

Chaque ebook généré sera enregistré sous la forme d'une page sur le wiki. Le nom de cette page sera constitué de la valeur du paramètre `pagenameprefix` suivie du titre de l'ebook.
Chaque publication est générée sous forme d'une page wiki. Le nom de cette page sera constitué de la valeur du paramètre `pagenameprefix` suivie du titre de l'ebook (par défaut `Ebook`).

On pourra utilement consulter la section [Action `{{publicationgenerator}}`](#action-publicationgenerator) ci-après.

Expand All @@ -89,6 +100,18 @@ Chaque newsletter générée sera enregistrée sous la forme d'une fiche bazar d

On pourra utilement consulter la section [Action `{{publicationgenerator}}`](#action-publicationgenerator) ci-après.

### Surcharger les styles d'impression par défaut

Des styles d'impression par défaut sont ajoutés pour vous donner le moins de travail possible lors de la création d'une publication.
Il y a plusieurs mécanismes pour **personnaliser vos styles d'impression** en créant des feuilles de styles (fichiers `.css`) :

| Répertoire | Noms possibles | À quoi ça s'applique ?
| --- | --- | ---
| `custom/tools/publication/*.css` | Peu importe | Toute publication, peu importe le thème
| `custom/tools/publication/print-layouts/*.css` | `fanzine.css`, `book.css` | Seulement les fanzines, ou les livres/livrets, peu importe le thème
| `themes/NOM_DU_THEME/tools/publication/*.css` | Peu importe | Toute publication, pour un thème donné
| `themes/NOM_DU_THEME/tools/publication/print-layouts/*.css` | `fanzine.css`, `book.css` | Seulement les fanzines, ou les livres/livrets, pour un thème donné

## Actions YesWiki

L'extension publication ajoute deux actions à votre wiki.
Expand Down
175 changes: 86 additions & 89 deletions actions/publicationgenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@
*/

use YesWiki\Bazar\Service\EntryManager;
use YesWiki\Publication\Service\Publication;

if (!defined("WIKINI_VERSION")) {
die("acc&egrave;s direct interdit");
}

$entryManager = $this->services->get(EntryManager::class);
$publicationService = $this->services->get(Publication::class);

include_once 'tools/tags/libs/tags.functions.php';

$this->addCssFile('tools/publication/presentation/styles/publication.css');

// Format of the output. Either you want to generate an ebook or a newsletter
// Default value is ebook
$name = _t('PUBLICATION_EBOOK');
$outputFormat = $this->getParameter('outputformat', 'Ebook');
$messages = [];

if ($outputFormat === 'newsletter') {
if (strcasecmp($outputFormat, 'newsletter') === 0) {
$formId = $this->getParameter('formid'); // Bazar form used to store the newsletter
if (empty($formId)) {
exit(_t('PUBLICATION_MISSING_NEWSLETTER_FORM'));
Expand Down Expand Up @@ -65,18 +65,15 @@
// include default pages in page listing ?
$addInstalledPages = $this->getParameter('addinstalledpage');

// default publication cover
$default = [];
$default['coverimage'] = $this->getParameter('coverimage');

// default publication title
$default['title'] = $this->getParameter('title');

// default publication description
$default['desc'] = $this->getParameter('desc');

// default publication author
$default['author'] = $this->getParameter('author');
// defaults from the action
$defaults = [
"publication-cover-image" => $this->getParameter('coverimage'),
"publication" => [
"title" => $this->getParameter('title'),
"description" => $this->getParameter('desc'),
"authors" => $this->getParameter('author') ?: $this->getParameter('authors'),
]
];

// default added pages that can be used to separate content
$chapterCoverPages = $this->getParameter('chapterpages');
Expand All @@ -92,9 +89,6 @@
$chapterCoverPages = $a;
}

// app display template
$template = $this->getParameter('template', 'exportpages_table');

// titles for groups
$titles = $this->getParameter('titles');
if (!empty($titles)) {
Expand Down Expand Up @@ -206,16 +200,22 @@

// Handling of data submitted by the form
// Page creation
if (isset($_POST["page"])) {
do { // use of a do-while loop in order to allow for breaks (in case of errors)

if (isset($_POST) && count($_POST)) {
do { // use of a do-while loop in order to allow for breaks (in case of errors)
if (!isset($_POST['antispam']) || $_POST['antispam'] != 1) {
// There may be a spamming problem
$output = '<div class="alert alert-danger">' . _t('PUBLICATION_SPAM_RISK') . '</div>' . "\n";
array_push($messages, array('danger', _t('PUBLICATION_SPAM_RISK')));
break; // Stops the current do-while loop
}
if (!isset($_POST["page"]) || count($_POST["page"]) === 0) {
// There is no page selected
array_push($messages, array('danger', _t('PUBLICATION_NO_PAGE_FOUND')));
break; // Stops the current do-while loop
}
if (!isset($_POST["publication-title"]) || $_POST["publication-title"] == '') {
if (!isset($_POST["publication"]["title"]) || trim($_POST["publication"]["title"]) === '') {
// There is no publication-title
$output = '<div class="alert alert-danger">' . _t('PUBLICATION_NO_TITLE_FOUND') . '</div>' . "\n";
array_push($messages, array('danger', _t('PUBLICATION_NO_TITLE_FOUND')));
break; // Stops the current do-while loop
}

Expand All @@ -231,7 +231,7 @@
if (isset($ebookPageName) && !empty($ebookPageName)) {
$pageName = $ebookPageName;
} else {
$pageName = generatePageName($ebookPageNamePrefix . ' ' . $_POST["publication-title"]);
$pageName = generatePageName($ebookPageNamePrefix . ' ' . $_POST["publication"]["title"]);
}


Expand All @@ -248,10 +248,8 @@
// $page can be 'SomeTag' or 'SomeTag?parameter=value'
// the query string is used to parametrize book creation
else {
list($page, $qs) = explode('?', $page);
parse_str($qs, $qs);

$output .= '{{include page="' . $page . '" class="'. trim(implode(' ', [$qs['type'], $qs['class']])) .'"}}' . "\n";
$includeCode = $publicationService->getIncludeActionFromPageTag($page);
$output .= $includeCode;
}
}

Expand All @@ -267,11 +265,11 @@
$output = $this->Format('""<div class="alert alert-danger alert-error">' . _t('PUBLICATION_EBOOK_PAGE_CREATION_FAILED') . '.""' . "\n" . '{{button class="btn-primary" link="' . $this->GetPageTag() . '" text="' . _t('PUBLICATION_GOTO_EBOOK_CREATION_PAGE') . ' ' . $this->GetPageTag() . '"}}""</div>""' . "\n");
}
} while (false); // end of ebook specific loop
} elseif (strcasecmp($outputFormat, 'newsletter') == 0) { // We want to produce a newsletter
} elseif (strcasecmp($outputFormat, 'newsletter') === 0) { // We want to produce a newsletter
$fiche['id_typeannonce'] = $formId;
$fiche['bf_titre'] = $_POST["publication-title"];
$fiche['bf_description'] = $_POST["publication-description"];
$fiche['bf_author'] = $_POST["publication-author"];
$fiche['bf_titre'] = implode(' ', [$outputFormat, $_POST["publication"]["title"]]);
$fiche['bf_description'] = $_POST["publication"]["description"];
$fiche['bf_author'] = $_POST["publication"]["authors"];
$fiche['bf_content'] = '';

// Generate the content of the page body
Expand All @@ -285,77 +283,76 @@
// we assume it is a page tag otherwise
// maybe we should also explicitly check it is a valid page tag instead?
else {
$fiche['bf_content'] .= $this->Format('{{include page="' . $page . '" class=""}}' . "\n");
$includeCode = $publicationService->getIncludeActionFromPageTag($page);
$fiche['bf_content'] .= $this->Format($includeCode);
}
}

$acceptedTags = '<h1><h2><h3><h4><h5><h6><hr><hr/><br><br/><span><blockquote><i><u><b><strong><ol><ul><li><small><div><p><a><table><tr><th><td><img><figure><caption><iframe>';
$acceptedTags = '<h1><h2><h3><h4><h5><h6><hr><hr/><br><br/><span><blockquote><i><u><b><strong><ol><ul><li><small><div><p><a><table><tr><th><td><img><figure><caption><iframe><style>';
$fiche['bf_content'] = strip_tags($fiche['bf_content'], $acceptedTags);
$fiche['antispam'] = 1;
$fiche = $entryManager->create($formId, $fiche);
array_push($messages, array('success', _t('PUBLICATION_NEWSLETTER_CREATED')));
}
} while (false); // End of global do-while loop
} else { // Not isset($_POST["page"])
// recuperation des pages creees a l'installation
$installedPageNames = [];
if (!empty($addInstalledPages)) {
$d = dir("setup/doc/");
while ($doc = $d->read()) {
if ($doc == '.' || $doc == '..' || is_dir($doc) || substr($doc, -4) != '.txt') {
continue;
}
}

if ($doc == '_root_page.txt') {
$installedPageNames[$this->GetConfigValue("root_page")] = $this->GetConfigValue("root_page");
} else {
$pageName = substr($doc, 0, strpos($doc, '.txt'));
$installedPageNames[$pageName] = $pageName;
}
// recuperation des pages creees a l'installation
$installedPageNames = [];
if (!empty($addInstalledPages)) {
$d = dir("setup/doc/");
while ($doc = $d->read()) {
if ($doc == '.' || $doc == '..' || is_dir($doc) || substr($doc, -4) != '.txt') {
continue;
}
}

if (isset($this->page["metadatas"]["publication-title"])) {
$ebookPageName = $this->GetPageTag();
preg_match_all('/{{include page="(.*)".*}}/Ui', $this->page['body'], $matches);
$publicationStart = $matches[1][0];
$last = count($matches[1]) - 1;
$publicationEnd = $matches[1][$last];
unset($matches[1][0]);
unset($matches[1][$last]);
foreach ($matches[1] as $key => $value) {
$pagesFiltre = filter_by_value($results, 'tag', $value);
$selectedPages[] = array_shift($pagesFiltre);
$key = array_keys($pagesFiltre);
if ($key && isset($pages[$key[0]])) {
unset($pages[$key[0]]);
}
if ($doc == '_root_page.txt') {
$installedPageNames[$this->GetConfigValue("root_page")] = $this->GetConfigValue("root_page");
} else {
$pageName = substr($doc, 0, strpos($doc, '.txt'));
$installedPageNames[$pageName] = $pageName;
}
} else {
$ebookPageName = '';
$selectedPages = array();
}
}

$this->AddJavascriptFile('tools/publication/libs/vendor/jquery-ui-sortable/jquery-ui.min.js');
$this->AddJavascriptFile('tools/publication/presentation/actions/publicationgenerator.js');

$output .= $this->render('@publication/'.$template.'.twig', [
'messages' => $messages,
'entries' => $results,
'areParamsReadonly' => $areParamsReadonly,
'publicationStart' => $this->loadPage($publicationStart),
'publicationEnd' => $this->loadPage($publicationEnd),
'addInstalledPages' => $addInstalledPages,
'installedPageNames' => $installedPageNames,
'defaults' => $default,
'ebookPageName' => $ebookPageName,
'metaDatas' => $this->page["metadatas"],
'selectedPages' => $selectedPages,
'chapterCoverPages' => $chapterCoverPages,
'url' => $this->href('', $this->GetPageTag()),
'name' => $name,
'outputFormat' => $outputFormat,
]);
if (isset($this->page["metadatas"]["publication-title"])) {
$ebookPageName = $this->GetPageTag();
preg_match_all('/{{include page="(.*)".*}}/Ui', $this->page['body'], $matches);
$publicationStart = $matches[1][0];
$last = count($matches[1]) - 1;
$publicationEnd = $matches[1][$last];
unset($matches[1][0]);
unset($matches[1][$last]);
foreach ($matches[1] as $key => $value) {
$pagesFiltre = filter_by_value($results, 'tag', $value);
$selectedPages[] = array_shift($pagesFiltre);
$key = array_keys($pagesFiltre);
if ($key && isset($pages[$key[0]])) {
unset($pages[$key[0]]);
}
}
} else {
$ebookPageName = '';
$selectedPages = array();
}

echo $output . "\n";
$this->addCssFile('tools/publication/presentation/styles/publication.css');
$this->AddJavascriptFile('tools/publication/libs/vendor/jquery-ui-sortable/jquery-ui.min.js');
$this->AddJavascriptFile('tools/publication/presentation/actions/publicationgenerator.js');

echo $this->render('@publication/publicationgenerator.twig', [
'messages' => $messages,
'entries' => $results,
'areParamsReadonly' => $areParamsReadonly,
'publicationStart' => $this->loadPage($publicationStart),
'publicationEnd' => $this->loadPage($publicationEnd),
'addInstalledPages' => $addInstalledPages,
'installedPageNames' => $installedPageNames,
'ebookPageName' => $ebookPageName,
'metadatas' => $publicationService->getOptions($defaults, $_POST, $this->page["metadatas"] ?: []),
'selectedPages' => $selectedPages,
'chapterCoverPages' => $chapterCoverPages,
'url' => $this->href('', $this->GetPageTag()),
'name' => $name,
'outputFormat' => $outputFormat,
]);
12 changes: 9 additions & 3 deletions actions/publicationlist.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,34 @@
*@version $Revision: 0.1 $ $Date: 2010/03/04 14:19:03 $
*/

use YesWiki\Publication\Service\Publication;

if (!defined("WIKINI_VERSION")) {
die ("acc&egrave;s direct interdit");
}

global $wiki;

$publicationService = $this->services->get(Publication::class);
$ebookPageNamePrefix = $this->getParameter('pagenameprefix', 'Ebook');

$output = '';

// recuperation des pages wikis
$sql = 'SELECT DISTINCT resource FROM '.$this->GetConfigValue('table_prefix').'triples';
$sql .= ' WHERE property="http://outils-reseaux.org/_vocabulary/metadata"
AND value LIKE "%publication-title%"
AND (value LIKE "%publication-title%" OR value LIKE "%\publication\":{\"title\":%")
AND resource LIKE "'.$ebookPageNamePrefix.'%" ';
$sql .= ' ORDER BY resource ASC';

$pages = array_map(function($page) use ($wiki) {
$pages = array_map(function($page) use ($wiki, $publicationService) {
$metas = $wiki->GetMetadatas($page['resource']);
$page['_metas'] = $metas;
$page['_metas'] = $publicationService->getOptions($metas);
return $page;
}, $wiki->LoadAll($sql));

$this->addCssFile('tools/publication/presentation/styles/publication.css');

echo $wiki->render('@publication/publicationlist.twig', [
'hasWriteAccess' => $this->HasAccess('write'),
'hasDeleteAccess' => $this->UserIsAdmin() || $this->UserIsOwner(),
Expand Down
4 changes: 1 addition & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
"test": "exit 0"
},
"require": {
"chrome-php/chrome": "^0.9.0"
},
"require-dev": {
"chrome-php/chrome": "^1"
}
}
Loading

0 comments on commit e77c90e

Please sign in to comment.