mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 23:29:52 +01:00
Allow messages to be deleted.
This commit is contained in:
@@ -63,6 +63,12 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
void addTransportKeys(ContactId c, TransportKeys k) throws DbException;
|
void addTransportKeys(ContactId c, TransportKeys k) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the message with the given ID. The message ID and any other
|
||||||
|
* associated data are not deleted.
|
||||||
|
*/
|
||||||
|
void deleteMessage(MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an acknowledgement for the given contact, or null if there are
|
* Returns an acknowledgement for the given contact, or null if there are
|
||||||
* no messages to acknowledge.
|
* no messages to acknowledge.
|
||||||
|
|||||||
@@ -215,6 +215,16 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
int countOfferedMessages(T txn, ContactId c) throws DbException;
|
int countOfferedMessages(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the message with the given ID. Unlike
|
||||||
|
* {@link #removeMessage(Object, MessageId)}, the message ID and any other
|
||||||
|
* associated data are not deleted, and
|
||||||
|
* {@link #containsMessage(Object, MessageId)} will continue to return true.
|
||||||
|
* <p>
|
||||||
|
* Locking: write.
|
||||||
|
*/
|
||||||
|
void deleteMessage(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -293,6 +293,23 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteMessage(MessageId m) throws DbException {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
if (!db.containsMessage(txn, m))
|
||||||
|
throw new NoSuchMessageException();
|
||||||
|
db.deleteMessage(txn, m);
|
||||||
|
} catch (DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Ack generateAck(ContactId c, int maxMessages) throws DbException {
|
public Ack generateAck(ContactId c, int maxMessages) throws DbException {
|
||||||
Collection<MessageId> ids;
|
Collection<MessageId> ids;
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " valid INT NOT NULL,"
|
+ " valid INT NOT NULL,"
|
||||||
+ " shared BOOLEAN NOT NULL,"
|
+ " shared BOOLEAN NOT NULL,"
|
||||||
+ " length INT NOT NULL,"
|
+ " length INT NOT NULL,"
|
||||||
+ " raw BLOB NOT NULL,"
|
+ " raw BLOB," // Null if message has been deleted
|
||||||
+ " PRIMARY KEY (messageId),"
|
+ " PRIMARY KEY (messageId),"
|
||||||
+ " FOREIGN KEY (groupId)"
|
+ " FOREIGN KEY (groupId)"
|
||||||
+ " REFERENCES groups (groupId)"
|
+ " REFERENCES groups (groupId)"
|
||||||
@@ -933,6 +933,22 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteMessage(Connection txn, MessageId m) throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "UPDATE messages SET raw = NULL WHERE messageId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, m.getBytes());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if (affected < 0) throw new DbStateException();
|
||||||
|
if (affected > 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Contact getContact(Connection txn, ContactId c) throws DbException {
|
public Contact getContact(Connection txn, ContactId c) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -1308,7 +1324,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND gv.contactId = s.contactId"
|
+ " AND gv.contactId = s.contactId"
|
||||||
+ " WHERE gv.contactId = ?"
|
+ " WHERE gv.contactId = ?"
|
||||||
+ " AND valid = ? AND shared = TRUE"
|
+ " AND valid = ? AND shared = TRUE AND raw IS NOT NULL"
|
||||||
+ " AND seen = FALSE AND requested = FALSE"
|
+ " AND seen = FALSE AND requested = FALSE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC LIMIT ?";
|
+ " ORDER BY timestamp DESC LIMIT ?";
|
||||||
@@ -1367,7 +1383,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND gv.contactId = s.contactId"
|
+ " AND gv.contactId = s.contactId"
|
||||||
+ " WHERE gv.contactId = ?"
|
+ " WHERE gv.contactId = ?"
|
||||||
+ " AND valid = ? AND shared = TRUE"
|
+ " AND valid = ? AND shared = TRUE AND raw IS NOT NULL"
|
||||||
+ " AND seen = FALSE"
|
+ " AND seen = FALSE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
@@ -1401,7 +1417,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
String sql = "SELECT messageId FROM messages AS m"
|
String sql = "SELECT messageId FROM messages AS m"
|
||||||
+ " JOIN groups AS g ON m.groupId = g.groupId"
|
+ " JOIN groups AS g ON m.groupId = g.groupId"
|
||||||
+ " WHERE valid = ? AND clientId = ?";
|
+ " WHERE valid = ? AND clientId = ? AND raw IS NOT NULL";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, UNKNOWN.getValue());
|
ps.setInt(1, UNKNOWN.getValue());
|
||||||
ps.setBytes(2, c.getBytes());
|
ps.setBytes(2, c.getBytes());
|
||||||
@@ -1453,7 +1469,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND gv.contactId = s.contactId"
|
+ " AND gv.contactId = s.contactId"
|
||||||
+ " WHERE gv.contactId = ?"
|
+ " WHERE gv.contactId = ?"
|
||||||
+ " AND valid = ? AND shared = TRUE"
|
+ " AND valid = ? AND shared = TRUE AND raw IS NOT NULL"
|
||||||
+ " AND seen = FALSE AND requested = TRUE"
|
+ " AND seen = FALSE AND requested = TRUE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ import static org.junit.Assert.assertArrayEquals;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
@@ -1071,6 +1073,51 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteMessage() throws Exception {
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, a group and a message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
db.addMessage(txn, message, VALID, true);
|
||||||
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
|
// The message should be visible to the contact
|
||||||
|
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
||||||
|
|
||||||
|
// The message should be sendable
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// The raw message should not be null
|
||||||
|
assertNotNull(db.getRawMessage(txn, messageId));
|
||||||
|
|
||||||
|
// Delete the message
|
||||||
|
db.deleteMessage(txn, messageId);
|
||||||
|
|
||||||
|
// The message should be visible to the contact
|
||||||
|
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
||||||
|
|
||||||
|
// The message should not be sendable
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// The raw message should be null
|
||||||
|
assertNull(db.getRawMessage(txn, messageId));
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExceptionHandling() throws Exception {
|
public void testExceptionHandling() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user