fix: NPE in highlighting messages for OGv2, deletion and moderation working

This commit is contained in:
jubb 2021-04-28 14:46:50 +10:00
parent 7f0962b3d4
commit 9d4a2d1505
3 changed files with 72 additions and 36 deletions

View File

@ -409,11 +409,11 @@ public class ConversationFragment extends Fragment
}
menu.findItem(R.id.menu_context_copy_public_key).setVisible(selectedMessageCount == 1 && !areAllSentByUser);
menu.findItem(R.id.menu_context_reply).setVisible(selectedMessageCount == 1);
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(requireContext());
boolean userCanModerate =
(isPublicChat &&
(OpenGroupAPI.isUserModerator(userHexEncodedPublicKey, publicChat.getChannel(), publicChat.getServer())
|| OpenGroupAPIV2.isUserModerator(userHexEncodedPublicKey, openGroupChat.getRoom(), openGroupChat.getServer()))
((publicChat != null && OpenGroupAPI.isUserModerator(userHexEncodedPublicKey, publicChat.getChannel(), publicChat.getServer()))
|| (openGroupChat != null && OpenGroupAPIV2.isUserModerator(userHexEncodedPublicKey, openGroupChat.getRoom(), openGroupChat.getServer())))
);
boolean isDeleteOptionVisible = !isPublicChat || (areAllSentByUser || userCanModerate);
// allow banning if moderating a public chat and only one user's messages are selected
@ -515,6 +515,7 @@ public class ConversationFragment extends Fragment
builder.setCancelable(true);
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
@Override
@ -525,7 +526,7 @@ public class ConversationFragment extends Fragment
{
@Override
protected Void doInBackground(MessageRecord... messageRecords) {
if (publicChat != null) {
if (publicChat != null || openGroupChat != null) {
ArrayList<Long> serverIDs = new ArrayList<>();
ArrayList<Long> ignoredMessages = new ArrayList<>();
ArrayList<Long> failedMessages = new ArrayList<>();
@ -561,7 +562,29 @@ public class ConversationFragment extends Fragment
Log.w("Loki", "Couldn't delete message due to error: " + e.toString() + ".");
return null;
});
}
} else if (openGroupChat != null) {
for (Long serverId : serverIDs) {
OpenGroupAPIV2
.deleteMessage(serverId, openGroupChat.getRoom(), openGroupChat.getServer())
.success(l -> {
for (MessageRecord messageRecord : messageRecords) {
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id);
if (serverID != null && serverID.equals(serverId)) {
if (messageRecord.isMms()) {
DatabaseFactory.getMmsDatabase(getContext()).delete(messageRecord.getId());
} else {
DatabaseFactory.getSmsDatabase(getContext()).deleteMessage(messageRecord.getId());
}
break;
}
}
return null;
}).fail(e->{
Log.e("Loki", "Couldn't delete message due to error",e);
return null;
});
}
}
} else {
for (MessageRecord messageRecord : messageRecords) {
if (messageRecord.isMms()) {
@ -597,7 +620,8 @@ public class ConversationFragment extends Fragment
builder.setTitle(R.string.ConversationFragment_ban_selected_user);
builder.setCancelable(true);
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
final PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
final OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
builder.setPositiveButton(R.string.ban, (dialog, which) -> {
ConversationAdapter chatAdapter = getListAdapter();
@ -616,9 +640,19 @@ public class ConversationFragment extends Fragment
Log.d("Loki", "User banned");
return Unit.INSTANCE;
}).fail(e -> {
Log.d("Loki", "Couldn't ban user due to error: " + e.toString() + ".");
Log.e("Loki", "Couldn't ban user due to error",e);
return null;
});
} else if (openGroupChat != null) {
OpenGroupAPIV2
.ban(userPublicKey, openGroupChat.getRoom(), openGroupChat.getServer())
.success(l -> {
Log.d("Loki", "User banned");
return Unit.INSTANCE;
}).fail(e -> {
Log.e("Loki", "Failed to ban user",e);
return null;
});
} else {
Log.d("Loki", "Tried to ban user from a non-public chat");
}

View File

@ -580,7 +580,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val mmsDb = DatabaseFactory.getMmsDatabase(context)
val cursor = mmsDb.getMessage(mmsId)
val reader = mmsDb.readerFor(cursor)
return reader.next.threadId
val threadId = reader.next.threadId
cursor.close()
return threadId
}
override fun getSessionRequestSentTimestamp(publicKey: String): Long? {

View File

@ -1,5 +1,7 @@
package org.session.libsession.messaging.opengroups
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.annotation.JsonNaming
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@ -36,8 +38,6 @@ object OpenGroupAPIV2 {
const val DEFAULT_SERVER = "https://sog.ibolpap.finance"
private const val DEFAULT_SERVER_PUBLIC_KEY = "b464aa186530c97d6bcf663a3a3b7465a5f782beaa67c83bee99468824b4aa10"
// https://sog.ibolpap.finance/main?public_key=b464aa186530c97d6bcf663a3a3b7465a5f782beaa67c83bee99468824b4aa10
val defaultRooms = MutableSharedFlow<List<DefaultGroup>>(replay = 1)
private val sharedContext = Kovenant.createContext()
@ -64,6 +64,13 @@ object OpenGroupAPIV2 {
val imageID: String?
)
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy::class)
data class CompactPollRequest(val roomId: String,
val authToken: String,
val fromDeletionServerId: Long?,
val fromMessageServerId: Long?
)
data class CompactPollResult(val messages: List<OpenGroupMessageV2>,
val deletions: List<Long>,
val moderators: List<String>
@ -83,7 +90,9 @@ object OpenGroupAPIV2 {
val useOnionRouting: Boolean = true
)
private fun createBody(parameters: Any): RequestBody {
private fun createBody(parameters: Any?): RequestBody? {
if (parameters == null) return null
val parametersAsJSON = JsonUtil.toJson(parameters)
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
}
@ -111,9 +120,9 @@ object OpenGroupAPIV2 {
}
when (request.verb) {
GET -> requestBuilder.get()
PUT -> requestBuilder.put(createBody(request.parameters!!))
POST -> requestBuilder.post(createBody(request.parameters!!))
DELETE -> requestBuilder.delete(createBody(request.parameters!!))
PUT -> requestBuilder.put(createBody(request.parameters))
POST -> requestBuilder.post(createBody(request.parameters))
DELETE -> requestBuilder.delete(createBody(request.parameters))
}
if (!request.room.isNullOrEmpty()) {
@ -145,21 +154,6 @@ object OpenGroupAPIV2 {
}
}
fun downloadOpenGroupProfilePicture(imageUrl: String): ByteArray? {
Log.d("Loki", "Downloading open group profile picture from \"$imageUrl\".")
val outputStream = ByteArrayOutputStream()
try {
DownloadUtilities.downloadFile(outputStream, imageUrl, FileServerAPI.maxFileSize, null)
Log.d("Loki", "Open group profile picture was successfully loaded from \"$imageUrl\"")
return outputStream.toByteArray()
} catch (e: Exception) {
Log.d("Loki", "Failed to download open group profile picture from \"$imageUrl\" due to error: $e.")
return null
} finally {
outputStream.close()
}
}
fun downloadOpenGroupProfilePicture(roomID: String, server: String): Promise<ByteArray, Exception> {
val request = Request(verb = GET, room = roomID, server = server, endpoint = "rooms/$roomID/image", isAuthRequired = false)
return send(request).map(sharedContext) { json ->
@ -291,8 +285,9 @@ object OpenGroupAPIV2 {
// endregion
// region Message Deletion
@JvmStatic
fun deleteMessage(serverID: Long, room: String, server: String): Promise<Unit, Exception> {
val request = Request(verb = DELETE, room = room, server = server, endpoint = "message/$serverID")
val request = Request(verb = DELETE, room = room, server = server, endpoint = "messages/$serverID")
return send(request).map(sharedContext) {
Log.d("Loki", "Deleted server message")
}
@ -306,9 +301,9 @@ object OpenGroupAPIV2 {
}
val request = Request(verb = GET, room = room, server = server, endpoint = "deleted_messages", queryParameters = queryParameters)
return send(request).map(sharedContext) { json ->
@Suppress("UNCHECKED_CAST") val serverIDs = json["ids"] as? List<Long>
@Suppress("UNCHECKED_CAST") val serverIDs = (json["ids"] as? List<Int>)?.map { it.toLong() }
?: throw Error.PARSING_FAILED
val lastMessageServerId = storage.getLastMessageServerId(room, server) ?: 0
val lastMessageServerId = storage.getLastDeletionServerId(room, server) ?: 0
val serverID = serverIDs.maxOrNull() ?: 0
if (serverID > lastMessageServerId) {
storage.setLastDeletionServerId(room, server, serverID)
@ -330,6 +325,7 @@ object OpenGroupAPIV2 {
}
}
@JvmStatic
fun ban(publicKey: String, room: String, server: String): Promise<Unit, Exception> {
val parameters = mapOf("public_key" to publicKey)
val request = Request(verb = POST, room = room, server = server, endpoint = "block_list", parameters = parameters)
@ -351,8 +347,11 @@ object OpenGroupAPIV2 {
// endregion
// region General
// fun getCompactPoll(): Promise<CompactPollResult, Exception> {
// val request = Request()
// fun getCompactPoll(rooms: List<String>, server: String): Promise<Map<String,CompactPollResult>, Exception> {
// val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false)
//
// // build a request for all rooms
//
// }
fun getDefaultRoomsIfNeeded(): Promise<List<DefaultGroup>, Exception> {
@ -362,8 +361,9 @@ object OpenGroupAPIV2 {
val earlyGroups = groups.map { group ->
DefaultGroup(group.id, group.name, null)
}
defaultRooms.replayCache.firstOrNull()?.let { groups ->
if (groups.none { it.image?.isNotEmpty() == true}) {
// see if we have any cached rooms, and if they already have images, don't overwrite with early non-image results
defaultRooms.replayCache.firstOrNull()?.let { replayed ->
if (replayed.none { it.image?.isNotEmpty() == true}) {
defaultRooms.tryEmit(earlyGroups)
}
}