1
0
mirror of https://github.com/typemill/typemill.git synced 2025-07-25 00:02:28 +02:00

finish api

This commit is contained in:
trendschau
2025-02-10 21:32:31 +01:00
parent 113a913ef3
commit fc5b3c75c7
5 changed files with 321 additions and 8 deletions

View File

@@ -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)!

View File

@@ -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([

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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());