Updating reports to the latest spec
This commit is contained in:
@@ -408,8 +408,8 @@ object LocalCache {
|
|||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
val mentions = event.reportedAuthor.mapNotNull { checkGetOrCreateUser(it) }
|
val mentions = event.reportedAuthor.mapNotNull { checkGetOrCreateUser(it.key) }
|
||||||
val repliesTo = event.reportedPost.mapNotNull { checkGetOrCreateNote(it) }
|
val repliesTo = event.reportedPost.mapNotNull { checkGetOrCreateNote(it.key) }
|
||||||
|
|
||||||
note.loadEvent(event, author, mentions, repliesTo)
|
note.loadEvent(event, author, mentions, repliesTo)
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ class User(val pubkeyHex: String) {
|
|||||||
|
|
||||||
fun hasReport(loggedIn: User, type: ReportEvent.ReportType): Boolean {
|
fun hasReport(loggedIn: User, type: ReportEvent.ReportType): Boolean {
|
||||||
return reports[loggedIn]?.firstOrNull() {
|
return reports[loggedIn]?.firstOrNull() {
|
||||||
it.event is ReportEvent && (it.event as ReportEvent).reportType.contains(type)
|
it.event is ReportEvent && (it.event as ReportEvent).reportedAuthor.any { it.reportType == type }
|
||||||
} != null
|
} != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import nostr.postr.Utils
|
|||||||
import nostr.postr.events.Event
|
import nostr.postr.events.Event
|
||||||
import nostr.postr.toHex
|
import nostr.postr.toHex
|
||||||
|
|
||||||
|
data class ReportedKey(val key: String, val reportType: ReportEvent.ReportType)
|
||||||
|
|
||||||
// NIP 56 event.
|
// NIP 56 event.
|
||||||
class ReportEvent (
|
class ReportEvent (
|
||||||
id: ByteArray,
|
id: ByteArray,
|
||||||
@@ -15,14 +17,37 @@ class ReportEvent (
|
|||||||
sig: ByteArray
|
sig: ByteArray
|
||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
|
|
||||||
@Transient val reportType: List<ReportType>
|
@Transient val reportedPost: List<ReportedKey>
|
||||||
@Transient val reportedPost: List<String>
|
@Transient val reportedAuthor: List<ReportedKey>
|
||||||
@Transient val reportedAuthor: List<String>
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
reportType = tags.filter { it.firstOrNull() == "report" }.mapNotNull { it.getOrNull(1) }.map { ReportType.valueOf(it.toUpperCase()) }
|
// Works with old and new structures for report.
|
||||||
reportedPost = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
|
||||||
reportedAuthor = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
var reportType = tags.filter { it.firstOrNull() == "report" }.mapNotNull { it.getOrNull(1) }.map { ReportType.valueOf(it.toUpperCase()) }.firstOrNull()
|
||||||
|
if (reportType == null) {
|
||||||
|
reportType = tags.mapNotNull { it.getOrNull(2) }.map { ReportType.valueOf(it.toUpperCase()) }.firstOrNull()
|
||||||
|
}
|
||||||
|
if (reportType == null) {
|
||||||
|
reportType = ReportType.SPAM
|
||||||
|
}
|
||||||
|
|
||||||
|
reportedPost = tags
|
||||||
|
.filter { it.firstOrNull() == "e" && it.getOrNull(1) != null }
|
||||||
|
.map {
|
||||||
|
ReportedKey(
|
||||||
|
it[1],
|
||||||
|
it.getOrNull(2)?.toUpperCase()?.let { it1 -> ReportType.valueOf(it1) }?: reportType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
reportedAuthor = tags
|
||||||
|
.filter { it.firstOrNull() == "p" && it.getOrNull(1) != null }
|
||||||
|
.map {
|
||||||
|
ReportedKey(
|
||||||
|
it[1],
|
||||||
|
it.getOrNull(2)?.toUpperCase()?.let { it1 -> ReportType.valueOf(it1) }?: reportType
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -31,12 +56,11 @@ class ReportEvent (
|
|||||||
fun create(reportedPost: Event, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent {
|
fun create(reportedPost: Event, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent {
|
||||||
val content = ""
|
val content = ""
|
||||||
|
|
||||||
val reportTypeTag = listOf("report", type.name.toLowerCase())
|
val reportPostTag = listOf("e", reportedPost.id.toHex(), type.name.toLowerCase())
|
||||||
val reportPostTag = listOf("e", reportedPost.id.toHex())
|
val reportAuthorTag = listOf("p", reportedPost.pubKey.toHex(), type.name.toLowerCase())
|
||||||
val reportAuthorTag = listOf("p", reportedPost.pubKey.toHex())
|
|
||||||
|
|
||||||
val pubKey = Utils.pubkeyCreate(privateKey)
|
val pubKey = Utils.pubkeyCreate(privateKey)
|
||||||
val tags:List<List<String>> = listOf(reportTypeTag, reportPostTag, reportAuthorTag)
|
val tags:List<List<String>> = listOf(reportPostTag, reportAuthorTag)
|
||||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||||
val sig = Utils.sign(id, privateKey)
|
val sig = Utils.sign(id, privateKey)
|
||||||
return ReportEvent(id, pubKey, createdAt, tags, content, sig)
|
return ReportEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
@@ -45,11 +69,10 @@ class ReportEvent (
|
|||||||
fun create(reportedUser: String, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent {
|
fun create(reportedUser: String, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent {
|
||||||
val content = ""
|
val content = ""
|
||||||
|
|
||||||
val reportTypeTag = listOf("report", type.name.toLowerCase())
|
val reportAuthorTag = listOf("p", reportedUser, type.name.toLowerCase())
|
||||||
val reportAuthorTag = listOf("p", reportedUser)
|
|
||||||
|
|
||||||
val pubKey = Utils.pubkeyCreate(privateKey)
|
val pubKey = Utils.pubkeyCreate(privateKey)
|
||||||
val tags:List<List<String>> = listOf(reportTypeTag, reportAuthorTag)
|
val tags:List<List<String>> = listOf(reportAuthorTag)
|
||||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||||
val sig = Utils.sign(id, privateKey)
|
val sig = Utils.sign(id, privateKey)
|
||||||
return ReportEvent(id, pubKey, createdAt, tags, content, sig)
|
return ReportEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
@@ -57,9 +80,11 @@ class ReportEvent (
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class ReportType() {
|
enum class ReportType() {
|
||||||
EXPLICIT,
|
EXPLICIT, // Not used anymore.
|
||||||
ILLEGAL,
|
ILLEGAL,
|
||||||
SPAM,
|
SPAM,
|
||||||
IMPERSONATION
|
IMPERSONATION,
|
||||||
|
NUDITY,
|
||||||
|
PROFANITY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,22 +315,24 @@ fun NoteCompose(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (noteEvent is ReportEvent) {
|
} else if (noteEvent is ReportEvent) {
|
||||||
val reportType = noteEvent.reportType.map {
|
val reportType = (noteEvent.reportedPost + noteEvent.reportedAuthor).map {
|
||||||
when (it) {
|
when (it.reportType) {
|
||||||
ReportEvent.ReportType.EXPLICIT -> "Explicit Content"
|
ReportEvent.ReportType.EXPLICIT -> "Explicit Content"
|
||||||
|
ReportEvent.ReportType.NUDITY -> "Nudity"
|
||||||
|
ReportEvent.ReportType.PROFANITY -> "Profanity / Hateful speech"
|
||||||
ReportEvent.ReportType.SPAM -> "Spam"
|
ReportEvent.ReportType.SPAM -> "Spam"
|
||||||
ReportEvent.ReportType.IMPERSONATION -> "Impersonation"
|
ReportEvent.ReportType.IMPERSONATION -> "Impersonation"
|
||||||
ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior"
|
ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior"
|
||||||
else -> "Unknown"
|
else -> "Unknown"
|
||||||
}
|
}
|
||||||
}.joinToString(", ")
|
}.toSet().joinToString(", ")
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = reportType
|
text = reportType
|
||||||
)
|
)
|
||||||
|
|
||||||
Divider(
|
Divider(
|
||||||
modifier = Modifier.padding(top = 10.dp),
|
modifier = Modifier.padding(top = 40.dp),
|
||||||
thickness = 0.25.dp
|
thickness = 0.25.dp
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -602,6 +604,13 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
|||||||
}) {
|
}) {
|
||||||
Text("Report Spam / Scam")
|
Text("Report Spam / Scam")
|
||||||
}
|
}
|
||||||
|
DropdownMenuItem(onClick = {
|
||||||
|
accountViewModel.report(note, ReportEvent.ReportType.PROFANITY);
|
||||||
|
note.author?.let { accountViewModel.hide(it, context) }
|
||||||
|
onDismiss()
|
||||||
|
}) {
|
||||||
|
Text("Report Hateful Speech")
|
||||||
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.IMPERSONATION);
|
accountViewModel.report(note, ReportEvent.ReportType.IMPERSONATION);
|
||||||
note.author?.let { accountViewModel.hide(it, context) }
|
note.author?.let { accountViewModel.hide(it, context) }
|
||||||
@@ -610,11 +619,11 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
|||||||
Text("Report Impersonation")
|
Text("Report Impersonation")
|
||||||
}
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.EXPLICIT);
|
accountViewModel.report(note, ReportEvent.ReportType.NUDITY);
|
||||||
note.author?.let { accountViewModel.hide(it, context) }
|
note.author?.let { accountViewModel.hide(it, context) }
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}) {
|
}) {
|
||||||
Text("Report Explicit Content")
|
Text("Report Nudity")
|
||||||
}
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL);
|
accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL);
|
||||||
|
|||||||
@@ -828,6 +828,13 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
|
|||||||
}) {
|
}) {
|
||||||
Text("Report Spam / Scam")
|
Text("Report Spam / Scam")
|
||||||
}
|
}
|
||||||
|
DropdownMenuItem(onClick = {
|
||||||
|
accountViewModel.report(user, ReportEvent.ReportType.PROFANITY);
|
||||||
|
user.let { accountViewModel.hide(it, context) }
|
||||||
|
onDismiss()
|
||||||
|
}) {
|
||||||
|
Text("Report Hateful speech")
|
||||||
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION);
|
accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION);
|
||||||
user.let { accountViewModel.hide(it, context) }
|
user.let { accountViewModel.hide(it, context) }
|
||||||
@@ -836,11 +843,11 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
|
|||||||
Text("Report Impersonation")
|
Text("Report Impersonation")
|
||||||
}
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(user, ReportEvent.ReportType.EXPLICIT);
|
accountViewModel.report(user, ReportEvent.ReportType.NUDITY);
|
||||||
user.let { accountViewModel.hide(it, context) }
|
user.let { accountViewModel.hide(it, context) }
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}) {
|
}) {
|
||||||
Text("Report Explicit Content")
|
Text("Report Nudity / Porn")
|
||||||
}
|
}
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL);
|
accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL);
|
||||||
|
|||||||
Reference in New Issue
Block a user