mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-17 21:31:57 +01:00
Updates NIP-56 to the newest tag structure for Quartz
This commit is contained in:
parent
5766bb1887
commit
b017e03728
@ -149,6 +149,7 @@ import com.vitorpamplona.quartz.nip51Lists.GeneralListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.MuteListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetup
|
||||
@ -1616,18 +1617,18 @@ class Account(
|
||||
|
||||
suspend fun report(
|
||||
note: Note,
|
||||
type: ReportEvent.ReportType,
|
||||
type: ReportType,
|
||||
content: String = "",
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
if (note.hasReacted(userProfile(), "⚠️")) {
|
||||
// has already liked this note
|
||||
if (note.hasReport(userProfile(), type)) {
|
||||
// has already reported this note
|
||||
return
|
||||
}
|
||||
|
||||
note.event?.let {
|
||||
ReportEvent.create(it, type, signer, content) {
|
||||
signer.sign(ReportEvent.build(it, type)) {
|
||||
Amethyst.instance.client.send(it)
|
||||
LocalCache.justConsume(it, null)
|
||||
}
|
||||
@ -1636,7 +1637,7 @@ class Account(
|
||||
|
||||
suspend fun report(
|
||||
user: User,
|
||||
type: ReportEvent.ReportType,
|
||||
type: ReportType,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
@ -1645,7 +1646,8 @@ class Account(
|
||||
return
|
||||
}
|
||||
|
||||
ReportEvent.create(user.pubkeyHex, type, signer) {
|
||||
val template = ReportEvent.build(user.pubkeyHex, type)
|
||||
signer.sign(template) {
|
||||
Amethyst.instance.client.send(it)
|
||||
LocalCache.justConsume(it, null)
|
||||
}
|
||||
|
@ -695,8 +695,8 @@ object LocalCache {
|
||||
event.originalPost().mapNotNull { checkGetOrCreateNote(it) } +
|
||||
event.taggedAddresses().map { getOrCreateAddressableNote(it) }
|
||||
is ReportEvent ->
|
||||
event.reportedPost().mapNotNull { checkGetOrCreateNote(it.key) } +
|
||||
event.taggedAddresses().map { getOrCreateAddressableNote(it) }
|
||||
event.reportedPost().mapNotNull { checkGetOrCreateNote(it.eventId) } +
|
||||
event.reportedAddresses().map { getOrCreateAddressableNote(it.address) }
|
||||
is ChannelMessageEvent ->
|
||||
event
|
||||
.tagsWithoutCitations()
|
||||
@ -1342,7 +1342,7 @@ object LocalCache {
|
||||
// Already processed this event.
|
||||
if (note.event != null) return
|
||||
|
||||
val mentions = event.reportedAuthor().mapNotNull { checkGetOrCreateUser(it.key) }
|
||||
val mentions = event.reportedAuthor().mapNotNull { checkGetOrCreateUser(it.pubkey) }
|
||||
val repliesTo = computeReplyTo(event)
|
||||
|
||||
note.loadEvent(event, author, repliesTo)
|
||||
@ -2218,7 +2218,7 @@ object LocalCache {
|
||||
}
|
||||
if (noteEvent is ReportEvent) {
|
||||
noteEvent.reportedAuthor().mapNotNull {
|
||||
val author = getUserIfExists(it.key)
|
||||
val author = getUserIfExists(it.pubkey)
|
||||
author?.removeReport(note)
|
||||
author?.clearEOSE()
|
||||
}
|
||||
|
@ -68,6 +68,8 @@ import com.vitorpamplona.quartz.nip47WalletConnect.LnZapPaymentResponseEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent
|
||||
@ -717,6 +719,15 @@ open class Note(
|
||||
)
|
||||
}
|
||||
|
||||
fun hasReport(
|
||||
loggedIn: User,
|
||||
type: ReportType,
|
||||
): Boolean =
|
||||
reports[loggedIn]?.firstOrNull {
|
||||
it.event is ReportEvent &&
|
||||
(it.event as ReportEvent).reportedAuthor().any { it.type == type }
|
||||
} != null
|
||||
|
||||
fun hasPledgeBy(user: User): Boolean =
|
||||
replies
|
||||
.filter { it.event?.hasAdditionalReward() ?: false }
|
||||
|
@ -46,6 +46,7 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
|
||||
import com.vitorpamplona.quartz.nip19Bech32.toNpub
|
||||
import com.vitorpamplona.quartz.nip51Lists.BookmarkListEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||
import com.vitorpamplona.quartz.utils.DualCase
|
||||
@ -357,11 +358,11 @@ class User(
|
||||
|
||||
fun hasReport(
|
||||
loggedIn: User,
|
||||
type: ReportEvent.ReportType,
|
||||
type: ReportType,
|
||||
): Boolean =
|
||||
reports[loggedIn]?.firstOrNull {
|
||||
it.event is ReportEvent &&
|
||||
(it.event as ReportEvent).reportedAuthor().any { it.reportType == type }
|
||||
(it.event as ReportEvent).reportedAuthor().any { it.type == type }
|
||||
} != null
|
||||
|
||||
fun containsAny(hiddenWordsCase: List<DualCase>): Boolean {
|
||||
|
@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
|
||||
@Composable
|
||||
fun RenderReport(
|
||||
@ -52,16 +53,17 @@ fun RenderReport(
|
||||
val reportType =
|
||||
base
|
||||
.map {
|
||||
when (it.reportType) {
|
||||
ReportEvent.ReportType.EXPLICIT -> stringRes(R.string.explicit_content)
|
||||
ReportEvent.ReportType.NUDITY -> stringRes(R.string.nudity)
|
||||
ReportEvent.ReportType.PROFANITY -> stringRes(R.string.profanity_hateful_speech)
|
||||
ReportEvent.ReportType.SPAM -> stringRes(R.string.spam)
|
||||
ReportEvent.ReportType.IMPERSONATION -> stringRes(R.string.impersonation)
|
||||
ReportEvent.ReportType.ILLEGAL -> stringRes(R.string.illegal_behavior)
|
||||
ReportEvent.ReportType.MALWARE -> stringRes(R.string.malware)
|
||||
ReportEvent.ReportType.MOD -> stringRes(R.string.mod)
|
||||
ReportEvent.ReportType.OTHER -> stringRes(R.string.other)
|
||||
when (it.type) {
|
||||
ReportType.EXPLICIT -> stringRes(R.string.explicit_content)
|
||||
ReportType.NUDITY -> stringRes(R.string.nudity)
|
||||
ReportType.PROFANITY -> stringRes(R.string.profanity_hateful_speech)
|
||||
ReportType.SPAM -> stringRes(R.string.spam)
|
||||
ReportType.IMPERSONATION -> stringRes(R.string.impersonation)
|
||||
ReportType.ILLEGAL -> stringRes(R.string.illegal_behavior)
|
||||
ReportType.MALWARE -> stringRes(R.string.malware)
|
||||
ReportType.MOD -> stringRes(R.string.mod)
|
||||
ReportType.OTHER -> stringRes(R.string.other)
|
||||
null -> stringRes(R.string.other)
|
||||
}
|
||||
}.toSet()
|
||||
.joinToString(", ")
|
||||
|
@ -102,7 +102,7 @@ import com.vitorpamplona.quartz.nip37Drafts.DraftEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.Response
|
||||
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.GeneralListEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||
@ -741,7 +741,7 @@ class AccountViewModel(
|
||||
|
||||
fun report(
|
||||
note: Note,
|
||||
type: ReportEvent.ReportType,
|
||||
type: ReportType,
|
||||
content: String = "",
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) { account.report(note, type, content) }
|
||||
@ -749,7 +749,7 @@ class AccountViewModel(
|
||||
|
||||
fun report(
|
||||
user: User,
|
||||
type: ReportEvent.ReportType,
|
||||
type: ReportType,
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
account.report(user, type)
|
||||
|
@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.WarningColor
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -75,13 +75,13 @@ fun ReportNoteDialog(
|
||||
) {
|
||||
val reportTypes =
|
||||
listOf(
|
||||
Pair(ReportEvent.ReportType.SPAM, stringRes(R.string.report_dialog_spam)),
|
||||
Pair(ReportEvent.ReportType.PROFANITY, stringRes(R.string.report_dialog_profanity)),
|
||||
Pair(ReportEvent.ReportType.IMPERSONATION, stringRes(R.string.report_dialog_impersonation)),
|
||||
Pair(ReportEvent.ReportType.NUDITY, stringRes(R.string.report_dialog_nudity)),
|
||||
Pair(ReportEvent.ReportType.ILLEGAL, stringRes(R.string.report_dialog_illegal)),
|
||||
Pair(ReportEvent.ReportType.MALWARE, stringRes(R.string.report_malware)),
|
||||
Pair(ReportEvent.ReportType.MOD, stringRes(R.string.report_mod)),
|
||||
Pair(ReportType.SPAM, stringRes(R.string.report_dialog_spam)),
|
||||
Pair(ReportType.PROFANITY, stringRes(R.string.report_dialog_profanity)),
|
||||
Pair(ReportType.IMPERSONATION, stringRes(R.string.report_dialog_impersonation)),
|
||||
Pair(ReportType.NUDITY, stringRes(R.string.report_dialog_nudity)),
|
||||
Pair(ReportType.ILLEGAL, stringRes(R.string.report_dialog_illegal)),
|
||||
Pair(ReportType.MALWARE, stringRes(R.string.report_malware)),
|
||||
Pair(ReportType.MOD, stringRes(R.string.report_mod)),
|
||||
)
|
||||
|
||||
val reasonOptions = remember { reportTypes.map { TitleExplainer(it.second) }.toImmutableList() }
|
||||
|
@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.ui.note.externalLinkForUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
|
||||
@Composable
|
||||
fun UserProfileDropDownMenu(
|
||||
@ -108,42 +108,42 @@ fun UserProfileDropDownMenu(
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(id = R.string.report_spam_scam)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.SPAM)
|
||||
accountViewModel.report(user, ReportType.SPAM)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.report_hateful_speech)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.PROFANITY)
|
||||
accountViewModel.report(user, ReportType.PROFANITY)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(id = R.string.report_impersonation)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION)
|
||||
accountViewModel.report(user, ReportType.IMPERSONATION)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.report_nudity_porn)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.NUDITY)
|
||||
accountViewModel.report(user, ReportType.NUDITY)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(id = R.string.report_illegal_behaviour)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL)
|
||||
accountViewModel.report(user, ReportType.ILLEGAL)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(id = R.string.report_malware)) },
|
||||
onClick = {
|
||||
accountViewModel.report(user, ReportEvent.ReportType.MALWARE)
|
||||
accountViewModel.report(user, ReportType.MALWARE)
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
|
@ -25,14 +25,15 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.DefaultReportTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAddressTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAuthorTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedEventTag
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable data class ReportedKey(
|
||||
val key: String,
|
||||
val reportType: ReportEvent.ReportType,
|
||||
)
|
||||
|
||||
// NIP 56 event.
|
||||
@Immutable
|
||||
class ReportEvent(
|
||||
@ -43,48 +44,35 @@ class ReportEvent(
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
@Transient
|
||||
private var defaultType: ReportType? = null
|
||||
|
||||
private fun defaultReportTypes() = tags.mapNotNull(DefaultReportTag::parse)
|
||||
|
||||
private fun defaultReportType(): ReportType {
|
||||
defaultType?.let { return it }
|
||||
|
||||
// Works with old and new structures for report.
|
||||
var reportType =
|
||||
tags
|
||||
.filter { it.firstOrNull() == "report" }
|
||||
.mapNotNull { it.getOrNull(1) }
|
||||
.map { ReportType.valueOf(it.uppercase()) }
|
||||
.firstOrNull()
|
||||
var reportType = defaultReportTypes().firstOrNull()
|
||||
if (reportType == null) {
|
||||
reportType =
|
||||
tags.mapNotNull { it.getOrNull(2) }.map { ReportType.valueOf(it.uppercase()) }.firstOrNull()
|
||||
reportType = tags.mapNotNull { it.getOrNull(2) }.map { ReportType.parseOrNull(it, emptyArray()) }.firstOrNull()
|
||||
}
|
||||
if (reportType == null) {
|
||||
reportType = ReportType.SPAM
|
||||
}
|
||||
defaultType = reportType
|
||||
return reportType
|
||||
}
|
||||
|
||||
fun reportedPost() =
|
||||
tags
|
||||
.filter { it.size > 1 && it[0] == "e" }
|
||||
.map {
|
||||
ReportedKey(
|
||||
it[1],
|
||||
it.getOrNull(2)?.uppercase()?.let { it1 -> ReportType.valueOf(it1) }
|
||||
?: defaultReportType(),
|
||||
)
|
||||
}
|
||||
fun reportedPost() = tags.mapNotNull { ReportedEventTag.parse(it, defaultReportType()) }
|
||||
|
||||
fun reportedAuthor() =
|
||||
tags
|
||||
.filter { it.size > 1 && it[0] == "p" }
|
||||
.map {
|
||||
ReportedKey(
|
||||
it[1],
|
||||
it.getOrNull(2)?.uppercase()?.let { it1 -> ReportType.valueOf(it1) }
|
||||
?: defaultReportType(),
|
||||
)
|
||||
}
|
||||
fun reportedAddresses() = tags.mapNotNull { ReportedAddressTag.parse(it, defaultReportType()) }
|
||||
|
||||
fun reportedAuthor() = tags.mapNotNull { ReportedAuthorTag.parse(it, defaultReportType()) }
|
||||
|
||||
companion object {
|
||||
const val KIND = 1984
|
||||
const val ALT_PREFIX = "Report for "
|
||||
|
||||
fun create(
|
||||
reportedPost: Event,
|
||||
@ -108,32 +96,27 @@ class ReportEvent(
|
||||
signer.sign(createdAt, KIND, tags, content, onReady)
|
||||
}
|
||||
|
||||
fun create(
|
||||
reportedUser: String,
|
||||
fun build(
|
||||
reportedPost: Event,
|
||||
type: ReportType,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
onReady: (ReportEvent) -> Unit,
|
||||
) {
|
||||
val content = ""
|
||||
) = eventTemplate(KIND, "", createdAt) {
|
||||
alt(ALT_PREFIX + type.code)
|
||||
event(reportedPost.id, type)
|
||||
user(reportedPost.pubKey, type)
|
||||
|
||||
val reportAuthorTag = arrayOf("p", reportedUser, type.name.lowercase())
|
||||
val alt = AltTag.assemble("Report for ${type.name}")
|
||||
|
||||
val tags: Array<Array<String>> = arrayOf(reportAuthorTag, alt)
|
||||
signer.sign(createdAt, KIND, tags, content, onReady)
|
||||
if (reportedPost is AddressableEvent) {
|
||||
address(reportedPost.address(), type)
|
||||
}
|
||||
}
|
||||
|
||||
enum class ReportType {
|
||||
EXPLICIT, // Not used anymore.
|
||||
ILLEGAL,
|
||||
SPAM,
|
||||
IMPERSONATION,
|
||||
NUDITY,
|
||||
PROFANITY,
|
||||
MALWARE,
|
||||
MOD,
|
||||
OTHER,
|
||||
fun build(
|
||||
reportedUser: HexKey,
|
||||
type: ReportType,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
) = eventTemplate(KIND, "", createdAt) {
|
||||
alt(ALT_PREFIX + type.code)
|
||||
user(reportedUser, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports
|
||||
|
||||
import android.util.Log
|
||||
|
||||
enum class ReportType(
|
||||
val code: String,
|
||||
) {
|
||||
EXPLICIT("explicit"), // Not used anymore.
|
||||
ILLEGAL("illegal"),
|
||||
SPAM("spam"),
|
||||
IMPERSONATION("impersonation"),
|
||||
NUDITY("nudity"),
|
||||
PROFANITY("profanity"),
|
||||
MALWARE("malware"),
|
||||
MOD("mod"),
|
||||
OTHER("other"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun parseOrNull(
|
||||
code: String,
|
||||
tag: Array<String>,
|
||||
): ReportType? =
|
||||
when (code) {
|
||||
EXPLICIT.code -> EXPLICIT
|
||||
ILLEGAL.code -> ILLEGAL
|
||||
SPAM.code -> SPAM
|
||||
IMPERSONATION.code -> IMPERSONATION
|
||||
NUDITY.code -> NUDITY
|
||||
PROFANITY.code -> PROFANITY
|
||||
MALWARE.code -> MALWARE
|
||||
MOD.code -> MOD
|
||||
"MOD" -> MOD
|
||||
OTHER.code -> OTHER
|
||||
else -> {
|
||||
Log.w("ReportedEventTag", "Report type not supported: $code ${tag.joinToString(", ")}")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.HashSha256Tag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAddressTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAuthorTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ReportedEventTag
|
||||
import com.vitorpamplona.quartz.nip56Reports.tags.ServerTag
|
||||
|
||||
fun TagArrayBuilder<ReportEvent>.event(
|
||||
eventId: HexKey,
|
||||
reportType: ReportType,
|
||||
) = addUnique(ReportedEventTag.assemble(eventId, reportType))
|
||||
|
||||
fun TagArrayBuilder<ReportEvent>.address(
|
||||
address: Address,
|
||||
reportType: ReportType,
|
||||
) = addUnique(ReportedAddressTag.assemble(address, reportType))
|
||||
|
||||
fun TagArrayBuilder<ReportEvent>.user(
|
||||
pubkey: HexKey,
|
||||
reportType: ReportType,
|
||||
) = addUnique(ReportedAuthorTag.assemble(pubkey, reportType))
|
||||
|
||||
fun TagArrayBuilder<ReportEvent>.hash(
|
||||
x: String,
|
||||
reportType: ReportType,
|
||||
) = addUnique(HashSha256Tag.assemble(x, reportType))
|
||||
|
||||
fun TagArrayBuilder<ReportEvent>.server(url: String) = addUnique(ServerTag.assemble(url))
|
@ -18,10 +18,10 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip70ProtectedEvts
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
class ProtectedTagSerializer {
|
||||
companion object {
|
||||
fun toTagArray(reason: String = "") = arrayOf("-", reason)
|
||||
}
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
|
||||
interface BaseReportTag {
|
||||
val type: ReportType?
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
@Immutable
|
||||
class DefaultReportTag {
|
||||
companion object {
|
||||
const val TAG_NAME = "report"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(tag: Array<String>): ReportType? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
|
||||
return ReportType.parseOrNull(tag[1], tag)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(type: ReportType? = null) = arrayOfNotNull(TAG_NAME, type?.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class HashSha256Tag(
|
||||
val hash: HexKey,
|
||||
override val type: ReportType? = null,
|
||||
) : BaseReportTag {
|
||||
companion object {
|
||||
const val TAG_NAME = "x"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(
|
||||
tag: Array<String>,
|
||||
defaultReportType: ReportType? = null,
|
||||
): HashSha256Tag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val type = tag.getOrNull(2)?.let { ReportType.parseOrNull(it, tag) } ?: defaultReportType
|
||||
return HashSha256Tag(tag[1], type)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(
|
||||
hash: String,
|
||||
type: ReportType? = null,
|
||||
) = arrayOfNotNull(TAG_NAME, hash, type?.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
@Immutable
|
||||
class ReportedAddressTag(
|
||||
val address: Address,
|
||||
override val type: ReportType? = null,
|
||||
) : BaseReportTag {
|
||||
fun toTagArray() = assemble(address, type)
|
||||
|
||||
companion object {
|
||||
const val TAG_NAME = "a"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(
|
||||
tag: Array<String>,
|
||||
defaultReportType: ReportType? = null,
|
||||
): ReportedAddressTag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
|
||||
val address = Address.parse(tag[1])
|
||||
|
||||
ensure(address != null) { return null }
|
||||
|
||||
val type =
|
||||
if (tag.size == 2) {
|
||||
defaultReportType
|
||||
} else if (tag.size == 3) {
|
||||
ReportType.parseOrNull(tag[2], tag) ?: defaultReportType
|
||||
} else {
|
||||
ReportType.parseOrNull(tag[3], tag) ?: defaultReportType
|
||||
}
|
||||
|
||||
return ReportedAddressTag(address, type)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(
|
||||
address: Address,
|
||||
type: ReportType? = null,
|
||||
) = arrayOfNotNull(TAG_NAME, address.toValue(), type?.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
@Immutable
|
||||
class ReportedAuthorTag(
|
||||
val pubkey: HexKey,
|
||||
override val type: ReportType? = null,
|
||||
) : BaseReportTag {
|
||||
fun toTagArray() = assemble(pubkey, type)
|
||||
|
||||
companion object {
|
||||
const val TAG_NAME = "p"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(
|
||||
tag: Array<String>,
|
||||
defaultReportType: ReportType? = null,
|
||||
): ReportedAuthorTag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val type =
|
||||
if (tag.size == 2) {
|
||||
defaultReportType
|
||||
} else if (tag.size == 3) {
|
||||
ReportType.parseOrNull(tag[2], tag) ?: defaultReportType
|
||||
} else {
|
||||
ReportType.parseOrNull(tag[3], tag) ?: defaultReportType
|
||||
}
|
||||
|
||||
return ReportedAuthorTag(tag[1], type)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(
|
||||
pubkey: HexKey,
|
||||
type: ReportType? = null,
|
||||
) = arrayOfNotNull(TAG_NAME, pubkey, type?.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
@Immutable
|
||||
class ReportedEventTag(
|
||||
val eventId: HexKey,
|
||||
override val type: ReportType? = null,
|
||||
) : BaseReportTag {
|
||||
fun toTagArray() = assemble(eventId, type)
|
||||
|
||||
companion object {
|
||||
const val TAG_NAME = "e"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(
|
||||
tag: Array<String>,
|
||||
defaultReportType: ReportType? = null,
|
||||
): ReportedEventTag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val type =
|
||||
if (tag.size == 2) {
|
||||
defaultReportType
|
||||
} else if (tag.size == 3) {
|
||||
ReportType.parseOrNull(tag[2], tag) ?: defaultReportType
|
||||
} else {
|
||||
ReportType.parseOrNull(tag[3], tag) ?: defaultReportType
|
||||
}
|
||||
|
||||
return ReportedEventTag(tag[1], type)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(
|
||||
eventId: HexKey,
|
||||
type: ReportType? = null,
|
||||
) = arrayOfNotNull(TAG_NAME, eventId, type?.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip56Reports.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class ServerTag {
|
||||
companion object {
|
||||
const val TAG_NAME = "server"
|
||||
|
||||
@JvmStatic
|
||||
fun parse(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(url: String) = arrayOf(TAG_NAME, url)
|
||||
|
||||
@JvmStatic
|
||||
fun assemble(urls: List<String>) = urls.map { assemble(it) }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user