Skip to content

Commit

Permalink
Version 1.4.6: Change content, CSRF-notification, fix blox editor, al…
Browse files Browse the repository at this point in the history
…ert for raw editor, cyanine optimizations
  • Loading branch information
trendschau committed Jun 3, 2021
1 parent 156e2c6 commit 14ea7c7
Show file tree
Hide file tree
Showing 22 changed files with 297 additions and 108 deletions.
2 changes: 1 addition & 1 deletion content/00-welcome/01-write-content.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Write Content

Typemill is a simple Flat File Content Management System (CMS). We (the community) work hard to provide the best author experience with easy and intuitive authoring tools. But Typemill is still in early development and it is likely that not everything will work perfectly out of the box. If you miss something or if you have ideas for improvements, then post a new issue on [GitHub](https://github.com/typemill/typemill/issues).
Typemill provides easy and intuitive authoring tools and we work hard to create a good author experience. With the interactive navigation you can create pages and structure your websites. The visual markdown editor will help you to create content in a wysiwyg mode. The publish bar gives you full control over the status of each page. Watch the following video tutorial to learn all the details.

![youtube-video](media/live/youtube-6i2-uv88gke.jpeg "click to load video"){#6I2-uV88GkE .youtube}

Expand Down
2 changes: 1 addition & 1 deletion content/00-welcome/02-manage-access.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Manage Access

Typemill has a build-in system to restrict access to pages or to the whole websites. You can activate both features in the system settings under the section "access rights". If you activate one of the features, then Typemill will use session cookies on all frontend pages.
Typemill has a build-in system to restrict access to pages or to the whole websites. You can activate both features in the system settings under the section "access rights". If you activate one of the features, then Typemill will use session cookies on all frontend pages. Learn all the details in the following video tutorial:

![youtube-video](media/live/youtube-uw-m-4g1kaa.jpeg "click to load video"){#UW_m-4g1kAA .youtube}

Expand Down
2 changes: 1 addition & 1 deletion content/00-welcome/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Welcome

Great that you give Typemill a try!! Typemill is a small open source cms and a project in work. You will probably miss some important features, but we are working hard to add everything that is needed for a handy and productive writing-system.
Great that you give Typemill a try!! Typemill is a simple Flat File Content Management System (CMS). We (the community) work hard to provide the best author experience with easy and intuitive authoring tools. But Typemill is still in early development and it is likely that not everything will work perfectly out of the box. If you miss something or if you have ideas for improvements, then post a new issue on [GitHub](https://github.com/typemill/typemill/issues).

32 changes: 19 additions & 13 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# About TYPEMILL

TYPEMILL is a small flat file cms created for editors and writers. It provides an author-friendly dashboard and a visual-block-editor for markdown based on vue.js. Use TYPEMILL for manuals, documentations, web-books and similar publications. The website http://typemill.net itself is an example for TYPEMILL.
TYPEMILL is a lightweight flat file cms for micro-publishers. You can use it for documentations, manuals, special interest websites, and any other information-driven web-project. You can also enhance Typemill with plugins and generate professional e-books in pdf-format with it. The website http://typemill.net runs with Typemill.

![TYPEMILL Screenshot](https://typemill.net/media/tm-demo.gif)

## Features

* Website with markdown-files.
* Flexible drag & drop navigation.
* Visual markdown editor (VUE.js) and raw markdown mode.
* Flexible drag & drop navigation.
* Markdown extras with
* table of contents (TOC)
* tables
Expand All @@ -22,8 +22,15 @@ TYPEMILL is a small flat file cms created for editors and writers. It provides a
* System configurations.
* User management.
* Flexible form management with YAML-files.
* Plugins (with symfony event dispatcher).
* Flexible access rights.
* Themes (with TWIG).
* Plugins (with symfony event dispatcher).

Some plugin highlights are:

* **Ebooks**: Generate one or many professional pdf books from your typemill website.
* **Register**: Let users register to your website and give them access to pro-content.
* **Subscribe** (in work): Sell subscriptions for premium content with traditional pdf-invoices.

## Requirements

Expand Down Expand Up @@ -62,7 +69,7 @@ You can use your ftp-software for that.

## Setup

You will be redirected to the `/setup` page, please create an initial user and configure your system in the author panel.
If you visit your website first, then you will be redirected to the `/setup` page. Please create an initial user and configure your system in the author panel.

## Login

Expand Down Expand Up @@ -91,39 +98,38 @@ TYPEMILL is published under MIT licence. Please check the licence of the include

## IMPORTANT: How to Contribute

Typemill is still in an early stage and contributions are highly welcome. Please follow these rules:
Contributions are highly welcome. Please follow these rules:

* If you plan bigger changes, then please create an issue first so we can discuss it.
* Fork the "DEVELOP" branch from typemill. Never use the master branch, because it is protected and only contains tested releases.
* Do your changes.
* Before your request, please pull the recent develop branch again to get latest changes.
* Then make a pull request for the DEVELOP branch again.
* After that pull the recent develop branch again to get the latest changes.
* Then make a pull request for the DEVELOP branch.

You can check the [roadmap for Typemill](https://github.com/typemill/typemill/issues/35) and scroll through the issues. I will mark issues in future that are easy to start with or where help is highly appreciated.

Here are some contribution-ideas for non-coder:

* Share typemill with social media.
* Write about typemill.
* Share Typemill with social media.
* Write about Typemill.
* Improve the documentation.
* Find bugs and errors (open a new issue on github for it).
* Describe some missing features and explain, why they are important for other users.

Some ideas for devs (please fork this repository make your changes and create a pull request):
Some ideas for devs:

* Fix a bug.
* Create or port a theme, especially for documentations, knowlegde bases or web-books.
* Create a fancy plugin.
* An auto-update functionality for core system, plugins and themes is highly needed.
* An auto-update functionality for the core system, for plugins and for themes is highly welcome.
* Improve the accessibility of html and css.
* Implement user roles and rights with RBAC or ACL.
* Write autotests with Cypress.

For hints, questions, problems and support, please open up a new issue on GitHub.

## Support

This is an open source project. I love it and I spend about 20 hours a week on it (starting in 2017). There is no business model right now, but you can support this project with a donation or simply hire me for implementations.
This is an open source project. I love it and I spend about 20 hours a week on it (starting in 2017). There is no business model right now, but you can support this project with a donation or simply [hire me](https://trendschau.net) for implementations.

Donate: https://www.paypal.me/typemill

Expand Down
6 changes: 6 additions & 0 deletions system/Controllers/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ public function show(Request $request, Response $response, $args)

public function login(Request $request, Response $response)
{
if( ( null !== $request->getattribute('csrf_result') ) OR ( $request->getattribute('csrf_result') === false ) )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('auth.show'));
}

/* log user attemps to authenticate */
$yaml = new WriteYaml();
$logins = $yaml->getYaml('settings/users', '.logins');
Expand Down
1 change: 0 additions & 1 deletion system/Controllers/BlockApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ public function updateBlock(Request $request, Response $response, $args)
{
return $response->withJson(['errors' => ['message' => 'Could not write to file. Please check if the file is writable']], 404);
}


/* parse markdown-file to content-array, if title parse title. */
if($this->params['block_id'] == 0)
Expand Down
9 changes: 8 additions & 1 deletion system/Controllers/FormController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@ class FormController extends Controller
public function savePublicForm($request, $response, $args)
{
if($request->isPost())
{
{
$params = $request->getParams();
reset($params);
$pluginName = key($params);
$referer = $request->getHeader('HTTP_REFERER');

# check csrf protection
if($request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout. Please try again.');
return $response->withRedirect($referer[0]);
}

# simple bot check with honeypot
if(isset($params[$pluginName]['personal-mail']))
{
Expand Down
44 changes: 41 additions & 3 deletions system/Controllers/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,14 @@ public function showSettings($request, $response, $args)
public function saveSettings($request, $response, $args)
{
if($request->isPost())
{
{

if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('settings.show'));
}

$settings = \Typemill\Settings::getUserSettings();
$defaultSettings = \Typemill\Settings::getDefaultSettings();
$params = $request->getParams();
Expand Down Expand Up @@ -378,7 +385,13 @@ public function showPlugins($request, $response, $args)
public function saveThemes($request, $response, $args)
{
if($request->isPost())
{
{
if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('themes.show'));
}

$userSettings = \Typemill\Settings::getUserSettings();
$params = $request->getParams();
$themeName = isset($params['theme']) ? $params['theme'] : false;
Expand Down Expand Up @@ -465,6 +478,13 @@ public function savePlugins($request, $response, $args)
{
if($request->isPost())
{

if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('plugins.show'));
}

$userSettings = \Typemill\Settings::getUserSettings();
$pluginSettings = array();
$userInput = $request->getParams();
Expand Down Expand Up @@ -764,6 +784,12 @@ public function createUser($request, $response, $args)
{
if($request->isPost())
{
if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('user.new'));
}

$params = $request->getParams();
$user = new User();
$validate = new Validation();
Expand Down Expand Up @@ -793,6 +819,12 @@ public function updateUser($request, $response, $args)

if($request->isPost())
{
if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('user.account'));
}

$params = $request->getParams();
$userdata = $params['user'];
$user = new User();
Expand Down Expand Up @@ -886,7 +918,13 @@ public function updateUser($request, $response, $args)
public function deleteUser($request, $response, $args)
{
if($request->isPost())
{
{
if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('user.account'));
}

$params = $request->getParams();
$validate = new Validation();
$user = new User();
Expand Down
6 changes: 6 additions & 0 deletions system/Controllers/SetupController.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public function create($request, $response, $args)
{
if($request->isPost())
{
if( $request->getattribute('csrf_result') === false )
{
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
return $response->withRedirect($this->c->router->pathFor('setup.welcome'));
}

$params = $request->getParams();
$validate = new Validation();
$user = new User();
Expand Down
8 changes: 7 additions & 1 deletion system/Middleware/RestrictApiAccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ public function __invoke(Request $request, Response $response, $next)
{
if(!isset($_SESSION['login']) || !isset($_SESSION['role']))
{
return $response->withJson(['errors' => ['access denied']], 403);
return $response->withJson(['data' => false, 'errors' => ['message' => 'You are probably logged out. Please login and try again.']], 403);
}

# check csrf protection
if( $request->getattribute('csrf_result') === false )
{
return $response->withJson(array('data' => false, 'errors' => ['message' => 'The form has a timeout. Please reload the page and try again.']), 403);
}
return $next($request, $response);
}
}
14 changes: 8 additions & 6 deletions system/author/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ h3{ font-size: 1em; margin: 0.6em 0 0.6em; text-transform: uppercase; font-weigh
}
section{
background: #FFFFFF;
box-shadow: 0 0 4px #ddd;
box-shadow: 0 4px 4px #ddd;
position: relative;
margin-bottom: 40px;
padding: 20px 5px 40px;
Expand Down Expand Up @@ -949,7 +949,7 @@ header a.button{
position: absolute;
width: 100%;
margin-top: -35px;
z-index: 1;
/* z-index: 1; */
}
.tab-button{
font-size: 0.9em;
Expand All @@ -968,7 +968,7 @@ header a.button{
outline: none;
}
section.tab{
z-index: -1;
/* z-index: -1; */
padding: 40px;
}
/********************
Expand Down Expand Up @@ -2358,18 +2358,20 @@ button.format-item.close:hover{
display: inline-block;
margin-top: 15px;
}
input.definitionTerm{
.definitionTerm{
width: 29%;
display: inline-block;
vertical-align: top;
background: #fff;
}
textarea.definitionDescription{
.definitionDescription{
width: 60%;
display: inline-block;
vertical-align: top;
background: #fff;
}
.definitionRow input, .definitionRow textarea{
background: #fff;
}
button.addDL,
button.delDL{
display: inline-block;
Expand Down
50 changes: 29 additions & 21 deletions system/author/editor/publish-controller.twig
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,37 @@
{% endif %}
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
<a v-if="visual" href="{{ base_url }}/tm/content/raw{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('raw mode') }}</span><span class="mobile">{{ __('raw') }}</span></a>
<a v-if="raw" href="{{ base_url }}/tm/content/visual{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('visual mode') }}</span><span class="mobile">{{ __('visual') }}</span></a>
<a v-if="raw" @click="checkUnsafedContent(event)" href="{{ base_url }}/tm/content/visual{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('visual mode') }}</span><span class="mobile">{{ __('visual') }}</span></a>
{% endif %}
<a target="_blank" class="button--secondary" href="{{ item.urlAbs }}"><svg class="icon baseline icon-external-link"><use xlink:href="#icon-external-link"></use></svg></a>
</div>
<transition name="fade">
<div v-if="modalWindow" id="modalWindow" class="modalWindow">
<div class="modalInner">
<div @click="hideModal" id="closeModal" class="closeModal">X</div>
{% if (acl.isAllowed(get_role(), 'content', 'delete')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'delete')) ) %}
<div v-if="modalType == 'delete'">
<h2>{{ __('Delete page') }}</h2>
<p>{{ __('Do you really want to delete this page') }} {{ __('Please confirm') }}</p>
<button @click.prevent="deleteArticle" class="large alert" :class="deleteResult" :disabled="deleteDisabled">{{ __('Delete Page') }}</button>
</div>
{% endif %}
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
<div v-if="modalType == 'discard'">
<h2>{{ __('Discard Changes') }}</h2>
<p>{{ __('Do you want to discard your changes and set the content back to the live version') }}</p>
<button @click.prevent="discardDraft" class="large fullwidth" :class="discardResult" :disabled="publishDisabled">{{ __('Discard Changes') }}</button>
</div>
{% endif %}
</div>
<transition name="fade">
<div v-if="modalWindow" id="modalWindow" class="modalWindow">
<div class="modalInner">
<div @click="hideModal" id="closeModal" class="closeModal">X</div>
{% if (acl.isAllowed(get_role(), 'content', 'delete')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'delete')) ) %}
<div v-if="modalType == 'delete'">
<h2>{{ __('Delete page') }}</h2>
<p>{{ __('Do you really want to delete this page') }} {{ __('Please confirm') }}</p>
<button @click.prevent="deleteArticle" class="large alert" :class="deleteResult" :disabled="deleteDisabled">{{ __('Delete Page') }}</button>
</div>
{% endif %}
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
<div v-if="modalType == 'discard'">
<h2>{{ __('Discard Changes') }}</h2>
<p>{{ __('Do you want to discard your changes and set the content back to the live version') }}</p>
<button @click.prevent="discardDraft" class="large fullwidth" :class="discardResult" :disabled="publishDisabled">{{ __('Discard Changes') }}</button>
</div>
{% endif %}
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
<div v-if="modalType == 'unsafed'">
<h2>{{ __('Save Your Changes') }}</h2>
<p>{{ __('You have unsaved changes. Go back and save your changes. If you proceed to the visual mode now, then you will loose your changes.') }}</p>
<button @click="hideModal" class="large fullwidth">{{ __('Go back and save') }}</button>
<a class="w-100 tc ma2 tm-red hover-bg-tm-red hover-white" href="{{ base_url }}/tm/content/visual{{ itemurl }}">{{ __('go to visual mode') }}</a>
</div>
{% endif %}
</div>
</transition>
</div>
</transition>
</div>
Loading

0 comments on commit 14ea7c7

Please sign in to comment.