mirror of
https://github.com/typemill/typemill.git
synced 2025-07-25 00:02:28 +02:00
finish api
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Typemill
|
||||
# Typemill
|
||||
|
||||
Typemill is a lightweight, flat-file CMS designed for simple, fast, and flexible website and eBook creation using Markdown. Create handbooks, documentations, manuals, reports, traditional websites, online novels, and more.
|
||||
Typemill is a lightweight, flat-file CMS designed for simple, fast, and flexible website and eBook creation using Markdown. Create handbooks, documentation, manuals, reports, traditional websites, online novels, and more.
|
||||
|
||||
Stay in the loop and subscribe to the [Typemill newsletter](https://typemill.net/news)!
|
||||
|
||||
|
@@ -5,7 +5,11 @@ namespace Typemill\Controllers;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Typemill\Models\Navigation;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\Content;
|
||||
use Typemill\Models\Meta;
|
||||
use Typemill\Models\Sitemap;
|
||||
use Typemill\Static\Translations;
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
class ControllerApiGlobals extends Controller
|
||||
@@ -46,6 +50,39 @@ class ControllerApiGlobals extends Controller
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
|
||||
public function getNavigation(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getQueryParams();
|
||||
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
$navigation = new Navigation();
|
||||
|
||||
if(isset($params['draft']) && $params['draft'] == true)
|
||||
{
|
||||
$contentnavi = $navigation->getFullDraftNavigation($urlinfo, $langattr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$contentnavi = $navigation->getLiveNavigation($urlinfo, $langattr);
|
||||
}
|
||||
|
||||
if(!$contentnavi)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('navigation not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'navigation' => $contentnavi
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function clearNavigation(Request $request, Response $response)
|
||||
{
|
||||
$navigation = new Navigation();
|
||||
@@ -59,6 +96,215 @@ class ControllerApiGlobals extends Controller
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);;
|
||||
}
|
||||
|
||||
public function getItemForUrl(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getQueryParams();
|
||||
$validate = new Validation();
|
||||
$validInput = $validate->articleUrl($params);
|
||||
if($validInput !== true)
|
||||
{
|
||||
$errors = $validate->returnFirstValidationErrors($validInput);
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => reset($errors),
|
||||
'errors' => $errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
$navigation = new Navigation();
|
||||
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
|
||||
|
||||
if(!$item)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('page not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'item' => $item
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function getItemsForSlug(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getQueryParams();
|
||||
$validate = new Validation();
|
||||
$validInput = $validate->articleSlug($params);
|
||||
if($validInput !== true)
|
||||
{
|
||||
$errors = $validate->returnFirstValidationErrors($validInput);
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => reset($errors),
|
||||
'errors' => $errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
$navigation = new Navigation();
|
||||
$items = $navigation->getItemsForSlug($params['slug'], $urlinfo, $langattr);
|
||||
|
||||
if(!$items)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('page not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'items' => $items
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function getArticleContent(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getQueryParams();
|
||||
$validate = new Validation();
|
||||
$validInput = $validate->articleUrl($params);
|
||||
if($validInput !== true)
|
||||
{
|
||||
$errors = $validate->returnFirstValidationErrors($validInput);
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => reset($errors),
|
||||
'errors' => $errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
$navigation = new Navigation();
|
||||
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
|
||||
if(!$item)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('page not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
# if user is not allowed to perform this action (e.g. not admin)
|
||||
if(!$this->userroleIsAllowed($request->getAttribute('c_userrole'), 'content', 'read'))
|
||||
{
|
||||
# then check if user is the owner of this content
|
||||
$meta = new Meta();
|
||||
$metadata = $meta->getMetaData($item);
|
||||
if(!$this->userIsAllowed($request->getAttribute('c_username'), $metadata))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('You do not have enough rights.'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(403);
|
||||
}
|
||||
}
|
||||
|
||||
# GET THE CONTENT
|
||||
$content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher'));
|
||||
$markdown = $content->getLiveMarkdown($item);
|
||||
|
||||
if(isset($params['draft']) && $params['draft'] == true)
|
||||
{
|
||||
# if draft is explicitly requested
|
||||
$markdown = $content->getDraftMarkdown($item);
|
||||
}
|
||||
|
||||
if(!$markdown)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('page not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
if(!is_array($markdown))
|
||||
{
|
||||
$markdown = $content->markdownTextToArray($markdown);
|
||||
}
|
||||
$markdownHtml = $content->addDraftHtml($markdown);
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'content' => $markdownHtml
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function getArticleMeta(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getQueryParams();
|
||||
$validate = new Validation();
|
||||
$validInput = $validate->articleUrl($params);
|
||||
if($validInput !== true)
|
||||
{
|
||||
$errors = $validate->returnFirstValidationErrors($validInput);
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => reset($errors),
|
||||
'errors' => $errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
$navigation = new Navigation();
|
||||
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
|
||||
if(!$item)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('page not found'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
# if user is not allowed to perform this action (e.g. not admin)
|
||||
if(!$this->userroleIsAllowed($request->getAttribute('c_userrole'), 'content', 'read'))
|
||||
{
|
||||
# then check if user is the owner of this content
|
||||
$meta = new Meta();
|
||||
$metadata = $meta->getMetaData($item);
|
||||
if(!$this->userIsAllowed($request->getAttribute('c_username'), $metadata))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => Translations::translate('You do not have enough rights.'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(403);
|
||||
}
|
||||
}
|
||||
|
||||
# GET THE META
|
||||
$meta = new Meta();
|
||||
$metadata = $meta->getMetaData($item);
|
||||
$metadata = $meta->addMetaDefaults($metadata, $item, $this->settings['author']);
|
||||
# $metadata = $meta->addMetaTitleDescription($metadata, $item, $markdown);
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'meta' => $metadata
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function showSecurityLog(Request $request, Response $response)
|
||||
{
|
||||
$storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
@@ -154,7 +400,6 @@ class ControllerApiGlobals extends Controller
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function getTranslations(Request $request, Response $response)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
|
@@ -140,6 +140,19 @@ class Navigation extends Folder
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getItemsForSlug($slug, $urlinfo, $langattr)
|
||||
{
|
||||
$draftNavigation = $this->getFullDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
if(!$draftNavigation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$items = $this->findItemsWithSlug($draftNavigation, $slug);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function getItemForUrl($url, $urlinfo, $langattr)
|
||||
{
|
||||
@@ -813,6 +826,26 @@ class Navigation extends Folder
|
||||
return $flat;
|
||||
}
|
||||
|
||||
# only used by public api
|
||||
public function findItemsWithSlug($navigation, $slug, $result = NULL)
|
||||
{
|
||||
foreach($navigation as $key => $item)
|
||||
{
|
||||
# set item active, needed to move item in navigation
|
||||
if($item->slug === $slug)
|
||||
{
|
||||
$result[] = $item;
|
||||
}
|
||||
elseif($item->elementType === "folder")
|
||||
{
|
||||
$result = self::findItemsWithSlug($item->folderContent, $slug, $result);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
# NOT IN USE ANYMORE BUT KEEP IT
|
||||
public function getItemWithUrl($navigation, $url, $result = NULL)
|
||||
{
|
||||
|
@@ -522,6 +522,36 @@ class Validation
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
public function articleUrl(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', 'url');
|
||||
$v->rule('regex', 'url', '/^\/?[a-z0-9\-\/]+(?:\?[a-z0-9\-=&]*)?$/i');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
public function articleSlug(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', 'slug');
|
||||
$v->rule('regex', 'slug', '/^[a-z0-9-]+$/i');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
public function blockInput(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
@@ -23,10 +23,6 @@ use Typemill\Controllers\ControllerApiTestmail;
|
||||
|
||||
$app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
|
||||
# GLOBALS
|
||||
$group->get('/systemnavi', ControllerApiGlobals::class . ':getSystemnavi')->setName('api.systemnavi.get')->add(new ApiAuthorization($acl, 'account', 'read')); # member
|
||||
$group->get('/mainnavi', ControllerApiGlobals::class . ':getMainnavi')->setName('api.mainnavi.get')->add(new ApiAuthorization($acl, 'account', 'read')); # member
|
||||
|
||||
# SYSTEM
|
||||
$group->get('/settings', ControllerApiSystemSettings::class . ':getSettings')->setName('api.settings.get')->add(new ApiAuthorization($acl, 'system', 'read')); # manager
|
||||
$group->post('/settings', ControllerApiSystemSettings::class . ':updateSettings')->setName('api.settings.set')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
@@ -92,10 +88,19 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
$group->post('/meta', ControllerApiAuthorMeta::class . ':updateMeta')->setName('api.metadata.update')->add(new ApiAuthorization($acl, 'mycontent', 'update'));
|
||||
|
||||
# KIXOTE
|
||||
$group->delete('/clearnavigation', ControllerApiGlobals::class . ':clearNavigation')->setName('api.navigation.clear')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
$group->get('/securitylog', ControllerApiGlobals::class . ':showSecurityLog')->setName('api.securitylog.show')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
$group->delete('/securitylog', ControllerApiGlobals::class . ':deleteSecurityLog')->setName('api.securitylog.delete')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
$group->delete('/cache', ControllerApiGlobals::class . ':deleteCache')->setName('api.cache.delete')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
$group->delete('/clearnavigation', ControllerApiGlobals::class . ':clearNavigation')->setName('api.navigation.clear')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
|
||||
|
||||
# API USED ONLY EXTERNALLY
|
||||
$group->get('/systemnavi', ControllerApiGlobals::class . ':getSystemnavi')->setName('api.systemnavi.get')->add(new ApiAuthorization($acl, 'account', 'read')); # member
|
||||
$group->get('/mainnavi', ControllerApiGlobals::class . ':getMainnavi')->setName('api.mainnavi.get')->add(new ApiAuthorization($acl, 'account', 'read')); # member
|
||||
$group->get('/navigation', ControllerApiGlobals::class . ':getNavigation')->setName('api.navigation.get')->add(new ApiAuthorization($acl, 'content', 'read')); # author
|
||||
$group->get('/article/items', ControllerApiGlobals::class . ':getItemsForSlug')->setName('api.articleitems.get')->add(new ApiAuthorization($acl, 'content', 'read')); # author
|
||||
$group->get('/article/item', ControllerApiGlobals::class . ':getItemForUrl')->setName('api.articleitem.get')->add(new ApiAuthorization($acl, 'content', 'read')); # author
|
||||
$group->get('/article/content', ControllerApiGlobals::class . ':getArticleContent')->setName('api.articlecontent.get')->add(new ApiAuthorization($acl, 'content', 'read')); # author
|
||||
$group->get('/article/meta', ControllerApiGlobals::class . ':getArticleMeta')->setName('api.articlemeta.get')->add(new ApiAuthorization($acl, 'content', 'read')); # author
|
||||
|
||||
})->add(new CorsHeadersMiddleware($settings, $urlinfo))->add(new ApiAuthentication());
|
||||
|
||||
|
Reference in New Issue
Block a user