Implement banning

This commit is contained in:
Niels Andriesse 2021-01-21 14:49:50 +11:00
parent 3e5baca72d
commit 18c646987a
6 changed files with 74 additions and 30 deletions

View File

@ -1528,15 +1528,17 @@ typedef enum : NSUInteger {
[self showDetailViewForViewItem:conversationViewItem];
}
- (void)report:(id<ConversationViewItem>)conversationViewItem
- (void)banUser:(id<ConversationViewItem>)conversationViewItem
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Report?" message:@"If the message is found to violate the Session Public Chat code of conduct it will be removed." preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
uint64_t messageID = 0;
if ([conversationViewItem.interaction isKindOfClass:TSMessage.class]) {
messageID = ((TSMessage *)conversationViewItem.interaction).openGroupServerMessageID;
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Ban This User?" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSString* publicKey;
if ([conversationViewItem.interaction isKindOfClass:TSIncomingMessage.class]) {
publicKey = ((TSIncomingMessage *)conversationViewItem.interaction).authorId;
}
[SNOpenGroupAPI reportMessageWithID:messageID inChannel:1 onServer:@"https://chat.getsession.org"];
SNOpenGroup *openGroup = [LKStorage.shared getOpenGroupForThreadID:self.thread.uniqueId];
if (openGroup == nil) return;
[[SNOpenGroupAPI banPublicKey:publicKey fromServer:openGroup.server] retainUntilComplete];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];

View File

@ -67,6 +67,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
@property (nonatomic, readonly) BOOL isGroupThread;
@property (nonatomic, readonly) BOOL userCanDeleteGroupMessage;
@property (nonatomic, readonly) BOOL userHasModerationPermission;
@property (nonatomic, readonly) BOOL hasBodyText;

View File

@ -1184,6 +1184,23 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
}
}
- (BOOL)userHasModerationPermission
{
if (!self.isGroupThread) return false;
TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread;
// Make sure it's an open group message
TSMessage *message = (TSMessage *)self.interaction;
if (!message.isOpenGroupMessage) return false;
// Ensure we have the details needed to contact the server
SNOpenGroup *openGroup = [LKStorage.shared getOpenGroupForThreadID:groupThread.uniqueId];
if (openGroup == nil) return false;
// Check that we're a moderator
return [SNOpenGroupAPI isUserModerator:[SNGeneralUtilities getUserPublicKey] forChannel:openGroup.channel onServer:openGroup.server];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -6,7 +6,7 @@ import Foundation
@objc
protocol MessageActionsDelegate: class {
func report(_ conversationViewItem: ConversationViewItem)
func banUser(_ conversationViewItem: ConversationViewItem)
func messageActionsShowDetailsForItem(_ conversationViewItem: ConversationViewItem)
func messageActionsReplyToItem(_ conversationViewItem: ConversationViewItem)
func copyPublicKey(for conversationViewItem: ConversationViewItem)
@ -45,14 +45,6 @@ struct MessageActionBuilder {
block: { [weak delegate] _ in delegate?.messageActionsShowDetailsForItem(conversationViewItem) }
)
}
static func report(_ conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
return MenuAction(image: #imageLiteral(resourceName: "Flag"),
title: NSLocalizedString("Report", comment: ""),
subtitle: nil,
block: { [weak delegate] _ in delegate?.report(conversationViewItem) }
)
}
static func deleteMessage(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
return MenuAction(image: #imageLiteral(resourceName: "ic_trash"),
@ -61,6 +53,14 @@ struct MessageActionBuilder {
block: { _ in conversationViewItem.deleteAction() }
)
}
static func banUser(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
return MenuAction(image: #imageLiteral(resourceName: "ic_block"),
title: "Ban User",
subtitle: nil,
block: { [weak delegate] _ in delegate?.banUser(conversationViewItem) }
)
}
static func copyMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
return MenuAction(image: #imageLiteral(resourceName: "ic_copy"),
@ -108,10 +108,9 @@ class ConversationViewItemActions: NSObject {
actions.append(deleteAction)
}
if isGroup && conversationViewItem.interaction.thread.name() == "Loki Public Chat"
|| conversationViewItem.interaction.thread.name() == "Session Public Chat" {
let reportAction = MessageActionBuilder.report(conversationViewItem, delegate: delegate)
actions.append(reportAction)
if isGroup && conversationViewItem.interaction is TSIncomingMessage && conversationViewItem.userHasModerationPermission {
let banAction = MessageActionBuilder.banUser(conversationViewItem: conversationViewItem, delegate: delegate)
actions.append(banAction)
}
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
@ -152,10 +151,9 @@ class ConversationViewItemActions: NSObject {
actions.append(deleteAction)
}
if isGroup && conversationViewItem.interaction.thread.name() == "Loki Public Chat"
|| conversationViewItem.interaction.thread.name() == "Session Public Chat" {
let reportAction = MessageActionBuilder.report(conversationViewItem, delegate: delegate)
actions.append(reportAction)
if isGroup && conversationViewItem.interaction is TSIncomingMessage && conversationViewItem.userHasModerationPermission {
let banAction = MessageActionBuilder.banUser(conversationViewItem: conversationViewItem, delegate: delegate)
actions.append(banAction)
}
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
@ -185,10 +183,9 @@ class ConversationViewItemActions: NSObject {
actions.append(deleteAction)
}
if isGroup && conversationViewItem.interaction.thread.name() == "Loki Public Chat"
|| conversationViewItem.interaction.thread.name() == "Session Public Chat" {
let reportAction = MessageActionBuilder.report(conversationViewItem, delegate: delegate)
actions.append(reportAction)
if isGroup && conversationViewItem.interaction is TSIncomingMessage && conversationViewItem.userHasModerationPermission {
let banAction = MessageActionBuilder.banUser(conversationViewItem: conversationViewItem, delegate: delegate)
actions.append(banAction)
}
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)

View File

@ -205,7 +205,7 @@ public final class OpenGroupAPI : DotNetAPI {
}
let lastDeletionServerID = storage.getLastDeletionServerID(for: channel, on: server)
if serverID > (lastDeletionServerID ?? 0) {
storage.write { transaction in
storage.writeSync { transaction in
storage.setLastDeletionServerID(for: channel, on: server, to: serverID, using: transaction)
}
}
@ -238,6 +238,33 @@ public final class OpenGroupAPI : DotNetAPI {
}.handlingInvalidAuthTokenIfNeeded(for: server)
}
}
// MARK: Banning
@objc(banPublicKey:fromServer:)
public static func objc_ban(_ publicKey: String, from server: String) -> AnyPromise {
return AnyPromise.from(ban(publicKey, from: server))
}
public static func ban(_ publicKey: String, from server: String) -> Promise<Void> {
SNLog("Banning user with ID: \(publicKey) from server: \(server).")
return attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global(qos: .default)) {
getOpenGroupServerPublicKey(for: server).then(on: DispatchQueue.global(qos: .default)) { serverPublicKey in
getAuthToken(for: server).then(on: DispatchQueue.global(qos: .default)) { token -> Promise<Void> in
let url = URL(string: "\(server)/loki/v1/moderation/blacklist/@\(publicKey)")!
let request = TSRequest(url: url, method: "POST", parameters: [:])
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
let promise = OnionRequestAPI.sendOnionRequest(request, to: server, using: serverPublicKey, isJSONRequired: false)
promise.done(on: DispatchQueue.global(qos: .default)) { _ -> Void in
SNLog("Banned user with ID: \(publicKey) from server: \(server).")
}
promise.catch(on: DispatchQueue.main) { error in
print(error)
}
return promise.map { _ in }
}
}.handlingInvalidAuthTokenIfNeeded(for: server)
}
}
// MARK: Display Name & Profile Picture
public static func getDisplayNames(for channel: UInt64, on server: String) -> Promise<Void> {

View File

@ -19,7 +19,7 @@ public final class OpenGroupPoller : NSObject {
// MARK: Settings
private let pollForNewMessagesInterval: TimeInterval = 4
private let pollForDeletedMessagesInterval: TimeInterval = 60
private let pollForDeletedMessagesInterval: TimeInterval = 30
private let pollForModeratorsInterval: TimeInterval = 10 * 60
// MARK: Lifecycle