mirror of
https://github.com/matrix-construct/construct
synced 2024-11-26 00:32:35 +01:00
ircd:Ⓜ️ Implement 14.18 Room Tagging.
This commit is contained in:
parent
9e884b326d
commit
1f82b884ff
8 changed files with 777 additions and 9 deletions
|
@ -30,6 +30,7 @@ struct ircd::m::user
|
|||
struct profile;
|
||||
struct account_data;
|
||||
struct room_account_data;
|
||||
struct room_tags;
|
||||
struct filter;
|
||||
|
||||
using id = m::id::user;
|
||||
|
@ -252,6 +253,44 @@ struct ircd::m::user::room_account_data
|
|||
{}
|
||||
};
|
||||
|
||||
struct ircd::m::user::room_tags
|
||||
{
|
||||
using closure_bool = std::function<bool (const string_view &key, const json::object &)>;
|
||||
using closure = std::function<void (const string_view &key, const json::object &)>;
|
||||
|
||||
static constexpr const string_view &type_prefix
|
||||
{
|
||||
"ircd.room_tag"
|
||||
};
|
||||
|
||||
static constexpr const size_t &typebuf_size
|
||||
{
|
||||
m::room::id::MAX_SIZE + size(type_prefix)
|
||||
};
|
||||
|
||||
m::user user;
|
||||
m::room room;
|
||||
|
||||
static string_view _type(const mutable_buffer &out, const m::room::id &);
|
||||
static bool for_each(const m::user &, const m::room &, const closure_bool &);
|
||||
static bool get(std::nothrow_t, const m::user &, const m::room &, const string_view &type, const closure &);
|
||||
static event::id::buf set(const m::user &, const m::room &, const string_view &type, const json::object &value);
|
||||
static bool del(const m::user &, const m::room &, const string_view &type);
|
||||
|
||||
public:
|
||||
bool for_each(const closure_bool &) const;
|
||||
bool get(std::nothrow_t, const string_view &type, const closure &) const;
|
||||
void get(const string_view &type, const closure &) const;
|
||||
json::object get(const mutable_buffer &out, const string_view &type) const; //nothrow
|
||||
event::id::buf set(const string_view &type, const json::object &value) const;
|
||||
bool del(const string_view &type) const;
|
||||
|
||||
room_tags(const m::user &user, const m::room &room)
|
||||
:user{user}
|
||||
,room{room}
|
||||
{}
|
||||
};
|
||||
|
||||
struct ircd::m::user::filter
|
||||
{
|
||||
using closure_bool = std::function<bool (const string_view &, const json::object &)>;
|
||||
|
|
142
ircd/m.cc
142
ircd/m.cc
|
@ -3377,6 +3377,148 @@ ircd::m::user::room_account_data::_type(const mutable_buffer &out,
|
|||
return function(out, room_id);
|
||||
}
|
||||
|
||||
//
|
||||
// user::room_tags
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::del(const string_view &type)
|
||||
const
|
||||
{
|
||||
return del(user, room, type);
|
||||
}
|
||||
|
||||
ircd::m::event::id::buf
|
||||
ircd::m::user::room_tags::set(const string_view &type,
|
||||
const json::object &val)
|
||||
const
|
||||
{
|
||||
return set(user, room, type, val);
|
||||
}
|
||||
|
||||
ircd::json::object
|
||||
ircd::m::user::room_tags::get(const mutable_buffer &out,
|
||||
const string_view &type)
|
||||
const
|
||||
{
|
||||
json::object ret;
|
||||
get(std::nothrow, type, [&out, &ret]
|
||||
(const string_view &type, const json::object &val)
|
||||
{
|
||||
ret = string_view { data(out), copy(out, val) };
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::user::room_tags::get(const string_view &type,
|
||||
const closure &closure)
|
||||
const
|
||||
{
|
||||
if(!get(std::nothrow, user, room, type, closure))
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"account data type '%s' for user %s in room %s not found",
|
||||
type,
|
||||
string_view{user.user_id},
|
||||
string_view{room.room_id}
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::get(std::nothrow_t,
|
||||
const string_view &type,
|
||||
const closure &closure)
|
||||
const
|
||||
{
|
||||
return get(std::nothrow, user, room, type, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::for_each(const closure_bool &closure)
|
||||
const
|
||||
{
|
||||
return for_each(user, room, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::del(const m::user &u,
|
||||
const m::room &r,
|
||||
const string_view &t)
|
||||
{
|
||||
using prototype = bool (const m::user &, const m::room &, const string_view &);
|
||||
|
||||
static mods::import<prototype> function
|
||||
{
|
||||
"client_user", "ircd::m::user::room_tags::del"
|
||||
};
|
||||
|
||||
return function(u, r, t);
|
||||
}
|
||||
|
||||
ircd::m::event::id::buf
|
||||
ircd::m::user::room_tags::set(const m::user &u,
|
||||
const m::room &r,
|
||||
const string_view &t,
|
||||
const json::object &v)
|
||||
{
|
||||
using prototype = event::id::buf (const m::user &, const m::room &, const string_view &, const json::object &);
|
||||
|
||||
static mods::import<prototype> function
|
||||
{
|
||||
"client_user", "ircd::m::user::room_tags::set"
|
||||
};
|
||||
|
||||
return function(u, r, t, v);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::get(std::nothrow_t,
|
||||
const m::user &u,
|
||||
const m::room &r,
|
||||
const string_view &t,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (std::nothrow_t, const m::user &, const m::room &, const string_view &, const closure &);
|
||||
|
||||
static mods::import<prototype> function
|
||||
{
|
||||
"client_user", "ircd::m::user::room_tags::get"
|
||||
};
|
||||
|
||||
return function(std::nothrow, u, r, t, c);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::user::room_tags::for_each(const m::user &u,
|
||||
const m::room &r,
|
||||
const closure_bool &c)
|
||||
{
|
||||
using prototype = bool (const m::user &, const m::room &, const closure_bool &);
|
||||
|
||||
static mods::import<prototype> function
|
||||
{
|
||||
"client_user", "ircd::m::user::room_tags::for_each"
|
||||
};
|
||||
|
||||
return function(u, r, c);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::user::room_tags::_type(const mutable_buffer &out,
|
||||
const m::room::id &room_id)
|
||||
{
|
||||
using prototype = string_view (const mutable_buffer &, const m::room::id &);
|
||||
|
||||
static mods::import<prototype> function
|
||||
{
|
||||
"client_user", "ircd::m::user::room_tags::_type"
|
||||
};
|
||||
|
||||
return function(out, room_id);
|
||||
}
|
||||
|
||||
//
|
||||
// user::filter
|
||||
//
|
||||
|
|
|
@ -131,6 +131,46 @@ get__initialsync_local(client &client,
|
|||
|
||||
return true;
|
||||
});
|
||||
|
||||
const m::user::room_tags room_tags
|
||||
{
|
||||
user, room
|
||||
};
|
||||
|
||||
json::stack::object tag
|
||||
{
|
||||
account_data
|
||||
};
|
||||
|
||||
json::stack::member
|
||||
{
|
||||
tag, "type", "m.tag"
|
||||
};
|
||||
|
||||
json::stack::object tag_content
|
||||
{
|
||||
tag, "content"
|
||||
};
|
||||
|
||||
json::stack::object tags
|
||||
{
|
||||
tag_content, "tags"
|
||||
};
|
||||
|
||||
room_tags.for_each([&tags]
|
||||
(const string_view &type, const json::object &content)
|
||||
{
|
||||
json::stack::member
|
||||
{
|
||||
tags, type, content
|
||||
};
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
tags.~object();
|
||||
tag_content.~object();
|
||||
tag.~object();
|
||||
account_data.~array();
|
||||
|
||||
json::stack::array state
|
||||
|
|
|
@ -16,9 +16,13 @@ IRCD_MODULE
|
|||
|
||||
namespace ircd::m::sync
|
||||
{
|
||||
static bool room_account_data_polylog_tags(data &);
|
||||
static bool room_account_data_polylog_events_event(data &, const m::event &);
|
||||
static bool room_account_data_polylog_events(data &);
|
||||
static bool room_account_data_polylog(data &);
|
||||
|
||||
static bool room_account_data_linear_tags(data &, const m::event &);
|
||||
static bool room_account_data_linear_events(data &, const m::event &);
|
||||
static bool room_account_data_linear(data &);
|
||||
|
||||
extern item room_account_data;
|
||||
|
@ -42,37 +46,97 @@ ircd::m::sync::room_account_data_linear(data &data)
|
|||
if(json::get<"room_id"_>(event) != data.user_room.room_id)
|
||||
return false;
|
||||
|
||||
char typebuf[m::user::room_account_data::typebuf_size];
|
||||
if(room_account_data_linear_events(data, event))
|
||||
return true;
|
||||
|
||||
if(room_account_data_linear_tags(data, event))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_linear_events(data &data,
|
||||
const m::event &event)
|
||||
{
|
||||
if(!json::get<"state_key"_>(event))
|
||||
return false;
|
||||
|
||||
const auto type
|
||||
{
|
||||
m::user::room_account_data::_type(typebuf, data.room->room_id)
|
||||
split(json::get<"type"_>(event), '!')
|
||||
};
|
||||
|
||||
if(json::get<"type"_>(event) != type)
|
||||
if(type.first != "ircd.account_data")
|
||||
return false;
|
||||
|
||||
const m::room room
|
||||
{
|
||||
lstrip(json::get<"type"_>(event), type.first)
|
||||
};
|
||||
|
||||
json::stack::array array
|
||||
{
|
||||
*data.out, "events"
|
||||
};
|
||||
|
||||
const scope_restore room_{data.room, &room};
|
||||
return room_account_data_polylog_events_event(data, event);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_linear_tags(data &data,
|
||||
const m::event &event)
|
||||
{
|
||||
if(!json::get<"state_key"_>(event))
|
||||
return false;
|
||||
|
||||
const auto type
|
||||
{
|
||||
split(json::get<"type"_>(event), '!')
|
||||
};
|
||||
|
||||
if(type.first != "ircd.room_tag")
|
||||
return false;
|
||||
|
||||
const m::room room
|
||||
{
|
||||
lstrip(json::get<"type"_>(event), type.first)
|
||||
};
|
||||
|
||||
json::stack::array array
|
||||
{
|
||||
*data.out, "events"
|
||||
};
|
||||
|
||||
// Due to room tags being "all one event" we have to iterate all of the
|
||||
// tags for this room for this user polylog style. This is because the
|
||||
// merge algorithm for linear /sync isn't sophisticated enough to see
|
||||
// past the events[] array and know to combine all of room tags into
|
||||
// the required format. The event_idx is hacked to 0 here to trick the
|
||||
// polylog apropos() into composing all tags unconditionally.
|
||||
const scope_restore range{data.range.first, 0UL};
|
||||
const scope_restore room_{data.room, &room};
|
||||
return room_account_data_polylog_tags(data);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_polylog(data &data)
|
||||
{
|
||||
return room_account_data_polylog_events(data);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_polylog_events(data &data)
|
||||
{
|
||||
json::stack::array array
|
||||
{
|
||||
*data.out, "events"
|
||||
};
|
||||
|
||||
bool ret{false};
|
||||
ret |= room_account_data_polylog_events(data);
|
||||
ret |= room_account_data_polylog_tags(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_polylog_events(data &data)
|
||||
{
|
||||
assert(data.room);
|
||||
char typebuf[m::user::room_account_data::typebuf_size];
|
||||
const auto type
|
||||
|
@ -127,3 +191,72 @@ ircd::m::sync::room_account_data_polylog_events_event(data &data,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::room_account_data_polylog_tags(data &data)
|
||||
{
|
||||
json::stack::checkpoint checkpoint
|
||||
{
|
||||
*data.out
|
||||
};
|
||||
|
||||
json::stack::object object
|
||||
{
|
||||
*data.out
|
||||
};
|
||||
|
||||
json::stack::member
|
||||
{
|
||||
object, "type", "m.tag"
|
||||
};
|
||||
|
||||
json::stack::object content
|
||||
{
|
||||
object, "content"
|
||||
};
|
||||
|
||||
json::stack::object tags
|
||||
{
|
||||
content, "tags"
|
||||
};
|
||||
|
||||
assert(data.room);
|
||||
char typebuf[m::user::room_tags::typebuf_size];
|
||||
const auto type
|
||||
{
|
||||
m::user::room_tags::_type(typebuf, data.room->room_id)
|
||||
};
|
||||
|
||||
bool ret{false};
|
||||
data.user_state.for_each(type, [&data, &tags, &ret]
|
||||
(const m::event::idx &event_idx)
|
||||
{
|
||||
if(!apropos(data, event_idx))
|
||||
return;
|
||||
|
||||
static const event::fetch::opts fopts
|
||||
{
|
||||
event::keys::include {"state_key", "content"}
|
||||
};
|
||||
|
||||
const m::event::fetch event
|
||||
{
|
||||
event_idx, std::nothrow, fopts
|
||||
};
|
||||
|
||||
if(!event.valid)
|
||||
return;
|
||||
|
||||
json::stack::member tag
|
||||
{
|
||||
tags, json::get<"state_key"_>(event), json::get<"content"_>(event)
|
||||
};
|
||||
|
||||
ret = true;
|
||||
});
|
||||
|
||||
if(!ret)
|
||||
checkpoint.rollback();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,24 @@
|
|||
|
||||
using namespace ircd;
|
||||
|
||||
static resource::response
|
||||
put__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room_id);
|
||||
|
||||
static resource::response
|
||||
get__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room);
|
||||
|
||||
static resource::response
|
||||
delete__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room);
|
||||
|
||||
static resource::response
|
||||
put__account_data(client &client,
|
||||
const resource::request &request,
|
||||
|
@ -54,6 +72,9 @@ put__rooms(client &client,
|
|||
if(cmd == "account_data")
|
||||
return put__account_data(client, request, user_id, room_id);
|
||||
|
||||
if(cmd == "tags")
|
||||
return put__tags(client, request, user_id, room_id);
|
||||
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"/user/rooms/ command not found"
|
||||
|
@ -90,12 +111,302 @@ get__rooms(client &client,
|
|||
if(cmd == "account_data")
|
||||
return get__account_data(client, request, user_id, room_id);
|
||||
|
||||
if(cmd == "tags")
|
||||
return get__tags(client, request, user_id, room_id);
|
||||
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"/user/rooms/ command not found"
|
||||
};
|
||||
}
|
||||
|
||||
resource::response
|
||||
delete__rooms(client &client,
|
||||
const resource::request &request,
|
||||
const m::user::id &user_id)
|
||||
{
|
||||
if(request.parv.size() < 3)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"room_id required"
|
||||
};
|
||||
|
||||
m::room::id::buf room_id
|
||||
{
|
||||
url::decode(room_id, request.parv[2])
|
||||
};
|
||||
|
||||
if(request.parv.size() < 4)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"rooms command required"
|
||||
};
|
||||
|
||||
const string_view &cmd
|
||||
{
|
||||
request.parv[3]
|
||||
};
|
||||
|
||||
if(cmd == "tags")
|
||||
return delete__tags(client, request, user_id, room_id);
|
||||
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"/user/rooms/ command not found"
|
||||
};
|
||||
}
|
||||
|
||||
resource::response
|
||||
put__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room)
|
||||
{
|
||||
if(request.parv.size() < 5)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"tag path parameter required"
|
||||
};
|
||||
|
||||
char tagbuf[m::event::TYPE_MAX_SIZE];
|
||||
const auto &tag
|
||||
{
|
||||
url::decode(tagbuf, request.parv[4])
|
||||
};
|
||||
|
||||
const json::object &value
|
||||
{
|
||||
request
|
||||
};
|
||||
|
||||
const m::user::room_tags room_tags
|
||||
{
|
||||
user, room
|
||||
};
|
||||
|
||||
room_tags.set(tag, value);
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, http::OK
|
||||
};
|
||||
}
|
||||
|
||||
resource::response
|
||||
get__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room)
|
||||
{
|
||||
const m::user::room_tags room_tags
|
||||
{
|
||||
user, room
|
||||
};
|
||||
|
||||
resource::response::chunked response
|
||||
{
|
||||
client, http::OK
|
||||
};
|
||||
|
||||
json::stack out
|
||||
{
|
||||
response.buf, response.flusher()
|
||||
};
|
||||
|
||||
json::stack::object top{out};
|
||||
json::stack::object tags
|
||||
{
|
||||
top, "tags"
|
||||
};
|
||||
|
||||
room_tags.for_each([&tags]
|
||||
(const string_view &type, const json::object &content)
|
||||
{
|
||||
json::stack::member
|
||||
{
|
||||
tags, type, content
|
||||
};
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
resource::response
|
||||
delete__tags(client &client,
|
||||
const resource::request &request,
|
||||
const m::user &user,
|
||||
const m::room &room)
|
||||
{
|
||||
|
||||
if(request.parv.size() < 5)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"tag path parameter required"
|
||||
};
|
||||
|
||||
char tagbuf[m::event::TYPE_MAX_SIZE];
|
||||
const auto &tag
|
||||
{
|
||||
url::decode(tagbuf, request.parv[4])
|
||||
};
|
||||
|
||||
const m::user::room_tags room_tags
|
||||
{
|
||||
user, room
|
||||
};
|
||||
|
||||
const bool deleted
|
||||
{
|
||||
room_tags.del(tag)
|
||||
};
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, deleted? http::OK : http::NOT_FOUND
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::user::room_tags::del(const m::user &user,
|
||||
const m::room &room,
|
||||
const string_view &user_type)
|
||||
{
|
||||
char typebuf[typebuf_size];
|
||||
const string_view type
|
||||
{
|
||||
_type(typebuf, room.room_id)
|
||||
};
|
||||
|
||||
const user::room user_room
|
||||
{
|
||||
user
|
||||
};
|
||||
|
||||
const auto event_idx
|
||||
{
|
||||
user_room.get(std::nothrow, type, user_type)
|
||||
};
|
||||
|
||||
if(!event_idx)
|
||||
return false;
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(event_idx)
|
||||
};
|
||||
|
||||
redact(user_room, user, event_id, "deleted");
|
||||
return true;
|
||||
}
|
||||
|
||||
m::event::id::buf
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::user::room_tags::set(const m::user &user,
|
||||
const m::room &room,
|
||||
const string_view &user_type,
|
||||
const json::object &value)
|
||||
{
|
||||
char typebuf[typebuf_size];
|
||||
const string_view type
|
||||
{
|
||||
_type(typebuf, room.room_id)
|
||||
};
|
||||
|
||||
const user::room user_room
|
||||
{
|
||||
user
|
||||
};
|
||||
|
||||
return send(user_room, user, type, user_type, value);
|
||||
}
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::user::room_tags::get(std::nothrow_t,
|
||||
const m::user &user,
|
||||
const m::room &room,
|
||||
const string_view &user_type,
|
||||
const closure &closure)
|
||||
{
|
||||
char typebuf[typebuf_size];
|
||||
const string_view type
|
||||
{
|
||||
_type(typebuf, room.room_id)
|
||||
};
|
||||
|
||||
const user::room user_room
|
||||
{
|
||||
user
|
||||
};
|
||||
|
||||
const event::idx event_idx
|
||||
{
|
||||
user_room.get(std::nothrow, type, user_type)
|
||||
};
|
||||
|
||||
return event_idx && m::get(std::nothrow, event_idx, "content", [&user_type, &closure]
|
||||
(const json::object &content)
|
||||
{
|
||||
closure(user_type, content);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::user::room_tags::for_each(const m::user &user,
|
||||
const m::room &room,
|
||||
const closure_bool &closure)
|
||||
{
|
||||
char typebuf[typebuf_size];
|
||||
const string_view type
|
||||
{
|
||||
_type(typebuf, room.room_id)
|
||||
};
|
||||
|
||||
static const event::fetch::opts fopts
|
||||
{
|
||||
event::keys::include {"state_key", "content"}
|
||||
};
|
||||
|
||||
const user::room user_room{user};
|
||||
const room::state state
|
||||
{
|
||||
user_room, &fopts
|
||||
};
|
||||
|
||||
return state.for_each(type, event::closure_bool{[&closure]
|
||||
(const m::event &event)
|
||||
{
|
||||
const auto &user_type
|
||||
{
|
||||
at<"state_key"_>(event)
|
||||
};
|
||||
|
||||
const auto &content
|
||||
{
|
||||
json::get<"content"_>(event)
|
||||
};
|
||||
|
||||
return closure(user_type, content);
|
||||
}});
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::user::room_tags::_type(const mutable_buffer &out,
|
||||
const m::room::id &room_id)
|
||||
{
|
||||
assert(size(out) >= typebuf_size);
|
||||
|
||||
string_view ret;
|
||||
ret = strlcpy(out, type_prefix);
|
||||
ret = strlcat(out, room_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
resource::response
|
||||
put__account_data(client &client,
|
||||
const resource::request &request,
|
||||
|
|
|
@ -174,3 +174,52 @@ put_method
|
|||
put_method.REQUIRES_AUTH
|
||||
}
|
||||
};
|
||||
|
||||
resource::response
|
||||
delete_user(client &client, const resource::request &request)
|
||||
{
|
||||
if(request.parv.size() < 1)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"user_id required"
|
||||
};
|
||||
|
||||
m::user::id::buf user_id
|
||||
{
|
||||
url::decode(user_id, request.parv[0])
|
||||
};
|
||||
|
||||
if(request.user_id != user_id)
|
||||
throw m::UNSUPPORTED
|
||||
{
|
||||
"Deleting user data as someone else is not yet supported"
|
||||
};
|
||||
|
||||
if(request.parv.size() < 2)
|
||||
throw m::NEED_MORE_PARAMS
|
||||
{
|
||||
"user command required"
|
||||
};
|
||||
|
||||
const string_view &cmd
|
||||
{
|
||||
request.parv[1]
|
||||
};
|
||||
|
||||
if(cmd == "rooms")
|
||||
return delete__rooms(client, request, user_id);
|
||||
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"/user command not found"
|
||||
};
|
||||
}
|
||||
|
||||
resource::method
|
||||
delete_method
|
||||
{
|
||||
user_resource, "DELETE", delete_user,
|
||||
{
|
||||
delete_method.REQUIRES_AUTH
|
||||
}
|
||||
};
|
||||
|
|
|
@ -64,3 +64,8 @@ ircd::resource::response
|
|||
put__rooms(ircd::client &client,
|
||||
const ircd::resource::request &request,
|
||||
const ircd::m::user::id &user_id);
|
||||
|
||||
ircd::resource::response
|
||||
delete__rooms(ircd::client &client,
|
||||
const ircd::resource::request &request,
|
||||
const ircd::m::user::id &user_id);
|
||||
|
|
|
@ -9200,6 +9200,55 @@ console_cmd__user__room_account_data(opt &out, const string_view &line)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__room_tags(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"user_id", "room_id", "tag"
|
||||
}};
|
||||
|
||||
const m::user::id &user_id
|
||||
{
|
||||
param.at("user_id")
|
||||
};
|
||||
|
||||
const auto &room_id
|
||||
{
|
||||
m::room_id(param.at("room_id"))
|
||||
};
|
||||
|
||||
const string_view &tag
|
||||
{
|
||||
param["tag"]
|
||||
};
|
||||
|
||||
const m::user::room_tags room_tags
|
||||
{
|
||||
user_id, room_id
|
||||
};
|
||||
|
||||
if(tag)
|
||||
{
|
||||
room_tags.get(tag, [&out]
|
||||
(const string_view &key, const json::object &val)
|
||||
{
|
||||
out << val << std::endl;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
room_tags.for_each([&out]
|
||||
(const string_view &key, const json::object &val)
|
||||
{
|
||||
out << key << ": " << val << std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__devices(opt &out, const string_view &line)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue