BREAKING: remove announcements

For small instances it is assumed that a feature like this is not necessary.

Changelog: Removed
This commit is contained in:
Johann150 2025-05-04 00:07:19 +02:00
parent a986656a2d
commit 50b2bba44a
Signed by: Johann150
GPG key ID: 9EE6577A2A06F8F1
50 changed files with 21 additions and 857 deletions

View file

@ -202,13 +202,10 @@ featured: "المتداولة"
usernameOrUserId: "اسم المستخدم أو معرّفه"
noSuchUser: "لم يُعثَر على المستخدم"
lookup: "البحث"
announcements: "الإعلانات"
imageUrl: "رابط الصورة"
remove: "حذف"
removeAreYouSure: "متأكد من أنك تريد حذف {x}؟"
deleteAreYouSure: "متأكد من أنك تريد حذف {x}؟"
resetAreYouSure: "هل تريد إعادة التعيين؟"
saved: "حُفظ"
messaging: "المحادثة"
upload: "ارفع"
keepOriginalUploading: "ابق الصورة الأصلية"
@ -223,7 +220,6 @@ uploadFromUrlMayTakeTime: "سيستغرق بعض الوقت لاتمام الر
messageRead: "مقروءة"
noMoreHistory: "لا يوجد المزيد من التاريخ"
startMessaging: "ابدأ محادثة"
nUsersRead: "قرأه {n}"
agreeTo: "اوافق على {0}"
tos: "شروط الخدمة"
start: "البداية"
@ -360,8 +356,6 @@ members: "الأعضاء"
transfer: "نقل"
messagingWithUser: "تحدث مع مستخدم"
messagingWithGroup: "محادثة جماعية"
title: "العنوان"
text: "النص"
enable: "تشغيل"
retype: "أعد الكتابة"
noteOf: "ملاحظات {user}"

View file

@ -216,13 +216,10 @@ featured: "হাইলাইট"
usernameOrUserId: "ব্যাবহারকারীর নাম বা ব্যাবহারকারী ID"
noSuchUser: "কোন ব্যবহারকারী খুঁজে পাওয়া যায়নি"
lookup: "খুঁজে দেখো"
announcements: "ঘোষণা"
imageUrl: "চিত্রের URL"
remove: "মুছুন"
removeAreYouSure: "আপনি কি \"{x}\" সরানোর ব্যাপারে নিশ্চিত?"
deleteAreYouSure: "আপনি কি \"{x}\" সরানোর ব্যাপারে নিশ্চিত?"
resetAreYouSure: "রিসেট করার ব্যাপারে নিশ্চিত?"
saved: "সংরক্ষিত হয়েছে"
messaging: "চ্যাট"
upload: "আপলোড"
keepOriginalUploading: "আসল ছবি রাখুন"
@ -237,7 +234,6 @@ uploadFromUrlMayTakeTime: "URL হতে আপলোড হতে কিছু
messageRead: "পড়া"
noMoreHistory: "আর কোন ইতিহাস নেই"
startMessaging: "চ্যাট শুরু করুন"
nUsersRead: "{n} জন পড়েছেন"
agreeTo: "{0} এর প্রতি আমি সম্মত"
tos: "পরিষেবার শর্তাদি"
start: "শুরু করুন"
@ -375,8 +371,6 @@ members: "সদস্যবৃন্দ"
transfer: "হস্তান্তর"
messagingWithUser: "প্রাইভেট চ্যাট"
messagingWithGroup: "গ্রুপ চ্যাট"
title: "শিরোনাম"
text: "পাঠ্য"
enable: "সক্রিয়"
retype: "পুনঃ প্রবেশ"
noteOf: "{user} এর নোট"

View file

@ -196,13 +196,10 @@ more: "Více!"
featured: "Oblíbené poznámky"
usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
noSuchUser: "Uživatel nebyl nalezen"
announcements: "Oznámení"
imageUrl: "URL obrázku"
remove: "Smazat"
removeAreYouSure: "Jste si jistí že chcete smazat \"{x}\"?"
deleteAreYouSure: "Jste si jistí že chcete smazat \"{x}\"?"
resetAreYouSure: "Opravdu resetovat?"
saved: "Uloženo"
messaging: "Zprávy"
upload: "Nahrát soubory"
fromDrive: "Z disku"
@ -213,7 +210,6 @@ uploadFromUrlMayTakeTime: "Může trvat nějakou dobu, dokud nebude dokončeno n
messageRead: "Přečtené"
noMoreHistory: "To je vše"
startMessaging: "Zahájit chat"
nUsersRead: "přečteno {n} uživateli"
agreeTo: "Souhlasím s {0}"
tos: "Podmínky užívání"
start: "Začít"
@ -322,8 +318,6 @@ invites: "Pozvat"
groupName: "Název skupiny"
members: "Členové"
transfer: "Převod"
title: "Titulek"
text: "Text"
enable: "Povolit"
retype: "Zadejte znovu"
noteOf: "{user} poznámky"

View file

@ -226,13 +226,10 @@ featured: "Beliebt"
usernameOrUserId: "Benutzername oder Benutzer-ID"
noSuchUser: "Benutzer nicht gefunden"
lookup: "Anfragen"
announcements: "Ankündigungen"
imageUrl: "Bild-URL"
remove: "Löschen"
removeAreYouSure: "Möchtest du „{x}“ wirklich entfernen?"
deleteAreYouSure: "Möchtest du „{x}“ wirklich löschen?"
resetAreYouSure: "Wirklich zurücksetzen?"
saved: "Erfolgreich gespeichert"
messaging: "Chat"
upload: "Hochladen"
keepOriginalUploading: "Originalbild speichern"
@ -248,7 +245,6 @@ uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschl
messageRead: "Gelesen"
noMoreHistory: "Kein weiterer Verlauf vorhanden"
startMessaging: "Neuen Chat erstellen"
nUsersRead: "Von {n} Benutzern gelesen"
agreeTo: "Ich stimme {0} zu"
tos: "Nutzungsbedingungen"
start: "Anfangen"
@ -390,8 +386,6 @@ members: "Mitglieder"
transfer: "Übertragen"
messagingWithUser: "Privatchat"
messagingWithGroup: "Gruppenchat"
title: "Titel"
text: "Text"
enable: "Aktivieren"
retype: "Erneut eingeben"
noteOf: "Notiz von {user}"

View file

@ -221,13 +221,10 @@ featured: "Featured"
usernameOrUserId: "Username or user id"
noSuchUser: "User not found"
lookup: "Lookup"
announcements: "Announcements"
imageUrl: "Image URL"
remove: "Delete"
removeAreYouSure: "Are you sure that you want to remove \"{x}\"?"
deleteAreYouSure: "Are you sure that you want to delete \"{x}\"?"
resetAreYouSure: "Really reset?"
saved: "Saved"
messaging: "Chat"
upload: "Upload"
uploadFailed: "Upload failed"
@ -245,7 +242,6 @@ uploadFromUrlMayTakeTime: "It may take some time until the upload is complete."
messageRead: "Read"
noMoreHistory: "There is no further history"
startMessaging: "Start a new chat"
nUsersRead: "read by {n}"
agreeTo: "I agree to {0}"
tos: "Terms of Service"
start: "Begin"
@ -386,8 +382,6 @@ members: "Members"
transfer: "Transfer"
messagingWithUser: "Private chat"
messagingWithGroup: "Group chat"
title: "Title"
text: "Text"
enable: "Enable"
retype: "Enter again"
noteOf: "Note by {user}"

View file

@ -219,13 +219,10 @@ featured: "Destacados"
usernameOrUserId: "Nombre o ID del usuario"
noSuchUser: "No se encuentra el usuario"
lookup: "Búsqueda"
announcements: "Anuncios"
imageUrl: "URL de la imágen"
remove: "Borrar"
removeAreYouSure: "¿Desea borrar \"{x}\"?"
deleteAreYouSure: "¿Desea borrar \"{x}\"?"
resetAreYouSure: "¿Desea reestablecer?"
saved: "Guardado"
messaging: "Chat"
upload: "Subir"
keepOriginalUploading: "Mantener la imagen original"
@ -241,7 +238,6 @@ uploadFromUrlMayTakeTime: "Subir el fichero puede tardar un tiempo."
messageRead: "Ya leído"
noMoreHistory: "El historial se ha acabado"
startMessaging: "Iniciar chat"
nUsersRead: "Leído por {n} personas"
agreeTo: "De acuerdo con {0}"
tos: "Términos de uso"
start: "Comenzar"
@ -379,8 +375,6 @@ members: "Miembros"
transfer: "Transferir"
messagingWithUser: "Chatear con usuario"
messagingWithGroup: "Chatear en grupo"
title: "Título"
text: "Texto"
enable: "Activar"
retype: "Intentar de nuevo"
noteOf: "Notas de {user}"

View file

@ -221,13 +221,10 @@ featured: "Tendances"
usernameOrUserId: "Nom dutilisateur·rice ou ID utilisateur"
noSuchUser: "Utilisateur·rice non trouvé·e"
lookup: "Recherche"
announcements: "Annonces"
imageUrl: "URL de limage"
remove: "Supprimer"
removeAreYouSure: "Êtes-vous sûr·e de vouloir supprimer \"{x}\" ?"
deleteAreYouSure: "Êtes-vous sûr·e de vouloir supprimer \"{x}\" ?"
resetAreYouSure: "Voulez-vous réinitialiser ?"
saved: "Enregistré"
messaging: "Discuter"
upload: "Téléverser"
keepOriginalUploading: "Garder limage dorigine"
@ -241,7 +238,6 @@ uploadFromUrlMayTakeTime: "Le téléversement de votre fichier peut prendre un c
messageRead: "Lu"
noMoreHistory: "Il ny a plus dhistorique"
startMessaging: "Commencer à discuter"
nUsersRead: "Lu par {n} personnes"
agreeTo: "Jaccepte {0}"
tos: "les conditions dutilisation"
start: "Commencer"
@ -382,8 +378,6 @@ members: "Membres"
transfer: "Transférer"
messagingWithUser: "Discuter avec un·e autre utilisateur·rice"
messagingWithGroup: "Discuter avec un groupe"
title: "Titre"
text: "Texte"
enable: "Activer"
retype: "Confirmation"
noteOf: "Notes de {user}"

View file

@ -217,13 +217,10 @@ featured: "Sorotan"
usernameOrUserId: "Nama pengguna atau User ID"
noSuchUser: "Pengguna tidak ditemukan"
lookup: "Mencari"
announcements: "Pengumuman"
imageUrl: "URL Gambar"
remove: "Hapus"
removeAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?"
deleteAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?"
resetAreYouSure: "Yakin mau atur ulang?"
saved: "Telah disimpan"
messaging: "Pesan"
upload: "Unggah"
keepOriginalUploading: "Simpan gambar asli"
@ -238,7 +235,6 @@ uploadFromUrlMayTakeTime: "Mungkin diperlukan waktu hingga unggahan selesai."
messageRead: "Telah dibaca"
noMoreHistory: "Tidak ada sejarah lagi"
startMessaging: "Mulai mengirim pesan"
nUsersRead: "Dibaca oleh {n}"
agreeTo: "Saya setuju kepada {0}"
tos: "Syarat dan ketentuan"
start: "Mulai"
@ -377,8 +373,6 @@ members: "Anggota"
transfer: "Transfer"
messagingWithUser: "Obrolan dengan pengguna lain"
messagingWithGroup: "Obrolan di dalam grup"
title: "Judul"
text: "Teks"
enable: "Aktifkan"
retype: "Masukkan ulang"
noteOf: "Catatan milik {user}"

View file

@ -214,13 +214,10 @@ featured: "Tendenze"
usernameOrUserId: "Nome utente o ID utente"
noSuchUser: "Nessun utente trovato"
lookup: "Cercare"
announcements: "Annunci"
imageUrl: "URL dell'immagine"
remove: "Elimina"
removeAreYouSure: "Eliminare \"{x}\"?"
deleteAreYouSure: "Eliminare \"{x}\"?"
resetAreYouSure: "Reimposta"
saved: "Salvato"
messaging: "Messaggi"
upload: "Carica"
fromDrive: "Dal Drive"
@ -232,7 +229,6 @@ uploadFromUrlMayTakeTime: "Il caricamento del file può richiedere tempo."
messageRead: "Visualizzato"
noMoreHistory: "Non c'è più cronologia da visualizzare"
startMessaging: "Nuovo messaggio"
nUsersRead: "Letto da {n} persone"
agreeTo: "Sono d'accordo con {0}"
tos: "Termini di servizio"
start: "Inizia!"
@ -371,8 +367,6 @@ members: "Membri"
transfer: "Trasferisci"
messagingWithUser: "Iniziare una chat con un altr@ utente"
messagingWithGroup: "Chattare in gruppo"
title: "Titolo"
text: "Testo"
enable: "Abilita"
retype: "Conferma"
noteOf: "Note di {user}"

View file

@ -196,13 +196,10 @@ featured: "ハイライト"
usernameOrUserId: "ユーザー名かユーザーID"
noSuchUser: "ユーザーが見つかりません"
lookup: "照会"
announcements: "お知らせ"
imageUrl: "画像URL"
remove: "削除"
removeAreYouSure: "「{x}」を削除しますか?"
deleteAreYouSure: "「{x}」を削除しますか?"
resetAreYouSure: "リセットしますか?"
saved: "保存しました"
messaging: "チャット"
upload: "アップロード"
keepOriginalUploading: "オリジナル画像を保持"
@ -216,7 +213,6 @@ uploadFromUrlMayTakeTime: "アップロードが完了するまで時間がか
messageRead: "既読"
noMoreHistory: "これより過去の履歴はありません"
startMessaging: "チャットを開始"
nUsersRead: "{n}人が読みました"
agreeTo: "{0}に同意"
tos: "利用規約"
start: "始める"
@ -351,8 +347,6 @@ members: "メンバー"
transfer: "譲渡"
messagingWithUser: "ユーザーとチャット"
messagingWithGroup: "グループでチャット"
title: "タイトル"
text: "テキスト"
enable: "有効にする"
retype: "再入力"
noteOf: "{user}のノート"

View file

@ -201,13 +201,10 @@ featured: "하이라이트"
usernameOrUserId: "유저명이나 ID"
noSuchUser: "유저를 찾을 수 없습니다"
lookup: "조회"
announcements: "공지사항"
imageUrl: "이미지 URL"
remove: "삭제"
removeAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
deleteAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
resetAreYouSure: "초기화 하시겠습니까?"
saved: "저장하였습니다"
messaging: "대화"
upload: "업로드"
keepOriginalUploading: "원본 이미지를 유지"
@ -222,7 +219,6 @@ uploadFromUrlMayTakeTime: "업로드가 완료될 때까지 시간이 소요될
messageRead: "읽음"
noMoreHistory: "이것보다 과거의 기록이 없습니다"
startMessaging: "대화 시작하기"
nUsersRead: "{n}명이 읽음"
agreeTo: "{0}에 동의"
tos: "이용 약관"
start: "시작하기"
@ -357,8 +353,6 @@ members: "멤버"
transfer: "양도"
messagingWithUser: "유저와 대화하기"
messagingWithGroup: "그룹끼리 대화하기"
title: "제목"
text: "텍스트"
enable: "사용"
retype: "다시 입력"
noteOf: "{user}의 노트"

View file

@ -205,13 +205,10 @@ featured: "Uitgelicht"
usernameOrUserId: "Gebruikersnaam of id"
noSuchUser: "Gebruiker niet gevonden"
lookup: "Opzoeken"
announcements: "Aankondigingen"
imageUrl: "AfbeeldingsURL"
remove: "Verwijderen"
removeAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
deleteAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
resetAreYouSure: "Resetten?"
saved: "Opgeslagen"
messaging: "Chat"
upload: "Uploaden"
keepOriginalUploading: "Origineel beeld behouden"
@ -227,7 +224,6 @@ uploadFromUrlMayTakeTime: "Het kan even duren voordat het uploaden voltooid is."
messageRead: "Lezen"
noMoreHistory: "Er is geen verdere geschiedenis"
startMessaging: "Start een gesprek"
nUsersRead: "gelezen door {n}"
agreeTo: "Ik stem in met {0}"
tos: "Gebruiksvoorwaarden"
start: "Aan de slag"

View file

@ -210,13 +210,10 @@ featured: "Wyróżnione"
usernameOrUserId: "Nazwa lub id użytkownika"
noSuchUser: "Nie znaleziono użytkownika"
lookup: "Zapytania"
announcements: "Ogłoszenia"
imageUrl: "Adres URL obrazka"
remove: "Usuń"
removeAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
deleteAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
resetAreYouSure: "Czy na pewno chcesz zresetować?"
saved: "Zapisano"
messaging: "Wiadomości"
upload: "Wyślij"
fromDrive: "Z dysku"
@ -228,7 +225,6 @@ uploadFromUrlMayTakeTime: "Wysyłanie może chwilę potrwać."
messageRead: "Przeczytano"
noMoreHistory: "Nie ma dalszej historii"
startMessaging: "Rozpocznij czat"
nUsersRead: "przeczytano przez {n}"
agreeTo: "Wyrażam zgodę na {0}"
tos: "Regulamin"
start: "Rozpocznij"
@ -367,8 +363,6 @@ members: "Członkowie"
transfer: "Transfer"
messagingWithUser: "Rozmowy z innym użytkownikiem"
messagingWithGroup: "Rozmowy wewnątrz grupy"
title: "Tytuł"
text: "Tekst"
enable: "Włącz"
retype: "Wprowadź ponownie"
noteOf: "Wpisy {user}"

View file

@ -218,13 +218,10 @@ featured: "Evidențiat"
usernameOrUserId: "Nume sau ID de utilizator"
noSuchUser: "Utilizatorul nu a fost găsit"
lookup: "Privire"
announcements: "Anunțuri"
imageUrl: "URL-ul imaginii"
remove: "Şterge"
removeAreYouSure: "Ești sigur că vrei să înlături {x}?"
deleteAreYouSure: "Ești sigur că vrei să ștergi {x}?"
resetAreYouSure: "Sigur vrei să resetezi?"
saved: "Salvat"
messaging: "Chat"
upload: "Încarcă"
keepOriginalUploading: "Păstrează imaginea originală"
@ -239,7 +236,6 @@ uploadFromUrlMayTakeTime: "S-ar putea să ia puțin până se finalizează înc
messageRead: "Citit"
noMoreHistory: "Nu există mai mult istoric"
startMessaging: "Începe un chat nou"
nUsersRead: "citit de {n}"
agreeTo: "Sunt de acord cu {0}"
tos: "Termenii de utilizare"
start: "Să începem"
@ -378,8 +374,6 @@ members: "Membri"
transfer: "Transferă"
messagingWithUser: "Chat privat"
messagingWithGroup: "Chat de grup"
title: "Titlu"
text: "Text"
enable: "Activează"
retype: "Introdu din nou"
noteOf: "Notă de {user}"

View file

@ -213,13 +213,10 @@ featured: "Горячее"
usernameOrUserId: "Имя или идентификатор пользователя"
noSuchUser: "Таких пользователей не найдено"
lookup: "Запрос"
announcements: "Оповещения"
imageUrl: "Ссылка на изображение"
remove: "Удалить"
removeAreYouSure: "Хотите удалить «{x}»?"
deleteAreYouSure: "Хотите удалить «{x}»?"
resetAreYouSure: "На самом деле сбросить?"
saved: "Сохранено"
messaging: "Сообщения"
upload: "Загрузить"
keepOriginalUploading: "Сохранить исходное изображение"
@ -234,7 +231,6 @@ uploadFromUrlMayTakeTime: "Загрузка может занять некото
messageRead: "Прочитали"
noMoreHistory: "История закончилась"
startMessaging: "Начать общение"
nUsersRead: "Прочитали {n}"
agreeTo: "Я соглашаюсь с {0}"
tos: "Пользовательское соглашение"
start: "Начать"
@ -373,8 +369,6 @@ members: "Участники"
transfer: "Отдать"
messagingWithUser: "Общение с другим пользователем"
messagingWithGroup: "Общение в группе"
title: "Заголовок"
text: "Текст"
enable: "Включить"
retype: "Введите ещё раз"
noteOf: "Что пишет {user}"

View file

@ -212,13 +212,10 @@ featured: "Obľúbené poznámky"
usernameOrUserId: "Meno používateľa alebo ID používateľa"
noSuchUser: "Používateľ sa nenašiel"
lookup: "Vyhľadať"
announcements: "Oznamy"
imageUrl: "URL obrázku"
remove: "Odstrániť"
removeAreYouSure: "Naozaj chcete odstrániť \"{x}\"?"
deleteAreYouSure: "Naozaj chcete odstrániť \"{x}\"?"
resetAreYouSure: "Naozaj resetovať?"
saved: "Uložené"
messaging: "Chat"
upload: "Nahrať súbor"
keepOriginalUploading: "Zachovať pôvodný obrázok"
@ -233,7 +230,6 @@ uploadFromUrlMayTakeTime: "Nahrávanie môže nejaký čas trvať."
messageRead: "Prečítané"
noMoreHistory: "To je všetko"
startMessaging: "Začať chat"
nUsersRead: "prečítané {n} používateľmi"
agreeTo: "Súhlasím s {0}"
tos: "Podmienky používania"
start: "Začať"
@ -372,8 +368,6 @@ members: "Členovia"
transfer: "Presun"
messagingWithUser: "Súkromný chat"
messagingWithGroup: "Skupinový chat"
title: "Nadpis"
text: "Text"
enable: "Povoliť"
retype: "Zadajte znovu"
noteOf: "Poznámky používateľa {user}"

View file

@ -217,13 +217,10 @@ featured: "Utvalda"
usernameOrUserId: "Användarnamn eller användar-id"
noSuchUser: "Kan inte hitta användaren"
lookup: "Sökning"
announcements: "Nyheter"
imageUrl: "Bild-URL"
remove: "Radera"
removeAreYouSure: "Är du säker att du vill radera \"{x}\"?"
deleteAreYouSure: "Är du säker att du vill radera \"{x}\"?"
resetAreYouSure: "Vill du återställa?"
saved: "Sparad"
messaging: "Chatt"
upload: "Ladda upp"
keepOriginalUploading: "Behåll originalbild"

View file

@ -216,13 +216,10 @@ featured: "Популярні"
usernameOrUserId: "Ім'я або ID користувача"
noSuchUser: "Користувача не знайдено"
lookup: "Пошук"
announcements: "Оголошення"
imageUrl: "Посилання на зображення"
remove: "Видалити"
removeAreYouSure: "Ви впевнені, що хочете видалити \"{x}\"?"
deleteAreYouSure: "Ви впевнені, що хочете видалити \"{x}\"?"
resetAreYouSure: "Справді скинути?"
saved: "Збережено"
messaging: "Чати"
upload: "Завантажити"
keepOriginalUploading: "Зберегти оригінальне зображення"
@ -237,7 +234,6 @@ uploadFromUrlMayTakeTime: "Завантаження може зайняти де
messageRead: "Прочитано"
noMoreHistory: "Подальшої історії немає"
startMessaging: "Розпочати діалог"
nUsersRead: "Прочитали {n}"
agreeTo: "Я погоджуюсь з {0}"
tos: "Умови використання"
start: "Розпочати"
@ -374,8 +370,6 @@ members: "Учасники"
transfer: "Передача"
messagingWithUser: "Чат з користувачами"
messagingWithGroup: "Чат з групою"
title: "Тема"
text: "Текст"
enable: "Увімкнути"
retype: "Введіть ще раз"
noteOf: "Нотатка {user}"

View file

@ -212,13 +212,10 @@ featured: "Nổi bật"
usernameOrUserId: "Tên người dùng hoặc ID"
noSuchUser: "Không tìm thấy người dùng"
lookup: "Tìm kiếm"
announcements: "Thông báo"
imageUrl: "URL ảnh"
remove: "Xóa"
removeAreYouSure: "Bạn có chắc muốn gỡ \"{x}\"?"
deleteAreYouSure: "Bạn có chắc muốn xóa \"{x}\"?"
resetAreYouSure: "Bạn có chắc muốn đặt lại?"
saved: "Đã lưu"
messaging: "Trò chuyện"
upload: "Tải lên"
keepOriginalUploading: "Giữ hình ảnh gốc"
@ -233,7 +230,6 @@ uploadFromUrlMayTakeTime: "Sẽ mất một khoảng thời gian để tải lê
messageRead: "Đã đọc"
noMoreHistory: "Không còn gì để đọc"
startMessaging: "Bắt đầu trò chuyện"
nUsersRead: "đọc bởi {n}"
agreeTo: "Tôi đồng ý {0}"
tos: "Điều khoản dịch vụ"
start: "Bắt đầu"
@ -372,8 +368,6 @@ members: "Thành viên"
transfer: "Chuyển giao"
messagingWithUser: "Nhắn riêng"
messagingWithGroup: "Chat nhóm"
title: "Tựa đề"
text: "Nội dung"
enable: "Bật"
retype: "Nhập lại"
noteOf: "Tút của {user}"

View file

@ -194,13 +194,10 @@ featured: "热门"
usernameOrUserId: "用户名或用户ID"
noSuchUser: "用户不存在"
lookup: "查询"
announcements: "公告"
imageUrl: "图片URL"
remove: "删除"
removeAreYouSure: "要删掉「{x}」吗?"
deleteAreYouSure: "要删掉「{x}」吗?"
resetAreYouSure: "恢复默认设置?"
saved: "已保存"
messaging: "聊天"
upload: "本地上传"
keepOriginalUploading: "保留原图"
@ -214,7 +211,6 @@ uploadFromUrlMayTakeTime: "上传可能需要一些时间完成。"
messageRead: "已读"
noMoreHistory: "没有更多的历史记录"
startMessaging: "添加聊天"
nUsersRead: "{n}人已读"
agreeTo: "{0}勾选则表示已阅读并同意"
tos: "服务条款"
start: "开始"
@ -349,8 +345,6 @@ members: "成员"
transfer: "转让"
messagingWithUser: "与用户聊天"
messagingWithGroup: "与群组聊天"
title: "标题"
text: "文本"
enable: "启用"
retype: "重新输入"
noteOf: "{user}的帖子"

View file

@ -194,13 +194,10 @@ featured: "精選"
usernameOrUserId: "使用者名稱或使用者ID"
noSuchUser: "使用者不存在"
lookup: "查詢"
announcements: "公告"
imageUrl: "圖片URL"
remove: "刪除"
removeAreYouSure: "確定要刪掉「{x}」嗎?"
deleteAreYouSure: "確定要刪掉「{x}」嗎?"
resetAreYouSure: "確定要重設嗎?"
saved: "已儲存"
messaging: "傳送訊息"
upload: "上傳"
keepOriginalUploading: "保留原圖"
@ -214,7 +211,6 @@ uploadFromUrlMayTakeTime: "還需要一些時間才能完成上傳。"
messageRead: "已讀"
noMoreHistory: "沒有更多歷史紀錄"
startMessaging: "開始傳送訊息"
nUsersRead: "{n}人已讀"
agreeTo: "我同意{0}"
tos: "使用條款"
start: "開始"
@ -349,8 +345,6 @@ members: "成員"
transfer: "轉讓"
messagingWithUser: "傳送訊息給其他使用者"
messagingWithGroup: "發送訊息至群組"
title: "標題"
text: "文字"
enable: "啟用"
retype: "重新輸入"
noteOf: "{user}的貼文"

View file

@ -0,0 +1,19 @@
export class removeAnnouncements1746308911356 {
async up(queryRunner) {
await queryRunner.query(`DROP TABLE "announcement_read";`);
await queryRunner.query(`DROP TABLE "announcement";`);
}
async down(queryRunner) {
await queryRunner.query(`CREATE TABLE announcement ("id" character varying(32) NOT NULL PRIMARY KEY, "createdAt" timestamp with time zone NOT NULL, "text" character varying(8192) NOT NULL, "title" character varying(256) NOT NULL, "imageUrl" character varying(1024), "updatedAt" timestamp with time zone, CONSTRAINT "PK_e0ef0550174fd1099a308fd18a0" PRIMARY KEY (id))`);
await queryRunner.query(`COMMENT ON COLUMN announcement."createdAt" IS 'The created date of the Announcement.'`);
await queryRunner.query(`COMMENT ON COLUMN announcement."updatedAt" IS 'The updated date of the Announcement.'`);
await queryRunner.query(`CREATE INDEX "IDX_118ec703e596086fc4515acb39" ON announcement USING btree ("createdAt")`);
await queryRunner.query(`CREATE TABLE announcement_read ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "announcementId" character varying(32) NOT NULL, "createdAt" timestamp with time zone NOT NULL, CONSTRAINT "PK_4b90ad1f42681d97b2683890c5e" PRIMARY KEY ("id"), CONSTRAINT "FK_603a7b1e7aa0533c6c88e9bfafe" FOREIGN KEY ("announcementId") REFERENCES "announcement"("id") ON DELETE CASCADE, CONSTRAINT "FK_8288151386172b8109f7239ab28" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE);`);
await queryRunner.query(`COMMENT ON COLUMN announcement_read."createdAt" IS 'The created date of the AnnouncementRead.'`);
await queryRunner.query(`CREATE INDEX "IDX_603a7b1e7aa0533c6c88e9bfaf" ON "announcement_read" USING btree ("announcementId")`);
await queryRunner.query(`CREATE INDEX "IDX_8288151386172b8109f7239ab2" ON "announcement_read" USING btree ("userId")`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_924fa71815cfa3941d003702a0" ON "announcement_read" USING btree ("userId", "announcementId")`);
}
}

View file

@ -50,8 +50,6 @@ import { Page } from '@/models/entities/page.js';
import { PageLike } from '@/models/entities/page-like.js';
import { ModerationLog } from '@/models/entities/moderation-log.js';
import { UsedUsername } from '@/models/entities/used-username.js';
import { Announcement } from '@/models/entities/announcement.js';
import { AnnouncementRead } from '@/models/entities/announcement-read.js';
import { Clip } from '@/models/entities/clip.js';
import { ClipNote } from '@/models/entities/clip-note.js';
import { Antenna } from '@/models/entities/antenna.js';
@ -99,8 +97,6 @@ class MyCustomLogger implements Logger {
}
export const entities = [
Announcement,
AnnouncementRead,
Meta,
Instance,
App,

View file

@ -1,36 +0,0 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
import { id } from '../id.js';
import { User } from './user.js';
import { Announcement } from './announcement.js';
@Entity()
@Index(['userId', 'announcementId'], { unique: true })
export class AnnouncementRead {
@PrimaryColumn(id())
public id: string;
@Column('timestamp with time zone', {
comment: 'The created date of the AnnouncementRead.',
})
public createdAt: Date;
@Index()
@Column(id())
public userId: User['id'];
@ManyToOne(() => User, {
onDelete: 'CASCADE',
})
@JoinColumn()
public user: User | null;
@Index()
@Column(id())
public announcementId: Announcement['id'];
@ManyToOne(() => Announcement, {
onDelete: 'CASCADE',
})
@JoinColumn()
public announcement: Announcement | null;
}

View file

@ -1,35 +0,0 @@
import { Entity, Index, Column, PrimaryColumn } from 'typeorm';
import { id } from '../id.js';
@Entity()
export class Announcement {
@PrimaryColumn(id())
public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Announcement.',
})
public createdAt: Date;
@Column('timestamp with time zone', {
comment: 'The updated date of the Announcement.',
nullable: true,
})
public updatedAt: Date | null;
@Column('varchar', {
length: 8192, nullable: false,
})
public text: string;
@Column('varchar', {
length: 256, nullable: false,
})
public title: string;
@Column('varchar', {
length: 1024, nullable: true,
})
public imageUrl: string | null;
}

View file

@ -1,7 +1,5 @@
import { db } from '@/db/postgre.js';
import { Announcement } from './entities/announcement.js';
import { AnnouncementRead } from './entities/announcement-read.js';
import { Poll } from './entities/poll.js';
import { PollVote } from './entities/poll-vote.js';
import { Meta } from './entities/meta.js';
@ -59,8 +57,6 @@ import { UserPending } from './entities/user-pending.js';
import { InstanceRepository } from './repositories/instance.js';
import { Webhook } from './entities/webhook.js';
export const Announcements = db.getRepository(Announcement);
export const AnnouncementReads = db.getRepository(AnnouncementRead);
export const Apps = (AppRepository);
export const Notes = (NoteRepository);
export const NoteWatchings = db.getRepository(NoteWatching);

View file

@ -10,7 +10,7 @@ import { Cache } from '@/misc/cache.js';
import { db } from '@/db/postgre.js';
import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js';
import { Instance } from '../entities/instance.js';
import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, RenoteMutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js';
import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, RenoteMutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js';
type IsUserDetailed<Detailed extends boolean> = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>;
type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends boolean> =
@ -157,13 +157,6 @@ export const UserRepository = db.getRepository(User).extend({
).then(res => res[0].exists);
},
async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> {
return await db.query(
`SELECT EXISTS (SELECT 1 FROM "announcement" WHERE "id" NOT IN (SELECT "announcementId" FROM "announcement_read" WHERE "userId" = $1)) AS exists`,
[userId]
).then(res => res[0].exists);
},
async getHasUnreadAntenna(userId: User['id']): Promise<boolean> {
return await db.query(
`SELECT EXISTS (SELECT 1 FROM "antenna_note" WHERE NOT "read" AND "antennaId" IN (SELECT "id" FROM "antenna" WHERE "userId" = $1)) AS exists`,
@ -387,7 +380,6 @@ export const UserRepository = db.getRepository(User).extend({
where: { userId: user.id, isMentioned: true },
take: 1,
}).then(count => count > 0),
hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id),
hasUnreadAntenna: this.getHasUnreadAntenna(user.id),
hasUnreadChannel: this.getHasUnreadChannel(user.id),
hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage(user.id),

View file

@ -320,10 +320,6 @@ export const packedMeDetailedOnlySchema = {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadAnnouncement: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadAntenna: {
type: 'boolean',
nullable: false, optional: false,

View file

@ -2,10 +2,6 @@ import { Schema } from '@/misc/schema.js';
import { errors } from './error.js';
import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_announcements_create from './endpoints/admin/announcements/create.js';
import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js';
import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js';
import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
import * as ep___admin_drive_showFile from './endpoints/admin/drive/show-file.js';
@ -54,7 +50,6 @@ import * as ep___admin_users_unsilence from './endpoints/admin/users/unsilence.j
import * as ep___admin_users_unsuspend from './endpoints/admin/users/unsuspend.js';
import * as ep___admin_updateMeta from './endpoints/admin/update-meta.js';
import * as ep___admin_vacuum from './endpoints/admin/vacuum.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
import * as ep___antennas_list from './endpoints/antennas/list.js';
@ -172,7 +167,6 @@ import * as ep___i_pages from './endpoints/i/pages.js';
import * as ep___i_pin from './endpoints/i/pin.js';
import * as ep___i_readAllMessagingMessages from './endpoints/i/read-all-messaging-messages.js';
import * as ep___i_readAllUnreadNotes from './endpoints/i/read-all-unread-notes.js';
import * as ep___i_readAnnouncement from './endpoints/i/read-announcement.js';
import * as ep___i_regenerateToken from './endpoints/i/regenerate-token.js';
import * as ep___i_registry_getAll from './endpoints/i/registry/get-all.js';
import * as ep___i_registry_getDetail from './endpoints/i/registry/get-detail.js';
@ -295,10 +289,6 @@ import * as ep___fetchRss from './endpoints/fetch-rss.js';
const eps = [
['admin/meta', ep___admin_meta],
['admin/announcements/create', ep___admin_announcements_create],
['admin/announcements/delete', ep___admin_announcements_delete],
['admin/announcements/list', ep___admin_announcements_list],
['admin/announcements/update', ep___admin_announcements_update],
['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles],
['admin/drive/files', ep___admin_drive_files],
['admin/drive/show-file', ep___admin_drive_showFile],
@ -347,7 +337,6 @@ const eps = [
['admin/users/unsuspend', ep___admin_users_unsuspend],
['admin/update-meta', ep___admin_updateMeta],
['admin/vacuum', ep___admin_vacuum],
['announcements', ep___announcements],
['antennas/create', ep___antennas_create],
['antennas/delete', ep___antennas_delete],
['antennas/list', ep___antennas_list],
@ -465,7 +454,6 @@ const eps = [
['i/pin', ep___i_pin],
['i/read-all-messaging-messages', ep___i_readAllMessagingMessages],
['i/read-all-unread-notes', ep___i_readAllUnreadNotes],
['i/read-announcement', ep___i_readAnnouncement],
['i/regenerate-token', ep___i_regenerateToken],
['i/registry/get-all', ep___i_registry_getAll],
['i/registry/get-detail', ep___i_registry_getDetail],

View file

@ -1,69 +0,0 @@
import { Announcements } from '@/models/index.js';
import { genId } from '@/misc/gen-id.js';
import define from '@/server/api/define.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
title: {
type: 'string',
optional: false, nullable: false,
},
text: {
type: 'string',
optional: false, nullable: false,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
title: { type: 'string', minLength: 1 },
text: { type: 'string', minLength: 1 },
imageUrl: { type: 'string', nullable: true, minLength: 1 },
},
required: ['title', 'text', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps) => {
const announcement = await Announcements.insert({
id: genId(),
createdAt: new Date(),
updatedAt: null,
title: ps.title,
text: ps.text,
imageUrl: ps.imageUrl,
}).then(x => Announcements.findOneByOrFail(x.identifiers[0]));
return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null });
});

View file

@ -1,29 +0,0 @@
import { Announcements } from '@/models/index.js';
import define from '@/server/api/define.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: ['NO_SUCH_ANNOUNCEMENT'],
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps) => {
const announcement = await Announcements.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError('NO_SUCH_ANNOUNCEMENT');
await Announcements.delete(announcement.id);
});

View file

@ -1,89 +0,0 @@
import { Announcements, AnnouncementReads } from '@/models/index.js';
import { Announcement } from '@/models/entities/announcement.js';
import define from '@/server/api/define.js';
import { makePaginationQuery } from '@/server/api/common/make-pagination-query.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: false,
},
title: {
type: 'string',
optional: false, nullable: false,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
},
reads: {
type: 'number',
optional: false, nullable: false,
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps) => {
const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const announcements = await query.take(ps.limit).getMany();
const reads = new Map<Announcement, number>();
for (const announcement of announcements) {
reads.set(announcement, await AnnouncementReads.countBy({
announcementId: announcement.id,
}));
}
return announcements.map(announcement => ({
id: announcement.id,
createdAt: announcement.createdAt.toISOString(),
updatedAt: announcement.updatedAt?.toISOString() ?? null,
title: announcement.title,
text: announcement.text,
imageUrl: announcement.imageUrl,
reads: reads.get(announcement),
}));
});

View file

@ -1,37 +0,0 @@
import { Announcements } from '@/models/index.js';
import define from '@/server/api/define.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: ['NO_SUCH_ANNOUNCEMENT'],
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
title: { type: 'string', minLength: 1 },
text: { type: 'string', minLength: 1 },
imageUrl: { type: 'string', nullable: true, minLength: 1 },
},
required: ['id', 'title', 'text', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps) => {
const announcement = await Announcements.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError('NO_SUCH_ANNOUNCEMENT');
await Announcements.update(announcement.id, {
updatedAt: new Date(),
title: ps.title,
text: ps.text,
imageUrl: ps.imageUrl,
});
});

View file

@ -1,86 +0,0 @@
import { Announcements, AnnouncementReads } from '@/models/index.js';
import define from '@/server/api/define.js';
import { makePaginationQuery } from '@/server/api/common/make-pagination-query.js';
export const meta = {
tags: ['meta'],
requireCredential: false,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: false,
},
title: {
type: 'string',
optional: false, nullable: false,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
},
isRead: {
type: 'boolean',
optional: true, nullable: false,
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
withUnreads: { type: 'boolean', default: false },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, user) => {
const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const announcements = await query.take(ps.limit).getMany();
if (user) {
const reads = (await AnnouncementReads.findBy({
userId: user.id,
})).map(x => x.announcementId);
for (const announcement of announcements) {
(announcement as any).isRead = reads.includes(announcement.id);
}
}
return (ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements).map((a) => ({
...a,
createdAt: a.createdAt.toISOString(),
updatedAt: a.updatedAt?.toISOString() ?? null,
}));
});

View file

@ -16,7 +16,6 @@ export const meta = {
example: [
'admin/abuse-user-reports',
'admin/accounts/create',
'admin/announcements/create',
'...',
],
},

View file

@ -1,51 +0,0 @@
import { genId } from '@/misc/gen-id.js';
import { AnnouncementReads, Announcements, Users } from '@/models/index.js';
import { publishMainStream } from '@/services/stream.js';
import define from '@/server/api/define.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['account'],
requireCredential: true,
kind: 'write:account',
errors: ['NO_SUCH_ANNOUNCEMENT'],
} as const;
export const paramDef = {
type: 'object',
properties: {
announcementId: { type: 'string', format: 'misskey:id' },
},
required: ['announcementId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, user) => {
// Check if announcement exists
const exists = await Announcements.countBy({ id: ps.announcementId });
if (!exists) throw new ApiError('NO_SUCH_ANNOUNCEMENT');
// Check if already read
const read = await AnnouncementReads.countBy({
announcementId: ps.announcementId,
userId: user.id,
});
if (read) return;
// Create read
await AnnouncementReads.insert({
id: genId(),
createdAt: new Date(),
announcementId: ps.announcementId,
userId: user.id,
});
if (!await Users.getHasUnreadAnnouncement(user.id)) {
publishMainStream(user.id, 'readAllAnnouncements');
}
});

View file

@ -216,10 +216,6 @@ export const errors: Record<string, { message: string, httpStatusCode: number }>
message: 'The note does not have an attached poll.',
httpStatusCode: 404,
},
NO_SUCH_ANNOUNCEMENT: {
message: 'No such announcement.',
httpStatusCode: 404,
},
NO_SUCH_ANTENNA: {
message: 'No such antenna.',
httpStatusCode: 404,

View file

@ -84,7 +84,6 @@ export interface MainStreamTypes {
unreadMessagingMessage: Packed<'MessagingMessage'>;
readAllAntennas: undefined;
unreadAntenna: Antenna;
readAllAnnouncements: undefined;
readAllChannels: undefined;
unreadChannel: Note['id'];
myTokenRegenerated: undefined;

View file

@ -404,10 +404,6 @@ import { getAccountFromId } from '@/scripts/get-account-from-id';
sound.play('antenna');
});
main.on('readAllAnnouncements', () => {
updateAccount({ hasUnreadAnnouncement: false });
});
main.on('readAllChannels', () => {
updateAccount({ hasUnreadChannel: false });
});

View file

@ -34,12 +34,6 @@ export const menuDef = reactive({
indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest),
to: '/my/follow-requests',
},
announcements: {
title: 'announcements',
icon: 'fas fa-broadcast-tower',
indicated: computed(() => $i != null && $i.hasUnreadAnnouncement),
to: '/announcements',
},
search: {
title: 'search',
icon: 'fas fa-search',

View file

@ -1,108 +0,0 @@
<template>
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions"/></template>
<MkSpacer :content-max="900">
<div class="ztgjmzrw">
<section v-for="announcement in announcements" class="_card _gap announcements">
<div class="_content announcement">
<FormInput v-model="announcement.title">
<template #label>{{ i18n.ts.title }}</template>
</FormInput>
<FormTextarea v-model="announcement.text">
<template #label>{{ i18n.ts.text }}</template>
</FormTextarea>
<FormInput v-model="announcement.imageUrl">
<template #label>{{ i18n.ts.imageUrl }}</template>
</FormInput>
<p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
<div class="buttons">
<MkButton class="button" inline primary @click="save(announcement)"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton>
<MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ i18n.ts.remove }}</MkButton>
</div>
</div>
</section>
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import MkButton from '@/components/ui/button.vue';
import FormInput from '@/components/form/input.vue';
import FormTextarea from '@/components/form/textarea.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
let announcements: any[] = $ref([]);
os.api('admin/announcements/list').then(announcementResponse => {
announcements = announcementResponse;
});
function add() {
announcements.unshift({
id: null,
title: '',
text: '',
imageUrl: null,
});
}
function remove(announcement) {
os.confirm({
type: 'warning',
text: i18n.t('removeAreYouSure', { x: announcement.title }),
}).then(({ canceled }) => {
if (canceled) return;
announcements = announcements.filter(x => x !== announcement);
os.api('admin/announcements/delete', announcement);
});
}
function save(announcement) {
if (announcement.id == null) {
os.api('admin/announcements/create', announcement).then(() => {
os.alert({
type: 'success',
text: i18n.ts.saved,
});
}).catch(err => {
os.alert({
type: 'error',
text: err,
});
});
} else {
os.api('admin/announcements/update', announcement).then(() => {
os.alert({
type: 'success',
text: i18n.ts.saved,
});
}).catch(err => {
os.alert({
type: 'error',
text: err,
});
});
}
}
const headerActions = $computed(() => [{
asFullButton: true,
icon: 'fas fa-plus',
text: i18n.ts.add,
handler: add,
}]);
definePageMetadata({
title: i18n.ts.announcements,
icon: 'fas fa-broadcast-tower',
});
</script>
<style lang="scss" scoped>
.ztgjmzrw {
margin: var(--margin);
}
</style>

View file

@ -119,11 +119,6 @@ const menuDef = $computed(() => [{
text: i18n.ts.files,
to: '/admin/files',
active: props.initialPage === 'files',
}, {
icon: 'fas fa-broadcast-tower',
text: i18n.ts.announcements,
to: '/admin/announcements',
active: props.initialPage === 'announcements',
}, {
icon: 'fas fa-exclamation-circle',
text: i18n.ts.abuseReports,
@ -191,7 +186,6 @@ const component = $computed(() => {
case 'federation': return defineAsyncComponent(() => import('./federation.vue'));
case 'queue': return defineAsyncComponent(() => import('./queue.vue'));
case 'files': return defineAsyncComponent(() => import('./files.vue'));
case 'announcements': return defineAsyncComponent(() => import('./announcements.vue'));
case 'database': return defineAsyncComponent(() => import('./database.vue'));
case 'abuses': return defineAsyncComponent(() => import('./abuses.vue'));
case 'settings': return defineAsyncComponent(() => import('./settings.vue'));

View file

@ -1,64 +0,0 @@
<template>
<MkStickyContainer>
<template #header><MkPageHeader/></template>
<MkSpacer :content-max="800">
<MkPagination v-slot="{items}" :pagination="pagination" class="ruryvtyk _content">
<section v-for="(announcement, i) in items" :key="announcement.id" class="_card announcement">
<div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
<div class="_content">
<Mfm :text="announcement.text"/>
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
</div>
<div v-if="$i && !announcement.isRead" class="_footer">
<MkButton primary @click="read(items, announcement, i)"><i class="fas fa-check"></i> {{ i18n.ts.gotIt }}</MkButton>
</div>
</section>
</MkPagination>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import MkPagination from '@/components/ui/pagination.vue';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
const pagination = {
endpoint: 'announcements' as const,
limit: 10,
};
// TODO:
function read(items, announcement, i) {
items[i] = {
...announcement,
isRead: true,
};
os.api('i/read-announcement', { announcementId: announcement.id });
}
definePageMetadata({
title: i18n.ts.announcements,
icon: 'fas fa-broadcast-tower',
});
</script>
<style lang="scss" scoped>
.ruryvtyk {
> .announcement {
&:not(:last-child) {
margin-bottom: var(--margin);
}
> ._content {
> img {
display: block;
max-height: 300px;
max-width: 100%;
}
}
}
}
</style>

View file

@ -50,9 +50,6 @@ export const routes = [{
}, {
path: '/signup-complete/:code',
component: page(() => import('./pages/signup-complete.vue')),
}, {
path: '/announcements',
component: page(() => import('./pages/announcements.vue')),
}, {
path: '/about',
component: page(() => import('./pages/about.vue')),

View file

@ -58,7 +58,6 @@ export const defaultStore = markRaw(new Storage('base', {
'drive',
'followRequests',
'-',
'announcements',
'search',
'-',
'ui',

View file

@ -73,10 +73,6 @@ provideMetadataReceiver((info) => {
}
});
const announcements = {
endpoint: 'announcements',
limit: 10,
};
let showMenu = $ref(false);
let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD);
let narrow = $ref(window.innerWidth < 1280);

View file

@ -15,18 +15,6 @@
<button class="_buttonPrimary" @click="signup()">{{ i18n.ts.signup }}</button>
<button class="_button" @click="signin()">{{ i18n.ts.login }}</button>
</div>
<div class="announcements panel">
<header>{{ i18n.ts.announcements }}</header>
<MkPagination v-slot="{items}" :pagination="announcements" class="list">
<section v-for="announcement in items" :key="announcement.id" class="item">
<div class="title">{{ announcement.title }}</div>
<div class="content">
<Mfm :text="announcement.text"/>
<img v-if="announcement.imageUrl" :src="announcement.imageUrl" alt="announcement image"/>
</div>
</section>
</MkPagination>
</div>
<div v-if="poweredBy" class="powered-by">
<b><MkA to="/">{{ host }}</MkA></b>
<small>Powered by <a href="https://akkoma.dev/FoundKeyGang/FoundKey" target="_blank">FoundKey</a></small>
@ -56,11 +44,6 @@ withDefaults(defineProps<{
poweredBy: false,
});
const announcements = {
endpoint: 'announcements',
limit: 10,
};
function signin(): void {
os.popup(XSigninDialog, {
autoSet: true,
@ -173,39 +156,6 @@ function signup(): void {
}
}
> .announcements {
margin: 32px 0;
text-align: left;
> header {
padding: 12px 16px;
border-bottom: solid 1px rgba(255, 255, 255, 0.5);
}
> .list {
max-height: 300px;
overflow: auto;
> .item {
padding: 12px 16px;
& + .item {
border-top: solid 1px rgba(255, 255, 255, 0.5);
}
> .title {
font-weight: bold;
}
> .content {
> img {
max-width: 100%;
}
}
}
}
}
> .powered-by {
padding: 28px;
font-size: 14px;

View file

@ -1,5 +1,5 @@
import {
Announcement, Antenna, App, AuthSession, Blocking, Channel, Clip, DateString, InstanceMetadata, DriveFile, DriveFolder, Following, FollowingFolloweePopulated, FollowingFollowerPopulated, FollowRequest, Instance,
Antenna, App, AuthSession, Blocking, Channel, Clip, DateString, InstanceMetadata, DriveFile, DriveFolder, Following, FollowingFolloweePopulated, FollowingFollowerPopulated, FollowRequest, Instance,
MeDetailed,
Note, OriginType, Page, ServerInfo, Stats, User, UserDetailed, UserGroup, UserList, UserSorting, Notification, NoteReaction, Signin, MessagingMessage,
} from './entities.js';
@ -12,10 +12,6 @@ type ShowUserReq = { username: string; host?: string; } | { userId: User['id'];
export type Endpoints = {
'admin/meta': { req: TODO; res: TODO; };
'admin/announcements/create': { req: TODO; res: TODO; };
'admin/announcements/delete': { req: { id: Announcement['id'] }; res: null; };
'admin/announcements/list': { req: TODO; res: TODO; };
'admin/announcements/update': { req: TODO; res: TODO; };
'admin/drive/clean-remote-files': { req: TODO; res: TODO; };
'admin/drive/files': { req: TODO; res: TODO; };
'admin/drive/show-file': { req: TODO; res: TODO; };
@ -64,7 +60,6 @@ export type Endpoints = {
'admin/users/unsuspend': { req: TODO; res: TODO; };
'admin/update-meta': { req: TODO; res: TODO; };
'admin/vacuum': { req: TODO; res: TODO; };
'announcements': { req: { limit?: number; withUnreads?: boolean; sinceId?: Announcement['id']; untilId?: Announcement['id']; }; res: Announcement[]; };
'antennas/create': { req: TODO; res: Antenna; };
'antennas/delete': { req: { antennaId: Antenna['id']; }; res: null; };
'antennas/list': { req: NoParams; res: Antenna[]; };
@ -322,7 +317,6 @@ export type Endpoints = {
'i/pin': { req: { noteId: Note['id']; }; res: MeDetailed; };
'i/read-all-messaging-messages': { req: TODO; res: TODO; };
'i/read-all-unread-notes': { req: TODO; res: TODO; };
'i/read-announcement': { req: TODO; res: TODO; };
'i/regenerate-token': { req: { password: string; }; res: null; };
'i/registry/get-all': { req: { scope?: string[]; }; res: Record<string, any>; };
'i/registry/get-detail': { req: { key: string; scope?: string[]; }; res: { updatedAt: DateString; value: any; }; };

View file

@ -89,7 +89,6 @@ export type MeDetailed = UserDetailed & {
carefulBot: boolean;
emailNotificationTypes: string[];
hasPendingReceivedFollowRequest: boolean;
hasUnreadAnnouncement: boolean;
hasUnreadAntenna: boolean;
hasUnreadChannel: boolean;
hasUnreadMentions: boolean;
@ -353,16 +352,6 @@ export type PageEvent = {
user: User;
};
export type Announcement = {
id: ID;
createdAt: DateString;
updatedAt: DateString | null;
text: string;
title: string;
imageUrl: string | null;
isRead?: boolean;
};
export type Antenna = {
id: ID;
createdAt: DateString;

View file

@ -27,7 +27,6 @@ export type Channels = {
unreadMessagingMessage: (payload: MessagingMessage) => void;
readAllAntennas: () => void;
unreadAntenna: (payload: Antenna) => void;
readAllAnnouncements: () => void;
readAllChannels: () => void;
unreadChannel: (payload: Note['id']) => void;
myTokenRegenerated: () => void;