85
85
%% ================
87
%% @spec (Host, ServerHost, Opts) -> any()
88
%% Host = mod_pubsub:host()
89
%% ServerHost = mod_pubsub:host()
87
%% @spec (Host, ServerHost, Options) -> ok
89
%% ServerHost = string()
90
%% Options = [{atom(), term()}]
91
91
%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
92
92
%% implement this function. It can return anything.</p>
93
93
%% <p>This function is mainly used to trigger the setup task necessary for the
94
94
%% plugin. It can be used for example by the developer to create the specific
95
95
%% module database schema if it does not exists yet.</p>
96
init(_Host, _ServerHost, _Opts) ->
96
init(_Host, _ServerHost, _Options) ->
97
97
pubsub_subscription:init(),
98
98
mnesia:create_table(pubsub_state,
99
99
[{disc_copies, [node()]},
112
%% @spec (Host, ServerHost) -> any()
113
%% Host = mod_pubsub:host()
114
%% ServerHost = host()
112
%% @spec (Host, ServerHost) -> ok
114
%% ServerHost = string()
115
115
%% @doc <p>Called during pubsub modules termination. Any pubsub plugin must
116
116
%% implement this function. It can return anything.</p>
117
117
terminate(_Host, _ServerHost) ->
120
%% @spec () -> [Option]
121
%% Option = mod_pubsub:nodeOption()
120
%% @spec () -> Options
121
%% Options = [mod_pubsub:nodeOption()]
122
122
%% @doc Returns the default pubsub node options.
123
123
%% <p>Example of function return value:</p>
178
179
"subscription-options"
181
%% @spec (Host, ServerHost, Node, ParentNode, Owner, Access) -> bool()
182
%% Host = mod_pubsub:host()
183
%% ServerHost = mod_pubsub:host()
184
%% Node = mod_pubsub:pubsubNode()
185
%% ParentNode = mod_pubsub:pubsubNode()
186
%% Owner = mod_pubsub:jid()
187
%% Access = all | atom()
182
%% @spec (Host, ServerHost, NodeId, ParentNodeId, Owner, Access) -> {result, Allowed}
183
%% Host = mod_pubsub:hostPubsub()
184
%% ServerHost = string()
185
%% NodeId = mod_pubsub:nodeId()
186
%% ParentNodeId = mod_pubsub:nodeId()
187
%% Owner = mod_pubsub:jid()
188
%% Access = all | atom()
189
%% Allowed = boolean()
188
190
%% @doc Checks if the current user has the permission to create the requested node
189
191
%% <p>In {@link node_default}, the permission is decided by the place in the
190
192
%% hierarchy where the user is creating the node. The access parameter is also
195
197
%% <p>PubSub plugins can redefine the PubSub node creation rights as they
196
198
%% which. They can simply delegate this check to the {@link node_default}
197
199
%% module by implementing this function like this:
198
%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
199
%% node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''</p>
200
create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
200
%% ```check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access) ->
201
%% node_default:check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access).'''</p>
202
create_node_permission(Host, ServerHost, NodeId, _ParentNodeId, Owner, Access) ->
201
203
LOwner = jlib:jid_tolower(Owner),
202
204
{User, Server, _Resource} = LOwner,
203
205
Allowed = case LOwner of
217
219
{result, Allowed}.
219
%% @spec (NodeId, Owner) ->
220
%% {result, Result} | exit
221
%% NodeId = mod_pubsub:pubsubNodeId()
222
%% Owner = mod_pubsub:jid()
221
%% @spec (NodeIdx, Owner) -> {result, {default, broadcast}}
222
%% NodeIdx = mod_pubsub:nodeIdx()
223
%% Owner = mod_pubsub:jid()
224
create_node(NodeId, Owner) ->
225
create_node(NodeIdx, Owner) ->
225
226
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
226
set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}),
227
set_state(#pubsub_state{stateid = {OwnerKey, NodeIdx}, affiliation = owner}),
227
228
{result, {default, broadcast}}.
229
%% @spec (Removed) -> ok
230
%% Removed = [mod_pubsub:pubsubNode()]
230
%% @spec (Nodes) -> {result, {default, broadcast, Reply}}
231
%% Nodes = [mod_pubsub:pubsubNode()]
232
%% Reply = [{mod_pubsub:pubsubNode(),
233
%% [{mod_pubsub:ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]}]}]
231
234
%% @doc <p>purge items of deleted nodes after effective deletion.</p>
232
delete_node(Removed) ->
235
delete_node(Nodes) ->
233
236
Tr = fun(#pubsub_state{stateid = {J, _}, subscriptions = Ss}) ->
234
237
lists:map(fun(S) ->
244
247
del_state(NodeId, LJID)
246
249
{PubsubNode, lists:flatmap(Tr, States)}
248
251
{result, {default, broadcast, Reply}}.
250
%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) ->
251
%% {error, Reason} | {result, Result}
253
%% @spec (NodeIdx, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> {error, Reason} | {result, Result}
254
%% NodeIdx = mod_pubsub:nodeIdx()
255
%% Sender = mod_pubsub:jid()
256
%% Subscriber = mod_pubsub:jid()
257
%% AccessModel = mod_pubsub:accessModel()
259
%% PresenceSubscription = boolean()
260
%% RosterGroup = boolean()
261
%% Options = [mod_pubsub:nodeOption()]
262
%% Reason = mod_pubsub:stanzaError()
263
%% Result = {result, {default, subscribed, mod_pubsub:subId()}}
264
%% | {result, {default, subscribed, mod_pubsub:subId(), send_last}}
265
%% | {result, {default, pending, mod_pubsub:subId()}}
252
267
%% @doc <p>Accepts or rejects subcription requests on a PubSub node.</p>
253
268
%% <p>The mechanism works as follow:
280
295
%% to completly disable persistance.</li></ul>
282
297
%% <p>In the default plugin module, the record is unchanged.</p>
283
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
298
subscribe_node(NodeIdx, Sender, Subscriber, AccessModel,
284
299
SendLast, PresenceSubscription, RosterGroup, Options) ->
285
300
SubKey = jlib:jid_tolower(Subscriber),
286
301
GenKey = jlib:jid_remove_resource(SubKey),
287
302
Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
288
GenState = get_state(NodeId, GenKey),
303
GenState = get_state(NodeIdx, GenKey),
289
304
SubState = case SubKey of
290
305
GenKey -> GenState;
291
_ -> get_state(NodeId, SubKey)
306
_ -> get_state(NodeIdx, SubKey)
293
308
Affiliation = GenState#pubsub_state.affiliation,
294
309
Subscriptions = SubState#pubsub_state.subscriptions,
345
%% @spec (NodeId, Sender, Subscriber, SubId) ->
346
%% {error, Reason} | {result, []}
347
%% NodeId = mod_pubsub:pubsubNodeId()
348
%% Sender = mod_pubsub:jid()
360
%% @spec (NodeIdx, Sender, Subscriber, SubId) -> {error, Reason} | {result, default}
361
%% NodeIdx = mod_pubsub:nodeIdx()
362
%% Sender = mod_pubsub:jid()
349
363
%% Subscriber = mod_pubsub:jid()
350
%% SubId = mod_pubsub:subid()
351
%% Reason = mod_pubsub:stanzaError()
364
%% SubId = mod_pubsub:subId()
365
%% Reason = mod_pubsub:stanzaError()
352
366
%% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
353
unsubscribe_node(NodeId, Sender, Subscriber, SubId) ->
367
unsubscribe_node(NodeIdx, Sender, Subscriber, SubId) ->
354
368
SubKey = jlib:jid_tolower(Subscriber),
355
369
GenKey = jlib:jid_remove_resource(SubKey),
356
370
Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
357
GenState = get_state(NodeId, GenKey),
371
GenState = get_state(NodeIdx, GenKey),
358
372
SubState = case SubKey of
359
373
GenKey -> GenState;
360
_ -> get_state(NodeId, SubKey)
374
_ -> get_state(NodeIdx, SubKey)
362
376
Subscriptions = lists:filter(fun({_Sub, _SubId}) -> true;
363
377
(_SubId) -> false
390
404
end, SubState#pubsub_state.subscriptions),
393
delete_subscriptions(SubKey, NodeId, [S], SubState),
407
delete_subscriptions(SubKey, NodeIdx, [S], SubState),
394
408
{result, default};
396
410
{error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST_CANCEL, "not-subscribed")}
398
412
%% Asking to remove all subscriptions to the given node
400
delete_subscriptions(SubKey, NodeId, Subscriptions, SubState),
414
delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
401
415
{result, default};
402
416
%% No subid supplied, but there's only one matching subscription
403
417
length(Subscriptions) == 1 ->
404
delete_subscriptions(SubKey, NodeId, Subscriptions, SubState),
418
delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
405
419
{result, default};
406
420
%% No subid and more than one possible subscription match.
408
422
{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}
411
delete_subscriptions(SubKey, NodeId, Subscriptions, SubState) ->
425
delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState) ->
412
426
NewSubs = lists:foldl(fun({Subscription, SubId}, Acc) ->
413
pubsub_subscription:delete_subscription(SubKey, NodeId, SubId),
427
pubsub_subscription:delete_subscription(SubKey, NodeIdx, SubId),
414
428
Acc -- [{Subscription, SubId}]
415
429
end, SubState#pubsub_state.subscriptions, Subscriptions),
416
430
case {SubState#pubsub_state.affiliation, NewSubs} of
418
432
% Just a regular subscriber, and this is final item, so
419
433
% delete the state.
420
del_state(NodeId, SubKey);
434
del_state(NodeIdx, SubKey);
422
436
set_state(SubState#pubsub_state{subscriptions = NewSubs})
425
%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
426
%% {true, PubsubItem} | {result, Reply}
427
%% NodeId = mod_pubsub:pubsubNodeId()
428
%% Publisher = mod_pubsub:jid()
439
%% @spec (NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
440
%% {result, {default, broadcast, ItemIds}} | {error, Reason}
441
%% NodeIdx = mod_pubsub:nodeIdx()
442
%% Publisher = mod_pubsub:jid()
429
443
%% PublishModel = atom()
430
%% MaxItems = integer()
444
%% MaxItems = integer()
445
%% ItemId = mod_pubsub:itemId()
446
%% Payload = mod_pubsub:payload()
447
%% ItemIds = [mod_pubsub:itemId()] | []
448
%% Reason = mod_pubsub:stanzaError()
433
449
%% @doc <p>Publishes the item passed as parameter.</p>
434
450
%% <p>The mechanism works as follow:
460
476
%% to completly disable persistance.</li></ul>
462
478
%% <p>In the default plugin module, the record is unchanged.</p>
463
publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
479
publish_item(NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
464
480
SubKey = jlib:jid_tolower(Publisher),
465
481
GenKey = jlib:jid_remove_resource(SubKey),
466
GenState = get_state(NodeId, GenKey),
482
GenState = get_state(NodeIdx, GenKey),
467
483
SubState = case SubKey of
468
484
GenKey -> GenState;
469
_ -> get_state(NodeId, SubKey)
485
_ -> get_state(NodeIdx, SubKey)
471
487
Affiliation = GenState#pubsub_state.affiliation,
472
488
Subscribed = case PublishModel of
485
501
if MaxItems > 0 ->
487
503
PubId = {Now, SubKey},
488
Item = case get_item(NodeId, ItemId) of
504
Item = case get_item(NodeIdx, ItemId) of
489
505
{result, OldItem} ->
490
506
OldItem#pubsub_item{modification = PubId,
491
507
payload = Payload};
493
#pubsub_item{itemid = {ItemId, NodeId},
509
#pubsub_item{itemid = {ItemId, NodeIdx},
494
510
creation = {Now, GenKey},
495
511
modification = PubId,
496
512
payload = Payload}
498
514
Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
499
{result, {NI, OI}} = remove_extra_items(NodeId, MaxItems, Items),
515
{result, {NI, OI}} = remove_extra_items(NodeIdx, MaxItems, Items),
501
517
set_state(GenState#pubsub_state{items = NI}),
502
518
{result, {default, broadcast, OI}};
508
%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
509
%% NodeId = mod_pubsub:pubsubNodeId()
510
%% MaxItems = integer() | unlimited
511
%% ItemIds = [ItemId::string()]
512
%% NewItemIds = [ItemId::string()]
524
%% @spec (NodeIdx, MaxItems, ItemIds) -> {result, {NewItemIds,OldItemIds}}
525
%% NodeIdx = mod_pubsub:nodeIdx()
526
%% MaxItems = integer() | unlimited
527
%% ItemIds = [mod_pubsub:itemId()]
528
%% NewItemIds = [mod_pubsub:itemId()]
529
%% OldItemIds = [mod_pubsub:itemId()] | []
513
530
%% @doc <p>This function is used to remove extra items, most notably when the
514
531
%% maximum number of items has been reached.</p>
515
532
%% <p>This function is used internally by the core PubSub module, as no
518
535
%% rules can be used.</p>
519
536
%% <p>If another PubSub plugin wants to delegate the item removal (and if the
520
537
%% plugin is using the default pubsub storage), it can implements this function like this:
521
%% ```remove_extra_items(NodeId, MaxItems, ItemIds) ->
522
%% node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''</p>
523
remove_extra_items(_NodeId, unlimited, ItemIds) ->
538
%% ```remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
539
%% node_default:remove_extra_items(NodeIdx, MaxItems, ItemIds).'''</p>
540
remove_extra_items(_NodeIdx, unlimited, ItemIds) ->
524
541
{result, {ItemIds, []}};
525
remove_extra_items(NodeId, MaxItems, ItemIds) ->
542
remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
526
543
NewItems = lists:sublist(ItemIds, MaxItems),
527
544
OldItems = lists:nthtail(length(NewItems), ItemIds),
528
545
%% Remove extra items:
529
del_items(NodeId, OldItems),
546
del_items(NodeIdx, OldItems),
530
547
%% Return the new items list:
531
548
{result, {NewItems, OldItems}}.
533
%% @spec (NodeId, Publisher, PublishModel, ItemId) ->
534
%% {error, Reason::stanzaError()} |
536
%% NodeId = mod_pubsub:pubsubNodeId()
537
%% Publisher = mod_pubsub:jid()
550
%% @spec (NodeIdx, Publisher, PublishModel, ItemId) ->
551
%% {result, {default, broadcast}} | {error, Reason}
552
%% NodeIdx = mod_pubsub:nodeIdx()
553
%% Publisher = mod_pubsub:jid()
538
554
%% PublishModel = atom()
555
%% ItemId = mod_pubsub:itemId()
556
%% Reason = mod_pubsub:stanzaError()
540
557
%% @doc <p>Triggers item deletion.</p>
541
558
%% <p>Default plugin: The user performing the deletion must be the node owner
542
559
%% or a publisher, or PublishModel being open.</p>
543
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
560
delete_item(NodeIdx, Publisher, PublishModel, ItemId) ->
544
561
SubKey = jlib:jid_tolower(Publisher),
545
562
GenKey = jlib:jid_remove_resource(SubKey),
546
GenState = get_state(NodeId, GenKey),
563
GenState = get_state(NodeIdx, GenKey),
547
564
#pubsub_state{affiliation = Affiliation, items = Items} = GenState,
548
565
Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
549
566
orelse (PublishModel == open)
550
orelse case get_item(NodeId, ItemId) of
567
orelse case get_item(NodeIdx, ItemId) of
551
568
{result, #pubsub_item{creation = {_, GenKey}}} -> true;
559
576
case lists:member(ItemId, Items) of
561
del_item(NodeId, ItemId),
578
del_item(NodeIdx, ItemId),
562
579
set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}),
563
580
{result, {default, broadcast}};
565
582
case Affiliation of
567
584
%% Owner can delete other publishers items as well
568
{result, States} = get_states(NodeId),
585
{result, States} = get_states(NodeIdx),
570
587
fun(#pubsub_state{items = PI, affiliation = publisher} = S, Res) ->
571
588
case lists:member(ItemId, PI) of
573
del_item(NodeId, ItemId),
590
del_item(NodeIdx, ItemId),
574
591
set_state(S#pubsub_state{items = lists:delete(ItemId, PI)}),
575
592
{result, {default, broadcast}};
589
%% @spec (NodeId, Owner) ->
590
%% {error, Reason::stanzaError()} |
591
%% {result, {default, broadcast}}
592
%% NodeId = mod_pubsub:pubsubNodeId()
593
%% Owner = mod_pubsub:jid()
594
purge_node(NodeId, Owner) ->
606
%% @spec (NodeIdx, Owner) -> {error, Reason} | {result, {default, broadcast}}
607
%% NodeIdx = mod_pubsub:nodeIdx()
608
%% Owner = mod_pubsub:jid()
609
%% Reason = mod_pubsub:stanzaError()
610
purge_node(NodeIdx, Owner) ->
595
611
SubKey = jlib:jid_tolower(Owner),
596
612
GenKey = jlib:jid_remove_resource(SubKey),
597
GenState = get_state(NodeId, GenKey),
613
GenState = get_state(NodeIdx, GenKey),
599
615
#pubsub_state{affiliation = owner} ->
600
{result, States} = get_states(NodeId),
616
{result, States} = get_states(NodeIdx),
602
618
fun(#pubsub_state{items = []}) ->
604
620
(#pubsub_state{items = Items} = S) ->
605
del_items(NodeId, Items),
621
del_items(NodeIdx, Items),
606
622
set_state(S#pubsub_state{items = []})
608
624
{result, {default, broadcast}};
611
627
{error, ?ERR_FORBIDDEN}
614
%% @spec (Host, JID) -> [{Node,Affiliation}]
616
%% JID = mod_pubsub:jid()
630
%% @spec (Host, Owner) -> {result, Reply}
631
%% Host = mod_pubsub:hostPubsub()
632
%% Owner = mod_pubsub:jid()
633
%% Reply = [] | [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]
617
634
%% @doc <p>Return the current affiliations for the given user</p>
618
635
%% <p>The default module reads affiliations in the main Mnesia
619
636
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
661
678
set_state(GenState#pubsub_state{affiliation = Affiliation})
664
%% @spec (Host, Owner) -> [{Node,Subscription}]
666
%% Owner = mod_pubsub:jid()
681
%% @spec (Host, Owner) ->
683
%% | [{Node, Subscription, SubId, Entity}]
684
%% | [{Node, Subscription, Entity}]}
685
%% Host = mod_pubsub:hostPubsub()
686
%% Owner = mod_pubsub:jid()
687
%% Node = mod_pubsub:pubsubNode()
688
%% Subscription = mod_pubsub:subscription()
689
%% SubId = mod_pubsub:subId()
690
%% Entity = mod_pubsub:ljid()
667
691
%% @doc <p>Return the current subscriptions for the given user</p>
668
692
%% <p>The default module reads subscriptions in the main Mnesia
669
693
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
774
798
set_state(SubState#pubsub_state{subscriptions = NewSubs})
777
%% @spec (Host, Owner) -> {result, [Node]} | {error, Reason}
780
%% Node = pubsubNode()
802
%% @spec (Host, Owner) -> {result, Reply} | {error, Reason}
803
%% Host = mod_pubsub:hostPubsub()
804
%% Owner = mod_pubsub:jid()
805
%% Reply = [] | [mod_pubsub:nodeId()]
781
806
%% @doc <p>Returns a list of Owner's nodes on Host with pending
782
807
%% subscriptions.</p>
783
808
get_pending_nodes(Host, Owner) ->
831
857
%% relational database).</p>
832
858
%% <p>If a PubSub plugin wants to delegate the states storage to the default node,
833
859
%% they can implement this function like this:
834
%% ```get_states(NodeId) ->
835
%% node_default:get_states(NodeId).'''</p>
836
get_states(NodeId) ->
860
%% ```get_states(NodeIdx) ->
861
%% node_default:get_states(NodeIdx).'''</p>
862
get_states(NodeIdx) ->
837
863
States = case catch mnesia:match_object(
838
#pubsub_state{stateid = {'_', NodeId}, _ = '_'}) of
864
#pubsub_state{stateid = {'_', NodeIdx}, _ = '_'}) of
839
865
List when is_list(List) -> List;
842
868
{result, States}.
844
%% @spec (NodeId, JID) -> [State] | []
845
%% NodeId = mod_pubsub:pubsubNodeId()
846
%% JID = mod_pubsub:jid()
847
%% State = mod_pubsub:pubsubItems()
870
%% @spec (NodeIdx, JID) -> State
871
%% NodeIdx = mod_pubsub:nodeIdx()
872
%% JID = mod_pubsub:jid()
873
%% State = mod_pubsub:pubsubState()
848
874
%% @doc <p>Returns a state (one state list), given its reference.</p>
849
get_state(NodeId, JID) ->
850
StateId = {JID, NodeId},
875
get_state(NodeIdx, JID) ->
876
StateId = {JID, NodeIdx},
851
877
case catch mnesia:read({pubsub_state, StateId}) of
852
878
[State] when is_record(State, pubsub_state) -> State;
853
879
_ -> #pubsub_state{stateid=StateId}
856
%% @spec (State) -> ok | {error, Reason::stanzaError()}
857
%% State = mod_pubsub:pubsubStates()
882
%% @spec (State) -> ok | {error, Reason}
883
%% State = mod_pubsub:pubsubState()
884
%% Reason = mod_pubsub:stanzaError()
858
885
%% @doc <p>Write a state into database.</p>
859
886
set_state(State) when is_record(State, pubsub_state) ->
860
887
mnesia:write(State);
862
889
{error, ?ERR_INTERNAL_SERVER_ERROR}.
864
%% @spec (NodeId, JID) -> ok | {error, Reason::stanzaError()}
865
%% NodeId = mod_pubsub:pubsubNodeId()
866
%% JID = mod_pubsub:jid()
891
%% @spec (NodeIdx, JID) -> ok | {error, Reason}
892
%% NodeIdx = mod_pubsub:nodeIdx()
893
%% JID = mod_pubsub:jid()
894
%% Reason = mod_pubsub:stanzaError()
867
895
%% @doc <p>Delete a state from database.</p>
868
del_state(NodeId, JID) ->
869
mnesia:delete({pubsub_state, {JID, NodeId}}).
896
del_state(NodeIdx, JID) ->
897
mnesia:delete({pubsub_state, {JID, NodeIdx}}).
871
%% @spec (NodeId, From) -> [Items] | []
872
%% NodeId = mod_pubsub:pubsubNodeId()
873
%% Items = mod_pubsub:pubsubItems()
899
%% @spec (NodeIdx, From) -> {result, Items}
900
%% NodeIdx = mod_pubsub:nodeIdx()
901
%% From = mod_pubsub:jid()
902
%% Items = [] | [mod_pubsub:pubsubItem()]
874
903
%% @doc Returns the list of stored items for a given node.
875
904
%% <p>For the default PubSub module, items are stored in Mnesia database.</p>
876
905
%% <p>We can consider that the pubsub_item table have been created by the main
879
908
%% relational database), or they can even decide not to persist any items.</p>
880
909
%% <p>If a PubSub plugin wants to delegate the item storage to the default node,
881
910
%% they can implement this function like this:
882
%% ```get_items(NodeId, From) ->
883
%% node_default:get_items(NodeId, From).'''</p>
884
get_items(NodeId, _From) ->
885
Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'}),
911
%% ```get_items(NodeIdx, From) ->
912
%% node_default:get_items(NodeIdx, From).'''</p>
913
get_items(NodeIdx, _From) ->
914
Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeIdx}, _ = '_'}),
886
915
{result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}.
887
get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
917
get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
888
918
SubKey = jlib:jid_tolower(JID),
889
919
GenKey = jlib:jid_remove_resource(SubKey),
890
GenState = get_state(NodeId, GenKey),
891
SubState = get_state(NodeId, SubKey),
920
GenState = get_state(NodeIdx, GenKey),
921
SubState = get_state(NodeIdx, SubKey),
892
922
Affiliation = GenState#pubsub_state.affiliation,
893
923
Subscriptions = SubState#pubsub_state.subscriptions,
894
924
Whitelisted = can_fetch_item(Affiliation, Subscriptions),
918
948
%% % Payment is required for a subscription
919
949
%% {error, ?ERR_PAYMENT_REQUIRED};
921
get_items(NodeId, JID)
951
get_items(NodeIdx, JID)
924
%% @spec (NodeId, ItemId) -> [Item] | []
925
%% NodeId = mod_pubsub:pubsubNodeId()
927
%% Item = mod_pubsub:pubsubItems()
954
%% @spec (NodeIdx, ItemId) -> {result, Item} | {error, 'item-not-found'}
955
%% NodeIdx = mod_pubsub:nodeIdx()
956
%% ItemId = mod_pubsub:itemId()
957
%% Item = mod_pubsub:pubsubItem()
928
958
%% @doc <p>Returns an item (one item list), given its reference.</p>
929
get_item(NodeId, ItemId) ->
930
case mnesia:read({pubsub_item, {ItemId, NodeId}}) of
959
get_item(NodeIdx, ItemId) ->
960
case mnesia:read({pubsub_item, {ItemId, NodeIdx}}) of
931
961
[Item] when is_record(Item, pubsub_item) ->
934
964
{error, ?ERR_ITEM_NOT_FOUND}
936
get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
967
%% @spec (NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> {result, Item} | {error, Reason}
968
%% NodeIdx = mod_pubsub:nodeIdx()
969
%% ItemId = mod_pubsub:itemId()
970
%% JID = mod_pubsub:jid()
971
%% AccessModel = mod_pubsub:accessModel()
972
%% PresenceSubscription = boolean()
973
%% RosterGroup = boolean()
974
%% SubId = mod_pubsub:subId()
975
%% Item = mod_pubsub:pubsubItem()
976
%% Reason = mod_pubsub:stanzaError() | 'item-not-found'
978
get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
937
979
SubKey = jlib:jid_tolower(JID),
938
980
GenKey = jlib:jid_remove_resource(SubKey),
939
GenState = get_state(NodeId, GenKey),
981
GenState = get_state(NodeIdx, GenKey),
940
982
Affiliation = GenState#pubsub_state.affiliation,
941
983
Subscriptions = GenState#pubsub_state.subscriptions,
942
984
Whitelisted = can_fetch_item(Affiliation, Subscriptions),
966
1008
%% % Payment is required for a subscription
967
1009
%% {error, ?ERR_PAYMENT_REQUIRED};
969
get_item(NodeId, ItemId)
1011
get_item(NodeIdx, ItemId)
972
%% @spec (Item) -> ok | {error, Reason::stanzaError()}
973
%% Item = mod_pubsub:pubsubItems()
1014
%% @spec (Item) -> ok | {error, Reason}
1015
%% Item = mod_pubsub:pubsubItem()
1016
%% Reason = mod_pubsub:stanzaError()
974
1017
%% @doc <p>Write an item into database.</p>
975
1018
set_item(Item) when is_record(Item, pubsub_item) ->
976
1019
mnesia:write(Item);
978
1021
{error, ?ERR_INTERNAL_SERVER_ERROR}.
980
%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()}
981
%% NodeId = mod_pubsub:pubsubNodeId()
1023
%% @spec (NodeIdx, ItemId) -> ok | {error, Reason}
1024
%% NodeIdx = mod_pubsub:nodeIdx()
1025
%% ItemId = mod_pubsub:itemId()
1026
%% Reason = mod_pubsub:stanzaError()
983
1027
%% @doc <p>Delete an item from database.</p>
984
del_item(NodeId, ItemId) ->
985
mnesia:delete({pubsub_item, {ItemId, NodeId}}).
986
del_items(NodeId, ItemIds) ->
1028
del_item(NodeIdx, ItemId) ->
1029
mnesia:delete({pubsub_item, {ItemId, NodeIdx}}).
1031
del_items(NodeIdx, ItemIds) ->
987
1032
lists:foreach(fun(ItemId) ->
988
del_item(NodeId, ItemId)
1033
del_item(NodeIdx, ItemId)
991
1036
%% @doc <p>Return the name of the node if known: Default is to return