mirror of
https://github.com/processone/ejabberd.git
synced 2024-10-13 15:16:49 +02:00
* src/web/ejabberd_web_admin.erl: Added hooks to allow plugins to
add their pages without modifying ejabberd_web_admin.erl (thanks to Badlop) * src/web/ejabberd_web_admin.hrl: Macro definitions moved here * src/mod_shared_roster.erl: Updated * src/mod_offline.erl: Likewise * src/mod_offline_odbc.erl: Likewise SVN Revision: 884
This commit is contained in:
parent
106cf7f963
commit
727a70c2cb
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2007-08-23 Alexey Shchepin <alexey@process-one.net>
|
||||
|
||||
* src/web/ejabberd_web_admin.erl: Added hooks to allow plugins to
|
||||
add their pages without modifying ejabberd_web_admin.erl (thanks
|
||||
to Badlop)
|
||||
* src/web/ejabberd_web_admin.hrl: Macro definitions moved here
|
||||
* src/mod_shared_roster.erl: Updated
|
||||
* src/mod_offline.erl: Likewise
|
||||
* src/mod_offline_odbc.erl: Likewise
|
||||
|
||||
2007-08-22 Alexey Shchepin <alexey@process-one.net>
|
||||
|
||||
* src/jlib.erl: Use http_base_64:decode if available
|
||||
|
@ -18,10 +18,14 @@
|
||||
pop_offline_messages/3,
|
||||
remove_expired_messages/0,
|
||||
remove_old_messages/1,
|
||||
remove_user/2]).
|
||||
remove_user/2,
|
||||
webadmin_page/3,
|
||||
webadmin_user/4]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("web/ejabberd_http.hrl").
|
||||
-include("web/ejabberd_web_admin.hrl").
|
||||
|
||||
-record(offline_msg, {us, timestamp, expire, from, to, packet}).
|
||||
|
||||
@ -42,6 +46,10 @@ start(Host, Opts) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:add(anonymous_purge_hook, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:add(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:add(webadmin_user, Host,
|
||||
?MODULE, webadmin_user, 50),
|
||||
MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity),
|
||||
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
spawn(?MODULE, init, [MaxOfflineMsgs])).
|
||||
@ -106,6 +114,10 @@ stop(Host) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:delete(webadmin_user, Host,
|
||||
?MODULE, webadmin_user, 50),
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
exit(whereis(Proc), stop),
|
||||
{wait, Proc}.
|
||||
@ -420,3 +432,107 @@ discard_warn_sender(Msgs) ->
|
||||
To,
|
||||
From, Err)
|
||||
end, Msgs).
|
||||
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = _US,
|
||||
path = ["user", U, "queue"],
|
||||
q = Query,
|
||||
lang = Lang} = _Request) ->
|
||||
Res = user_queue(U, Host, Query, Lang),
|
||||
{stop, Res};
|
||||
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
user_queue(User, Server, Query, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
Res = user_queue_parse_query(US, Query),
|
||||
Msgs = lists:keysort(#offline_msg.timestamp,
|
||||
mnesia:dirty_read({offline_msg, US})),
|
||||
FMsgs =
|
||||
lists:map(
|
||||
fun(#offline_msg{timestamp = TimeStamp, from = From, to = To,
|
||||
packet = {xmlelement, Name, Attrs, Els}} = Msg) ->
|
||||
ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))),
|
||||
{{Year, Month, Day}, {Hour, Minute, Second}} =
|
||||
calendar:now_to_local_time(TimeStamp),
|
||||
Time = lists:flatten(
|
||||
io_lib:format(
|
||||
"~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
|
||||
[Year, Month, Day, Hour, Minute, Second])),
|
||||
SFrom = jlib:jid_to_string(From),
|
||||
STo = jlib:jid_to_string(To),
|
||||
Attrs2 = jlib:replace_from_to_attrs(SFrom, STo, Attrs),
|
||||
Packet = {xmlelement, Name, Attrs2, Els},
|
||||
FPacket = ejabberd_web_admin:pretty_print_xml(Packet),
|
||||
?XE("tr",
|
||||
[?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]),
|
||||
?XAC("td", [{"class", "valign"}], Time),
|
||||
?XAC("td", [{"class", "valign"}], SFrom),
|
||||
?XAC("td", [{"class", "valign"}], STo),
|
||||
?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])]
|
||||
)
|
||||
end, Msgs),
|
||||
[?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"),
|
||||
[us_to_list(US)]))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[?XE("table",
|
||||
[?XE("thead",
|
||||
[?XE("tr",
|
||||
[?X("td"),
|
||||
?XCT("td", "Time"),
|
||||
?XCT("td", "From"),
|
||||
?XCT("td", "To"),
|
||||
?XCT("td", "Packet")
|
||||
])]),
|
||||
?XE("tbody",
|
||||
if
|
||||
FMsgs == [] ->
|
||||
[?XE("tr",
|
||||
[?XAC("td", [{"colspan", "4"}], " ")]
|
||||
)];
|
||||
true ->
|
||||
FMsgs
|
||||
end
|
||||
)]),
|
||||
?BR,
|
||||
?INPUTT("submit", "delete", "Delete Selected")
|
||||
])].
|
||||
|
||||
user_queue_parse_query(US, Query) ->
|
||||
case lists:keysearch("delete", 1, Query) of
|
||||
{value, _} ->
|
||||
Msgs = lists:keysort(#offline_msg.timestamp,
|
||||
mnesia:dirty_read({offline_msg, US})),
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
fun(Msg) ->
|
||||
ID = jlib:encode_base64(
|
||||
binary_to_list(term_to_binary(Msg))),
|
||||
case lists:member({"selected", ID}, Query) of
|
||||
true ->
|
||||
mnesia:delete_object(Msg);
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end, Msgs)
|
||||
end,
|
||||
mnesia:transaction(F),
|
||||
ok;
|
||||
false ->
|
||||
nothing
|
||||
end.
|
||||
|
||||
us_to_list({User, Server}) ->
|
||||
jlib:jid_to_string({User, Server, ""}).
|
||||
|
||||
webadmin_user(Acc, User, Server, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
QueueLen = length(mnesia:dirty_read({offline_msg, US})),
|
||||
FQueueLen = [?AC("queue/",
|
||||
integer_to_list(QueueLen))],
|
||||
Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen.
|
||||
|
@ -3,8 +3,8 @@
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose :
|
||||
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_offline_odbc).
|
||||
-author('alexey@sevcom.net').
|
||||
|
||||
@ -15,10 +15,14 @@
|
||||
stop/1,
|
||||
store_packet/3,
|
||||
pop_offline_messages/3,
|
||||
remove_user/2]).
|
||||
remove_user/2,
|
||||
webadmin_page/3,
|
||||
webadmin_user/4]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("web/ejabberd_http.hrl").
|
||||
-include("web/ejabberd_web_admin.hrl").
|
||||
|
||||
-record(offline_msg, {user, timestamp, expire, from, to, packet}).
|
||||
|
||||
@ -34,6 +38,10 @@ start(Host, _Opts) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:add(anonymous_purge_hook, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:add(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:add(webadmin_user, Host,
|
||||
?MODULE, webadmin_user, 50),
|
||||
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
spawn(?MODULE, init, [Host])).
|
||||
|
||||
@ -98,6 +106,10 @@ stop(Host) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(anonymous_purge_hook, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:delete(webadmin_user, Host,
|
||||
?MODULE, webadmin_user, 50),
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
exit(whereis(Proc), stop),
|
||||
ok.
|
||||
@ -180,20 +192,16 @@ find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||
find_x_expire(TimeStamp, [El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EXPIRE ->
|
||||
case xml:get_tag_attr_s("seconds", El) of
|
||||
Val ->
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
Val = xml:get_tag_attr_s("seconds", El),
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
@ -238,3 +246,139 @@ remove_user(User, Server) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
odbc_queries:del_spool_msg(LServer, Username).
|
||||
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = _US,
|
||||
path = ["user", U, "queue"],
|
||||
q = Query,
|
||||
lang = Lang} = _Request) ->
|
||||
Res = user_queue(U, Host, Query, Lang),
|
||||
{stop, Res};
|
||||
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
user_queue(User, Server, Query, Lang) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
US = {LUser, LServer},
|
||||
Res = user_queue_parse_query(Username, LServer, Query),
|
||||
Msgs = case catch ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select username, xml from spool"
|
||||
" where username='", Username, "'"
|
||||
" order by seq;"]) of
|
||||
{selected, ["username", "xml"], Rs} ->
|
||||
lists:flatmap(
|
||||
fun({_, XML}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
[El]
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
FMsgs =
|
||||
lists:map(
|
||||
fun({xmlelement, Name, Attrs, Els} = Msg) ->
|
||||
ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))),
|
||||
Packet = Msg,
|
||||
FPacket = ejabberd_web_admin:pretty_print_xml(Packet),
|
||||
?XE("tr",
|
||||
[?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]),
|
||||
?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])]
|
||||
)
|
||||
end, Msgs),
|
||||
[?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"),
|
||||
[us_to_list(US)]))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[?XE("table",
|
||||
[?XE("thead",
|
||||
[?XE("tr",
|
||||
[?X("td"),
|
||||
?XCT("td", "Packet")
|
||||
])]),
|
||||
?XE("tbody",
|
||||
if
|
||||
FMsgs == [] ->
|
||||
[?XE("tr",
|
||||
[?XAC("td", [{"colspan", "4"}], " ")]
|
||||
)];
|
||||
true ->
|
||||
FMsgs
|
||||
end
|
||||
)]),
|
||||
?BR,
|
||||
?INPUTT("submit", "delete", "Delete Selected")
|
||||
])].
|
||||
|
||||
user_queue_parse_query(Username, LServer, Query) ->
|
||||
case lists:keysearch("delete", 1, Query) of
|
||||
{value, _} ->
|
||||
Msgs = case catch ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select xml, seq from spool"
|
||||
" where username='", Username, "'"
|
||||
" order by seq;"]) of
|
||||
{selected, ["xml", "seq"], Rs} ->
|
||||
lists:flatmap(
|
||||
fun({XML, Seq}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
[{El, Seq}]
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
fun({Msg, Seq}) ->
|
||||
ID = jlib:encode_base64(
|
||||
binary_to_list(term_to_binary(Msg))),
|
||||
case lists:member({"selected", ID}, Query) of
|
||||
true ->
|
||||
SSeq = ejabberd_odbc:escape(Seq),
|
||||
catch ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from spool"
|
||||
" where username='", Username, "'"
|
||||
" and seq='", SSeq, "';"]);
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end, Msgs)
|
||||
end,
|
||||
mnesia:transaction(F),
|
||||
ok;
|
||||
false ->
|
||||
nothing
|
||||
end.
|
||||
|
||||
us_to_list({User, Server}) ->
|
||||
jlib:jid_to_string({User, Server, ""}).
|
||||
|
||||
webadmin_user(Acc, User, Server, Lang) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
QueueLen = case catch ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select count(*) from spool"
|
||||
" where username='", Username, "';"]) of
|
||||
{selected, [_], [{SCount}]} ->
|
||||
SCount;
|
||||
_ ->
|
||||
0
|
||||
end,
|
||||
FQueueLen = [?AC("queue/", QueueLen)],
|
||||
Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen.
|
||||
|
@ -12,6 +12,7 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1,
|
||||
webadmin_menu/2, webadmin_page/3,
|
||||
get_user_roster/2,
|
||||
get_subscription_lists/3,
|
||||
get_jid_info/4,
|
||||
@ -32,6 +33,8 @@
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
-include("web/ejabberd_http.hrl").
|
||||
-include("web/ejabberd_web_admin.hrl").
|
||||
|
||||
-record(sr_group, {group_host, opts}).
|
||||
-record(sr_user, {us, group_host}).
|
||||
@ -45,6 +48,10 @@ start(Host, _Opts) ->
|
||||
{type, bag},
|
||||
{attributes, record_info(fields, sr_user)}]),
|
||||
mnesia:add_table_index(sr_user, group_host),
|
||||
ejabberd_hooks:add(webadmin_menu_host, Host,
|
||||
?MODULE, webadmin_menu, 70),
|
||||
ejabberd_hooks:add(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:add(roster_get, Host,
|
||||
?MODULE, get_user_roster, 70),
|
||||
ejabberd_hooks:add(roster_in_subscription, Host,
|
||||
@ -61,6 +68,10 @@ start(Host, _Opts) ->
|
||||
% ?MODULE, remove_user, 50),
|
||||
|
||||
stop(Host) ->
|
||||
ejabberd_hooks:delete(webadmin_menu_host, Host,
|
||||
?MODULE, webadmin_menu, 70),
|
||||
ejabberd_hooks:delete(webadmin_page_host, Host,
|
||||
?MODULE, webadmin_page, 50),
|
||||
ejabberd_hooks:delete(roster_get, Host,
|
||||
?MODULE, get_user_roster, 70),
|
||||
ejabberd_hooks:delete(roster_in_subscription, Host,
|
||||
@ -352,3 +363,249 @@ remove_user_from_group(Host, US, Group) ->
|
||||
mnesia:delete_object(R)
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
|
||||
%%---------------------
|
||||
%% Web Admin
|
||||
%%---------------------
|
||||
|
||||
webadmin_menu(Acc, _Host) ->
|
||||
[{"shared-roster", "Shared Roster"} | Acc].
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = US,
|
||||
path = ["shared-roster"],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Res = list_shared_roster_groups(Host, Query, Lang),
|
||||
{stop, Res};
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = US,
|
||||
path = ["shared-roster", Group],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Res = shared_roster_group(Host, Group, Query, Lang),
|
||||
{stop, Res};
|
||||
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
list_shared_roster_groups(Host, Query, Lang) ->
|
||||
Res = list_sr_groups_parse_query(Host, Query),
|
||||
SRGroups = mod_shared_roster:list_groups(Host),
|
||||
FGroups =
|
||||
?XAE("table", [],
|
||||
[?XE("tbody",
|
||||
lists:map(
|
||||
fun(Group) ->
|
||||
?XE("tr",
|
||||
[?XE("td", [?INPUT("checkbox", "selected",
|
||||
Group)]),
|
||||
?XE("td", [?AC(Group ++ "/", Group)])
|
||||
]
|
||||
)
|
||||
end, lists:sort(SRGroups)) ++
|
||||
[?XE("tr",
|
||||
[?X("td"),
|
||||
?XE("td", [?INPUT("text", "namenew", "")]),
|
||||
?XE("td", [?INPUTT("submit", "addnew", "Add New")])
|
||||
]
|
||||
)]
|
||||
)]),
|
||||
[?XC("h1", ?T("Shared Roster Groups"))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
error -> [?CT("Bad format"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[FGroups,
|
||||
?BR,
|
||||
?INPUTT("submit", "delete", "Delete Selected")
|
||||
])
|
||||
].
|
||||
|
||||
list_sr_groups_parse_query(Host, Query) ->
|
||||
case lists:keysearch("addnew", 1, Query) of
|
||||
{value, _} ->
|
||||
list_sr_groups_parse_addnew(Host, Query);
|
||||
_ ->
|
||||
case lists:keysearch("delete", 1, Query) of
|
||||
{value, _} ->
|
||||
list_sr_groups_parse_delete(Host, Query);
|
||||
_ ->
|
||||
nothing
|
||||
end
|
||||
end.
|
||||
|
||||
list_sr_groups_parse_addnew(Host, Query) ->
|
||||
case lists:keysearch("namenew", 1, Query) of
|
||||
{value, {_, Group}} when Group /= "" ->
|
||||
mod_shared_roster:create_group(Host, Group),
|
||||
ok;
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
list_sr_groups_parse_delete(Host, Query) ->
|
||||
SRGroups = mod_shared_roster:list_groups(Host),
|
||||
lists:foreach(
|
||||
fun(Group) ->
|
||||
case lists:member({"selected", Group}, Query) of
|
||||
true ->
|
||||
mod_shared_roster:delete_group(Host, Group);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, SRGroups),
|
||||
ok.
|
||||
|
||||
|
||||
shared_roster_group(Host, Group, Query, Lang) ->
|
||||
Res = shared_roster_group_parse_query(Host, Group, Query),
|
||||
GroupOpts = mod_shared_roster:get_group_opts(Host, Group),
|
||||
Name = get_opt(GroupOpts, name, ""),
|
||||
Description = get_opt(GroupOpts, description, ""),
|
||||
AllUsers = get_opt(GroupOpts, all_users, false),
|
||||
Disabled = false,
|
||||
DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
|
||||
Members = mod_shared_roster:get_group_explicit_users(Host, Group),
|
||||
FMembers =
|
||||
if
|
||||
AllUsers ->
|
||||
"@all@\n";
|
||||
true ->
|
||||
[]
|
||||
end ++ [[us_to_list(Member), $\n] || Member <- Members],
|
||||
FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
|
||||
FGroup =
|
||||
?XAE("table", [],
|
||||
[?XE("tbody",
|
||||
[?XE("tr",
|
||||
[?XCT("td", "Name:"),
|
||||
?XE("td", [?INPUT("text", "name", Name)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Description:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "description"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
Description)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Members:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "members"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
FMembers)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Displayed Groups:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "dispgroups"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
FDisplayedGroups)])
|
||||
]
|
||||
)]
|
||||
)]),
|
||||
[?XC("h1", ?T("Shared Roster Groups"))] ++
|
||||
[?XC("h2", ?T("Group ") ++ Group)] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
error -> [?CT("Bad format"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[FGroup,
|
||||
?BR,
|
||||
?INPUTT("submit", "submit", "Submit")
|
||||
])
|
||||
].
|
||||
|
||||
shared_roster_group_parse_query(Host, Group, Query) ->
|
||||
case lists:keysearch("submit", 1, Query) of
|
||||
{value, _} ->
|
||||
{value, {_, Name}} = lists:keysearch("name", 1, Query),
|
||||
{value, {_, Description}} = lists:keysearch("description", 1, Query),
|
||||
{value, {_, SMembers}} = lists:keysearch("members", 1, Query),
|
||||
{value, {_, SDispGroups}} = lists:keysearch("dispgroups", 1, Query),
|
||||
NameOpt =
|
||||
if
|
||||
Name == "" -> [];
|
||||
true -> [{name, Name}]
|
||||
end,
|
||||
DescriptionOpt =
|
||||
if
|
||||
Description == "" -> [];
|
||||
true -> [{description, Description}]
|
||||
end,
|
||||
DispGroups = string:tokens(SDispGroups, "\r\n"),
|
||||
DispGroupsOpt =
|
||||
if
|
||||
DispGroups == [] -> [];
|
||||
true -> [{displayed_groups, DispGroups}]
|
||||
end,
|
||||
|
||||
OldMembers = mod_shared_roster:get_group_explicit_users(
|
||||
Host, Group),
|
||||
SJIDs = string:tokens(SMembers, ", \r\n"),
|
||||
NewMembers =
|
||||
lists:foldl(
|
||||
fun(_SJID, error) -> error;
|
||||
(SJID, USs) ->
|
||||
case SJID of
|
||||
"@all@" ->
|
||||
USs;
|
||||
_ ->
|
||||
case jlib:string_to_jid(SJID) of
|
||||
JID when is_record(JID, jid) ->
|
||||
[{JID#jid.luser, JID#jid.lserver} | USs];
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
end, [], SJIDs),
|
||||
AllUsersOpt =
|
||||
case lists:member("@all@", SJIDs) of
|
||||
true -> [{all_users, true}];
|
||||
false -> []
|
||||
end,
|
||||
|
||||
mod_shared_roster:set_group_opts(
|
||||
Host, Group,
|
||||
NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt),
|
||||
|
||||
if
|
||||
NewMembers == error -> error;
|
||||
true ->
|
||||
AddedMembers = NewMembers -- OldMembers,
|
||||
RemovedMembers = OldMembers -- NewMembers,
|
||||
lists:foreach(
|
||||
fun(US) ->
|
||||
mod_shared_roster:remove_user_from_group(
|
||||
Host, US, Group)
|
||||
end, RemovedMembers),
|
||||
lists:foreach(
|
||||
fun(US) ->
|
||||
mod_shared_roster:add_user_to_group(
|
||||
Host, US, Group)
|
||||
end, AddedMembers),
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
nothing
|
||||
end.
|
||||
|
||||
get_opt(Opts, Opt, Default) ->
|
||||
case lists:keysearch(Opt, 1, Opts) of
|
||||
{value, {_, Val}} ->
|
||||
Val;
|
||||
false ->
|
||||
Default
|
||||
end.
|
||||
|
||||
us_to_list({User, Server}) ->
|
||||
jlib:jid_to_string({User, Server, ""}).
|
||||
|
@ -3,7 +3,6 @@
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose : Administration web interface
|
||||
%%% Created : 9 Apr 2004 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Copyright (c) 2004-2006 Alexey Shchepin
|
||||
%%% Copyright (c) 2004-2006 Process One
|
||||
@ -15,46 +14,14 @@
|
||||
|
||||
%% External exports
|
||||
-export([process/2,
|
||||
%% XXX bard: unexported, since it is only called from process/2 now
|
||||
%% process_admin/2,
|
||||
list_users/4,
|
||||
list_users_in_diapason/4]).
|
||||
list_users_in_diapason/4,
|
||||
pretty_print_xml/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
-define(X(Name), {xmlelement, Name, [], []}).
|
||||
-define(XA(Name, Attrs), {xmlelement, Name, Attrs, []}).
|
||||
-define(XE(Name, Els), {xmlelement, Name, [], Els}).
|
||||
-define(XAE(Name, Attrs, Els), {xmlelement, Name, Attrs, Els}).
|
||||
-define(C(Text), {xmlcdata, Text}).
|
||||
-define(XC(Name, Text), ?XE(Name, [?C(Text)])).
|
||||
-define(XAC(Name, Attrs, Text), ?XAE(Name, Attrs, [?C(Text)])).
|
||||
|
||||
-define(T(Text), translate:translate(Lang, Text)).
|
||||
-define(CT(Text), ?C(?T(Text))).
|
||||
-define(XCT(Name, Text), ?XC(Name, ?T(Text))).
|
||||
-define(XACT(Name, Attrs, Text), ?XAC(Name, Attrs, ?T(Text))).
|
||||
|
||||
|
||||
-define(LI(Els), ?XE("li", Els)).
|
||||
-define(A(URL, Els), ?XAE("a", [{"href", URL}], Els)).
|
||||
-define(AC(URL, Text), ?A(URL, [?C(Text)])).
|
||||
-define(ACT(URL, Text), ?AC(URL, ?T(Text))).
|
||||
-define(P, ?X("p")).
|
||||
-define(BR, ?X("br")).
|
||||
-define(INPUT(Type, Name, Value),
|
||||
?XA("input", [{"type", Type},
|
||||
{"name", Name},
|
||||
{"value", Value}])).
|
||||
-define(INPUTT(Type, Name, Value), ?INPUT(Type, Name, ?T(Value))).
|
||||
-define(INPUTS(Type, Name, Value, Size),
|
||||
?XA("input", [{"type", Type},
|
||||
{"name", Name},
|
||||
{"value", Value},
|
||||
{"size", Size}])).
|
||||
-define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)).
|
||||
-include("ejabberd_web_admin.hrl").
|
||||
|
||||
|
||||
process(["server", SHost | RPath], #request{auth = Auth,
|
||||
@ -126,6 +93,8 @@ get_auth(Auth) ->
|
||||
end.
|
||||
|
||||
make_xhtml(Els, global, Lang) ->
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_main, [], []),
|
||||
MenuItems2 = [?LI([?ACT("/admin/"++MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
{200, [html],
|
||||
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"},
|
||||
{"xml:lang", Lang},
|
||||
@ -153,7 +122,7 @@ make_xhtml(Els, global, Lang) ->
|
||||
?LI([?ACT("/admin/vhosts/", "Virtual Hosts")]),
|
||||
?LI([?ACT("/admin/nodes/", "Nodes")]),
|
||||
?LI([?ACT("/admin/stats/", "Statistics")])
|
||||
]
|
||||
] ++ MenuItems2
|
||||
)]),
|
||||
?XAE("div",
|
||||
[{"id", "content"}],
|
||||
@ -172,6 +141,8 @@ make_xhtml(Els, global, Lang) ->
|
||||
|
||||
make_xhtml(Els, Host, Lang) ->
|
||||
Base = "/admin/server/" ++ Host ++ "/",
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host]),
|
||||
MenuItems2 = [?LI([?ACT(Base ++ MI_uri ++ "/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
{200, [html],
|
||||
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"},
|
||||
{"xml:lang", Lang},
|
||||
@ -205,14 +176,7 @@ make_xhtml(Els, Host, Lang) ->
|
||||
?LI([?ACT(Base ++ "last-activity/", "Last Activity")]),
|
||||
?LI([?ACT(Base ++ "nodes/", "Nodes")]),
|
||||
?LI([?ACT(Base ++ "stats/", "Statistics")])
|
||||
] ++
|
||||
case lists:member(mod_shared_roster,
|
||||
gen_mod:loaded_modules(Host)) of
|
||||
true ->
|
||||
[?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])];
|
||||
false ->
|
||||
[]
|
||||
end
|
||||
] ++ MenuItems2
|
||||
)]),
|
||||
?XAE("div",
|
||||
[{"id", "content"}],
|
||||
@ -607,6 +571,8 @@ process_admin(global,
|
||||
path = [],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_main, [], []),
|
||||
MenuItems2 = [?LI([?ACT("/admin/"++MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
make_xhtml([?XCT("h1", "Administration"),
|
||||
?XE("ul",
|
||||
[?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "),
|
||||
@ -616,7 +582,7 @@ process_admin(global,
|
||||
?LI([?ACT("/admin/vhosts/", "Virtual Hosts")]),
|
||||
?LI([?ACT("/admin/nodes/", "Nodes")]),
|
||||
?LI([?ACT("/admin/stats/", "Statistics")])
|
||||
]
|
||||
] ++ MenuItems2
|
||||
)
|
||||
], global, Lang);
|
||||
|
||||
@ -626,6 +592,8 @@ process_admin(Host,
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Base = "/admin/server/" ++ Host ++ "/",
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host]),
|
||||
MenuItems2 = [?LI([?ACT(Base ++ MI_uri ++ "/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
make_xhtml([?XCT("h1", "Administration"),
|
||||
?XE("ul",
|
||||
[?LI([?ACT(Base ++ "acls/", "Access Control Lists"), ?C(" "),
|
||||
@ -637,14 +605,7 @@ process_admin(Host,
|
||||
?LI([?ACT(Base ++ "last-activity/", "Last Activity")]),
|
||||
?LI([?ACT(Base ++ "nodes/", "Nodes")]),
|
||||
?LI([?ACT(Base ++ "stats/", "Statistics")])
|
||||
] ++
|
||||
case lists:member(mod_shared_roster,
|
||||
gen_mod:loaded_modules(Host)) of
|
||||
true ->
|
||||
[?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])];
|
||||
false ->
|
||||
[]
|
||||
end
|
||||
] ++ MenuItems2
|
||||
)
|
||||
], Host, Lang);
|
||||
|
||||
@ -996,14 +957,6 @@ process_admin(Host,
|
||||
Res = user_info(U, Host, Query, Lang),
|
||||
make_xhtml(Res, Host, Lang);
|
||||
|
||||
process_admin(Host,
|
||||
#request{us = US,
|
||||
path = ["user", U, "queue"],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Res = user_queue(U, Host, Query, Lang),
|
||||
make_xhtml(Res, Host, Lang);
|
||||
|
||||
process_admin(Host,
|
||||
#request{us = US,
|
||||
path = ["user", U, "roster"],
|
||||
@ -1033,25 +986,15 @@ process_admin(Host,
|
||||
make_xhtml(Res, Host, Lang)
|
||||
end;
|
||||
|
||||
process_admin(Host,
|
||||
#request{us = US,
|
||||
path = ["shared-roster"],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Res = list_shared_roster_groups(Host, Query, Lang),
|
||||
make_xhtml(Res, Host, Lang);
|
||||
|
||||
process_admin(Host,
|
||||
#request{us = US,
|
||||
path = ["shared-roster", Group],
|
||||
q = Query,
|
||||
lang = Lang} = Request) ->
|
||||
Res = shared_roster_group(Host, Group, Query, Lang),
|
||||
make_xhtml(Res, Host, Lang);
|
||||
|
||||
process_admin(Host,
|
||||
#request{lang = Lang}) ->
|
||||
setelement(1, make_xhtml([?XC("h1", "Not Found")], Host, Lang), 404).
|
||||
process_admin(Host, #request{lang = Lang} = Request) ->
|
||||
{Hook, Opts} = case Host of
|
||||
global -> {webadmin_page_main, [Request]};
|
||||
Host -> {webadmin_page_host, [Host, Request]}
|
||||
end,
|
||||
case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of
|
||||
[] -> setelement(1, make_xhtml([?XC("h1", "Not Found")], Host, Lang), 404);
|
||||
Res -> make_xhtml(Res, Host, Lang)
|
||||
end.
|
||||
|
||||
|
||||
|
||||
@ -1076,8 +1019,6 @@ acls_to_xhtml(ACLs) ->
|
||||
)]
|
||||
)]).
|
||||
|
||||
-define(ACLINPUT(Text), ?XE("td", [?INPUT("text", "value" ++ ID, Text)])).
|
||||
|
||||
acl_spec_to_text({user, U}) ->
|
||||
{user, U};
|
||||
|
||||
@ -1489,7 +1430,8 @@ list_online_users(Host, _Lang) ->
|
||||
end, SUsers).
|
||||
|
||||
user_info(User, Server, Query, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
LServer = jlib:nameprep(Server),
|
||||
US = {jlib:nodeprep(User), LServer},
|
||||
Res = user_parse_query(User, Server, Query),
|
||||
Resources = ejabberd_sm:get_user_resources(User, Server),
|
||||
FResources =
|
||||
@ -1516,9 +1458,8 @@ user_info(User, Server, Query, Lang) ->
|
||||
Password = ejabberd_auth:get_password_s(User, Server),
|
||||
FPassword = [?INPUT("password", "password", Password), ?C(" "),
|
||||
?INPUTT("submit", "chpassword", "Change Password")],
|
||||
QueueLen = length(mnesia:dirty_read({offline_msg, US})),
|
||||
FQueueLen = [?AC("queue/",
|
||||
integer_to_list(QueueLen))],
|
||||
UserItems = ejabberd_hooks:run_fold(webadmin_user, LServer, [],
|
||||
[User, Server, Lang]),
|
||||
[?XC("h1", ?T("User ") ++ us_to_list(US))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
@ -1528,9 +1469,9 @@ user_info(User, Server, Query, Lang) ->
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[?XCT("h3", "Connected Resources:")] ++ FResources ++
|
||||
[?XCT("h3", "Password:")] ++ FPassword ++
|
||||
[?XCT("h3", "Offline Messages:")] ++ FQueueLen ++
|
||||
[?XE("h3", [?ACT("roster/", "Roster")])] ++
|
||||
[?BR, ?INPUTT("submit", "removeuser", "Remove User")])].
|
||||
UserItems ++
|
||||
[?P, ?INPUTT("submit", "removeuser", "Remove User")])].
|
||||
|
||||
|
||||
user_parse_query(User, Server, Query) ->
|
||||
@ -1556,89 +1497,6 @@ user_parse_query(User, Server, Query) ->
|
||||
end.
|
||||
|
||||
|
||||
user_queue(User, Server, Query, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
Res = user_queue_parse_query(US, Query),
|
||||
Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})),
|
||||
FMsgs =
|
||||
lists:map(
|
||||
fun({offline_msg, _US, TimeStamp, _Expire, From, To,
|
||||
{xmlelement, Name, Attrs, Els}} = Msg) ->
|
||||
ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))),
|
||||
{{Year, Month, Day}, {Hour, Minute, Second}} =
|
||||
calendar:now_to_local_time(TimeStamp),
|
||||
Time = lists:flatten(
|
||||
io_lib:format(
|
||||
"~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
|
||||
[Year, Month, Day, Hour, Minute, Second])),
|
||||
SFrom = jlib:jid_to_string(From),
|
||||
STo = jlib:jid_to_string(To),
|
||||
Attrs2 = jlib:replace_from_to_attrs(SFrom, STo, Attrs),
|
||||
Packet = jlib:remove_attr(
|
||||
"jeai-id", {xmlelement, Name, Attrs2, Els}),
|
||||
FPacket = pretty_print(Packet),
|
||||
?XE("tr",
|
||||
[?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]),
|
||||
?XAC("td", [{"class", "valign"}], Time),
|
||||
?XAC("td", [{"class", "valign"}], SFrom),
|
||||
?XAC("td", [{"class", "valign"}], STo),
|
||||
?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])]
|
||||
)
|
||||
end, Msgs),
|
||||
[?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"),
|
||||
[us_to_list(US)]))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[?XE("table",
|
||||
[?XE("thead",
|
||||
[?XE("tr",
|
||||
[?X("td"),
|
||||
?XCT("td", "Time"),
|
||||
?XCT("td", "From"),
|
||||
?XCT("td", "To"),
|
||||
?XCT("td", "Packet")
|
||||
])]),
|
||||
?XE("tbody",
|
||||
if
|
||||
FMsgs == [] ->
|
||||
[?XE("tr",
|
||||
[?XAC("td", [{"colspan", "4"}], " ")]
|
||||
)];
|
||||
true ->
|
||||
FMsgs
|
||||
end
|
||||
)]),
|
||||
?BR,
|
||||
?INPUTT("submit", "delete", "Delete Selected")
|
||||
])].
|
||||
|
||||
user_queue_parse_query(US, Query) ->
|
||||
case lists:keysearch("delete", 1, Query) of
|
||||
{value, _} ->
|
||||
Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})),
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
fun(Msg) ->
|
||||
ID = jlib:encode_base64(
|
||||
binary_to_list(term_to_binary(Msg))),
|
||||
case lists:member({"selected", ID}, Query) of
|
||||
true ->
|
||||
mnesia:delete_object(Msg);
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end, Msgs)
|
||||
end,
|
||||
mnesia:transaction(F),
|
||||
ok;
|
||||
false ->
|
||||
nothing
|
||||
end.
|
||||
|
||||
|
||||
|
||||
-record(roster, {usj,
|
||||
us,
|
||||
@ -1922,6 +1780,8 @@ search_running_node(SNode, [Node | Nodes]) ->
|
||||
|
||||
get_node(global, Node, [], Query, Lang) ->
|
||||
Res = node_parse_query(Node, Query),
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_node, [], [Node]),
|
||||
MenuItems2 = [?LI([?ACT(MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
[?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
@ -1934,7 +1794,7 @@ get_node(global, Node, [], Query, Lang) ->
|
||||
?LI([?ACT("ports/", "Listened Ports")]),
|
||||
?LI([?ACT("stats/", "Statistics")]),
|
||||
?LI([?ACT("update/", "Update")])
|
||||
]),
|
||||
] ++ MenuItems2),
|
||||
?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[?INPUTT("submit", "restart", "Restart"),
|
||||
?C(" "),
|
||||
@ -1942,9 +1802,11 @@ get_node(global, Node, [], Query, Lang) ->
|
||||
];
|
||||
|
||||
get_node(Host, Node, [], Query, Lang) ->
|
||||
MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_hostnode, Host, [], [Host, Node]),
|
||||
MenuItems2 = [?LI([?ACT(MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1],
|
||||
[?XC("h1", ?T("Node ") ++ atom_to_list(Node)),
|
||||
?XE("ul",
|
||||
[?LI([?ACT("modules/", "Modules")])])
|
||||
[?LI([?ACT("modules/", "Modules")])] ++ MenuItems2)
|
||||
];
|
||||
|
||||
get_node(global, Node, ["db"], Query, Lang) ->
|
||||
@ -2176,7 +2038,15 @@ get_node(global, Node, ["update"], Query, Lang) ->
|
||||
];
|
||||
|
||||
get_node(Host, Node, NPath, Query, Lang) ->
|
||||
[?XCT("h1", "Not Found")].
|
||||
{Hook, Opts} = case Host of
|
||||
global -> {webadmin_page_node, [Node, NPath, Query]};
|
||||
Host -> {webadmin_page_hostnode, [Host, Node, NPath, Query]}
|
||||
end,
|
||||
case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of
|
||||
[] -> [?XC("h1", "Not Found")];
|
||||
Res -> Res
|
||||
end.
|
||||
|
||||
|
||||
|
||||
node_parse_query(Node, Query) ->
|
||||
@ -2464,12 +2334,12 @@ node_update_parse_query(Node, Query) ->
|
||||
end.
|
||||
|
||||
|
||||
pretty_print(El) ->
|
||||
lists:flatten(pretty_print(El, "")).
|
||||
pretty_print_xml(El) ->
|
||||
lists:flatten(pretty_print_xml(El, "")).
|
||||
|
||||
pretty_print({xmlcdata, CData}, Prefix) ->
|
||||
pretty_print_xml({xmlcdata, CData}, Prefix) ->
|
||||
[Prefix, CData, $\n];
|
||||
pretty_print({xmlelement, Name, Attrs, Els}, Prefix) ->
|
||||
pretty_print_xml({xmlelement, Name, Attrs, Els}, Prefix) ->
|
||||
[Prefix, $<, Name,
|
||||
case Attrs of
|
||||
[] ->
|
||||
@ -2499,7 +2369,7 @@ pretty_print({xmlelement, Name, Attrs, Els}, Prefix) ->
|
||||
true ->
|
||||
[$>, $\n,
|
||||
lists:map(fun(E) ->
|
||||
pretty_print(E, [Prefix, " "])
|
||||
pretty_print_xml(E, [Prefix, " "])
|
||||
end, Els),
|
||||
Prefix, $<, $/, Name, $>, $\n
|
||||
]
|
||||
@ -2507,225 +2377,6 @@ pretty_print({xmlelement, Name, Attrs, Els}, Prefix) ->
|
||||
end].
|
||||
|
||||
|
||||
list_shared_roster_groups(Host, Query, Lang) ->
|
||||
Res = list_sr_groups_parse_query(Host, Query),
|
||||
SRGroups = mod_shared_roster:list_groups(Host),
|
||||
FGroups =
|
||||
?XAE("table", [],
|
||||
[?XE("tbody",
|
||||
lists:map(
|
||||
fun(Group) ->
|
||||
?XE("tr",
|
||||
[?XE("td", [?INPUT("checkbox", "selected",
|
||||
Group)]),
|
||||
?XE("td", [?AC(Group ++ "/", Group)])
|
||||
]
|
||||
)
|
||||
end, lists:sort(SRGroups)) ++
|
||||
[?XE("tr",
|
||||
[?X("td"),
|
||||
?XE("td", [?INPUT("text", "namenew", "")]),
|
||||
?XE("td", [?INPUTT("submit", "addnew", "Add New")])
|
||||
]
|
||||
)]
|
||||
)]),
|
||||
[?XC("h1", ?T("Shared Roster Groups"))] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
error -> [?CT("Bad format"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[FGroups,
|
||||
?BR,
|
||||
?INPUTT("submit", "delete", "Delete Selected")
|
||||
])
|
||||
].
|
||||
|
||||
list_sr_groups_parse_query(Host, Query) ->
|
||||
case lists:keysearch("addnew", 1, Query) of
|
||||
{value, _} ->
|
||||
list_sr_groups_parse_addnew(Host, Query);
|
||||
_ ->
|
||||
case lists:keysearch("delete", 1, Query) of
|
||||
{value, _} ->
|
||||
list_sr_groups_parse_delete(Host, Query);
|
||||
_ ->
|
||||
nothing
|
||||
end
|
||||
end.
|
||||
|
||||
list_sr_groups_parse_addnew(Host, Query) ->
|
||||
case lists:keysearch("namenew", 1, Query) of
|
||||
{value, {_, Group}} when Group /= "" ->
|
||||
mod_shared_roster:create_group(Host, Group),
|
||||
ok;
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
list_sr_groups_parse_delete(Host, Query) ->
|
||||
SRGroups = mod_shared_roster:list_groups(Host),
|
||||
lists:foreach(
|
||||
fun(Group) ->
|
||||
case lists:member({"selected", Group}, Query) of
|
||||
true ->
|
||||
mod_shared_roster:delete_group(Host, Group);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, SRGroups),
|
||||
ok.
|
||||
|
||||
|
||||
shared_roster_group(Host, Group, Query, Lang) ->
|
||||
Res = shared_roster_group_parse_query(Host, Group, Query),
|
||||
GroupOpts = mod_shared_roster:get_group_opts(Host, Group),
|
||||
Name = get_opt(GroupOpts, name, ""),
|
||||
Description = get_opt(GroupOpts, description, ""),
|
||||
AllUsers = get_opt(GroupOpts, all_users, false),
|
||||
Disabled = false,
|
||||
DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
|
||||
Members = mod_shared_roster:get_group_explicit_users(Host, Group),
|
||||
FMembers =
|
||||
if
|
||||
AllUsers ->
|
||||
"@all@\n";
|
||||
true ->
|
||||
[]
|
||||
end ++ [[us_to_list(Member), $\n] || Member <- Members],
|
||||
FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
|
||||
FGroup =
|
||||
?XAE("table", [],
|
||||
[?XE("tbody",
|
||||
[?XE("tr",
|
||||
[?XCT("td", "Name:"),
|
||||
?XE("td", [?INPUT("text", "name", Name)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Description:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "description"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
Description)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Members:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "members"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
FMembers)])
|
||||
]
|
||||
),
|
||||
?XE("tr",
|
||||
[?XCT("td", "Displayed Groups:"),
|
||||
?XE("td", [?XAC("textarea", [{"name", "dispgroups"},
|
||||
{"rows", "3"},
|
||||
{"cols", "20"}],
|
||||
FDisplayedGroups)])
|
||||
]
|
||||
)]
|
||||
)]),
|
||||
[?XC("h1", ?T("Shared Roster Groups"))] ++
|
||||
[?XC("h2", ?T("Group ") ++ Group)] ++
|
||||
case Res of
|
||||
ok -> [?CT("Submitted"), ?P];
|
||||
error -> [?CT("Bad format"), ?P];
|
||||
nothing -> []
|
||||
end ++
|
||||
[?XAE("form", [{"action", ""}, {"method", "post"}],
|
||||
[FGroup,
|
||||
?BR,
|
||||
?INPUTT("submit", "submit", "Submit")
|
||||
])
|
||||
].
|
||||
|
||||
shared_roster_group_parse_query(Host, Group, Query) ->
|
||||
case lists:keysearch("submit", 1, Query) of
|
||||
{value, _} ->
|
||||
{value, {_, Name}} = lists:keysearch("name", 1, Query),
|
||||
{value, {_, Description}} = lists:keysearch("description", 1, Query),
|
||||
{value, {_, SMembers}} = lists:keysearch("members", 1, Query),
|
||||
{value, {_, SDispGroups}} = lists:keysearch("dispgroups", 1, Query),
|
||||
NameOpt =
|
||||
if
|
||||
Name == "" -> [];
|
||||
true -> [{name, Name}]
|
||||
end,
|
||||
DescriptionOpt =
|
||||
if
|
||||
Description == "" -> [];
|
||||
true -> [{description, Description}]
|
||||
end,
|
||||
DispGroups = string:tokens(SDispGroups, "\r\n"),
|
||||
DispGroupsOpt =
|
||||
if
|
||||
DispGroups == [] -> [];
|
||||
true -> [{displayed_groups, DispGroups}]
|
||||
end,
|
||||
|
||||
OldMembers = mod_shared_roster:get_group_explicit_users(
|
||||
Host, Group),
|
||||
SJIDs = string:tokens(SMembers, ", \r\n"),
|
||||
NewMembers =
|
||||
lists:foldl(
|
||||
fun(_SJID, error) -> error;
|
||||
(SJID, USs) ->
|
||||
case SJID of
|
||||
"@all@" ->
|
||||
USs;
|
||||
_ ->
|
||||
case jlib:string_to_jid(SJID) of
|
||||
JID when is_record(JID, jid) ->
|
||||
[{JID#jid.luser, JID#jid.lserver} | USs];
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
end, [], SJIDs),
|
||||
AllUsersOpt =
|
||||
case lists:member("@all@", SJIDs) of
|
||||
true -> [{all_users, true}];
|
||||
false -> []
|
||||
end,
|
||||
|
||||
mod_shared_roster:set_group_opts(
|
||||
Host, Group,
|
||||
NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt),
|
||||
|
||||
if
|
||||
NewMembers == error -> error;
|
||||
true ->
|
||||
AddedMembers = NewMembers -- OldMembers,
|
||||
RemovedMembers = OldMembers -- NewMembers,
|
||||
lists:foreach(
|
||||
fun(US) ->
|
||||
mod_shared_roster:remove_user_from_group(
|
||||
Host, US, Group)
|
||||
end, RemovedMembers),
|
||||
lists:foreach(
|
||||
fun(US) ->
|
||||
mod_shared_roster:add_user_to_group(
|
||||
Host, US, Group)
|
||||
end, AddedMembers),
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
nothing
|
||||
end.
|
||||
|
||||