Skip to content

Commit ce3c404

Browse files
committed
Merge pull request #81 from surevine/issue-68
Only allow owner unsubscribe if there is more than 1 owner (i.e. another owner)
2 parents 3d7efeb + 68e70c2 commit ce3c404

8 files changed

Lines changed: 257 additions & 37 deletions

File tree

src/main/java/org/buddycloud/channelserver/channel/ChannelManagerImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ public ResultSet<NodeAffiliation> getNodeAffiliations(String nodeId,
143143
maxItemsToReturn);
144144
}
145145

146+
@Override
147+
public ArrayList<JID> getNodeOwners(String node) throws NodeStoreException {
148+
return nodeStore.getNodeOwners(node);
149+
}
150+
146151
@Override
147152
public int countNodeAffiliations(String nodeId) throws NodeStoreException {
148153
return nodeStore.countNodeAffiliations(nodeId);
@@ -468,6 +473,5 @@ public ResultSet<NodeThread> getNodeThreads(String node, String afterId,
468473
@Override
469474
public int countNodeThreads(String node) throws NodeStoreException {
470475
return nodeStore.countNodeThreads(node);
471-
}
472-
476+
}
473477
}

src/main/java/org/buddycloud/channelserver/db/NodeStore.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,14 @@ ResultSet<NodeAffiliation> getNodeAffiliations(String nodeId)
231231
ResultSet<NodeAffiliation> getNodeAffiliations(String node
232232
, String afterItemId, int maxItemsToReturn) throws NodeStoreException;
233233

234+
/**
235+
* Get a list of node owners
236+
*
237+
* @param node
238+
* @throws NodeStoreException
239+
*/
240+
ArrayList<JID> getNodeOwners(String node) throws NodeStoreException;
241+
234242
/**
235243
* Count the number of affiliations for a node
236244
*
@@ -573,16 +581,57 @@ void deleteNodeItemById(String nodeId, String nodeItemId)
573581
*/
574582
int getFirehoseItemCount(boolean isAdmin) throws NodeStoreException;
575583

584+
/**
585+
* Get a list of posts for a user
586+
*
587+
* @param userJid
588+
* @return
589+
* @throws NodeStoreException
590+
*/
576591
ResultSet<NodeItem> getUserItems(JID userJid) throws NodeStoreException;
577592

593+
/**
594+
* Delete user posts
595+
*
596+
* @param userJid
597+
* @throws NodeStoreException
598+
*/
578599
void deleteUserItems(JID userJid) throws NodeStoreException;
579600

601+
/**
602+
* Delete affiliations for a user
603+
*
604+
* @param userJid
605+
* @throws NodeStoreException
606+
*/
580607
void deleteUserAffiliations(JID userJid) throws NodeStoreException;
581608

609+
/**
610+
* Delete user subscriptions
611+
*
612+
* @param userJid
613+
* @throws NodeStoreException
614+
*/
582615
void deleteUserSubscriptions(JID userJid) throws NodeStoreException;
583616

617+
/**
618+
* Get node threads
619+
*
620+
* @param node
621+
* @param afterId
622+
* @param limit
623+
* @return
624+
* @throws NodeStoreException
625+
*/
584626
ResultSet<NodeThread> getNodeThreads(String node, String afterId, int limit) throws NodeStoreException;
585627

628+
/**
629+
* Count node threads
630+
*
631+
* @param node
632+
* @return
633+
* @throws NodeStoreException
634+
*/
586635
int countNodeThreads(String node) throws NodeStoreException;
587636

588637
/**

src/main/java/org/buddycloud/channelserver/db/jdbc/JDBCNodeStore.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,30 @@ public ResultSet<NodeAffiliation> getNodeAffiliations(String nodeId,
584584
}
585585
}
586586

587+
@Override
588+
public ArrayList<JID> getNodeOwners(String node) throws NodeStoreException {
589+
PreparedStatement stmt = null;
590+
591+
try {
592+
stmt = conn.prepareStatement(dialect
593+
.selectNodeOwners());
594+
stmt.setString(1, node);
595+
596+
java.sql.ResultSet rs = stmt.executeQuery();
597+
ArrayList<JID> result = new ArrayList<JID>();
598+
599+
while (rs.next()) {
600+
result.add(new JID(rs.getString(1)));
601+
}
602+
603+
return result;
604+
} catch (SQLException e) {
605+
throw new NodeStoreException(e);
606+
} finally {
607+
close(stmt); // Will implicitly close the resultset if required
608+
}
609+
}
610+
587611
@Override
588612
public int countUserAffiliations(JID actorJid) throws NodeStoreException {
589613
PreparedStatement selectStatement = null;
@@ -1840,6 +1864,8 @@ public void close() throws NodeStoreException {
18401864
public interface NodeStoreSQLDialect {
18411865
String insertNode();
18421866

1867+
String selectNodeOwners();
1868+
18431869
String getUserItems();
18441870

18451871
String selectItemsForLocalNodesBeforeDate();

src/main/java/org/buddycloud/channelserver/db/jdbc/dialect/Sql92NodeStoreDialect.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public class Sql92NodeStoreDialect implements NodeStoreSQLDialect {
2525
private static final String SELECT_AFFILIATIONS_FOR_USER = "SELECT \"node\", \"user\", \"affiliation\", \"updated\""
2626
+ " FROM \"affiliations\" WHERE \"user\" = ? ORDER BY \"updated\" ASC";
2727

28+
private static final String SELECT_NODE_OWNERS = "SELECT \"user\" FROM \"affiliations\" WHERE \"node\" = ? AND \"affiliation\" = 'owner';";
29+
2830
private static final String SELECT_AFFILIATION_CHANGES = ""
2931
+ "SELECT \"node\", \"user\", \"affiliation\", \"updated\" FROM \"affiliations\" "
3032
+ "WHERE \"updated\" >= ? AND \"updated\" <= ? AND \"node\" IN "
@@ -278,6 +280,11 @@ public String selectAffiliation() {
278280
public String selectAffiliationsForUser() {
279281
return SELECT_AFFILIATIONS_FOR_USER;
280282
}
283+
284+
@Override
285+
public String selectNodeOwners() {
286+
return SELECT_NODE_OWNERS;
287+
}
281288

282289
@Override
283290
public String selectAffiliationChanges() {

src/main/java/org/buddycloud/channelserver/packetprocessor/iq/namespace/pubsub/set/UnsubscribeSet.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class UnsubscribeSet extends PubSubElementProcessorAbstract {
3434

3535
private String node;
3636
private IQ request;
37+
private IQ response;
3738
private JID unsubscribingJid;
3839

3940
public UnsubscribeSet(BlockingQueue<Packet> outQueue,
@@ -48,6 +49,7 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
4849

4950
node = elm.attributeValue("node");
5051
request = reqIQ;
52+
response = IQ.createResultIQ(request);
5153

5254
if ((node == null) || (node.equals(""))) {
5355
missingNodeName();
@@ -79,13 +81,12 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
7981

8082

8183
if (false == channelManager.nodeExists(node)) {
82-
IQ reply = IQ.createResultIQ(request);
83-
reply.setType(Type.error);
84+
response.setType(Type.error);
8485
PacketError pe = new PacketError(
8586
org.xmpp.packet.PacketError.Condition.item_not_found,
8687
org.xmpp.packet.PacketError.Type.cancel);
87-
reply.setError(pe);
88-
outQueue.put(reply);
88+
response.setError(pe);
89+
outQueue.put(response);
8990
return;
9091
}
9192

@@ -98,13 +99,24 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
9899
// Check that the requesting user is allowed to unsubscribe according to
99100
// XEP-0060 section 6.2.3.3
100101
if (false == unsubscribingJid.equals(existingSubscription.getUser())) {
101-
IQ reply = IQ.createResultIQ(request);
102-
reply.setType(Type.error);
102+
response.setType(Type.error);
103103
PacketError pe = new PacketError(
104104
org.xmpp.packet.PacketError.Condition.forbidden,
105105
org.xmpp.packet.PacketError.Type.auth);
106-
reply.setError(pe);
107-
outQueue.put(reply);
106+
response.setError(pe);
107+
outQueue.put(response);
108+
return;
109+
}
110+
111+
if ((Affiliations.owner == existingAffiliation.getAffiliation()) &&
112+
(channelManager.getNodeOwners(node).size() < 2)) {
113+
114+
response.setType(Type.error);
115+
PacketError pe = new PacketError(
116+
org.xmpp.packet.PacketError.Condition.not_allowed,
117+
org.xmpp.packet.PacketError.Type.cancel);
118+
response.setError(pe);
119+
outQueue.put(response);
108120
return;
109121
}
110122

@@ -120,8 +132,7 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
120132
Affiliations.none);
121133
}
122134

123-
IQ reply = IQ.createResultIQ(request);
124-
outQueue.put(reply);
135+
outQueue.put(response);
125136
notifySubscribers();
126137
}
127138

@@ -174,13 +185,12 @@ private void failAuthRequired() throws InterruptedException {
174185
* <registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
175186
* </error> </iq>
176187
*/
177-
IQ reply = IQ.createResultIQ(request);
178-
reply.setType(Type.error);
188+
response.setType(Type.error);
179189
PacketError pe = new PacketError(
180190
org.xmpp.packet.PacketError.Condition.not_authorized,
181191
org.xmpp.packet.PacketError.Type.auth);
182-
reply.setError(pe);
183-
outQueue.put(reply);
192+
response.setError(pe);
193+
outQueue.put(response);
184194
}
185195

186196
private void missingNodeName() throws InterruptedException {
@@ -194,8 +204,7 @@ private void missingNodeName() throws InterruptedException {
194204
* </error> </iq>
195205
*/
196206

197-
IQ reply = IQ.createResultIQ(request);
198-
reply.setType(Type.error);
207+
response.setType(Type.error);
199208

200209
Element badRequest = new DOMElement("bad-request",
201210
new org.dom4j.Namespace("", JabberPubsub.NS_XMPP_STANZAS));
@@ -208,9 +217,9 @@ private void missingNodeName() throws InterruptedException {
208217
error.add(badRequest);
209218
error.add(nodeIdRequired);
210219

211-
reply.setChildElement(error);
220+
response.setChildElement(error);
212221

213-
outQueue.put(reply);
222+
outQueue.put(response);
214223
}
215224

216225
private void makeRemoteRequest() throws InterruptedException {

src/test/java/org/buddycloud/channelserver/db/jdbc/JDBCNodeStoreTest.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ public class JDBCNodeStoreTest {
7777
private static final String TEST_SERVER1_HOSTNAME = "server1";
7878
private static final String TEST_SERVER2_HOSTNAME = "server2";
7979

80+
private static final String UNKNOWN_NODE = "/user/unknown@example.com/posts";
81+
8082
private static final HashMap<String, String> TEST_SERVER1_NODE1_CONF = new HashMap<String, String>() {
8183
{
8284
put("config1", "Value of config1");
@@ -1322,16 +1324,18 @@ public void testGetNodeItemsWithPaging() throws Exception {
13221324
dbTester.loadData("node_1");
13231325

13241326
long start = System.currentTimeMillis();
1325-
1327+
13261328
NodeItem[] items = new NodeItem[20];
1327-
1329+
13281330
for (int i = 0; i < 20; i++) {
1329-
items[i] = new NodeItemImpl(TEST_SERVER1_NODE1_ID, String
1330-
.valueOf(i), new Date(start + i * 10), "payload" + String.valueOf(i));
1331+
items[i] = new NodeItemImpl(TEST_SERVER1_NODE1_ID,
1332+
String.valueOf(i), new Date(start + i * 10), "payload"
1333+
+ String.valueOf(i));
13311334
store.addNodeItem(items[i]);
13321335
}
13331336

1334-
CloseableIterator<NodeItem> result = store.getNodeItems(TEST_SERVER1_NODE1_ID, "15", 3);
1337+
CloseableIterator<NodeItem> result = store.getNodeItems(
1338+
TEST_SERVER1_NODE1_ID, "15", 3);
13351339

13361340
assertEquals("Incorrect node item returned", items[14], result.next());
13371341
assertEquals("Incorrect node item returned", items[13], result.next());
@@ -1565,7 +1569,7 @@ public void testGetRecentItemsCanBePaged() throws Exception {
15651569
store.addUserSubscription(new NodeSubscriptionImpl(
15661570
TEST_SERVER1_NODE2_ID, TEST_SERVER1_USER1_JID,
15671571
Subscriptions.subscribed));
1568-
1572+
15691573
long now = System.currentTimeMillis();
15701574

15711575
NodeItem nodeItem1 = new NodeItemImpl(TEST_SERVER1_NODE1_ID, "123",
@@ -1585,7 +1589,9 @@ public void testGetRecentItemsCanBePaged() throws Exception {
15851589
store.addNodeItem(nodeItem4);
15861590

15871591
CloseableIterator<NodeItem> items = store.getRecentItems(
1588-
TEST_SERVER1_USER1_JID, since, -1, 2, new GlobalItemIDImpl(TEST_SERVER1_CHANNELS_JID, TEST_SERVER1_NODE1_ID, "124"), null);
1592+
TEST_SERVER1_USER1_JID, since, -1, 2,
1593+
new GlobalItemIDImpl(TEST_SERVER1_CHANNELS_JID,
1594+
TEST_SERVER1_NODE1_ID, "124"), null);
15891595

15901596
assertSameNodeItem(items.next(), nodeItem3);
15911597
assertSameNodeItem(items.next(), nodeItem1);
@@ -1646,7 +1652,7 @@ public void testCanPageGetRecentItemsUsingResultSetManagement()
16461652
dbTester.loadData("node_1");
16471653

16481654
Date since = new Date();
1649-
1655+
16501656
Thread.sleep(10);
16511657

16521658
store.addRemoteNode(TEST_SERVER1_NODE2_ID);
@@ -1659,8 +1665,9 @@ public void testCanPageGetRecentItemsUsingResultSetManagement()
16591665
store.addNodeItem(new NodeItemImpl(TEST_SERVER1_NODE1_ID, String
16601666
.valueOf(i), new Date(), "payload" + String.valueOf(i)));
16611667
}
1662-
1663-
GlobalItemID itemID = new GlobalItemIDImpl(TEST_SERVER1_CHANNELS_JID, TEST_SERVER1_NODE1_ID, "15");
1668+
1669+
GlobalItemID itemID = new GlobalItemIDImpl(TEST_SERVER1_CHANNELS_JID,
1670+
TEST_SERVER1_NODE1_ID, "15");
16641671

16651672
CloseableIterator<NodeItem> items = store.getRecentItems(
16661673
TEST_SERVER1_USER1_JID, since, -1, 10, itemID, null);
@@ -1785,8 +1792,8 @@ public void testCanGetItemThread() throws Exception {
17851792
@Test
17861793
public void testCanGetItemThreadWithResultSetManagement() throws Exception {
17871794
dbTester.loadData("node_1");
1788-
NodeItem testItemParent = new NodeItemImpl(TEST_SERVER1_NODE1_ID, "a100",
1789-
new Date(100), "<entry>payload parent</entry>");
1795+
NodeItem testItemParent = new NodeItemImpl(TEST_SERVER1_NODE1_ID,
1796+
"a100", new Date(100), "<entry>payload parent</entry>");
17901797
NodeItem testItem1 = new NodeItemImpl(TEST_SERVER1_NODE1_ID, "a6",
17911798
new Date(20), "<entry>payload</entry>", "a100");
17921799
NodeItem testItem2 = new NodeItemImpl(TEST_SERVER1_NODE1_ID, "a7",
@@ -2319,16 +2326,35 @@ private void assertSameNodeItem(NodeItem actual, NodeItem expected) {
23192326
assertEquals(expected.getPayload(), actual.getPayload());
23202327
assertEquals(expected.getInReplyTo(), actual.getInReplyTo());
23212328
}
2322-
2329+
23232330
@Test
23242331
public void testSelectNodeThreads() throws Exception {
23252332
dbTester.loadData("node_1");
2326-
assertEquals(5, store.getNodeThreads(TEST_SERVER1_NODE1_ID, null, 10).size());
2333+
assertEquals(5, store.getNodeThreads(TEST_SERVER1_NODE1_ID, null, 10)
2334+
.size());
23272335
}
2328-
2336+
23292337
@Test
23302338
public void testCountNodeThreads() throws Exception {
23312339
dbTester.loadData("node_1");
23322340
assertEquals(5, store.countNodeThreads(TEST_SERVER1_NODE1_ID));
23332341
}
2342+
2343+
@Test
2344+
public void testNoNodeOwnersReturnsEmptyList() throws Exception {
2345+
dbTester.loadData("node_1");
2346+
assertEquals(0, store.getNodeOwners(UNKNOWN_NODE).size());
2347+
}
2348+
2349+
@Test
2350+
public void testNodeOwnersReturnsExpectedList() throws Exception {
2351+
dbTester.loadData("node_1");
2352+
2353+
store.addUserSubscription(new NodeSubscriptionImpl(TEST_SERVER1_NODE1_ID, TEST_SERVER1_USER2_JID, Subscriptions.subscribed));
2354+
store.setUserAffiliation(TEST_SERVER1_NODE1_ID, TEST_SERVER1_USER2_JID, Affiliations.owner);
2355+
2356+
assertEquals(2, store.getNodeOwners(TEST_SERVER1_NODE1_ID).size());
2357+
assertEquals(TEST_SERVER1_USER1_JID, store.getNodeOwners(TEST_SERVER1_NODE1_ID).get(0));
2358+
assertEquals(TEST_SERVER1_USER2_JID, store.getNodeOwners(TEST_SERVER1_NODE1_ID).get(1));
2359+
}
23342360
}

0 commit comments

Comments
 (0)