cutelyst 3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
application.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "application_p.h"
6#include "common.h"
7#include "config.h"
8#include "context_p.h"
9#include "controller.h"
10#include "controller_p.h"
11#include "dispatchtype.h"
12#include "enginerequest.h"
13#include "request.h"
14#include "request_p.h"
15#include "response.h"
16#include "response_p.h"
17#include "stats.h"
18#include "utils.h"
19#include "view.h"
20
21#include <QtCore/QCoreApplication>
22#include <QtCore/QDataStream>
23#include <QtCore/QDir>
24#include <QtCore/QFileInfo>
25#include <QtCore/QLocale>
26#include <QtCore/QPluginLoader>
27#include <QtCore/QStringList>
28#include <QtCore/QTranslator>
29
30Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER, "cutelyst.dispatcher", QtWarningMsg)
31Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_PATH, "cutelyst.dispatcher.path", QtWarningMsg)
32Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_CHAINED, "cutelyst.dispatcher.chained", QtWarningMsg)
33Q_LOGGING_CATEGORY(CUTELYST_CONTROLLER, "cutelyst.controller", QtWarningMsg)
34Q_LOGGING_CATEGORY(CUTELYST_CORE, "cutelyst.core", QtWarningMsg)
35Q_LOGGING_CATEGORY(CUTELYST_ENGINE, "cutelyst.engine", QtWarningMsg)
36Q_LOGGING_CATEGORY(CUTELYST_UPLOAD, "cutelyst.upload", QtWarningMsg)
37Q_LOGGING_CATEGORY(CUTELYST_MULTIPART, "cutelyst.multipart", QtWarningMsg)
38Q_LOGGING_CATEGORY(CUTELYST_VIEW, "cutelyst.view", QtWarningMsg)
39Q_LOGGING_CATEGORY(CUTELYST_REQUEST, "cutelyst.request", QtWarningMsg)
40Q_LOGGING_CATEGORY(CUTELYST_RESPONSE, "cutelyst.response", QtWarningMsg)
41Q_LOGGING_CATEGORY(CUTELYST_STATS, "cutelyst.stats", QtWarningMsg)
42Q_LOGGING_CATEGORY(CUTELYST_COMPONENT, "cutelyst.component", QtWarningMsg)
43
44using namespace Cutelyst;
45
48 , d_ptr(new ApplicationPrivate)
49{
50 Q_D(Application);
51
52 d->q_ptr = this;
53
54 qRegisterMetaType<ParamsMultiMap>();
55#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
56 qRegisterMetaTypeStreamOperators<ParamsMultiMap>("ParamsMultiMap");
57#endif
58
59 d->dispatcher = new Dispatcher(this);
60
61 loadTranslations(QStringLiteral("cutelystcore"));
62}
63
64Application::~Application()
65{
66 delete d_ptr;
67}
68
70{
71 qCDebug(CUTELYST_CORE) << "Default Application::init called on pid:"
73 return true;
74}
75
77{
78 qCDebug(CUTELYST_CORE) << "Default Application::postFork called on pid:"
80 return true;
81}
82
84{
85 Q_D(Application);
86 return d->headers;
87}
88
90{
91 Q_D(Application);
92 d->headers.setHeader(QStringLiteral("X_CUTELYST"), QStringLiteral(VERSION));
93}
94
96{
97 Q_D(Application);
98 if (d->plugins.contains(plugin)) {
99 return false;
100 }
101 d->plugins.append(plugin);
102 return true;
103}
104
106{
107 Q_D(Application);
108 const auto name = QString::fromLatin1(controller->metaObject()->className());
109 if (d->controllersHash.contains(name)) {
110 return false;
111 }
112 d->controllersHash.insert(name, controller);
113 d->controllers.append(controller);
114 return true;
115}
116
118{
119 Q_D(Application);
120 if (d->views.contains(view->name())) {
121 qCWarning(CUTELYST_CORE) << "Not registering View." << view->metaObject()->className()
122 << "There is already a view with this name:" << view->name();
123 return false;
124 }
125 d->views.insert(view->name(), view);
126 return true;
127}
128
130{
131 Q_D(Application);
132 if (d->dispatchers.contains(dispatcher)) {
133 return false;
134 }
135 d->dispatchers.append(dispatcher);
136 return true;
137}
138
140{
141 Q_D(Application);
142 auto it = d->factories.constFind(name);
143 if (it != d->factories.constEnd()) {
144 ComponentFactory *factory = it.value();
145 if (factory) {
146 return factory->createComponent(parent);
147 } else {
148 return nullptr;
149 }
150 }
151
152 const QByteArrayList dirs = QByteArrayList{QByteArrayLiteral(CUTELYST_PLUGINS_DIR)} +
153 qgetenv("CUTELYST_PLUGINS_DIR").split(';');
154 for (const QByteArray &dir : dirs) {
155 Component *component = d->createComponentPlugin(name, parent, QString::fromLocal8Bit(dir));
156 if (component) {
157 return component;
158 }
159 }
160 qCDebug(CUTELYST_CORE) << "Did not find plugin" << name << "on" << dirs << "for" << parent;
161
162 return nullptr;
163}
164
165const char *Application::cutelystVersion() noexcept
166{
167 return VERSION;
168}
169
171{
172 Q_D(const Application);
173 return d->controllers;
174}
175
176View *Application::view(const QString &name) const
177{
178 Q_D(const Application);
179 return d->views.value(name);
180}
181
183{
184 Q_D(const Application);
185 return d->views.value(name);
186}
187
188QVariant Application::config(const QString &key, const QVariant &defaultValue) const
189{
190 Q_D(const Application);
191 auto it = d->config.constFind(key);
192 if (it != d->config.constEnd()) {
193 return it.value();
194 }
195 return defaultValue;
196}
197
199{
200 Q_D(const Application);
201 return d->dispatcher;
202}
203
205{
206 Q_D(const Application);
207 return d->dispatcher->dispatchers();
208}
209
211{
212 Q_D(const Application);
213 return d->plugins;
214}
215
216QVariantMap Application::config() const noexcept
217{
218 Q_D(const Application);
219 return d->config;
220}
221
223{
224 QDir home = config(QStringLiteral("home")).toString();
225 return home.absoluteFilePath(path);
226}
227
229{
230 QDir home = config(QStringLiteral("home")).toString();
231 return home.absoluteFilePath(path.join(u'/'));
232}
233
234bool Cutelyst::Application::inited() const noexcept
235{
236 Q_D(const Application);
237 return d->init;
238}
239
241{
242 Q_D(const Application);
243 return d->engine;
244}
245
246void Application::setConfig(const QString &key, const QVariant &value)
247{
248 Q_D(Application);
249 d->config.insert(key, value);
250}
251
253{
254 Q_D(Application);
255
256 if (d->init) {
257 return true;
258 }
259 d->init = true;
260
261 d->useStats = CUTELYST_STATS().isDebugEnabled();
262 d->engine = engine;
263 d->config = engine->config(QLatin1String("Cutelyst"));
264
265 d->setupHome();
266
267 // Call the virtual application init
268 // to setup Controllers plugins stuff
269 if (init()) {
270 d->setupChildren(children());
271
272 bool zeroCore = engine->workerCore() == 0;
273
274 QVector<QStringList> tablePlugins;
275 const auto plugins = d->plugins;
276 for (Plugin *plugin : plugins) {
277 if (plugin->objectName().isEmpty()) {
278 plugin->setObjectName(QString::fromLatin1(plugin->metaObject()->className()));
279 }
280 tablePlugins.append({plugin->objectName()});
281 // Configure plugins
282 plugin->setup(this);
283 }
284
285 if (zeroCore && !tablePlugins.isEmpty()) {
286 qCDebug(CUTELYST_CORE)
287 << Utils::buildTable(tablePlugins, QStringList(), QLatin1String("Loaded plugins:"))
288 .constData();
289 }
290
291 if (zeroCore) {
292 QVector<QStringList> tableDataHandlers;
293 tableDataHandlers.append({QLatin1String("application/x-www-form-urlencoded")});
294 tableDataHandlers.append({QLatin1String("application/json")});
295 tableDataHandlers.append({QLatin1String("multipart/form-data")});
296 qCDebug(CUTELYST_CORE)
297 << Utils::buildTable(tableDataHandlers,
298 QStringList(),
299 QLatin1String("Loaded Request Data Handlers:"))
300 .constData();
301
302 qCDebug(CUTELYST_CORE) << "Loaded dispatcher"
303 << QString::fromLatin1(d->dispatcher->metaObject()->className());
304 qCDebug(CUTELYST_CORE)
305 << "Using engine" << QString::fromLatin1(d->engine->metaObject()->className());
306 }
307
308 QString home = d->config.value(QLatin1String("home")).toString();
309 if (home.isEmpty()) {
310 if (zeroCore) {
311 qCDebug(CUTELYST_CORE) << "Couldn't find home";
312 }
313 } else {
314 QFileInfo homeInfo(home);
315 if (homeInfo.isDir()) {
316 if (zeroCore) {
317 qCDebug(CUTELYST_CORE) << "Found home" << home;
318 }
319 } else {
320 if (zeroCore) {
321 qCDebug(CUTELYST_CORE) << "Home" << home << "doesn't exist";
322 }
323 }
324 }
325
327 QStringList controllerNames = d->controllersHash.keys();
328 controllerNames.sort();
329 for (const QString &controller : controllerNames) {
330 table.append({controller, QLatin1String("Controller")});
331 }
332
333 const auto views = d->views;
334 for (View *view : views) {
335 if (view->reverse().isEmpty()) {
336 const QString className = QString::fromLatin1(view->metaObject()->className()) +
337 QLatin1String("->execute");
338 view->setReverse(className);
339 }
340 table.append({view->reverse(), QLatin1String("View")});
341 }
342
343 if (zeroCore && !table.isEmpty()) {
344 qCDebug(CUTELYST_CORE)
345 << Utils::buildTable(table,
346 {QLatin1String("Class"), QLatin1String("Type")},
347 QLatin1String("Loaded components:"))
348 .constData();
349 }
350
351 const auto controllers = d->controllers;
352 for (Controller *controller : controllers) {
353 controller->d_ptr->init(this, d->dispatcher);
354 }
355
356 d->dispatcher->setupActions(d->controllers, d->dispatchers, d->engine->workerCore() == 0);
357
358 if (zeroCore) {
359 qCInfo(CUTELYST_CORE) << qPrintable(
360 QString::fromLatin1("%1 powered by Cutelyst %2, Qt %3.")
363 QLatin1String(qVersion())));
364 }
365
366 Q_EMIT preForked(this);
367
368 return true;
369 }
370
371 return false;
372}
373
375{
376 Q_D(Application);
377
378 Engine *engine = d->engine;
379
380 auto priv = new ContextPrivate(this, engine, d->dispatcher, d->plugins);
381 auto c = new Context(priv);
382
383 request->context = c;
384 priv->engineRequest = request;
385 priv->response = new Response(d->headers, request);
386 priv->request = new Request(request);
387
388 if (d->useStats) {
389 priv->stats = new Stats(request);
390 }
391
392 // Process request
393 bool skipMethod = false;
394 Q_EMIT beforePrepareAction(c, &skipMethod);
395
396 if (!skipMethod) {
397 static bool log = CUTELYST_REQUEST().isEnabled(QtDebugMsg);
398 if (log) {
399 d->logRequest(priv->request);
400 }
401
402 d->dispatcher->prepareAction(c);
403
405
406 d->dispatcher->dispatch(c);
407
408 if (request->status & EngineRequest::Async) {
409 return;
410 }
411
413 }
414
415 c->finalize();
416}
417
419{
420 Q_D(Application);
421
422 if (!postFork()) {
423 return false;
424 }
425
426 const auto controllers = d->controllers;
427 for (Controller *controller : controllers) {
428 if (!controller->postFork(this)) {
429 return false;
430 }
431 }
432
433 Q_EMIT postForked(this);
434
435 return true;
436}
437
438void Application::addTranslator(const QLocale &locale, QTranslator *translator)
439{
440 Q_D(Application);
441 Q_ASSERT_X(translator, "add translator to application", "invalid QTranslator object");
442 auto it = d->translators.find(locale);
443 if (it != d->translators.end()) {
444 it.value().prepend(translator);
445 } else {
446 d->translators.insert(locale, QVector<QTranslator *>(1, translator));
447 }
448}
449
450void Application::addTranslator(const QString &locale, QTranslator *translator)
451{
452 addTranslator(QLocale(locale), translator);
453}
454
455void Application::addTranslators(const QLocale &locale, const QVector<QTranslator *> &translators)
456{
457 Q_D(Application);
458 Q_ASSERT_X(!translators.empty(), "add translators to application", "empty translators vector");
459 auto transIt = d->translators.find(locale);
460 if (transIt != d->translators.end()) {
461 for (auto it = translators.crbegin(); it != translators.crend(); ++it) {
462 transIt.value().prepend(*it);
463 }
464 } else {
465 d->translators.insert(locale, translators);
466 }
467}
468
469static void replacePercentN(QString *result, int n)
470{
471 if (n >= 0) {
472 auto percentPos = 0;
473 auto len = 0;
474 while ((percentPos = result->indexOf(u'%', percentPos + len)) != -1) {
475 len = 1;
476 QString fmt;
477 if (result->at(percentPos + len) == u'L') {
478 ++len;
479 fmt = QStringLiteral("%L1");
480 } else {
481 fmt = QStringLiteral("%1");
482 }
483 if (result->at(percentPos + len) == u'n') {
484 fmt = fmt.arg(n);
485 ++len;
486 result->replace(percentPos, len, fmt);
487 len = fmt.length();
488 }
489 }
490 }
491}
492
494 const char *context,
495 const char *sourceText,
496 const char *disambiguation,
497 int n) const
498{
499 QString result;
500
501 if (!sourceText) {
502 return result;
503 }
504
505 Q_D(const Application);
506
507 const QVector<QTranslator *> translators = d->translators.value(locale);
508 if (translators.empty()) {
509 result = QString::fromUtf8(sourceText);
510 replacePercentN(&result, n);
511 return result;
512 }
513
514 for (QTranslator *translator : translators) {
515 result = translator->translate(context, sourceText, disambiguation, n);
516 if (!result.isEmpty()) {
517 break;
518 }
519 }
520
521 if (result.isEmpty()) {
522 result = QString::fromUtf8(sourceText);
523 }
524
525 replacePercentN(&result, n);
526 return result;
527}
528
530 const QString &directory,
531 const QString &prefix,
532 const QString &suffix)
533{
534 loadTranslationsFromDir(filename, directory, prefix, suffix);
535}
536
538 const QString &directory,
539 const QString &prefix,
540 const QString &suffix)
541{
542 QVector<QLocale> locales;
543
544 if (Q_LIKELY(!filename.isEmpty())) {
545 const QString _dir = directory.isEmpty() ? QStringLiteral(I18NDIR) : directory;
546 const QDir i18nDir(_dir);
547 if (Q_LIKELY(i18nDir.exists())) {
548 const QString _prefix = prefix.isEmpty() ? QStringLiteral(".") : prefix;
549 const QString _suffix = suffix.isEmpty() ? QStringLiteral(".qm") : suffix;
550 const QStringList namesFilter = QStringList({filename + _prefix + u'*' + _suffix});
551
552 const QFileInfoList tsFiles = i18nDir.entryInfoList(namesFilter, QDir::Files);
553 if (Q_LIKELY(!tsFiles.empty())) {
554 locales.reserve(tsFiles.size());
555 for (const QFileInfo &ts : tsFiles) {
556 const QString fn = ts.fileName();
557 const int prefIdx = fn.indexOf(_prefix);
558 const QString locString =
559 fn.mid(prefIdx + _prefix.length(),
560 fn.length() - prefIdx - _suffix.length() - _prefix.length());
561 QLocale loc(locString);
562 if (Q_LIKELY(loc.language() != QLocale::C)) {
563 auto trans = new QTranslator(this);
564 if (Q_LIKELY(trans->load(loc, filename, _prefix, _dir))) {
565 addTranslator(loc, trans);
566 locales.append(loc);
567 qCDebug(CUTELYST_CORE) << "Loaded translations for" << loc << "from"
568 << ts.absoluteFilePath();
569 } else {
570 delete trans;
571 qCWarning(CUTELYST_CORE) << "Can not load translations for" << loc
572 << "from" << ts.absoluteFilePath();
573 }
574 } else {
575 qCWarning(CUTELYST_CORE)
576 << "Can not load translations for invalid locale string" << locString;
577 }
578 }
579 locales.squeeze();
580 } else {
581 qCWarning(CUTELYST_CORE)
582 << "Can not find translation files for" << filename << "in directory" << _dir;
583 }
584 } else {
585 qCWarning(CUTELYST_CORE)
586 << "Can not load translations from not existing directory:" << _dir;
587 }
588 } else {
589 qCWarning(CUTELYST_CORE) << "Can not load translations for empty file name.";
590 }
591
592 return locales;
593}
594
596 const QString &filename)
597{
598 QVector<QLocale> locales;
599
600 if (Q_LIKELY(!directory.isEmpty() && !filename.isEmpty())) {
601 const QDir dir(directory);
602 if (Q_LIKELY(dir.exists())) {
603 const auto dirs = dir.entryList(QDir::AllDirs);
604 if (Q_LIKELY(!dirs.empty())) {
605 locales.reserve(dirs.size());
606 for (const QString &subDir : dirs) {
607 const QString relFn = subDir + u'/' + filename;
608 if (dir.exists(relFn)) {
609 const QLocale l(subDir);
610 if (Q_LIKELY(l.language() != QLocale::C)) {
611 auto trans = new QTranslator(this);
612 const QFileInfo fi(dir, relFn);
613 if (Q_LIKELY(trans->load(
614 l, fi.baseName(), QString(), fi.absolutePath(), fi.suffix()))) {
615 addTranslator(l, trans);
616 locales.append(l);
617 qCDebug(CUTELYST_CORE) << "Loaded translations for" << l << "from"
618 << fi.absoluteFilePath();
619 } else {
620 delete trans;
621 qCWarning(CUTELYST_CORE) << "Can not load translations for" << l
622 << "from" << fi.absoluteFilePath();
623 }
624 } else {
625 qCWarning(CUTELYST_CORE)
626 << "Can not load translations for invalid locale string:" << subDir;
627 }
628 }
629 }
630 locales.squeeze();
631 } else {
632 qCWarning(CUTELYST_CORE) << "Can not find locale dirs under" << directory;
633 }
634 } else {
635 qCWarning(CUTELYST_CORE)
636 << "Can not load translations from not existing directory:" << directory;
637 }
638 } else {
639 qCWarning(CUTELYST_CORE)
640 << "Can not load translations for empty file name or directory name";
641 }
642
643 return locales;
644}
645
646void Cutelyst::ApplicationPrivate::setupHome()
647{
648 // Hook the current directory in config if "home" is not set
649 if (!config.contains(QLatin1String("home"))) {
650 config.insert(QStringLiteral("home"), QDir::currentPath());
651 }
652
653 if (!config.contains(QLatin1String("root"))) {
654 QDir home = config.value(QLatin1String("home")).toString();
655 config.insert(QStringLiteral("root"), home.absoluteFilePath(QLatin1String("root")));
656 }
657}
658
659void ApplicationPrivate::setupChildren(const QObjectList &children)
660{
661 Q_Q(Application);
662 for (QObject *child : children) {
663 auto controller = qobject_cast<Controller *>(child);
664 if (controller) {
665 q->registerController(controller);
666 continue;
667 }
668
669 auto plugin = qobject_cast<Plugin *>(child);
670 if (plugin) {
671 q->registerPlugin(plugin);
672 continue;
673 }
674
675 auto view = qobject_cast<View *>(child);
676 if (view) {
677 q->registerView(view);
678 continue;
679 }
680
681 auto dispatchType = qobject_cast<DispatchType *>(child);
682 if (dispatchType) {
683 q->registerDispatcher(dispatchType);
684 continue;
685 }
686 }
687}
688
689void Cutelyst::ApplicationPrivate::logRequest(Request *req)
690{
691 QString path = req->path();
692 if (path.isEmpty()) {
693 path = QStringLiteral("/");
694 }
695 qCDebug(CUTELYST_REQUEST) << req->method() << "request for" << path << "from"
696 << req->addressString();
697
698 ParamsMultiMap params = req->queryParameters();
699 if (!params.isEmpty()) {
700 logRequestParameters(params, QLatin1String("Query Parameters are:"));
701 }
702
703 params = req->bodyParameters();
704 if (!params.isEmpty()) {
705 logRequestParameters(params, QLatin1String("Body Parameters are:"));
706 }
707
708 const auto uploads = req->uploads();
709 if (!uploads.isEmpty()) {
710 logRequestUploads(uploads);
711 }
712}
713
714void Cutelyst::ApplicationPrivate::logRequestParameters(const ParamsMultiMap &params,
715 const QString &title)
716{
717 QVector<QStringList> table;
718 auto it = params.constBegin();
719 while (it != params.constEnd()) {
720 table.append({it.key(), it.value()});
721 ++it;
722 }
723 qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table,
724 {
725 QLatin1String("Parameter"),
726 QLatin1String("Value"),
727 },
728 title)
729 .constData();
730}
731
732void Cutelyst::ApplicationPrivate::logRequestUploads(const QVector<Cutelyst::Upload *> &uploads)
733{
734 QVector<QStringList> table;
735 for (Upload *upload : uploads) {
736 table.append({upload->name(),
737 upload->filename(),
738 upload->contentType(),
739 QString::number(upload->size())});
740 }
741 qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table,
742 {
743 QLatin1String("Parameter"),
744 QLatin1String("Filename"),
745 QLatin1String("Type"),
746 QLatin1String("Size"),
747 },
748 QLatin1String("File Uploads are:"))
749 .constData();
750}
751
752Component *ApplicationPrivate::createComponentPlugin(const QString &name,
753 QObject *parent,
754 const QString &directory)
755{
756 Component *component = nullptr;
757
758 QDir pluginsDir(directory);
759 QPluginLoader loader;
760 ComponentFactory *factory = nullptr;
761 const auto plugins = pluginsDir.entryList(QDir::Files);
762 for (const QString &fileName : plugins) {
763 loader.setFileName(pluginsDir.absoluteFilePath(fileName));
764 const QJsonObject json = loader.metaData()[QLatin1String("MetaData")].toObject();
765 if (json[QLatin1String("name")].toString() == name) {
766 QObject *plugin = loader.instance();
767 if (plugin) {
768 factory = qobject_cast<ComponentFactory *>(plugin);
769 if (!factory) {
770 qCCritical(CUTELYST_CORE)
771 << "Could not create a factory for" << loader.fileName();
772 } else {
773 component = factory->createComponent(parent);
774 }
775 break;
776 } else {
777 qCCritical(CUTELYST_CORE)
778 << "Could not load plugin" << loader.fileName() << loader.errorString();
779 }
780 }
781 }
782
783 if (factory) {
784 factories.insert(name, factory);
785 }
786
787 return component;
788}
789
790#include "moc_application.cpp"
The Cutelyst Application.
Definition application.h:43
Engine * engine() const noexcept
QVector< Controller * > controllers() const noexcept
void afterDispatch(Cutelyst::Context *c)
bool setup(Engine *engine)
Called by the Engine to setup the internal data.
void handleRequest(Cutelyst::EngineRequest *request)
Called by the Engine to handle a new Request object.
void beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
Application(QObject *parent=nullptr)
void setConfig(const QString &key, const QVariant &value)
QVariantMap config() const noexcept
Dispatcher * dispatcher() const noexcept
bool registerPlugin(Plugin *plugin)
bool registerController(Controller *controller)
bool registerDispatcher(DispatchType *dispatcher)
QString pathTo(const QString &path) const
Headers & defaultHeaders() noexcept
QString translate(const QLocale &locale, const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
bool inited() const noexcept
void beforeDispatch(Cutelyst::Context *c)
void preForked(Cutelyst::Application *app)
QVector< Plugin * > plugins() const noexcept
bool enginePostFork()
Called by the Engine once post fork happened.
void addTranslator(const QLocale &locale, QTranslator *translator)
bool registerView(View *view)
void addTranslators(const QLocale &locale, const QVector< QTranslator * > &translators)
QVector< DispatchType * > dispatchers() const noexcept
static const char * cutelystVersion() noexcept
QVector< QLocale > loadTranslationsFromDirs(const QString &directory, const QString &filename)
T plugin()
Returns the registered plugin that casts to the template type T.
Component * createComponentPlugin(const QString &name, QObject *parent=nullptr)
QVariant config(const QString &key, const QVariant &defaultValue={}) const
QVector< QLocale > loadTranslationsFromDir(const QString &filename, const QString &directory=QString(), const QString &prefix=QStringLiteral("."), const QString &suffix=QStringLiteral(".qm"))
View * view(const QString &name) const
virtual bool init()
void loadTranslations(const QString &filename, const QString &directory=QString(), const QString &prefix=QString(), const QString &suffix=QString())
void postForked(Cutelyst::Application *app)
virtual bool postFork()
virtual Component * createComponent(QObject *parent=nullptr)=0
The Cutelyst Component base class.
Definition component.h:26
Cutelyst Controller base class
Definition controller.h:88
The Cutelyst Dispatcher.
Definition dispatcher.h:28
Context * context
The Cutelyst::Context of this request.
Status status
Connection status.
The Cutelyst Engine.
Definition engine.h:21
QString addressString() const
Definition request.cpp:39
QVector< Upload * > uploads() const
Definition request.cpp:377
ParamsMultiMap bodyParameters() const
Definition request.cpp:216
ParamsMultiMap queryParameters() const
Definition request.cpp:252
Cutelyst Upload handles file upload request
Definition upload.h:23
Cutelyst View abstract view component
Definition view.h:22
The Cutelyst namespace holds all public Cutelyst API.
Definition Mainpage.dox:8
QMultiMap< QString, QString > ParamsMultiMap
qint64 applicationPid()
QString absoluteFilePath(const QString &fileName) const const
QString currentPath()
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
QStringList entryList(Filters filters, SortFlags sort) const const
bool exists() const const
QString absoluteFilePath() const const
QString absolutePath() const const
QString baseName() const const
bool isDir() const const
QString suffix() const const
Language language() const const
const char * className() const const
QObject(QObject *parent)
Q_EMITQ_EMIT
const QObjectList & children() const const
virtual const QMetaObject * metaObject() const const
QObject * parent() const const
QString errorString() const const
void setFileName(const QString &fileName)
QObject * instance()
QJsonObject metaData() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
QString fromLatin1(const char *str, int size)
QString fromLocal8Bit(const char *str, int size)
QString fromUtf8(const char *str, int size)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
int length() const const
QString mid(int position, int n) const const
QString number(int n, int base)
QString & replace(int position, int n, QChar after)
QString join(const QString &separator) const const
void sort(Qt::CaseSensitivity cs)
void append(const T &value)
const_reverse_iterator crbegin() const const
const_reverse_iterator crend() const const
bool empty() const const
bool isEmpty() const const
void reserve(int size)
void squeeze()
T value(int i) const const