Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst: New Crowdin translations by GitHub Action feat: implement NIP-32 Labeling protocol in quartz
This commit is contained in:
@@ -71,7 +71,7 @@ height="70">](https://github.com/vitorpamplona/amethyst/releases)
|
|||||||
- [ ] Relay-based Groups (NIP-29)
|
- [ ] Relay-based Groups (NIP-29)
|
||||||
- [x] Custom Emoji (NIP-30)
|
- [x] Custom Emoji (NIP-30)
|
||||||
- [x] Event alt descriptors (NIP-31)
|
- [x] Event alt descriptors (NIP-31)
|
||||||
- [ ] Labeling (NIP-32)
|
- [x] Labeling (NIP-32)
|
||||||
- [x] Git Stuff (NIP-34)
|
- [x] Git Stuff (NIP-34)
|
||||||
- [x] Torrents (NIP-35)
|
- [x] Torrents (NIP-35)
|
||||||
- [x] Sensitive Content (NIP-36)
|
- [x] Sensitive Content (NIP-36)
|
||||||
|
|||||||
@@ -387,6 +387,9 @@
|
|||||||
<string name="add_to_public_bookmarks">Hozzáadás a nyilvános könyvjelzőkhöz</string>
|
<string name="add_to_public_bookmarks">Hozzáadás a nyilvános könyvjelzőkhöz</string>
|
||||||
<string name="remove_from_private_bookmarks">Törlés a privát könyvjelzőkből</string>
|
<string name="remove_from_private_bookmarks">Törlés a privát könyvjelzőkből</string>
|
||||||
<string name="remove_from_public_bookmarks">Törlés a nyilvános könyvjelzőkből</string>
|
<string name="remove_from_public_bookmarks">Törlés a nyilvános könyvjelzőkből</string>
|
||||||
|
<string name="pinned_notes">Rögzített bejegyzések</string>
|
||||||
|
<string name="pin_to_profile">Rögzítés a profilhoz</string>
|
||||||
|
<string name="unpin_from_profile">Rögzítés megszüntetése a profiltól</string>
|
||||||
<string name="bookmark_lists">Könyvjelzőlisták</string>
|
<string name="bookmark_lists">Könyvjelzőlisták</string>
|
||||||
<string name="bookmark_list_icon_label">Könyvjelzőlista ikonja</string>
|
<string name="bookmark_list_icon_label">Könyvjelzőlista ikonja</string>
|
||||||
<string name="bookmark_list_creation_screen_title">Új könyvjelzőlista</string>
|
<string name="bookmark_list_creation_screen_title">Új könyvjelzőlista</string>
|
||||||
@@ -719,6 +722,17 @@
|
|||||||
<string name="terms_and_conditions">Általános szerződési feltételek</string>
|
<string name="terms_and_conditions">Általános szerződési feltételek</string>
|
||||||
<string name="not_available_acronym">Nem érhető el</string>
|
<string name="not_available_acronym">Nem érhető el</string>
|
||||||
<string name="relay_error_messages">Hibák és megjegyzések ettől az átjátszótól</string>
|
<string name="relay_error_messages">Hibák és megjegyzések ettől az átjátszótól</string>
|
||||||
|
<string name="relay_monitor_reports">Átjátszófigyelési jelentések</string>
|
||||||
|
<string name="relay_monitor_rtt_open">Megnyitás</string>
|
||||||
|
<string name="relay_monitor_rtt_read">Olvasás </string>
|
||||||
|
<string name="relay_monitor_rtt_write">Írás</string>
|
||||||
|
<string name="relay_monitor_rtt">RTT (válaszidő)</string>
|
||||||
|
<string name="relay_monitor_network">Hálózat</string>
|
||||||
|
<string name="relay_monitor_relay_type">Típus</string>
|
||||||
|
<string name="relay_monitor_supported_nips">Támogatott NIP-ek</string>
|
||||||
|
<string name="relay_monitor_requirements">Követelmények</string>
|
||||||
|
<string name="relay_monitor_last_check">Utoljára ellenőrizve</string>
|
||||||
|
<string name="relay_monitor_ms">%1$d ms</string>
|
||||||
<string name="relay_active_subscriptions">Aktív előfizetések</string>
|
<string name="relay_active_subscriptions">Aktív előfizetések</string>
|
||||||
<string name="relay_active_outbox">Függőben lévő kimenő események</string>
|
<string name="relay_active_outbox">Függőben lévő kimenő események</string>
|
||||||
<string name="relay_req_subscriptions">Szükséges előfizetések (%1$d)</string>
|
<string name="relay_req_subscriptions">Szükséges előfizetések (%1$d)</string>
|
||||||
@@ -1655,8 +1669,12 @@
|
|||||||
<string name="event_sync_no_events">nincsenek események</string>
|
<string name="event_sync_no_events">nincsenek események</string>
|
||||||
<string name="ots_explorer_settings">Bitcoin felfedező (OTS)</string>
|
<string name="ots_explorer_settings">Bitcoin felfedező (OTS)</string>
|
||||||
<string name="events">események</string>
|
<string name="events">események</string>
|
||||||
|
<string name="events_from_you">Öntől származó események</string>
|
||||||
|
<string name="events_to_you">Önnek szóló események</string>
|
||||||
|
<string name="searchable_events">kereshető események</string>
|
||||||
<string name="dms">Közvetlen üzenetek</string>
|
<string name="dms">Közvetlen üzenetek</string>
|
||||||
<string name="profiles">profilok</string>
|
<string name="profiles">profilok</string>
|
||||||
|
<string name="relay_settings_lower2">kimenő átjátszók listája</string>
|
||||||
<string name="relay_settings_lower">átjátszóbeállítások</string>
|
<string name="relay_settings_lower">átjátszóbeállítások</string>
|
||||||
<string name="last_seen">Utoljára %1$s ezelőtt látták</string>
|
<string name="last_seen">Utoljára %1$s ezelőtt látták</string>
|
||||||
<string name="event_sync_less_than_until"><%1$s</string>
|
<string name="event_sync_less_than_until"><%1$s</string>
|
||||||
@@ -1721,5 +1739,94 @@
|
|||||||
<string name="web_bookmark_delete_confirm">Törli ezt a webes könyvjelzőt?</string>
|
<string name="web_bookmark_delete_confirm">Törli ezt a webes könyvjelzőt?</string>
|
||||||
<string name="web_bookmark_open_url">Webcím megnyitása</string>
|
<string name="web_bookmark_open_url">Webcím megnyitása</string>
|
||||||
<!-- NIP-75 Zap Goals -->
|
<!-- NIP-75 Zap Goals -->
|
||||||
|
<string name="goal_closed">Ez a gyűjtési cél lezárult</string>
|
||||||
|
<string name="goal_progress">%1$s gyűlt össze a(z) %2$s satoshis célból</string>
|
||||||
|
<string name="goal_amount_label">Célösszeg (satoshiban)</string>
|
||||||
|
<string name="goal_amount_placeholder">100 000</string>
|
||||||
|
<string name="goal_description_label">Cél leírása, bemutatása</string>
|
||||||
|
<string name="goal_description_placeholder">Mire gyűjt adományokat?</string>
|
||||||
|
<string name="goal_summary_label">Rövid összefoglalás</string>
|
||||||
|
<string name="goal_summary_placeholder">Rövid leírás, amely megjelenik az előnézetekben</string>
|
||||||
|
<string name="goal_image_label">Kép webcíme (nem kötelező)</string>
|
||||||
|
<string name="goal_image_placeholder">https://pelda.hu/kep.jpg</string>
|
||||||
|
<string name="goal_website_label">Weboldal webcíme (nem kötelező)</string>
|
||||||
|
<string name="goal_website_placeholder">https://pelda.hu</string>
|
||||||
|
<string name="goal_deadline_label">Határidő (nem kötelező)</string>
|
||||||
|
<string name="goal_set_deadline">Határidő beállítása</string>
|
||||||
|
<string name="new_goal">Új cél</string>
|
||||||
|
<string name="goal_create">Cél létrehozása</string>
|
||||||
|
<string name="request_to_vanish">Törlési kérés</string>
|
||||||
|
<string name="request_to_vanish_description">Kérés az átjátszóknak, hogy a kiválasztott dátumig visszamenőleg véglegesen töröljék az Ön összes adatát. Ez a művelet a NIP-62 szabványon alapul, és egyes joghatóságokban jogilag kötelező érvényű.</string>
|
||||||
|
<string name="vanish_select_relay">Egy átjátszó kiválasztása</string>
|
||||||
|
<string name="vanish_target_relay">Célátjátszók</string>
|
||||||
|
<string name="vanish_all_relays">Összes átjátszó</string>
|
||||||
|
<string name="vanish_all_relays_warning">Ezzel az ÖSSZES átjátszót arra kéri, hogy a kiválasztott dátumig töröljön mindent, ami az Ön kulcsához kapcsolódik. Ezt az eseményt a lehető legszélesebb körben közzétesszük. Ez a művelet nem vonható vissza.</string>
|
||||||
|
<string name="vanish_date_label">Adatok törlése eddig:</string>
|
||||||
|
<string name="vanish_date_explainer">Az ezen időpont előtt létrehozott összes esemény törlését kérelmezi a kiválasztott átjátszótól.</string>
|
||||||
|
<string name="vanish_reason_label">Indoklás (nem kötelező)</string>
|
||||||
|
<string name="vanish_reason_placeholder">Indoklás vagy jogi nyilatkozat az átjátszó üzemeltetőjének</string>
|
||||||
|
<string name="vanish_send_request">Törlési kérés küldése</string>
|
||||||
|
<string name="vanish_confirm_title">Törlési kérés megerősítése</string>
|
||||||
|
<string name="vanish_confirm_single_relay">Ön arra kéri a(z) %1$s átjátszót, hogy a kiválasztott dátum előtt létrehozott összes adatát végleges törölje. Ez a művelet nem vonható vissza.</string>
|
||||||
|
<string name="vanish_confirm_all_relays">Ön arra kéri az ÖSSZES átjátszót, hogy a kiválasztott dátum előtt létrehozott összes adatát végleges törölje. Ez a művelet közvetítve lesz mindenhová és nem vonható vissza.</string>
|
||||||
|
<string name="vanish_request_sent">Törlési kérés elküldve</string>
|
||||||
|
<string name="vanish_select_date">Dátum kiválasztása</string>
|
||||||
|
<string name="vanish_select_time">Idő kiválasztása</string>
|
||||||
|
<string name="vanish_events_title">Törlési előzmények</string>
|
||||||
|
<string name="vanish_events_refresh">Frissítés</string>
|
||||||
|
<string name="vanish_events_description">Ezek az Ön korábbi, a kapcsolódott átjátszókon talált törlési kérései. Az ezekben az eseményekben megjelölt átjátszók nem tárolhatják az Ön adatait az esemény dátuma előtti időszakból.</string>
|
||||||
|
<string name="vanish_events_empty">Nem találhatók törlési kérések</string>
|
||||||
|
<string name="vanish_events_empty_hint">Ön még nem küldött törlési kérést.</string>
|
||||||
|
<string name="vanish_target_relays_label">Célátjátszók</string>
|
||||||
|
<string name="vanish_all_relays_compliance_hint">Ez a kérés érinti az összes átjátszót. Használja a törlési kérés menüjét az egyes átjátszók megfelelőségének teszteléséhez.</string>
|
||||||
|
<string name="vanish_test_button">Tesztelés</string>
|
||||||
|
<string name="vanish_compliant">Megfelelő</string>
|
||||||
|
<string name="vanish_non_compliant">Nem megfelelő</string>
|
||||||
|
<string name="vanish_test_error">Hiba</string>
|
||||||
|
<string name="vanish_history">Törlési előzmények</string>
|
||||||
<!-- NIP-86 Relay Management -->
|
<!-- NIP-86 Relay Management -->
|
||||||
|
<string name="relay_management_title">%1$s kezelése</string>
|
||||||
|
<string name="relay_management_loading">Átjátszókezelési funkciók betöltése…</string>
|
||||||
|
<string name="relay_management_error">Nem sikerült kapcsolódni az átjátszókezeléshez</string>
|
||||||
|
<string name="relay_management_no_methods">Nem érhető el kezelési eljárás</string>
|
||||||
|
<string name="relay_management_dismiss">Elvetés</string>
|
||||||
|
<string name="relay_management_tab_pubkeys">Felhasználók</string>
|
||||||
|
<string name="relay_management_tab_events">Események</string>
|
||||||
|
<string name="relay_management_tab_kinds">Típusok</string>
|
||||||
|
<string name="relay_management_tab_ips">IP-címek</string>
|
||||||
|
<string name="relay_management_tab_settings">Beállítások</string>
|
||||||
|
<string name="relay_management_banned_pubkeys">Letiltott felhasználók</string>
|
||||||
|
<string name="relay_management_no_banned_pubkeys">Nincsenek letiltott felhasználók</string>
|
||||||
|
<string name="relay_management_allowed_pubkeys">Engedélyezett felhasználók</string>
|
||||||
|
<string name="relay_management_no_allowed_pubkeys">Nincsenek engedélyezett felhasználók</string>
|
||||||
|
<string name="relay_management_moderation_queue">Moderációs várólista</string>
|
||||||
|
<string name="relay_management_no_moderation_events">Nincsenek moderálandó események</string>
|
||||||
|
<string name="relay_management_banned_events">Letiltott események</string>
|
||||||
|
<string name="relay_management_no_banned_events">Nincsenek letiltott események</string>
|
||||||
|
<string name="relay_management_allowed_kinds">Engedélyezett típusok</string>
|
||||||
|
<string name="relay_management_no_allowed_kinds">Nincsenek engedélyezett típusok</string>
|
||||||
|
<string name="relay_management_blocked_ips">Letiltott IP-címek</string>
|
||||||
|
<string name="relay_management_no_blocked_ips">Nincsenek letiltott IP-címek</string>
|
||||||
|
<string name="relay_management_add">Hozzáadás</string>
|
||||||
|
<string name="relay_management_remove">Eltávolítás</string>
|
||||||
|
<string name="relay_management_allow">Engedélyezés</string>
|
||||||
|
<string name="relay_management_ban">Letiltás</string>
|
||||||
|
<string name="relay_management_ban_pubkey">Nyilvános kulcs letiltása</string>
|
||||||
|
<string name="relay_management_allow_pubkey">Nyilvános kulcs engedélyezése</string>
|
||||||
|
<string name="relay_management_ban_event">Esemény letiltása</string>
|
||||||
|
<string name="relay_management_allow_kind">Típus engedélyezése</string>
|
||||||
|
<string name="relay_management_block_ip">IP-cím letiltása</string>
|
||||||
|
<string name="relay_management_pubkey_hex">Nyilvános kulcs (hex)</string>
|
||||||
|
<string name="relay_management_event_id_hex">Eseményazonosító (hex)</string>
|
||||||
|
<string name="relay_management_kind_number">Típus száma</string>
|
||||||
|
<string name="relay_management_ip_address">IP-cím</string>
|
||||||
|
<string name="relay_management_reason_optional">Indoklás (nem kötelező)</string>
|
||||||
|
<string name="relay_management_confirm">Megerősítés</string>
|
||||||
|
<string name="relay_management_cancel">Mégse</string>
|
||||||
|
<string name="relay_management_apply">Alkamaz</string>
|
||||||
|
<string name="relay_management_relay_name">Átjátszó neve</string>
|
||||||
|
<string name="relay_management_relay_description">Átjátszó leírása</string>
|
||||||
|
<string name="relay_management_relay_icon_url">Átjátszó ikonjának webcíme</string>
|
||||||
|
<string name="relay_management_button">Átjátszó kezelése</string>
|
||||||
|
<string name="manage">Kezelés</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -384,6 +384,9 @@
|
|||||||
<string name="add_to_public_bookmarks">Dodaj do publicznych zakładek</string>
|
<string name="add_to_public_bookmarks">Dodaj do publicznych zakładek</string>
|
||||||
<string name="remove_from_private_bookmarks">Usuń z prywatnych zakładek</string>
|
<string name="remove_from_private_bookmarks">Usuń z prywatnych zakładek</string>
|
||||||
<string name="remove_from_public_bookmarks">Usuń z publicznych zakładek</string>
|
<string name="remove_from_public_bookmarks">Usuń z publicznych zakładek</string>
|
||||||
|
<string name="pinned_notes">Przypięte notatki</string>
|
||||||
|
<string name="pin_to_profile">Przypnij do profilu</string>
|
||||||
|
<string name="unpin_from_profile">Odepnij z profilu</string>
|
||||||
<string name="bookmark_lists">Listy zakładek</string>
|
<string name="bookmark_lists">Listy zakładek</string>
|
||||||
<string name="bookmark_list_icon_label">Ikona listy zakładek</string>
|
<string name="bookmark_list_icon_label">Ikona listy zakładek</string>
|
||||||
<string name="bookmark_list_creation_screen_title">Nowa lista zakładek</string>
|
<string name="bookmark_list_creation_screen_title">Nowa lista zakładek</string>
|
||||||
@@ -716,6 +719,16 @@
|
|||||||
<string name="terms_and_conditions">Zasady i warunki użytkowania</string>
|
<string name="terms_and_conditions">Zasady i warunki użytkowania</string>
|
||||||
<string name="not_available_acronym">Nie dotyczy</string>
|
<string name="not_available_acronym">Nie dotyczy</string>
|
||||||
<string name="relay_error_messages">Błędy i powiadomienia z tego transmitera</string>
|
<string name="relay_error_messages">Błędy i powiadomienia z tego transmitera</string>
|
||||||
|
<string name="relay_monitor_reports">Raporty z monitoringu transmitera</string>
|
||||||
|
<string name="relay_monitor_rtt_open">Otwórz</string>
|
||||||
|
<string name="relay_monitor_rtt_read">Odczyt</string>
|
||||||
|
<string name="relay_monitor_rtt_write">Zapis</string>
|
||||||
|
<string name="relay_monitor_network">Sieć</string>
|
||||||
|
<string name="relay_monitor_relay_type">Typ</string>
|
||||||
|
<string name="relay_monitor_supported_nips">Obsługiwane Nipy</string>
|
||||||
|
<string name="relay_monitor_requirements">Wymagania</string>
|
||||||
|
<string name="relay_monitor_last_check">Ostatnie sprawdzenie</string>
|
||||||
|
<string name="relay_monitor_ms">%1$d ms</string>
|
||||||
<string name="relay_active_subscriptions">Aktywne subskrypcje</string>
|
<string name="relay_active_subscriptions">Aktywne subskrypcje</string>
|
||||||
<string name="relay_active_outbox">Wydarzenia oczekujące na wysłanie</string>
|
<string name="relay_active_outbox">Wydarzenia oczekujące na wysłanie</string>
|
||||||
<string name="relay_req_subscriptions">REQ Subskrypcje (%1$d)</string>
|
<string name="relay_req_subscriptions">REQ Subskrypcje (%1$d)</string>
|
||||||
@@ -1652,6 +1665,7 @@
|
|||||||
<string name="events">wydarzeń</string>
|
<string name="events">wydarzeń</string>
|
||||||
<string name="dms">DMs</string>
|
<string name="dms">DMs</string>
|
||||||
<string name="profiles">profile</string>
|
<string name="profiles">profile</string>
|
||||||
|
<string name="relay_settings_lower2">lista transmiterów wysyłających</string>
|
||||||
<string name="relay_settings_lower">ustawienia transmiterów</string>
|
<string name="relay_settings_lower">ustawienia transmiterów</string>
|
||||||
<string name="last_seen">Ostatnio widziano %1$s temu</string>
|
<string name="last_seen">Ostatnio widziano %1$s temu</string>
|
||||||
<string name="event_sync_less_than_until"><%1$s</string>
|
<string name="event_sync_less_than_until"><%1$s</string>
|
||||||
@@ -1716,5 +1730,56 @@
|
|||||||
<string name="web_bookmark_delete_confirm">Usunąć tę zakładkę?</string>
|
<string name="web_bookmark_delete_confirm">Usunąć tę zakładkę?</string>
|
||||||
<string name="web_bookmark_open_url">Otwórz adres URL</string>
|
<string name="web_bookmark_open_url">Otwórz adres URL</string>
|
||||||
<!-- NIP-75 Zap Goals -->
|
<!-- NIP-75 Zap Goals -->
|
||||||
|
<string name="goal_closed">Ta zbiórka została zamknięta</string>
|
||||||
|
<string name="goal_progress">Sfinansowano %1$s z %2$s satoszów</string>
|
||||||
|
<string name="goal_amount_label">Kwota zbiorki (w satoszach)</string>
|
||||||
|
<string name="goal_amount_placeholder">100000</string>
|
||||||
|
<string name="goal_description_label">Opisz cel zbiórki</string>
|
||||||
|
<string name="goal_description_placeholder">Na co zbierasz fundusze?</string>
|
||||||
|
<string name="goal_summary_label">Krótkie podsumowanie</string>
|
||||||
|
<string name="goal_summary_placeholder">Krótki opis wyświetlany w podglądzie</string>
|
||||||
|
<string name="goal_image_label">Adres URL zdjęcia (opcjonalnie)</string>
|
||||||
|
<string name="goal_image_placeholder">https://domena.pl/img.jpg</string>
|
||||||
|
<string name="goal_website_label">Adres strony (opcjonalnie)</string>
|
||||||
|
<string name="goal_website_placeholder">https://domena.pl</string>
|
||||||
|
<string name="goal_deadline_label">Termin ukończenia (opcjonalnie)</string>
|
||||||
|
<string name="goal_set_deadline">Ustaw ostateczny termin</string>
|
||||||
|
<string name="new_goal">Nowy cel zbiórki</string>
|
||||||
|
<string name="goal_create">Utwórz zbiórkę</string>
|
||||||
|
<string name="request_to_vanish">Prośba o usunięcie</string>
|
||||||
|
<string name="request_to_vanish_description">Poproś transmitery o całkowite usunięcie wszystkich Twoich danych z okresu do wybranej daty. Działanie to opiera się na standardzie NIP-62 i w niektórych jurysdykcjach ma moc prawną.</string>
|
||||||
|
<string name="vanish_select_relay">Wybierz transmiter</string>
|
||||||
|
<string name="vanish_target_relay">Transmitery docelowe</string>
|
||||||
|
<string name="vanish_all_relays">WSZYSTKIE TRANSMITERY</string>
|
||||||
|
<string name="vanish_all_relays_warning">Spowoduje to wysłanie żądania do WSZYSTKICH przekaźników o usunięcie wszystkich danych powiązanych z Twoim kluczem do wybranej daty. Informacja ta zostanie rozpowszechniona tak szeroko, jak to tylko możliwe. Czynności tej nie można cofnąć.</string>
|
||||||
|
<string name="vanish_date_label">Usuń dane aż do</string>
|
||||||
|
<string name="vanish_date_explainer">Wszystkie wydarzenia utworzone przed tą datą zostaną zgłoszone do usunięcia z wybranego transmitera.</string>
|
||||||
|
<string name="vanish_reason_label">Powód (Opcjonalne)</string>
|
||||||
|
<string name="vanish_reason_placeholder">Uzasadnienie lub informacja prawna dla operatora transmitera</string>
|
||||||
|
<string name="vanish_send_request">Wyślij prośbę o usunięcie</string>
|
||||||
|
<string name="vanish_confirm_title">Potwierdź żądanie usunięcia</string>
|
||||||
|
<string name="vanish_confirm_single_relay">Zamierzasz poprosić %1$s o trwałe usunięcie wszystkich danych utworzonych przed wybraną datą. Czynności tej nie można cofnąć.</string>
|
||||||
|
<string name="vanish_confirm_all_relays">Za chwilę wyślesz żądanie do KAŻDEGO transmitera, aby trwale usunął wszystkie Twoje dane utworzone przed wybraną datą. Komunikat ten zostanie rozesłany wszędzie i nie będzie można go cofnąć.</string>
|
||||||
|
<string name="vanish_request_sent">Wysłano prośbę o usunięcie</string>
|
||||||
|
<string name="vanish_select_date">Wybierz datę</string>
|
||||||
|
<string name="vanish_select_time">Wybierz godzinę</string>
|
||||||
|
<string name="vanish_events_title">Wyczyść historię</string>
|
||||||
|
<string name="vanish_events_refresh">Odśwież</string>
|
||||||
|
<string name="vanish_events_description">Oto Twoje wcześniejsze prośby o usunięcie danych znalezione na podłączonych transmiterach. Transmitery oznaczone w tych wydarzeniach nie powinny przechowywać żadnych Twoich danych sprzed daty wydarzenia.</string>
|
||||||
|
<string name="vanish_events_empty">Nie znaleziono wniosków o usunięcie</string>
|
||||||
|
<string name="vanish_events_empty_hint">Nie wysłano jeszcze żadnych żądań do usunięcia wydarzeń.</string>
|
||||||
|
<string name="vanish_target_relays_label">Transmitery docelowe</string>
|
||||||
|
<string name="vanish_all_relays_compliance_hint">To żądanie dotyczy wszystkich transmiterów. Aby sprawdzić zgodność poszczególnych transmiterów, skorzystaj z opcji \"Prośba o usunięcie\".</string>
|
||||||
|
<string name="vanish_test_button">Test</string>
|
||||||
|
<string name="vanish_compliant">Zgodny</string>
|
||||||
|
<string name="vanish_non_compliant">Niezgodny</string>
|
||||||
|
<string name="vanish_test_error">Błąd</string>
|
||||||
|
<string name="vanish_history">Wyczyść historię</string>
|
||||||
<!-- NIP-86 Relay Management -->
|
<!-- NIP-86 Relay Management -->
|
||||||
|
<string name="relay_management_title">Zarządzaj %1$s</string>
|
||||||
|
<string name="relay_management_loading">Wczytywanie funkcji zarządzania transmiterem…</string>
|
||||||
|
<string name="relay_management_no_methods">Brak dostępnych metod zarządzania</string>
|
||||||
|
<string name="relay_management_dismiss">Ignoruj</string>
|
||||||
|
<string name="relay_management_button">Zarządzaj Transmiterem</string>
|
||||||
|
<string name="manage">Zarządzaj</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelNamespaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelTag
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-32 self-reporting: `l` and `L` tags MAY be added to any event kind.
|
||||||
|
* For non-1985 events, labels refer to the event itself.
|
||||||
|
*/
|
||||||
|
fun Event.selfReportLabels() = tags.mapNotNull(LabelTag::parse)
|
||||||
|
|
||||||
|
fun Event.selfReportNamespaces() = tags.mapNotNull(LabelNamespaceTag::parse)
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.events.eTag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.HashtagTag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.people.pTag
|
||||||
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelNamespaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelTag
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-32: Label Event (kind 1985)
|
||||||
|
*
|
||||||
|
* Attaches labels to existing events, pubkeys, relays, or topics.
|
||||||
|
* Supports distributed moderation, collection management, license assignment,
|
||||||
|
* and content classification.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
class LabelEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey,
|
||||||
|
) : Event(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
|
EventHintProvider,
|
||||||
|
PubKeyHintProvider,
|
||||||
|
AddressHintProvider {
|
||||||
|
override fun pubKeyHints(): List<PubKeyHint> = tags.mapNotNull(PTag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedPubKeys(): List<HexKey> = tags.mapNotNull(PTag::parseKey)
|
||||||
|
|
||||||
|
override fun eventHints(): List<EventIdHint> = tags.mapNotNull(ETag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedEventIds(): List<HexKey> = tags.mapNotNull(ETag::parseId)
|
||||||
|
|
||||||
|
override fun addressHints(): List<AddressHint> = tags.mapNotNull(ATag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedAddressIds(): List<String> = tags.mapNotNull(ATag::parseAddressId)
|
||||||
|
|
||||||
|
/** All label namespace (`L`) tags on this event. */
|
||||||
|
fun namespaces() = tags.mapNotNull(LabelNamespaceTag::parse)
|
||||||
|
|
||||||
|
/** All label (`l`) tags on this event. */
|
||||||
|
fun labels() = tags.mapNotNull(LabelTag::parse)
|
||||||
|
|
||||||
|
/** Labels filtered by a specific namespace. */
|
||||||
|
fun labelsByNamespace(namespace: String) = labels().filter { it.namespace == namespace }
|
||||||
|
|
||||||
|
/** Referenced event IDs (label targets). */
|
||||||
|
fun labeledEvents() = tags.mapNotNull(ETag::parseId)
|
||||||
|
|
||||||
|
/** Referenced pubkeys (label targets). */
|
||||||
|
fun labeledPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||||
|
|
||||||
|
/** Referenced addresses (label targets). */
|
||||||
|
fun labeledAddresses() = tags.mapNotNull(ATag::parseAddressId)
|
||||||
|
|
||||||
|
/** Referenced hashtags/topics (label targets via `t` tag). */
|
||||||
|
fun labeledHashtags() = tags.mapNotNull(HashtagTag::parse)
|
||||||
|
|
||||||
|
/** Referenced relay URLs (label targets via `r` tag). */
|
||||||
|
fun labeledRelayUrls(): List<String> =
|
||||||
|
tags
|
||||||
|
.filter { it.size >= 2 && it[0] == "r" && it[1].isNotEmpty() }
|
||||||
|
.map { it[1] }
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KIND = 1985
|
||||||
|
const val ALT = "Label event"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a label event for labeling events.
|
||||||
|
*/
|
||||||
|
fun buildEventLabel(
|
||||||
|
labeledEventId: HexKey,
|
||||||
|
labeledEventRelay: String? = null,
|
||||||
|
labeledEventAuthor: HexKey? = null,
|
||||||
|
labels: List<LabelTag>,
|
||||||
|
content: String = "",
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
) = eventTemplate<LabelEvent>(KIND, content, createdAt) {
|
||||||
|
alt(ALT)
|
||||||
|
eTag(ETag(labeledEventId, labeledEventRelay?.let { RelayUrlNormalizer.normalizeOrNull(it) }, labeledEventAuthor))
|
||||||
|
labels.map { it.namespace }.distinct().forEach { labelNamespace(it) }
|
||||||
|
labels.forEach { label(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a label event for labeling pubkeys.
|
||||||
|
*/
|
||||||
|
fun buildPubKeyLabel(
|
||||||
|
labeledPubKey: HexKey,
|
||||||
|
labeledPubKeyRelay: String? = null,
|
||||||
|
labels: List<LabelTag>,
|
||||||
|
content: String = "",
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
) = eventTemplate<LabelEvent>(KIND, content, createdAt) {
|
||||||
|
alt(ALT)
|
||||||
|
pTag(labeledPubKey, labeledPubKeyRelay?.let { RelayUrlNormalizer.normalizeOrNull(it) })
|
||||||
|
labels.map { it.namespace }.distinct().forEach { labelNamespace(it) }
|
||||||
|
labels.forEach { label(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a label event with custom tag targets and labels.
|
||||||
|
*/
|
||||||
|
fun build(
|
||||||
|
labels: List<LabelTag>,
|
||||||
|
content: String = "",
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
) = eventTemplate<LabelEvent>(KIND, content, createdAt) {
|
||||||
|
alt(ALT)
|
||||||
|
labels.map { it.namespace }.distinct().forEach { labelNamespace(it) }
|
||||||
|
labels.forEach { label(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelNamespaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelTag
|
||||||
|
|
||||||
|
/** Adds a label (`l`) tag. */
|
||||||
|
fun <T : Event> TagArrayBuilder<T>.label(tag: LabelTag) = add(tag.toTagArray())
|
||||||
|
|
||||||
|
/** Adds a label (`l`) tag with explicit label and namespace values. */
|
||||||
|
fun <T : Event> TagArrayBuilder<T>.label(
|
||||||
|
label: String,
|
||||||
|
namespace: String,
|
||||||
|
) = add(LabelTag.assemble(label, namespace))
|
||||||
|
|
||||||
|
/** Adds a label namespace (`L`) tag. */
|
||||||
|
fun <T : Event> TagArrayBuilder<T>.labelNamespace(namespace: String) = add(LabelNamespaceTag.assemble(namespace))
|
||||||
|
|
||||||
|
/** Adds a label namespace (`L`) tag. */
|
||||||
|
fun <T : Event> TagArrayBuilder<T>.labelNamespace(tag: LabelNamespaceTag) = add(tag.toTagArray())
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling.tags
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-32: `L` tag — label namespace.
|
||||||
|
*
|
||||||
|
* Format: `["L", "<namespace>"]`
|
||||||
|
*
|
||||||
|
* Namespaces SHOULD be unambiguous (ISO standard or reverse domain name notation).
|
||||||
|
* The special `ugc` namespace MAY be used when label content is provided by an end user.
|
||||||
|
* `L` tags starting with `#` indicate that the label target should be associated
|
||||||
|
* with the label's value (attaching standard nostr tags to events, pubkeys, etc.).
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class LabelNamespaceTag(
|
||||||
|
val namespace: String,
|
||||||
|
) {
|
||||||
|
fun toTagArray() = assemble(namespace)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this namespace is a tag-association namespace (starts with `#`).
|
||||||
|
* When `L` = `#t`, an `l` tag like `["l", "bitcoin", "#t"]` means the target
|
||||||
|
* should be associated with the hashtag `bitcoin`.
|
||||||
|
*/
|
||||||
|
fun isTagAssociation() = namespace.startsWith("#")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "L"
|
||||||
|
|
||||||
|
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
namespace: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == namespace
|
||||||
|
|
||||||
|
fun parse(tag: Array<String>): LabelNamespaceTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
return LabelNamespaceTag(tag[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseNamespace(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assemble(namespace: String) = arrayOf(TAG_NAME, namespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling.tags
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-32: `l` tag — label value with an optional namespace mark.
|
||||||
|
*
|
||||||
|
* Format: `["l", "<label>", "<namespace>"]`
|
||||||
|
*
|
||||||
|
* If no namespace mark is included, `ugc` is implied.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class LabelTag(
|
||||||
|
val label: String,
|
||||||
|
val namespace: String,
|
||||||
|
) {
|
||||||
|
fun toTagArray() = assemble(label, namespace)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "l"
|
||||||
|
const val DEFAULT_NAMESPACE = "ugc"
|
||||||
|
|
||||||
|
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
label: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == label
|
||||||
|
|
||||||
|
fun isTaggedWithNamespace(
|
||||||
|
tag: Array<String>,
|
||||||
|
namespace: String,
|
||||||
|
) = tag.has(2) && tag[0] == TAG_NAME && tag[2] == namespace
|
||||||
|
|
||||||
|
fun parse(tag: Array<String>): LabelTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
val namespace = if (tag.has(2) && tag[2].isNotEmpty()) tag[2] else DEFAULT_NAMESPACE
|
||||||
|
return LabelTag(tag[1], namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseLabel(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assemble(
|
||||||
|
label: String,
|
||||||
|
namespace: String,
|
||||||
|
) = arrayOf(TAG_NAME, label, namespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent
|
|||||||
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
||||||
import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent
|
import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent
|
||||||
import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent
|
import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.LabelEvent
|
||||||
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
|
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
|
||||||
import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent
|
import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent
|
||||||
import com.vitorpamplona.quartz.nip34Git.reply.GitReplyEvent
|
import com.vitorpamplona.quartz.nip34Git.reply.GitReplyEvent
|
||||||
@@ -261,6 +262,7 @@ class EventFactory {
|
|||||||
InteractiveStoryPrologueEvent.KIND -> InteractiveStoryPrologueEvent(id, pubKey, createdAt, tags, content, sig)
|
InteractiveStoryPrologueEvent.KIND -> InteractiveStoryPrologueEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
InteractiveStorySceneEvent.KIND -> InteractiveStorySceneEvent(id, pubKey, createdAt, tags, content, sig)
|
InteractiveStorySceneEvent.KIND -> InteractiveStorySceneEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
InteractiveStoryReadingStateEvent.KIND -> InteractiveStoryReadingStateEvent(id, pubKey, createdAt, tags, content, sig)
|
InteractiveStoryReadingStateEvent.KIND -> InteractiveStoryReadingStateEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
LabelEvent.KIND -> LabelEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LabeledBookmarkListEvent.KIND -> LabeledBookmarkListEvent(id, pubKey, createdAt, tags, content, sig)
|
LabeledBookmarkListEvent.KIND -> LabeledBookmarkListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LiveActivitiesChatMessageEvent.KIND -> LiveActivitiesChatMessageEvent(id, pubKey, createdAt, tags, content, sig)
|
LiveActivitiesChatMessageEvent.KIND -> LiveActivitiesChatMessageEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LiveActivitiesEvent.KIND -> LiveActivitiesEvent(id, pubKey, createdAt, tags, content, sig)
|
LiveActivitiesEvent.KIND -> LiveActivitiesEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
|||||||
+189
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelTag
|
||||||
|
import com.vitorpamplona.quartz.utils.EventFactory
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class LabelEventTest {
|
||||||
|
private val signer = NostrSignerInternal(KeyPair())
|
||||||
|
private val testEventId = "a".repeat(64)
|
||||||
|
private val testPubKey = "b".repeat(64)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuildEventLabel() {
|
||||||
|
val labels = listOf(LabelTag("approve", "nip28.moderation"))
|
||||||
|
val template =
|
||||||
|
LabelEvent.buildEventLabel(
|
||||||
|
labeledEventId = testEventId,
|
||||||
|
labels = labels,
|
||||||
|
content = "Approved for channel",
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(1985, template.kind)
|
||||||
|
assertEquals("Approved for channel", template.content)
|
||||||
|
|
||||||
|
val hasLabelNamespace = template.tags.any { it[0] == "L" && it[1] == "nip28.moderation" }
|
||||||
|
assertTrue(hasLabelNamespace, "Should have L namespace tag")
|
||||||
|
|
||||||
|
val hasLabel = template.tags.any { it[0] == "l" && it[1] == "approve" && it[2] == "nip28.moderation" }
|
||||||
|
assertTrue(hasLabel, "Should have l label tag")
|
||||||
|
|
||||||
|
val hasEventRef = template.tags.any { it[0] == "e" && it[1] == testEventId }
|
||||||
|
assertTrue(hasEventRef, "Should have e tag targeting labeled event")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuildPubKeyLabel() {
|
||||||
|
val labels = listOf(LabelTag("permies", "#t"))
|
||||||
|
val template =
|
||||||
|
LabelEvent.buildPubKeyLabel(
|
||||||
|
labeledPubKey = testPubKey,
|
||||||
|
labels = labels,
|
||||||
|
content = "",
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(1985, template.kind)
|
||||||
|
|
||||||
|
val hasPubKeyRef = template.tags.any { it[0] == "p" && it[1] == testPubKey }
|
||||||
|
assertTrue(hasPubKeyRef, "Should have p tag targeting labeled pubkey")
|
||||||
|
|
||||||
|
val hasNamespace = template.tags.any { it[0] == "L" && it[1] == "#t" }
|
||||||
|
assertTrue(hasNamespace, "Should have L namespace tag")
|
||||||
|
|
||||||
|
val hasLabel = template.tags.any { it[0] == "l" && it[1] == "permies" && it[2] == "#t" }
|
||||||
|
assertTrue(hasLabel, "Should have l label tag")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuildMultipleLabels() {
|
||||||
|
val labels =
|
||||||
|
listOf(
|
||||||
|
LabelTag("IT-MI", "ISO-3166-2"),
|
||||||
|
LabelTag("en", "ISO-639-1"),
|
||||||
|
)
|
||||||
|
val template = LabelEvent.build(labels = labels)
|
||||||
|
|
||||||
|
val namespaces =
|
||||||
|
template.tags
|
||||||
|
.filter { it[0] == "L" }
|
||||||
|
.map { it[1] }
|
||||||
|
.toSet()
|
||||||
|
assertEquals(setOf("ISO-3166-2", "ISO-639-1"), namespaces)
|
||||||
|
|
||||||
|
val labelTags = template.tags.filter { it[0] == "l" }
|
||||||
|
assertEquals(2, labelTags.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEventFactoryCreatesLabelEvent() {
|
||||||
|
val event =
|
||||||
|
EventFactory.create<Event>(
|
||||||
|
id = testEventId,
|
||||||
|
pubKey = testPubKey,
|
||||||
|
createdAt = 1234567890L,
|
||||||
|
kind = 1985,
|
||||||
|
tags =
|
||||||
|
arrayOf(
|
||||||
|
arrayOf("L", "license"),
|
||||||
|
arrayOf("l", "MIT", "license"),
|
||||||
|
arrayOf("e", testEventId),
|
||||||
|
),
|
||||||
|
content = "",
|
||||||
|
sig = "c".repeat(128),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertIs<LabelEvent>(event)
|
||||||
|
assertEquals(1985, event.kind)
|
||||||
|
|
||||||
|
val labels = event.labels()
|
||||||
|
assertEquals(1, labels.size)
|
||||||
|
assertEquals("MIT", labels[0].label)
|
||||||
|
assertEquals("license", labels[0].namespace)
|
||||||
|
|
||||||
|
val namespaces = event.namespaces()
|
||||||
|
assertEquals(1, namespaces.size)
|
||||||
|
assertEquals("license", namespaces[0].namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLabelsByNamespace() {
|
||||||
|
val event =
|
||||||
|
EventFactory.create<LabelEvent>(
|
||||||
|
id = testEventId,
|
||||||
|
pubKey = testPubKey,
|
||||||
|
createdAt = 1234567890L,
|
||||||
|
kind = 1985,
|
||||||
|
tags =
|
||||||
|
arrayOf(
|
||||||
|
arrayOf("L", "license"),
|
||||||
|
arrayOf("L", "ISO-639-1"),
|
||||||
|
arrayOf("l", "MIT", "license"),
|
||||||
|
arrayOf("l", "en", "ISO-639-1"),
|
||||||
|
arrayOf("e", testEventId),
|
||||||
|
),
|
||||||
|
content = "",
|
||||||
|
sig = "c".repeat(128),
|
||||||
|
)
|
||||||
|
|
||||||
|
val licenseLabels = event.labelsByNamespace("license")
|
||||||
|
assertEquals(1, licenseLabels.size)
|
||||||
|
assertEquals("MIT", licenseLabels[0].label)
|
||||||
|
|
||||||
|
val languageLabels = event.labelsByNamespace("ISO-639-1")
|
||||||
|
assertEquals(1, languageLabels.size)
|
||||||
|
assertEquals("en", languageLabels[0].label)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLabeledTargets() {
|
||||||
|
val event =
|
||||||
|
EventFactory.create<LabelEvent>(
|
||||||
|
id = testEventId,
|
||||||
|
pubKey = testPubKey,
|
||||||
|
createdAt = 1234567890L,
|
||||||
|
kind = 1985,
|
||||||
|
tags =
|
||||||
|
arrayOf(
|
||||||
|
arrayOf("L", "ugc"),
|
||||||
|
arrayOf("l", "funny", "ugc"),
|
||||||
|
arrayOf("e", testEventId),
|
||||||
|
arrayOf("p", testPubKey),
|
||||||
|
arrayOf("t", "bitcoin"),
|
||||||
|
arrayOf("r", "wss://relay.example.com"),
|
||||||
|
),
|
||||||
|
content = "",
|
||||||
|
sig = "c".repeat(128),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(listOf(testEventId), event.labeledEvents())
|
||||||
|
assertEquals(listOf(testPubKey), event.labeledPubKeys())
|
||||||
|
assertEquals(listOf("bitcoin"), event.labeledHashtags())
|
||||||
|
assertEquals(listOf("wss://relay.example.com"), event.labeledRelayUrls())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 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.nip32Labeling
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelNamespaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip32Labeling.tags.LabelTag
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class LabelTagTest {
|
||||||
|
@Test
|
||||||
|
fun testParseLabelWithNamespace() {
|
||||||
|
val tag = arrayOf("l", "MIT", "license")
|
||||||
|
val label = LabelTag.parse(tag)
|
||||||
|
|
||||||
|
assertNotNull(label)
|
||||||
|
assertEquals("MIT", label.label)
|
||||||
|
assertEquals("license", label.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseLabelWithoutNamespaceDefaultsToUgc() {
|
||||||
|
val tag = arrayOf("l", "my-label")
|
||||||
|
val label = LabelTag.parse(tag)
|
||||||
|
|
||||||
|
assertNotNull(label)
|
||||||
|
assertEquals("my-label", label.label)
|
||||||
|
assertEquals("ugc", label.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseLabelWithEmptyNamespaceDefaultsToUgc() {
|
||||||
|
val tag = arrayOf("l", "my-label", "")
|
||||||
|
val label = LabelTag.parse(tag)
|
||||||
|
|
||||||
|
assertNotNull(label)
|
||||||
|
assertEquals("my-label", label.label)
|
||||||
|
assertEquals("ugc", label.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseLabelReturnsNullForInvalidTag() {
|
||||||
|
assertNull(LabelTag.parse(arrayOf("l")))
|
||||||
|
assertNull(LabelTag.parse(arrayOf("l", "")))
|
||||||
|
assertNull(LabelTag.parse(arrayOf("e", "something")))
|
||||||
|
assertNull(LabelTag.parse(arrayOf()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseLabelValue() {
|
||||||
|
val tag = arrayOf("l", "en", "ISO-639-1")
|
||||||
|
assertEquals("en", LabelTag.parseLabel(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssembleLabel() {
|
||||||
|
val assembled = LabelTag.assemble("MIT", "license")
|
||||||
|
assertEquals(3, assembled.size)
|
||||||
|
assertEquals("l", assembled[0])
|
||||||
|
assertEquals("MIT", assembled[1])
|
||||||
|
assertEquals("license", assembled[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRoundTrip() {
|
||||||
|
val original = LabelTag("approve", "nip28.moderation")
|
||||||
|
val assembled = original.toTagArray()
|
||||||
|
val parsed = LabelTag.parse(assembled)
|
||||||
|
|
||||||
|
assertNotNull(parsed)
|
||||||
|
assertEquals(original, parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsTagged() {
|
||||||
|
assertTrue(LabelTag.isTagged(arrayOf("l", "something")))
|
||||||
|
assertTrue(LabelTag.isTagged(arrayOf("l", "MIT", "license")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsTaggedWithValue() {
|
||||||
|
assertTrue(LabelTag.isTagged(arrayOf("l", "MIT", "license"), "MIT"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsTaggedWithNamespace() {
|
||||||
|
assertTrue(LabelTag.isTaggedWithNamespace(arrayOf("l", "MIT", "license"), "license"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseNamespace() {
|
||||||
|
val tag = arrayOf("L", "license")
|
||||||
|
val namespace = LabelNamespaceTag.parse(tag)
|
||||||
|
|
||||||
|
assertNotNull(namespace)
|
||||||
|
assertEquals("license", namespace.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseNamespaceReturnsNullForInvalid() {
|
||||||
|
assertNull(LabelNamespaceTag.parse(arrayOf("L")))
|
||||||
|
assertNull(LabelNamespaceTag.parse(arrayOf("L", "")))
|
||||||
|
assertNull(LabelNamespaceTag.parse(arrayOf("l", "something")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssembleNamespace() {
|
||||||
|
val assembled = LabelNamespaceTag.assemble("com.example.ontology")
|
||||||
|
assertEquals(2, assembled.size)
|
||||||
|
assertEquals("L", assembled[0])
|
||||||
|
assertEquals("com.example.ontology", assembled[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNamespaceRoundTrip() {
|
||||||
|
val original = LabelNamespaceTag("ISO-639-1")
|
||||||
|
val assembled = original.toTagArray()
|
||||||
|
val parsed = LabelNamespaceTag.parse(assembled)
|
||||||
|
|
||||||
|
assertNotNull(parsed)
|
||||||
|
assertEquals(original, parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTagAssociationNamespace() {
|
||||||
|
val ns = LabelNamespaceTag("#t")
|
||||||
|
assertTrue(ns.isTagAssociation())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParseNamespaceValue() {
|
||||||
|
assertEquals("ugc", LabelNamespaceTag.parseNamespace(arrayOf("L", "ugc")))
|
||||||
|
assertNull(LabelNamespaceTag.parseNamespace(arrayOf("l", "ugc")))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user