Overview
Comment:Refactor File class to add generic markdown support
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | stable
Files: files | file ages | folders
SHA3-256: da6e8ed150f2b35748e50c03b69d0633207e791884c64802b6ab67334da400a2
User & Date: bohwaz on 2021-05-20 16:16:36
Other Links: manifest | tags
Context
2021-05-20
18:06
Ditch ParsedownExtra and use our own footnotes implementation as ParsedownExtra is buggy and we only need footnotes check-in: 1116ef5677 user: bohwaz tags: trunk, stable
16:16
Refactor File class to add generic markdown support check-in: da6e8ed150 user: bohwaz tags: trunk, stable
15:58
Refactor rendering classes to use an abstract parent check-in: 6d5b0c3e04 user: bohwaz tags: trunk
Changes

Modified src/include/lib/Garradin/Entities/Files/File.php from [18ff5efb3f] to [a02c6a6277].

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721

722
723
724

725
726


727
728
729
730
731
732
733
734
735
...
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
...
911
912
913
914
915
916
917
918
919
920

921
922
923









924
925










926
927
928
929
930
	const ALLOWED_THUMB_SIZES = [200, 500];

	const THUMB_CACHE_ID = 'file.thumb.%s.%d';

	const THUMB_SIZE_TINY = 200;
	const THUMB_SIZE_SMALL = 500;

	const FILE_EXT_ENCRYPTED = '.skriv.enc';
	const FILE_EXT_SKRIV = '.skriv';

	const EDITOR_WEB = 'web';
	const EDITOR_ENCRYPTED = 'encrypted';
	const EDITOR_CODE = 'code';

	const CONTEXT_DOCUMENTS = 'documents';
	const CONTEXT_USER = 'user';
	const CONTEXT_TRANSACTION = 'transaction';
	const CONTEXT_CONFIG = 'config';
	const CONTEXT_WEB = 'web';
	const CONTEXT_SKELETON = 'skel';

................................................................................

	public function indexForSearch(?string $source_path, ?string $source_content, ?string $title = null): void
	{
		// Store content in search table
		if (substr($this->mime, 0, 5) == 'text/') {
			$content = $source_content !== null ? $source_content : Files::callStorage('fetch', $this);

			if ($this->customType() == self::FILE_EXT_ENCRYPTED) {
				$content = null;
			}
			else if ($this->mime === 'text/html' || $this->mime == 'text/xml') {
				$content = strip_tags($content);
			}
		}
		else {
			$content = null;
		}

................................................................................
	public function fetch()
	{
		return Files::callStorage('fetch', $this);
	}

	public function render(array $options = [])
	{
		$type = $this->customType();
		$content = $this->fetch();

		/*
		if (substr($this->name, -strlen(self::FILE_EXT_HTML)) == self::FILE_EXT_HTML) {
			return \Garradin\Web\Render\HTML::render($this, null, $options);
		}*/

		if ($type == self::FILE_EXT_SKRIV) {
			$format = Render::FORMAT_SKRIV;
		}
		else if ($type == self::FILE_EXT_ENCRYPTED) {
			$format = Render::FORMAT_ENCRYPTED;
		}
		else if ($type == self::FILE_EXT_MARKDOWN) {
			$format = Render::FORMAT_MARKDOWN;
		}
		else if (substr($this->mime, 0, 5) == 'text/') {

			return sprintf('<pre>%s</pre>', htmlspecialchars($this->fetch()));
		}
		else {

			throw new \LogicException('Cannot render file of this type');
		}



		return Render::render($format, $this, $this->fetch(), $options);
	}

	public function checkReadAccess(?Session $session): bool
	{
		// Web pages and config files are always public
		if ($this->isPublic()) {
			return true;
................................................................................
		if ($context == self::CONTEXT_SKELETON || $context == self::CONTEXT_CONFIG || $context == self::CONTEXT_WEB) {
			return true;
		}

		return false;
	}

	public function getEditor(): ?string
	{
		if ($this->customType() == self::FILE_EXT_SKRIV) {
			return self::EDITOR_WEB;
		}
		elseif ($this->customType() == self::FILE_EXT_ENCRYPTED) {
			return self::EDITOR_ENCRYPTED;
		}
		elseif (substr($this->mime, 0, 5) == 'text/') {
			return self::EDITOR_CODE;
		}

		return null;
	}

	static public function filterName(string $name): string
	{
		return preg_replace('/[^\w\d\p{L}_. -]+/iu', '-', $name);
	}

	static public function validateFileName(string $name): void
	{
................................................................................
		}

		$name = array_pop($path);
		$ref = implode('/', $path);
		return [$context, $ref ?: null, $name];
	}

	public function customType(): ?string
	{
		static $extensions = [self::FILE_EXT_ENCRYPTED, self::FILE_EXT_SKRIV];


		foreach ($extensions as $ext) {
			if (substr($this->name, -strlen($ext)) == $ext) {









				return $ext;
			}










		}

		return null;
	}
}







<
<
<
<
<
<
<







 







<
<
<
|







 







|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>


<
>


>
>
|
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|

|
>
|
<
|
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>





69
70
71
72
73
74
75







76
77
78
79
80
81
82
...
286
287
288
289
290
291
292



293
294
295
296
297
298
299
300
...
687
688
689
690
691
692
693
694

695















696
697
698

699
700
701
702
703
704

705
706
707
708
709
710
711
...
825
826
827
828
829
830
831















832
833
834
835
836
837
838
...
872
873
874
875
876
877
878
879
880
881
882
883

884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
	const ALLOWED_THUMB_SIZES = [200, 500];

	const THUMB_CACHE_ID = 'file.thumb.%s.%d';

	const THUMB_SIZE_TINY = 200;
	const THUMB_SIZE_SMALL = 500;








	const CONTEXT_DOCUMENTS = 'documents';
	const CONTEXT_USER = 'user';
	const CONTEXT_TRANSACTION = 'transaction';
	const CONTEXT_CONFIG = 'config';
	const CONTEXT_WEB = 'web';
	const CONTEXT_SKELETON = 'skel';

................................................................................

	public function indexForSearch(?string $source_path, ?string $source_content, ?string $title = null): void
	{
		// Store content in search table
		if (substr($this->mime, 0, 5) == 'text/') {
			$content = $source_content !== null ? $source_content : Files::callStorage('fetch', $this);




			if ($this->mime === 'text/html' || $this->mime == 'text/xml') {
				$content = strip_tags($content);
			}
		}
		else {
			$content = null;
		}

................................................................................
	public function fetch()
	{
		return Files::callStorage('fetch', $this);
	}

	public function render(array $options = [])
	{
		$editor_type = $this->renderFormat();

















		if ($editor_type == 'text') {
			return sprintf('<pre>%s</pre>', htmlspecialchars($this->fetch()));
		}

		elseif (!$editor_type) {
			throw new \LogicException('Cannot render file of this type');
		}
		else {
			return Render::render($editor_type, $this, $this->fetch(), $options);
		}

	}

	public function checkReadAccess(?Session $session): bool
	{
		// Web pages and config files are always public
		if ($this->isPublic()) {
			return true;
................................................................................
		if ($context == self::CONTEXT_SKELETON || $context == self::CONTEXT_CONFIG || $context == self::CONTEXT_WEB) {
			return true;
		}

		return false;
	}
















	static public function filterName(string $name): string
	{
		return preg_replace('/[^\w\d\p{L}_. -]+/iu', '-', $name);
	}

	static public function validateFileName(string $name): void
	{
................................................................................
		}

		$name = array_pop($path);
		$ref = implode('/', $path);
		return [$context, $ref ?: null, $name];
	}

	public function renderFormat(): ?string
	{
		if (substr($this->name, -6) == '.skriv') {
			$format = Render::FORMAT_SKRIV;
		}

		elseif (substr($this->name, -3) == '.md') {
			$format = Render::FORMAT_MARKDOWN;
		}
		else if (substr($this->mime, 0, 5) == 'text/') {
			$format = 'text';
		}
		else {
			$format = null;
		}

		return $format;
	}

	public function editorType(): ?string
	{
		$format = $this->renderFormat();

		if ($format == 'text') {
			return 'code';
		}
		elseif ($format == Render::FORMAT_SKRIV || $format == Render::FORMAT_MARKDOWN) {
			return 'web';
		}

		return null;
	}
}

Modified src/templates/common/files/edit_web.tpl from [1178627620] to [5e930c6a6c].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{include file="admin/_head.tpl" title="Édition de fichier" custom_js=['wiki_editor.js']}

<form method="post" action="{$self_url}">
	<p class="textEditor">
		{input type="textarea" name="content" cols="70" rows="30" default=$content data-preview-url="!common/files/_preview.php?f=%s"|local_url|args:$file.parent data-fullscreen="1" data-attachments="0" data-savebtn="1"}
	</p>

	<p class="submit">
		{csrf_field key=$csrf_key}
		{button type="submit" name="save" label="Enregistrer" shape="right" class="main"}
	</p>

</form>

{include file="admin/_foot.tpl"}




|










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{include file="admin/_head.tpl" title="Édition de fichier" custom_js=['wiki_editor.js']}

<form method="post" action="{$self_url}">
	<p class="textEditor">
		{input type="textarea" name="content" cols="70" rows="30" default=$content data-preview-url="!common/files/_preview.php?f=%s"|local_url|args:$file.parent data-fullscreen="1" data-attachments="0" data-savebtn="1" data-format=$file->renderFormat()}
	</p>

	<p class="submit">
		{csrf_field key=$csrf_key}
		{button type="submit" name="save" label="Enregistrer" shape="right" class="main"}
	</p>

</form>

{include file="admin/_foot.tpl"}

Modified src/templates/docs/index.tpl from [cb91864560] to [41690fac23].

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
							<a href="{$file->url(true)}" target="_blank">{$file.name}</a>
						{/if}
					</td>
					<td>{$file.modified|date}</td>
					<td>{$file.mime}</td>
					<td>{$file.size|size_in_bytes}</td>
					<td class="actions">
						{if $can_write && $file->getEditor()}
							{linkbutton href="!common/files/edit.php?p=%s"|args:$file.path label="Modifier" shape="edit" target="_dialog" data-dialog-height="90%"}
						{/if}
						{if $file->canPreview()}
							{linkbutton href="!common/files/preview.php?p=%s"|args:$file.path label="Voir" shape="eye" target="_dialog" data-mime=$file.mime}
						{/if}
						{linkbutton href=$file->url(true) label="Télécharger" shape="download"}
						{if $can_write}







|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
							<a href="{$file->url(true)}" target="_blank">{$file.name}</a>
						{/if}
					</td>
					<td>{$file.modified|date}</td>
					<td>{$file.mime}</td>
					<td>{$file.size|size_in_bytes}</td>
					<td class="actions">
						{if $can_write && $file->editorType()}
							{linkbutton href="!common/files/edit.php?p=%s"|args:$file.path label="Modifier" shape="edit" target="_dialog" data-dialog-height="90%"}
						{/if}
						{if $file->canPreview()}
							{linkbutton href="!common/files/preview.php?p=%s"|args:$file.path label="Voir" shape="eye" target="_dialog" data-mime=$file.mime}
						{/if}
						{linkbutton href=$file->url(true) label="Télécharger" shape="download"}
						{if $can_write}

Modified src/www/admin/common/files/edit.php from [9d117de49a] to [5a8ed5bb74].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	throw new UserException('Fichier inconnu');
}

if (!$file->checkWriteAccess($session)) {
	throw new UserException('Vous n\'avez pas le droit de modifier ce fichier.');
}

$editor = $file->getEditor();
$csrf_key = 'edit_file_' . $file->pathHash();

$form->runIf('content', function () use ($file) {
	$file->setContent(f('content'));

	if (qg('js') !== null) {
		die('{"success":true}');







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	throw new UserException('Fichier inconnu');
}

if (!$file->checkWriteAccess($session)) {
	throw new UserException('Vous n\'avez pas le droit de modifier ce fichier.');
}

$editor = $file->editorType();
$csrf_key = 'edit_file_' . $file->pathHash();

$form->runIf('content', function () use ($file) {
	$file->setContent(f('content'));

	if (qg('js') !== null) {
		die('{"success":true}');

Modified src/www/admin/config/edit_file.php from [a041a95b07] to [8a746033ac].

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	$file = File::create(Utils::dirname($file_path), Utils::basename($file_path), null, '');
	$content = '';
}
else {
	$content = $file->fetch();
}

$editor = $file->getEditor();
$csrf_key = 'edit_file_' . $file->pathHash();

$form->runIf('save', function () use ($file, $key) {
	// For config files, make sure config value is updated
	$config = Config::getInstance();

	if (trim(f('content')) === '') {







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	$file = File::create(Utils::dirname($file_path), Utils::basename($file_path), null, '');
	$content = '';
}
else {
	$content = $file->fetch();
}

$editor = $file->editorType();
$csrf_key = 'edit_file_' . $file->pathHash();

$form->runIf('save', function () use ($file, $key) {
	// For config files, make sure config value is updated
	$config = Config::getInstance();

	if (trim(f('content')) === '') {