1#include "mtx/requests.hpp"
2#include "mtx/events/collections.hpp"
3#include "mtx/events/encrypted.hpp"
4
5#include <nlohmann/json.hpp>
6
7using json = nlohmann::json;
8using namespace mtx::events::collections;
9
10namespace mtx {
11namespace requests {
12
13std::string
14presetToString(Preset preset)
15{
16 switch (preset) {
17 case Preset::PrivateChat:
18 return "private_chat";
19 break;
20 case Preset::PublicChat:
21 return "public_chat";
22 break;
23 case Preset::TrustedPrivateChat:
24 return "trusted_private_chat";
25 break;
26 }
27
28 return "private_chat";
29}
30
31void
32to_json(json &obj, const CreateRoom &request)
33{
34 if (!request.name.empty())
35 obj["name"] = request.name;
36
37 if (!request.topic.empty())
38 obj["topic"] = request.topic;
39
40 if (!request.room_alias_name.empty())
41 obj["room_alias_name"] = request.room_alias_name;
42
43 if (request.invite.size() != 0)
44 obj["invite"] = request.invite;
45
46 obj["is_direct"] = request.is_direct;
47 obj["preset"] = presetToString(preset: request.preset);
48 obj["visibility"] = visibilityToString(visibility: request.visibility);
49
50 if (!request.room_version.empty())
51 obj["room_version"] = request.room_version;
52
53 if (request.creation_content)
54 obj["creation_content"] = *request.creation_content;
55
56 if (!request.initial_state.empty()) {
57 auto arr = nlohmann::json::array();
58 for (const auto &ev : request.initial_state) {
59 auto event_json = std::visit(visitor: [](auto e) { return json(e); }, variants: ev);
60 event_json.erase(key: "sender");
61 arr.push_back(val: std::move(event_json));
62 }
63 obj["initial_state"] = std::move(arr);
64 }
65}
66
67void
68to_json(json &obj, const Login &request)
69{
70 if (!request.token.empty())
71 obj["token"] = request.token;
72
73 if (!request.password.empty())
74 obj["password"] = request.password;
75
76 if (!request.device_id.empty())
77 obj["device_id"] = request.device_id;
78
79 if (!request.initial_device_display_name.empty())
80 obj["initial_device_display_name"] = request.initial_device_display_name;
81
82 std::visit(
83 visitor: [&obj](const auto &id) {
84 if constexpr (std::is_same_v<const login_identifier::User &, decltype(id)>) {
85 obj["identifier"]["type"] = "m.id.user";
86 obj["identifier"]["user"] = id.user;
87 } else if constexpr (std::is_same_v<const login_identifier::Thirdparty &, decltype(id)>) {
88 obj["identifier"]["type"] = "m.id.thirdparty";
89 obj["identifier"]["medium"] = id.medium;
90 obj["identifier"]["address"] = id.address;
91 } else if constexpr (std::is_same_v<const login_identifier::PhoneNumber &,
92 decltype(id)>) {
93 obj["identifier"]["type"] = "m.id.phone";
94 obj["identifier"]["country"] = id.country;
95 obj["identifier"]["phone"] = id.phone;
96 }
97 },
98 variants: request.identifier);
99
100 obj["type"] = request.type;
101}
102
103void
104to_json(json &obj, const RequestEmailToken &request)
105{
106 obj["client_secret"] = request.client_secret;
107 obj["email"] = request.email;
108 obj["send_attempt"] = request.send_attempt;
109}
110
111void
112to_json(json &obj, const RequestMSISDNToken &request)
113{
114 obj["client_secret"] = request.client_secret;
115 obj["country"] = request.country;
116 obj["phone_number"] = request.phone_number;
117 obj["send_attempt"] = request.send_attempt;
118}
119
120void
121to_json(json &obj, const IdentitySubmitToken &request)
122{
123 obj["sid"] = request.sid;
124 obj["client_secret"] = request.client_secret;
125 obj["token"] = request.token;
126}
127
128void
129to_json(json &obj, const AvatarUrl &request)
130{
131 obj["avatar_url"] = request.avatar_url;
132}
133
134void
135to_json(json &obj, const DisplayName &request)
136{
137 obj["displayname"] = request.displayname;
138}
139
140void
141to_json(json &obj, const RoomMembershipChange &request)
142{
143 obj["user_id"] = request.user_id;
144
145 if (!request.reason.empty())
146 obj["reason"] = request.reason;
147}
148
149void
150to_json(json &obj, const TypingNotification &request)
151{
152 obj["typing"] = request.typing;
153 obj["timeout"] = request.timeout;
154}
155
156void
157to_json(json &obj, const PublicRoomVisibility &request)
158{
159 obj["visibility"] = mtx::common::visibilityToString(visibility: request.visibility);
160}
161
162void
163to_json(json &obj, const PublicRoomsFilter &request)
164{
165 obj["generic_search_term"] = request.generic_search_term;
166}
167
168void
169to_json(json &obj, const PublicRooms &request)
170{
171 if (request.limit > 0) {
172 obj["limit"] = request.limit;
173 }
174
175 if (!request.since.empty()) {
176 obj["since"] = request.since;
177 }
178
179 if (!request.filter.generic_search_term.empty()) {
180 obj["filter"] = request.filter;
181 }
182
183 // Based on the spec, third_party_instance_id can only be used if
184 // include_all_networks is false. A case where the latter is true and
185 // the former is set is invalid.
186 if (request.include_all_networks && !request.third_party_instance_id.empty()) {
187 throw std::invalid_argument(
188 "third_party_instance_id can only be set if include_all_networks is false");
189 } else if (!request.third_party_instance_id.empty()) {
190 obj["third_party_instance_id"] = request.third_party_instance_id;
191 obj["include_all_networks"] = false;
192 } else {
193 obj["include_all_networks"] = true;
194 }
195}
196
197void
198to_json(json &obj, const DeviceUpdate &request)
199{
200 obj["display_name"] = request.display_name;
201}
202
203void
204to_json(json &obj, const SignedOneTimeKey &request)
205{
206 if (request.fallback)
207 obj["fallback"] = true;
208 obj["key"] = request.key;
209 obj["signatures"] = request.signatures;
210}
211
212void
213to_json(json &obj, const UploadKeys &request)
214{
215 obj = json::object();
216
217 if (!request.device_keys.user_id.empty())
218 obj["device_keys"] = request.device_keys;
219
220 for (const auto &[key_id, key] : request.one_time_keys) {
221 obj["one_time_keys"][key_id] = std::visit(visitor: [](const auto &e) { return json(e); }, variants: key);
222 }
223
224 for (const auto &[key_id, key] : request.fallback_keys) {
225 obj["fallback_keys"][key_id] = std::visit(visitor: [](const auto &e) { return json(e); }, variants: key);
226 }
227}
228
229void
230to_json(json &obj, const ClaimKeys &request)
231{
232 obj["timeout"] = request.timeout;
233 obj["one_time_keys"] = request.one_time_keys;
234}
235
236void
237to_json(json &obj, const QueryKeys &request)
238{
239 obj["timeout"] = request.timeout;
240 obj["device_keys"] = request.device_keys;
241 obj["token"] = request.token;
242}
243
244void
245to_json(json &obj, const KeySignaturesUpload &req)
246{
247 for (const auto &[user_id, idToKey] : req.signatures)
248 for (const auto &[key_id, keyVar] : idToKey)
249 obj[user_id][key_id] = std::visit(visitor: [](const auto &e) { return json(e); }, variants: keyVar);
250}
251
252void
253to_json(json &obj, const DeviceSigningUpload &req)
254{
255 if (req.master_key)
256 obj["master_key"] = req.master_key.value();
257 if (req.self_signing_key)
258 obj["self_signing_key"] = req.self_signing_key.value();
259 if (req.user_signing_key)
260 obj["user_signing_key"] = req.user_signing_key.value();
261}
262
263void
264to_json(json &obj, const PusherData &data)
265{
266 if (!data.url.empty()) {
267 obj["url"] = data.url;
268 }
269 if (!data.format.empty()) {
270 obj["format"] = data.format;
271 }
272}
273
274void
275to_json(json &obj, const SetPusher &req)
276{
277 obj["pushkey"] = req.pushkey;
278 obj["kind"] = req.kind;
279 obj["app_id"] = req.app_id;
280 obj["app_display_name"] = req.app_display_name;
281 obj["device_display_name"] = req.device_display_name;
282 if (!req.profile_tag.empty()) {
283 obj["profile_tag"] = req.profile_tag;
284 }
285 obj["lang"] = req.lang;
286 obj["data"] = req.data;
287 obj["append"] = req.append;
288}
289
290} // namespace requests
291} // namespace mtx
292