25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-10-31 15:21:38 +01:00
xmpp.chapril.org-ejabberd/mod_pubsub_ng/pubsub_groups.erl

905 lines
32 KiB
Erlang

%%% ====================================================================
%%% ``The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
%%% compliance with the License. You should have received a copy of the
%%% Erlang Public License along with this software. If not, it can be
%%% retrieved via the world wide web at http://www.erlang.org/.
%%%
%%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations
%%% under the License.
%%%
%%% The Initial Developer of the Original Code is ProcessOne.
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
%%% All Rights Reserved.''
%%% This software is copyright 2006-2013, ProcessOne.
%%%
%%% @copyright 2006-2013 ProcessOne
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
%%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time}
%%% @end
%%% ====================================================================
%%% @headerfile "pubsub_dev.hrl"
-module(pubsub_groups).
-author('karim.gemayel@process-one.net').
-compile(export_all).
-include("pubsub_dev.hrl").
-import(pubsub_tools,
[
get_option/2,
get_option/3,
get_value/2,
get_value/3,
set_value/3,
%%
check_acces_model/3,
check_acces_model/7,
check_publish_model/3,
get_entity_roster/1,
is_contact_subscribed_to_node_owners/3,
is_contact_in_allowed_roster_groups/2,
has_subscriptions/1,
get_resources/2,
get_resources_show/2,
rosters_groups_allowed_cache/2
]).
-import(pubsub_db_mnesia,
[
table/2
]).
-type(group() :: binary()).
-type(node_group() :: group()).
-type(roster_group() :: group()).
-type(node_groups() :: [Node_Group::node_group(),...]).
-type(roster_groups() :: [Roster_Group::roster_group(),...]).
-type(nodeIdxs() :: [NodeIdx::exmpp_pubsub:nodeIdx(),...]).
-type(n0de()
:: {NodeIdx :: exmpp_pubsub:nodeIdx(),
Groups :: node_groups()}
).
-type(n0des() :: [Node::n0de(),...]).
-type(subscription()
:: {NodeIdx :: exmpp_pubsub:nodeIdx(),
Groups :: roster_groups()}
).
-type(subscriptions() :: [Subscription::subscription(),...]).
-type(contact()
:: {Entity :: xmpp_jid:usr_bare(),
Subscriptions :: subscriptions()}
).
-type(contacts() :: [Contact::contact(),...]).
-record(pubsub_groups,
{
owner :: xmpp_jid:usr_bare(),
nodes = [] :: n0des(),
contacts = [] :: [] | contacts()
}).
create_table_pubsub_groups(Suffix) ->
mnesia:create_table(table('pubsub_groups', Suffix),
[{type, set},
{disc_copies, [node()]},
{record_name, pubsub_groups},
{attributes, record_info(fields, pubsub_groups)}]).
%%
-spec(register_groups/4 ::
(
Suffix :: atom(),
NodeIdx :: exmpp_pubsub:nodeIdx(),
Owner :: xmpp_jid:usr_bare(),
Groups :: [] | node_groups())
-> undefined
%
| {Subscribers :: [Entity::xmpp_jid:usr_bare()],
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
register_groups(Suffix, NodeIdx, Owner, [] = _Groups) ->
case
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'),
Owner, write)
of
%%
[] ->
undefined;
%%
[#pubsub_groups{nodes = [{NodeIdx, _Node_Groups}]} = Pubsub_Groups] ->
mnesia:delete_object(Table_Pubsub_Groups, Pubsub_Groups, write),
%
{_Subscribers = [],
_Unsubscribers = lists:foldl(fun
({Entity, Subscriptions}, Unsubscribers) ->
case lists:keymember(NodeIdx, 1, Subscriptions) of
true -> [Entity | Unsubscribers];
false -> Unsubscribers
end
%
end, [], Pubsub_Groups#pubsub_groups.contacts)};
%%
[Pubsub_Groups] ->
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
{_NodeIdx, Node_Groups} ->
{Contacts, Unsubscribers} = subscriptions1(NodeIdx,
Pubsub_Groups#pubsub_groups.contacts),
%
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = Contacts
},
write),
%
{_Subscribers = [],
_Unsubscribers = Unsubscribers};
false ->
undefined
end
end;
%%
register_groups(Suffix, NodeIdx, Owner, Groups) ->
case
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'), Owner,
write)
of
[] ->
{Contacts, Subscribers} = subscriptions2(NodeIdx, Owner, Groups),
%
mnesia:write(Table_Pubsub_Groups,
#pubsub_groups{
owner = Owner,
nodes = [{NodeIdx, Groups}],
contacts = Contacts
},
write),
%
{_Subscribers = Subscribers,
_Unsubscribers = []};
[Pubsub_Groups] ->
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
{_NodeIdx, Node_Groups} ->
case diff_groups(Groups, Node_Groups) of
%%
{[] = _New_Groups, [] = _Old_Groups} ->
{_Subscribers = [],
_Unsubscribers = []};
%%
{[] = _New_Groups, Old_Groups} ->
{Contacts, Unsubscribers}
= subscriptions3(NodeIdx, Old_Groups,
Pubsub_Groups#pubsub_groups.contacts),
%
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
nodes = lists:keyreplace(NodeIdx, 1,
Pubsub_Groups#pubsub_groups.nodes,
{NodeIdx, Groups}),
contacts = Contacts
},
write),
%
{_Subscribers = [],
_Unsubscribers = Unsubscribers};
%%
{_New_Groups, _Old_Groups} ->
{Contacts, Subscribers, Unsubscribers}
= subscriptions4(NodeIdx, Owner, Node_Groups,
Pubsub_Groups#pubsub_groups.contacts),
%
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
nodes = lists:keyreplace(NodeIdx, 1,
Pubsub_Groups#pubsub_groups.nodes,
{NodeIdx, Node_Groups}),
contacts = Contacts
},
write),
%
{Subscribers = Subscribers,
_Unsubscribers = Unsubscribers}
end;
false ->
{Contacts, Subscribers}
= subscriptions5(NodeIdx, Owner, Groups,
_Contacts = Pubsub_Groups#pubsub_groups.contacts),
%
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
nodes = [{NodeIdx, Groups}
| Pubsub_Groups#pubsub_groups.nodes],
contacts = Contacts
},
write),
%
{_Subscribers = Subscribers,
_Unsubscribers = []}
end
end.
%% TODO : fix this hook managment
-spec(monitor_contacts/3 ::
(
_ :: 'subscribed',
Entity :: xmpp_jid:usr_bare(),
Jid_Contacts :: xmpp_jid:entity_bare())
-> undefined
%
| {Server :: xmpp_jid:raw_jid_component_bare(),
Entity :: xmpp_jid:usr_bare(),
Contact :: xmpp_jid:usr_bare(),
_ :: {'subscribed', NodeIdxs :: nodeIdxs()}}
).
monitor_contacts('subscribed', {_, Server, _} = Entity, Jid_Contact) ->
case roster_groups(Entity, Contact = jlid:jid_to_lower(Jid_Contact)) of
[] ->
undefined;
Roster_Groups ->
case
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
_Owner = Entity, write)
of
[] ->
undefined;
[Pubsub_Groups] ->
case
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
Roster_Groups)
of
[] ->
undefined;
Subscriptions ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = case
lists:keyreplace(Contact, 1,
Pubsub_Groups#pubsub_groups.contacts,
{Contact, Subscriptions})
of
_Contacts
when _Contacts ==
Pubsub_Groups#pubsub_groups.contacts ->
[{Contact, Subscriptions}
| Pubsub_Groups#pubsub_groups.contacts];
Contacts ->
Contacts
end
},
write),
{Server, Entity, Contact,
{'subscribed',
_NodeIdx = lists:map(fun
({NodeIdx, _Groups}) ->
NodeIdx
end, Subscriptions)}}
end
end
end.
%%
-spec(monitor_groups/2 ::
(
Server :: xmpp_jid:raw_jid_component_bare(),
Roster :: #roster{groups :: [] | roster_groups()})
-> undefined
%
| {Server :: xmpp_jid:raw_jid_component_bare(),
Entity :: xmpp_jid:usr_bare(),
Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}}
).
monitor_groups(Server, #roster{us = {U,S}} = _Roster) ->
case
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
_Owner = {U,S,undefined}, write)
of
[] ->
undefined;
[Pubsub_Groups] ->
case
lists:keyfind(_Roster#roster.jid, 1,
Pubsub_Groups#pubsub_groups.contacts)
of %%
{_Entity, Old_Subscriptions}
when _Roster#roster.subscription == 'delete'
orelse _Roster#roster.subscription == 'none' ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = lists:keydelete(_Roster#roster.jid, 1,
Pubsub_Groups#pubsub_groups.contacts)
},
write),
{Server,
_Entity = _Roster#roster.jid,
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
Old_Subscriptions)};
%%
{_Entity, Old_Subscriptions}
when (_Roster#roster.subscription == 'both'
orelse
_Roster#roster.subscription == 'from')
andalso _Roster#roster.groups == [] ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = lists:keydelete(_Roster#roster.jid, 1,
Pubsub_Groups#pubsub_groups.contacts)
},
write),
{Server,
_Roster#roster.jid,
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
Old_Subscriptions)};
%%
{_Entity, Old_Subscriptions}
when _Roster#roster.subscription == 'both'
orelse _Roster#roster.subscription == 'from' ->
case
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
_Roster#roster.groups)
of
[] ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = lists:keydelete(_Roster#roster.jid,
1, Pubsub_Groups#pubsub_groups.contacts)
},
write),
{Server, _Roster#roster.jid,
diff_nodeidxs(_New_Subscriptions = [],
Old_Subscriptions)};
New_Subscriptions ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = lists:keyreplace(_Roster#roster.jid,
1, Pubsub_Groups#pubsub_groups.contacts,
{_Roster#roster.jid, New_Subscriptions})
},
write),
{Server,
_Entity = _Roster#roster.jid,
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
Old_Subscriptions)}
end;
%%
false
when (_Roster#roster.subscription == 'both'
orelse
_Roster#roster.subscription == 'from')
andalso _Roster#roster.groups =/= [] ->
case
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
_Roster#roster.groups)
of
[] ->
undefined;
New_Subscriptions ->
mnesia:write(Table_Pubsub_Groups,
Pubsub_Groups#pubsub_groups{
contacts = [{_Roster#roster.jid, New_Subscriptions}
| Pubsub_Groups#pubsub_groups.contacts]
},
write),
{Server,
_Entity = _Roster#roster.jid,
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
_Old_Subscriptions = [])}
end;
%%
_ ->
undefined
end
end.
%%
%%
-spec(subscriptions1/2 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Old_Contacts :: [] | contacts())
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions1(NodeIdx, Contacts) ->
_Diff_Contacts = subscriptions1(NodeIdx, _Old_Contacts = Contacts,
{_New_Contacts = [], _Unsubscribers = []}).
%%
-spec(subscriptions1/3 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Old_Contacts :: [] | contacts(),
Diff_Contacts :: {Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions1(_NodeIdx, [] = _Old_Contacts, Diff_Contacts) ->
Diff_Contacts;
%%
subscriptions1(NodeIdx, [{Entity, Subscriptions} | Old_Contacts],
{Contacts, Unsubscribers}) ->
subscriptions1(NodeIdx, Old_Contacts,
_Diff_Contacts = case lists:keydelete(NodeIdx, 1, Subscriptions) of
[] ->
{_Contacts = Contacts,
_Unsubscribers = [Entity | Unsubscribers]};
Subscriptions ->
{_Contacts = [{Entity, Subscriptions} | Contacts],
_Unsubscribers = Unsubscribers};
New_Subscriptions ->
{_Contacts = [{Entity, New_Subscriptions} | Contacts],
_Unsubscribers = [Entity | Unsubscribers]}
end).
%%
-spec(subscriptions2/3 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Owner :: xmpp_jid:usr_bare(),
Node_Groups :: node_groups())
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions2(NodeIdx, Owner, Node_Groups) ->
subscriptions2(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
{_New_Contacts = [], _Subscribers = []}).
%%
-spec(subscriptions2/4 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Rosters :: [Roster::#roster{groups :: [] | roster_groups()}],
Node_Groups :: node_groups(),
Diff_Contacts :: {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions2(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
Diff_Contacts;
%%
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
when _Roster#roster.groups =/= [] ->
subscriptions2(NodeIdx, Rosters, Node_Groups,
_Diff_Contacts = case
filter_groups(_Roster#roster.groups, Node_Groups, [])
of
[] ->
{_Contacts = Contacts,
_Subscribers = Subscribers};
Roster_Groups ->
{_Contacts = [{_Roster#roster.jid, [{NodeIdx, Roster_Groups}]}
| Contacts],
_Subscribers = [_Roster#roster.jid | Subscribers]}
end);
%%
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
subscriptions2(NodeIdx, Rosters, Node_Groups, Diff_Contacts).
%%
-spec(subscriptions3/3 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Old_Groups :: roster_groups(),
Contacts :: contacts() | [])
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions3(NodeIdx, Old_Groups, Contacts) ->
subscriptions3(NodeIdx, Contacts, Old_Groups, {[],[]}).
%%
-spec(subscriptions3/4 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
Old_Contacts :: contacts() | [],
Old_Groups :: roster_groups(),
Diff_Contacts :: {Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions3(_NodeIdx, [] = _Contacts, _Old_Groups, Diff_Contacts) ->
Diff_Contacts;
%%
subscriptions3(NodeIdx, [{Entity, Subscriptions} | Old_Contacts], Old_Groups,
{Contacts, Unsubscribers}) ->
subscriptions3(NodeIdx, Old_Contacts, Old_Groups,
_Diff_Contacts = case lists:keyfind(NodeIdx, 1, Subscriptions) of
{_NodeIdx, Roster_Groups} ->
case delete_groups(Old_Groups, Roster_Groups) of
[] ->
{_Contacts = Contacts,
_Unsubscribers = [Entity | Unsubscribers]};
Groups ->
{_Contacts = [{Entity,
lists:keyreplace(NodeIdx, 1,
Subscriptions, {NodeIdx, Groups})}
| Contacts],
_Unsubscribers = Unsubscribers}
end;
false ->
{_Contacts = [{Entity, Subscriptions} | Contacts],
_Unsubscribers = Unsubscribers}
end).
%%
-spec(subscriptions4/4 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
_ :: xmpp_jid:usr_bare()
| [Roster::#roster{groups :: [] | roster_groups()}],
Node_Groups :: node_groups(),
_ :: [] | contacts()
| {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()],
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()],
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions4(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
Diff_Contacts;
%%
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups,
{Contacts, Subscribers, Unsubscribers})
when _Roster#roster.groups =/= [] ->
subscriptions4(NodeIdx, Rosters, Node_Groups,
_Diff_Contacts = case
{lists:keyfind(Entity = _Roster#roster.jid, 1, Contacts),
filter_groups(_Roster#roster.groups, Node_Groups, [])}
of
%%
{false, [] = _Groups} ->
{_Contacts = Contacts,
_Subscribers = Subscribers,
_Unsubscribers = Unsubscribers};
%%
{false, Groups} ->
{_Contacts = [{Entity, [{NodeIdx, Groups}]} | Contacts],
_Subscribers = [Entity | Subscribers],
_Unsubscribers = Unsubscribers};
%%
{{_Entity, [{NodeIdx, _Roster_Groups}] = _Subscriptions}, [] = _Groups} ->
{_Contacts = lists:keydelete(Entity, 1, Contacts),
_Subscribers = Subscribers,
_Unsubscribers = [Entity | Unsubscribers]};
%%
{{_Entity, Subscriptions}, [] = _Groups} ->
case lists:keydelete(NodeIdx, 1, Subscriptions) of
Subscriptions ->
{_Contacts = Contacts,
_Subscribers = Subscribers,
_Unsubscribers = Unsubscribers};
New_Subscriptions ->
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
{Entity, New_Subscriptions}),
_Subscribers = Subscribers,
_Unsubscribers = [Entity | Unsubscribers]}
end;
{{_Entity, Subscriptions}, Groups} ->
case lists:keyreplace(NodeIdx, 1, Subscriptions, {NodeIdx, Groups}) of
Subscriptions ->
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
{Entity,
[{NodeIdx, Groups} | Subscriptions]}),
_Subscribers = [Entity | Subscribers],
_Unsubscribers = Unsubscribers};
New_Subscriptions ->
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
{Entity, New_Subscriptions}),
_Subscribers = Subscribers,
_Unsubscribers = Unsubscribers}
end
end);
%%
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
subscriptions4(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
%%
subscriptions4(NodeIdx, Owner, Node_Groups, Contacts) ->
subscriptions4(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
_Diff_Contacts = {Contacts, _Subscribers = [], _Unsubscribers = []}).
-spec(subscriptions5/4 ::
(
NodeIdx :: exmpp_pubsub:nodeIdx(),
_ :: xmpp_jid:usr_bare()
| [Roster::#roster{groups :: [] | roster_groups()}],
Node_Groups :: node_groups(),
_ :: [] | contacts()
| {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
-> Diff_Contacts :: {Contacts :: [] | contacts(),
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
).
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
when _Roster#roster.groups =/= [] ->
subscriptions5(NodeIdx, Rosters, Node_Groups,
_Diff_Contacts = case
filter_groups(_Roster#roster.groups, Node_Groups, [])
of
[] ->
{_Contacts = Contacts,
_Subscribers = Subscribers};
Groups ->
{_Contacts = case
lists:keyfind(_Roster#roster.jid, 1, Contacts)
of
false ->
[{_Roster#roster.jid, [{NodeIdx, Groups}]} | Contacts];
{Entity, Subscriptions} ->
lists:keyreplace(Entity, 1, Contacts,
{Entity, [{NodeIdx, Groups} | Subscriptions]})
end,
_Subscribers = [_Roster#roster.jid | Subscribers]}
end);
%%
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
subscriptions5(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
%%
subscriptions5(NodeIdx, Owner, Node_Groups, Contacts) ->
subscriptions5(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
_Diff_Contacts = {Contacts, _Subscribers = []}).
%%
-spec(delete_groups/2 ::
(
Old_Groups :: roster_groups(),
Groups :: [] | roster_groups())
-> Groups :: [] | roster_groups()
).
delete_groups(_Old_Groups, [] = _Groups) ->
_Groups = [];
%%
delete_groups([] = _Old_Groups, Groups) ->
Groups;
%%
delete_groups([Old_Group | Old_Groups], Groups) ->
_Groups = delete_groups(Old_Groups, lists:delete(Old_Group, Groups)).
%%
-spec(diff_groups/2 ::
(
Groups :: node_groups() | [],
_ :: node_groups()
| {New_Groups :: [] | node_groups(),
Old_Groups :: [] | node_groups()})
-> Diff_Groups :: {New_Groups :: [] | node_groups(),
Old_Groups :: [] | node_groups()}
).
diff_groups([] = _Groups, Diff_Groups) -> %% when is_tuple(Diff_Groups)
Diff_Groups;
%%
diff_groups([Group | Groups], {New_Groups, Old_Groups}) ->
diff_groups(Groups,
_Diff_Groups = case lists:delete(Group, Old_Groups) of
Old_Groups -> {[Group | New_Groups], Old_Groups};
Old_Groups2 -> {New_Groups, Old_Groups2}
end);
%%
diff_groups(New_Groups, Old_Groups) ->
diff_groups(New_Groups, {[], Old_Groups}).
%%
-spec(filter_groups/3 ::
(
Roster_Groups :: roster_groups() | [],
Node_Groups :: node_groups(),
Groups :: [] | roster_groups())
-> Groups :: [] | roster_groups()
).
filter_groups([] = _Roster_Groups, _Node_Groups, Groups) ->
Groups;
%%
filter_groups([Roster_Group | Roster_Groups], Node_Groups, Groups) ->
filter_groups(Roster_Groups, Node_Groups,
_Groups = case lists:member(Roster_Group, Node_Groups) of
true -> [Roster_Group | Groups];
false -> Groups
end).
%%
-spec(filter_subscriptions/2 ::
(
Nodes :: n0des(),
Roster_Groups :: roster_groups())
-> Subscriptions :: [] | subscriptions()
).
filter_subscriptions(Nodes, Roster_Groups) ->
_Subscriptions = filter_subscriptions(Nodes, Roster_Groups, []).
%%
-spec(filter_subscriptions/3 ::
(
Nodes :: n0des(),
Roster_Groups :: roster_groups(),
Subscriptions :: [] | subscriptions())
-> Subscriptions :: [] | subscriptions()
).
filter_subscriptions([] = _Nodes, _Roster_Groups, Subscriptions) ->
Subscriptions;
%%
filter_subscriptions([{NodeIdx, Node_Groups} | Nodes], Roster_Groups,
Subscriptions) ->
filter_subscriptions(Nodes, Roster_Groups,
_Subscriptions = case filter_groups(Roster_Groups, Node_Groups, []) of
[] -> Subscriptions;
Groups -> [{NodeIdx, Groups} | Subscriptions]
end).
%%
-spec(diff_nodeidxs/2 ::
(
New_Subscriptions :: [] | subscriptions(),
Old_Subscriptions :: [] | subscriptions())
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
).
diff_nodeidxs(New_Subscriptions, Old_Subscriptions) ->
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions, Old_Subscriptions, []).
%%
-spec(diff_nodeidxs/3 ::
(
New_Subscriptions :: [] | subscriptions(),
Old_Subscriptions :: [] | subscriptions(),
NodeIdxs_Subscriptions :: [] | nodeIdxs())
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
).
diff_nodeidxs([] = _New_Subscriptions, Old_Subscriptions,
NodeIdxs_Subscriptions) ->
_Diff_NodeIdxs = {
_NodeIdxs_Subscriptions = NodeIdxs_Subscriptions,
_NodeIdxs_Unsubscriptions = lists:map(fun
({NodeIdx, _Roster_Groups}) ->
NodeIdx
end, Old_Subscriptions)};
%%
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], [] = Old_Subscriptions,
NodeIdxs_Subscriptions) ->
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
[NodeIdx | NodeIdxs_Subscriptions]);
%%
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], Old_Subscriptions,
NodeIdxs_Subscriptions) ->
case lists:keydelete(NodeIdx, 1, Old_Subscriptions) of
Old_Subscriptions ->
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
[NodeIdx | NodeIdxs_Subscriptions]);
Subscriptions ->
diff_nodeidxs(New_Subscriptions, _Old_Subscriptions = Subscriptions,
NodeIdxs_Subscriptions)
end.
%% TODO : use a new mod_roster_api for this call
-spec(roster_groups/2 ::
(
Entity :: xmpp_jid:usr_bare(),
Contact :: xmpp_jid:usr_bare())
-> Roster_Groups :: [] | roster_groups()
).
roster_groups({User, Server, _} = _Entity, Contact) ->
_Roster_Groups = case
gen_storage:transaction(Server, rosteritem,
fun() ->
gen_storage:select(Server, rostergroup,
[{'=', user_host_jid, {User, Server, Contact}}])
end)
of
{atomic, _RosterGroups} ->
lists:map(fun
(_RosterGroup) ->
_RosterGroup#roster.groups
end, _RosterGroups);
_Error
-> {error, 'internal-server-error'}
end.
%%
-spec(select_roster_groups/1 ::
(
Entity :: xmpp_jid:usr_entity())
-> Roster_Groups :: [] | roster_groups()
).
select_roster_groups({User, Server, _} = Entity) ->
_Roster_Groups = case
gen_storage:transaction(Server, rosteritem,
fun() ->
gen_storage:select(Server, rostergroup,
[{'=', user_host_jid, {User, Server, '_'}}])
end)
of
{atomic, _RosterGroups} ->
lists:map(fun
(_RosterGroup) ->
_RosterGroup#roster.groups
end, _RosterGroups);
_Error
-> {error, 'internal-server-error'}
end.
%% TESTS
%%
monitor_roster_groups(Server, Roster) ->
?INFO_MSG("SERVER ~p ROSTER ~p", [Server, Roster]),
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_groups,
[Server, Roster]),
?INFO_MSG("MONITOR ROSTER GROUPS ~p", [Result]).
monitor_contacts2('subscribed', Entity, Jid_Contact) ->
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_contacts,
['subscribed', Entity, Jid_Contact]),
?INFO_MSG("MONITOR CONTACTS2 ~p", [Result]).
register1(NodeIdx, User, Groups) ->
Server = <<"localhost">>,
Owner = {list_to_binary(atom_to_list(User)), Server, undefined},
Groups_B = lists:map(fun(Group) -> list_to_binary(atom_to_list(Group)) end, Groups),
register_groups(dev, NodeIdx, Owner, Groups_B).
register(NodeIdx, User, Groups) ->
pubsub_db:transaction('mnesia', ?MODULE, register1, [NodeIdx, User, Groups]).