cutelyst  5.0.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
urifor.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2017-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "urifor.h"
6 
7 #include <Context>
8 #include <Cutelyst/Context>
9 #include <Cutelyst/ParamsMultiMap>
10 #include <cutelee/exception.h>
11 #include <cutelee/parser.h>
12 
13 #include <QDebug>
14 
15 using namespace Qt::StringLiterals;
16 
17 UriFor::UriFor(const QString &path, const QStringList &args, Cutelee::Parser *parser)
18  : Cutelee::Node(parser)
19  , m_path(path, parser)
20 {
21  bool foundQuery = false;
22  for (const QString &expression : args) {
23  // WE require the QUERY keyword to know when we are dealing with query values
24  if (expression.compare(u"QUERY") == 0) {
25  foundQuery = true;
26  continue;
27  }
28 
29  if (foundQuery) {
30  m_queryExpressions.push_back(Cutelee::FilterExpression(expression, parser));
31  } else {
32  m_argsExpressions.push_back(Cutelee::FilterExpression(expression, parser));
33  }
34  }
35  std::reverse(m_queryExpressions.begin(), m_queryExpressions.end());
36 }
37 
38 std::pair<QString, QString> splitQuery(const QString &query)
39 {
40  std::pair<QString, QString> ret;
41 
42  ret.first = query.section(u'=', 0, 0);
43  ret.second = query.section(u'=', 1);
44 
45  return ret;
46 }
47 
48 void UriFor::render(Cutelee::OutputStream *stream, Cutelee::Context *gc) const
49 {
50  // In case cutelyst context is not set as "c"
51  auto c = gc->lookup(m_cutelystContext).value<Cutelyst::Context *>();
52  if (!c) {
53  const QVariantHash hash = gc->stackHash(0);
54  for (const auto &[key, value] : hash.asKeyValueRange()) {
55  if (value.userType() == qMetaTypeId<Cutelyst::Context *>()) {
56  c = value.value<Cutelyst::Context *>();
57  if (c) {
58  m_cutelystContext = key;
59  break;
60  }
61  }
62  }
63 
64  if (!c) {
65  return;
66  }
67  }
68 
69  QString path;
70  QStringList args;
71  Cutelyst::ParamsMultiMap queryValues;
72 
73  QVariant pathVar = m_path.resolve(gc);
74  if (pathVar.userType() == qMetaTypeId<Cutelee::SafeString>()) {
75  path = pathVar.value<Cutelee::SafeString>().get();
76  } else if (pathVar.typeId() == QMetaType::QString) {
77  path = pathVar.toString();
78  } else {
79  qWarning() << "c_uri_for PATH is not a valid type";
80  return;
81  }
82 
83  for (const Cutelee::FilterExpression &exp : m_argsExpressions) {
84  QVariant var = exp.resolve(gc);
85  if (var.userType() == qMetaTypeId<Cutelee::SafeString>()) {
86  args << var.value<Cutelee::SafeString>().get();
87  } else if (var.typeId() == QMetaType::QString) {
88  args << var.toString();
89  } else if (var.typeId() == QMetaType::QStringList) {
90  args << var.toStringList();
91  }
92  }
93 
94  for (const Cutelee::FilterExpression &exp : m_queryExpressions) {
95  QVariant var = exp.resolve(gc);
96  if (var.userType() == qMetaTypeId<Cutelyst::ParamsMultiMap>()) {
97  auto map = var.value<Cutelyst::ParamsMultiMap>();
98  queryValues.unite(map);
99  } else if (var.userType() == qMetaTypeId<Cutelee::SafeString>()) {
100  auto query = splitQuery(var.value<Cutelee::SafeString>().get());
101  queryValues.insert(query.first, query.second);
102  } else if (var.typeId() == QMetaType::QString) {
103  auto query = splitQuery(var.toString());
104  queryValues.insert(query.first, query.second);
105  } else if (var.typeId() == QMetaType::QStringList) {
106  const auto queries = var.toStringList();
107  for (const QString &str : queries) {
108  auto query = splitQuery(str);
109  queryValues.insert(query.first, query.second);
110  }
111  }
112  }
113 
114  *stream << c->uriFor(path, args, queryValues).toString(QUrl::FullyEncoded);
115 }
116 
117 Cutelee::Node *UriForTag::getNode(const QString &tagContent, Cutelee::Parser *p) const
118 {
119  // You almost always want to use smartSplit.
120  QStringList parts = smartSplit(tagContent);
121 
122  parts.removeFirst(); // Not interested in the name of the tag.
123  if (parts.isEmpty()) {
124  throw Cutelee::Exception(Cutelee::TagSyntaxError,
125  u"c_uri_for requires at least the path"_s);
126  }
127 
128  return new UriFor(parts.first(), parts.mid(1), p);
129 }
130 
131 #include "moc_urifor.cpp"
FullyEncoded
void removeFirst()
T value() const const
The Cutelyst Context.
Definition: context.h:42
bool isEmpty() const const
iterator insert(const Key &key, const T &value)
T & first()
int userType() const const
int typeId() const const
QStringList toStringList() const const
QList< T > mid(qsizetype pos, qsizetype length) const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QString first(qsizetype n) const const
QString toString() const const
QMultiMap< Key, T > & unite(QMultiMap< Key, T > &&other)