diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 262c79ab3d..ac7b8c59d5 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -64,6 +64,7 @@ jobs:
sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg
sudo apt update
sudo apt install oha
+ oha --version
- name: Benchmark PR
run: 'oha -z 180s http://localhost/v1/health/version --output-format json --output benchmark.json'
- name: Cleaning
diff --git a/app/config/locale/templates/email-inner-base.tpl b/app/config/locale/templates/email-inner-base.tpl
index 8cef391d2f..677f70ce7d 100644
--- a/app/config/locale/templates/email-inner-base.tpl
+++ b/app/config/locale/templates/email-inner-base.tpl
@@ -1,6 +1,6 @@
{{hello}}
{{body}}
-{{redirect}}
+{{buttonText}}
{{footer}}
{{thanks}}
diff --git a/app/config/locale/translations/af.json b/app/config/locale/translations/af.json
index e68fda2c75..9b313ac92a 100644
--- a/app/config/locale/translations/af.json
+++ b/app/config/locale/translations/af.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Volg hierdie skakel om u e-pos adres te bevestig.",
"emails.verification.footer": "Ignoreer gerus hierdie boodskap as u nie die versoek gestuur het om u adres te bevestig nie.",
"emails.verification.thanks": "Baie dankie,",
+ "emails.verification.buttonText": "Bevestig e-posadres",
"emails.verification.signature": "Die {{project}} span",
"emails.magicSession.subject": "Teken aan",
"emails.magicSession.hello": "Goeie dag,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Volg hierdie skakel om u {{project}} wagwoord te herstel.",
"emails.recovery.footer": "Ignoreer gerus hierdie boodskap as u nie die versoek gestuur het om u wagwoord te herstel nie.",
"emails.recovery.thanks": "Baie dankie,",
+ "emails.recovery.buttonText": "Stel wagwoord terug",
"emails.recovery.signature": "Die {{project}} span",
"emails.invitation.subject": "Uitnodiging om by die %s span aan te sluit by %s",
"emails.invitation.hello": "Goeie dag,",
"emails.invitation.body": "Hierdie boodskap is aan u gestuur omdat {{owner}} u uitnooi om 'n lid van die {{team}} groep by die {{project}} projek te wees.",
"emails.invitation.footer": "As u nie belang stel nie, kan u gerus hierdie boodskap ignoreer.",
"emails.invitation.thanks": "Baie dankie,",
+ "emails.invitation.buttonText": "Aanvaar uitnodiging na {{team}}",
"emails.invitation.signature": "Die {{project}} span",
"locale.country.unknown": "Onbekend",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ar-ma.json b/app/config/locale/translations/ar-ma.json
index efd2e95c31..e4b5b1f558 100644
--- a/app/config/locale/translations/ar-ma.json
+++ b/app/config/locale/translations/ar-ma.json
@@ -8,6 +8,7 @@
"emails.verification.body": "تبّع هاد الوصلة باش تيقّن لادريسة تاع ليميل ديالك.",
"emails.verification.footer": "إلا ماشي نتا اللي طلبتي تيقّن هاد لادريسة تاع ليميل، ممكن تنخّل هاد البرية.",
"emails.verification.thanks": "شكرا،",
+ "emails.verification.buttonText": "تأكيد عنوان البريد الإلكتروني",
"emails.verification.signature": "فرقة {{project}}",
"emails.magicSession.subject": "تكونيكطا",
"emails.magicSession.hello": "السلام،",
@@ -20,12 +21,14 @@
"emails.recovery.body": "تبّع هاد الوصلة باش تبدّل كلمة السر تاع {{project}}.",
"emails.recovery.footer": "إلا ماشي نتا اللي طلبتي تبدّل كلمة السر، ممكن تنخّل هاد البرية.",
"emails.recovery.thanks": "شكرا،",
+ "emails.recovery.buttonText": "إعادة تعيين كلمة السر",
"emails.recovery.signature": "فرقة {{project}}",
"emails.invitation.subject": "عراضة ل فرقة %s ف %s",
"emails.invitation.hello": "السلام،",
"emails.invitation.body": "هاد البرية تصيفطات ليك حيت {{owner}} بغى يعرض عليك تولّي عضو ف فرقة {{team}} عند {{project}}.",
"emails.invitation.footer": "إلا كنتي ما مسوّقش, ممكن تنخّل هاد البرية.",
"emails.invitation.thanks": "شكرا،",
+ "emails.invitation.buttonText": "اقبل الدعوة إلى {{team}}",
"emails.invitation.signature": "فرقة {{project}}",
"emails.certificate.subject": "السرتافيكة فشلات ل %s",
"emails.certificate.hello": "السلام،",
diff --git a/app/config/locale/translations/ar.json b/app/config/locale/translations/ar.json
index 1d67c2ecf7..eda0652fbe 100644
--- a/app/config/locale/translations/ar.json
+++ b/app/config/locale/translations/ar.json
@@ -8,6 +8,7 @@
"emails.verification.body": "برجاء اتباع الرابط التالي لتأكيد بريدك الإلكتروني",
"emails.verification.footer": "لو لم تطلب تأكيد هذا البريد الإلكتروني، يمكنك تجاهل هذه الرسالة",
"emails.verification.thanks": "شكرا،",
+ "emails.verification.buttonText": "تأكيد عنوان البريد الإلكتروني",
"emails.verification.signature": "فريق {{project}}",
"emails.magicSession.subject": "تسجيل الدخول",
"emails.magicSession.hello": "أهلا،",
@@ -20,12 +21,14 @@
"emails.recovery.body": "برجاء اتباع الراط التالي لتغيير كلمة السر الخاصة بـ{{project}}",
"emails.recovery.footer": "لولم تطلب تغيير كلمة السر، يمكنك تجاهل هذه الرسالة",
"emails.recovery.thanks": "شكرا،",
+ "emails.recovery.buttonText": "إعادة تعيين كلمة المرور",
"emails.recovery.signature": "فريق {{project}}",
"emails.invitation.subject": "دعوة لفريق %s في %s",
"emails.invitation.hello": "أهلا،",
"emails.invitation.body": "هذة الرسالة تم ارسالها لك لأن {{owner}} ارسل لك دعوة لتكون عضوا بفريق {{team}} في {{project}}",
"emails.invitation.footer": "اذا كنت غير مهتم، يمكنك تجاهل هذه الرسالة",
"emails.invitation.thanks": "شكرا،",
+ "emails.invitation.buttonText": "قبول الدعوة إلى {{team}}",
"emails.invitation.signature": "فريق {{project}}",
"locale.country.unknown": "مجهول",
"countries.af": "أفغانستان",
diff --git a/app/config/locale/translations/as.json b/app/config/locale/translations/as.json
index 572ed80f1a..60e385a8ac 100644
--- a/app/config/locale/translations/as.json
+++ b/app/config/locale/translations/as.json
@@ -8,6 +8,7 @@
"emails.verification.body": "আপোনাৰ ইমেইল ঠিকনা প্ৰমাণিত কৰিবলৈ এই লিংকটো অনুসৰণ কৰক।",
"emails.verification.footer": "যদি আপুনি এই ঠিকনাটো সত্যাপিত কৰিবলৈ কোৱা নাই, আপুনি এই বাৰ্তাটো উপেক্ষা কৰিব পাৰে।",
"emails.verification.thanks": "ধন্যবাদ,",
+ "emails.verification.buttonText": "ইমেইল ঠিকনা নিশ্চিত কৰক",
"emails.verification.signature": "{{project}} দল",
"emails.magicSession.subject": "লগইন",
"emails.magicSession.hello": "নমস্কাৰ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "আপোনাৰ {{project}} পাছৱৰ্ড ৰিছেট কৰিবলৈ এই লিংকটো অনুসৰণ কৰক।.",
"emails.recovery.footer": "যদি আপুনি আপোনাৰ পাছৱৰ্ড ৰিছেট কৰিবলৈ কোৱা নাছিল, আপুনি এই বাৰ্তাটো উপেক্ষা কৰিব পাৰে।",
"emails.recovery.thanks": "ধন্যবাদ,",
+ "emails.recovery.buttonText": "পাছৱৰ্ড ৰিছেট কৰক",
"emails.recovery.signature": "{{project}} দল",
"emails.invitation.subject": "%s বছৰত %s দললৈ নিমন্ত্ৰণ",
"emails.invitation.hello": "নমস্কাৰ,",
"emails.invitation.body": "এই মেইলটো আপোনালৈ প্ৰেৰণ কৰা হৈছিল কাৰণ {{owner}} জনে আপোনাক {{project}} বছৰবয়সত {{team}} দলৰ সদস্য হ'বলৈ আমন্ত্ৰণ জনাব বিচাৰিছিল।",
"emails.invitation.footer": "যদি আপুনি আগ্ৰহী নহয়, আপুনি এই বাৰ্তাটো উপেক্ষা কৰিব পাৰে।",
"emails.invitation.thanks": "ধন্যবাদ,",
+ "emails.invitation.buttonText": "{{team}}-লৈ নিমন্ত্ৰণ গ্ৰহণ কৰক",
"emails.invitation.signature": "{{project}} দল",
"locale.country.unknown": "অজ্ঞাত ",
"countries.af": "আফগানিস্তান ",
diff --git a/app/config/locale/translations/az.json b/app/config/locale/translations/az.json
index 5988c51786..63e442f7c5 100644
--- a/app/config/locale/translations/az.json
+++ b/app/config/locale/translations/az.json
@@ -8,6 +8,7 @@
"emails.verification.body": "E-poçt ünvanınızı təsdiq etmək üçün bu linki izləyin.",
"emails.verification.footer": "Bu ünvanı doğrulamağı xahiş etməmisinizsə, bu mesajı gözardı edə bilərsiniz.",
"emails.verification.thanks": "Təşəkkürlər,",
+ "emails.verification.buttonText": "E-poçt ünvanını təsdiqlə",
"emails.verification.signature": "{{project}} komandası",
"emails.magicSession.subject": "Daxil Olmaq",
"emails.magicSession.hello": "Salam,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "{{project}} şifrənizi sıfırlamaq üçün bu linki izləyin.",
"emails.recovery.footer": "Şifrənizi sıfırlamağı xahiş etməmisinizsə, bu mesajı gözardı edə bilərsiniz.",
"emails.recovery.thanks": "Təşəkkürlər,",
+ "emails.recovery.buttonText": "Şifrəni sıfırla",
"emails.recovery.signature": "{{project}} komandası",
"emails.invitation.subject": "%s Komandasına Dəvət %sdə",
"emails.invitation.hello": "Salam,",
"emails.invitation.body": "{{owner}}, {{project}}də {{team}} komandasına üzv olmağa dəvət etmək istədiyi üçün bu məktub sizə göndərildi.",
"emails.invitation.footer": "Əgər maraqlanmırsınızsa, bu mesajı gözardı edə bilərsiniz.",
"emails.invitation.thanks": "Təşəkkürlər,",
+ "emails.invitation.buttonText": "{{team}} dəvətini qəbul et",
"emails.invitation.signature": "{{project}} komandası",
"locale.country.unknown": "Naməlum",
"countries.af": "Əfqanıstan",
diff --git a/app/config/locale/translations/be.json b/app/config/locale/translations/be.json
index f03a9d5bef..b4ae0827c3 100644
--- a/app/config/locale/translations/be.json
+++ b/app/config/locale/translations/be.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Перайдзіце па гэтай спасылцы, каб пацвердзіць свой адрас электроннай пошты",
"emails.verification.footer": "Калі вы не запытвалі пацвярджэнне гэтага адрасу, праігнаруйце гэтае паведамленне.",
"emails.verification.thanks": "Дзякуем,",
+ "emails.verification.buttonText": "Пацвердзіць адрас электроннай пошты",
"emails.verification.signature": "каманда {{project}}",
"emails.magicSession.subject": "Лагін",
"emails.magicSession.hello": "Прывітанне,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Перайдзіце па гэтай спасылцы, каб скінуць пароль для праекта {{project}}.",
"emails.recovery.footer": "Калі вы не прасілі скінуць пароль, вы можаце праігнараваць гэта паведамленне.",
"emails.recovery.thanks": "Дзякуем,",
+ "emails.recovery.buttonText": "Аднавіць пароль",
"emails.recovery.signature": "каманда {{project}}",
"emails.invitation.subject": "Запрошення до Команди %s у %s",
"emails.invitation.hello": "Прывітанне,",
"emails.invitation.body": "Гэта паведамленне было адпраўлена вам, таму што {{owner}} хацеў запрасіць вас стаць членам каманды {{team}} у {{project}}.",
"emails.invitation.footer": "Калі вам гэта не цікава, вы можаце праігнараваць гэтае паведамленне.",
"emails.invitation.thanks": "Дзякуем,",
+ "emails.invitation.buttonText": "Прыняць запрашэнне ў {{team}}",
"emails.invitation.signature": "каманда {{project}}",
"locale.country.unknown": "Невядомы",
"countries.af": "Афганістан",
diff --git a/app/config/locale/translations/bh.json b/app/config/locale/translations/bh.json
index 5cf06bd1dd..7d2b469ed5 100644
--- a/app/config/locale/translations/bh.json
+++ b/app/config/locale/translations/bh.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ईमेल प्रमाणिकरण करे क लेल दिहल गइल लिंक फॉलो करें|",
"emails.verification.footer": "अगर ई पता को सत्यापित करे के लिए ना कहाले, तो आप ई संदेश क अनदेखा कर सकत अछि।",
"emails.verification.thanks": "धन्यवाद,",
+ "emails.verification.buttonText": "ईमेल पता के पुष्टि करीं",
"emails.verification.signature": "{{project}} टीम",
"emails.magicSession.subject": "लॉग इन करीं|",
"emails.magicSession.hello": "प्रणाम,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "पासवर्ड बदल क लेल दिहल गइल लिंक फॉलो करें|",
"emails.recovery.footer": "अगर पासवर्ड बदल क लेल ना कहाले, तो आप ई संदेश क अनदेखा कर सकत अछि।",
"emails.recovery.thanks": "धन्यवाद,",
+ "emails.recovery.buttonText": "पासवर्ड रीसेट करीं",
"emails.recovery.signature": "{{project}} टीम",
"emails.invitation.subject": "%s टीम क %s पे न्योता देवे क लेल|",
"emails.invitation.hello": "प्रणाम,",
"emails.invitation.body": "ई मेल आपके एही लेल भेजल गईल रहल काहे क {{owner}} आपके {{project}} क {{team}} टीम का सदस्य बनावे चाहित रहे|",
"emails.invitation.footer": "अगर आवे क इच्छा ना होवत, तो आप ई संदेश क अनदेखा कर सकत अछि।",
"emails.invitation.thanks": "धन्यवाद,",
+ "emails.invitation.buttonText": "{{team}} में नेवता स्वीकार करीं",
"emails.invitation.signature": "{{project}} टीम",
"locale.country.unknown": "अनजान",
"countries.af": "अफ़ग़ानिस्तान",
diff --git a/app/config/locale/translations/bn.json b/app/config/locale/translations/bn.json
index 495f56e012..1157d5cc0f 100644
--- a/app/config/locale/translations/bn.json
+++ b/app/config/locale/translations/bn.json
@@ -8,6 +8,7 @@
"emails.verification.body": "এই লিঙ্কের মাধ্যমে ইমেইল যাচাই করুন।",
"emails.verification.footer": "আপনি যদি এই ঠিকানা যাচাই করতে না বলেন, তাহলে আপনি এই বার্তাটি উপেক্ষা করতে পারেন।",
"emails.verification.thanks": "ধন্যবাদ,",
+ "emails.verification.buttonText": "ইমেইল ঠিকানা নিশ্চিত করুন",
"emails.verification.signature": "{{project}} টীম",
"emails.magicSession.subject": "লগ ইন",
"emails.magicSession.hello": "নমস্কার,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "এই লিঙ্কের মাধ্যমে আপনার {{project}} পাসওয়ার্ড পুনরায় সেট করুন।",
"emails.recovery.footer": "আপনি যদি আপনার পাসওয়ার্ড পুনরায় সেট করতে না বলেন, তাহলে আপনি এই বার্তাটি উপেক্ষা করতে পারেন।",
"emails.recovery.thanks": "ধন্যবাদ,",
+ "emails.recovery.buttonText": "পাসওয়ার্ড রিসেট করুন",
"emails.recovery.signature": "{{project}} টীম",
"emails.invitation.subject": "%s টিমকে %s তে আমন্ত্রণ জানান",
"emails.invitation.hello": "নমস্কার,",
"emails.invitation.body": "এই মেইলটি আপনাকে পাঠানো হয়েছে কারণ {{owner}} আপনাকে {{project}} এর সাথে যুক্ত {{team}} টিমের সদস্য হওয়ার জন্য আমন্ত্রণ জানাতে চেয়েছিলেন।",
"emails.invitation.footer": "যদি এটি আপনার জন্য প্রয়োজনীয় না হয়, আপনি এই বার্তাটি উপেক্ষা করতে পারেন।",
"emails.invitation.thanks": "ধন্যবাদ,",
+ "emails.invitation.buttonText": "{{team}}-এর আমন্ত্রণ গ্রহণ করুন",
"emails.invitation.signature": "{{project}} টীম",
"locale.country.unknown": "অজানা",
"countries.af": "আফগানিস্তান",
diff --git a/app/config/locale/translations/ca.json b/app/config/locale/translations/ca.json
index 98940a4a48..ec5112f075 100644
--- a/app/config/locale/translations/ca.json
+++ b/app/config/locale/translations/ca.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Accedeix a aquest enllaç per tal de verificar la teva adreça electrònica.",
"emails.verification.footer": "Si no has sol·licitat la verificació d'aquesta adreça electrònica, pots ignorar aquest missatge.",
"emails.verification.thanks": "Gràcies,",
+ "emails.verification.buttonText": "Confirma l'adreça electrònica",
"emails.verification.signature": "Equip {{project}}",
"emails.magicSession.subject": "Entrar",
"emails.magicSession.hello": "Hola,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Accedeix a aquest enllaç per a reinicialitzar la teva contrasenya de {{project}}.",
"emails.recovery.footer": "Si no has sol·licitat reinicialitzar la teva contrasenya, pots ignorar aquest missatge.",
"emails.recovery.thanks": "Gràcies,",
+ "emails.recovery.buttonText": "Restableix la contrasenya",
"emails.recovery.signature": "Equip {{project}}",
"emails.invitation.subject": "Invitació a l'equip %s a s%",
"emails.invitation.hello": "Hola,",
"emails.invitation.body": "Aquest correu se t'ha enviat perquè {{owner}} vol convidar-te a formar part de l'equip {{team}} al {{project}}.",
"emails.invitation.footer": "Si no és del teu interès, pots ignorar aquest missatge.",
"emails.invitation.thanks": "Gràcies,",
+ "emails.invitation.buttonText": "Accepta la invitació a {{team}}",
"emails.invitation.signature": "Equip {{project}}",
"locale.country.unknown": "Desconegut",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/da.json b/app/config/locale/translations/da.json
index 9cec74dbed..ae93b3c3b5 100644
--- a/app/config/locale/translations/da.json
+++ b/app/config/locale/translations/da.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Følg dette link, for at verificere din email adresse.",
"emails.verification.footer": "Hvis du ikke har bedt om at verificere denne adresse, ignorer venligst denne besked.",
"emails.verification.thanks": "Tak,",
+ "emails.verification.buttonText": "Bekræft e-mailadresse",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Hej,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Følg dette link for at nulstille koden til {{project}}.",
"emails.recovery.footer": "Hvis du ikke har bedt om at nulstille dit password, ignorer venligst denne besked.",
"emails.recovery.thanks": "Tak,",
+ "emails.recovery.buttonText": "Nulstil adgangskode",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Invitation til %s Team på %s",
"emails.invitation.hello": "Hej,",
"emails.invitation.body": "Denne mail blev sendt til dig, fordi {{owner}} vil invitere dig til at blive medlem af {{team}} teamet på {{project}}.",
"emails.invitation.footer": "Hvis du ikke er interesseret, ignorer venligst denne besked.",
"emails.invitation.thanks": "Tak,",
+ "emails.invitation.buttonText": "Accepter invitation til {{team}}",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Ukendt",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/de.json b/app/config/locale/translations/de.json
index 38b1e46870..a5a2f0ba43 100644
--- a/app/config/locale/translations/de.json
+++ b/app/config/locale/translations/de.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Folge diesem Link, um deine E-Mail-Adresse zu bestätigen.",
"emails.verification.footer": "Solltest du keine Verifizierung dieser E-Mail-Adresse angefordert haben, kannst du diese Nachricht ignorieren.",
"emails.verification.thanks": "Danke,",
+ "emails.verification.buttonText": "E-Mail-Adresse bestätigen",
"emails.verification.signature": "{{project}}-Team",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Hey,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Folge diesem Link, um dein {{project}}-Kennwort zurückzusetzen.",
"emails.recovery.footer": "Solltest du keine Kennwort-Zurücksetzung angefordert haben, kannst du diese Nachricht ignorieren.",
"emails.recovery.thanks": "Danke,",
+ "emails.recovery.buttonText": "Passwort zurücksetzen",
"emails.recovery.signature": "{{project}}-Team",
"emails.invitation.subject": "Einladung zum %s-Team auf %s",
"emails.invitation.hello": "Hello,",
"emails.invitation.body": "Du erhälst diese E-Mail, weil {{owner}} dich in das Team {{team}} auf {{project}} eingeladen hat.",
"emails.invitation.footer": "Wenn du nicht interessiert bist, kannst du diese Nachricht ignorieren.",
"emails.invitation.thanks": "Danke,",
+ "emails.invitation.buttonText": "Einladung zu {{team}} annehmen",
"emails.invitation.signature": "{{project}}-Team",
"locale.country.unknown": "Unbekannt",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/el.json b/app/config/locale/translations/el.json
index 1ef9cd30df..3576ffb865 100644
--- a/app/config/locale/translations/el.json
+++ b/app/config/locale/translations/el.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Ακολουθήστε αυτό το link για να επαληθεύσετε τη δ/νση του email σας",
"emails.verification.footer": "Εάν δεν ζητήσατε επαλήθευση αυτής της δ/νσης email, μπορείτε να αγνοήσετε αυτό το μήνυμα",
"emails.verification.thanks": "Ευχαριστούμε,",
+ "emails.verification.buttonText": "Επιβεβαιώστε διεύθυνση email",
"emails.verification.signature": "Η ομάδα του {{project}}",
"emails.magicSession.subject": "Είσοδος",
"emails.magicSession.hello": "Γεια σου,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Ακολουθήστε αυτό το link για να αλλάξετε τον {{project}} κωδικό σας",
"emails.recovery.footer": "Εάν δεν ζητήσατε αλλαγή του κωδικού σας πρόσβασης, μπορείτε να αγνοήσετε αυτό το μήνυμα",
"emails.recovery.thanks": "Ευχαριστούμε,",
+ "emails.recovery.buttonText": "Επαναφορά κωδικού πρόσβασης",
"emails.recovery.signature": "Η ομάδα του {{project}}",
"emails.invitation.subject": "Πρόσκληση στην %s Ομάδα στον %s",
"emails.invitation.hello": "Γεια σου,",
"emails.invitation.body": "Αυτό το email στάλθηκε επειδή ο/η {{owner}} θέλει να σας προσκαλέσει να γίνετε μέλος της ομάδας {{team}} του {{project}}.",
"emails.invitation.footer": "Εάν δεν ενδιαφέρεστε, μπορείτε να αγνοήσετε αυτό το μήνυμα.",
"emails.invitation.thanks": "Ευχαριστούμε,",
+ "emails.invitation.buttonText": "Αποδεχόμενος την πρόσκληση στην {{team}}",
"emails.invitation.signature": "Η ομάδα του {{project}}",
"locale.country.unknown": "Άγνωστο",
"countries.af": "Αφγανιστάν",
diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json
index d9dfddb017..dbfa2e1be8 100644
--- a/app/config/locale/translations/en.json
+++ b/app/config/locale/translations/en.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Follow this link to verify your email address to your {{b}}{{project}}{{/b}} account.",
"emails.verification.footer": "If you didn’t ask to verify this address, you can ignore this message.",
"emails.verification.thanks": "Thanks,",
+ "emails.verification.buttonText": "Confirm email address",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "{{project}} Login",
"emails.magicSession.hello": "Hello {{user}},",
@@ -45,12 +46,14 @@
"emails.recovery.body": "Follow this link to reset your {{b}}{{project}}{{/b}} password.",
"emails.recovery.footer": "If you didn't ask to reset your password, you can ignore this message.",
"emails.recovery.thanks": "Thanks,",
+ "emails.recovery.buttonText": "Reset password",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Invitation to %s Team at %s",
"emails.invitation.hello": "Hello {{user}},",
"emails.invitation.body": "This mail was sent to you because {{b}}{{owner}}{{/b}} wanted to invite you to become a member of the {{b}}{{team}}{{/b}} team at {{b}}{{project}}{{/b}}.",
"emails.invitation.footer": "If you are not interested, you can ignore this message.",
"emails.invitation.thanks": "Thanks,",
+ "emails.invitation.buttonText": "Accept invite to {{team}}",
"emails.invitation.signature": "{{project}} team",
"emails.certificate.subject": "Certificate failure for %s",
"emails.certificate.hello": "Hello,",
diff --git a/app/config/locale/translations/eo.json b/app/config/locale/translations/eo.json
index ba80bc602d..8aba49098b 100644
--- a/app/config/locale/translations/eo.json
+++ b/app/config/locale/translations/eo.json
@@ -7,6 +7,7 @@
"emails.verification.body": "Alklaku ĉi tiun ligon por kontroli vian retpoŝtan adreson.",
"emails.verification.footer": "Se vi ne petis ĉi tiun konfirmon de ĉi tiu retpoŝto, vi povas ignori ĉi tiun mesaĝon.",
"emails.verification.thanks": "Dankegon.,",
+ "emails.verification.buttonText": "Konfirmi retadreson",
"emails.verification.signature": "Teamo {{project}}",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Saluton,",
@@ -19,12 +20,14 @@
"emails.recovery.body": "Alklaku ĉi tiun ligon por reagordi vian pasvorton. {{project}}",
"emails.recovery.footer": "Se vi ne petis reagordi vian pasvorton, vi povas ignori ĉi tiun mesaĝon.",
"emails.recovery.thanks": "Dankegon,",
+ "emails.recovery.buttonText": "Pasvorton restarigi",
"emails.recovery.signature": "Teamo {{project}}",
"emails.invitation.subject": "Invito al la Teamo %s em %s",
"emails.invitation.hello": "Dankegon,",
"emails.invitation.body": "Ĉi tiu retpoŝto estis sendita ĉar la {{owner}} volas inviti vin fariĝi membro de la Teamo {{team}} en {{project}}.",
"emails.invitation.footer": "Se vi ne interesiĝas, vi povas ignori ĉi tiun mesaĝon.",
"emails.invitation.thanks": "Dankegon,",
+ "emails.invitation.buttonText": "Akcepti inviton al {{team}}",
"emails.invitation.signature": "Teamo {{project}}",
"locale.country.unknown": "Unknown",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/es.json b/app/config/locale/translations/es.json
index ff98fd28c7..e986b15f3c 100644
--- a/app/config/locale/translations/es.json
+++ b/app/config/locale/translations/es.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Haz clic en este enlace para verificar tu correo:",
"emails.verification.footer": "Si no has solicitado verificar este correo, puedes ignorar este mensaje.",
"emails.verification.thanks": "Gracias.,",
+ "emails.verification.buttonText": "Confirmar dirección de correo",
"emails.verification.signature": "El equipo de {{project}}.",
"emails.magicSession.subject": "Inicio de sesión",
"emails.magicSession.hello": "Hola,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Haz clic en este enlace para restablecer la contraseña de {{project}}:",
"emails.recovery.footer": "Si no has solicitado restablecer la contraseña, puedes ignorar este mensaje.",
"emails.recovery.thanks": "Gracias.,",
+ "emails.recovery.buttonText": "Restablecer contraseña",
"emails.recovery.signature": "El equipo de {{project}}",
"emails.invitation.subject": "Invitación al equipo %s en %s",
"emails.invitation.hello": "Hola,",
"emails.invitation.body": "Este correo ha sido enviado a petición de {{owner}} quién quiere invitarte a formar parte del equipo {{team}} en {{project}}.",
"emails.invitation.footer": "Si no estás interesado, puedes ignorar este mensaje.",
"emails.invitation.thanks": "Gracias.,",
+ "emails.invitation.buttonText": "Aceptar invitación a {{team}}",
"emails.invitation.signature": "El equipo de {{project}}",
"locale.country.unknown": "Desconocido",
"countries.af": "Afganistán",
diff --git a/app/config/locale/translations/fa.json b/app/config/locale/translations/fa.json
index f826a75118..9434b9ff03 100644
--- a/app/config/locale/translations/fa.json
+++ b/app/config/locale/translations/fa.json
@@ -8,6 +8,7 @@
"emails.verification.body": "برای تأیید ایمیلتان پیوند زیر را دنبال کنید.",
"emails.verification.footer": "اگر شما درخواست تأیید حساب ندادهاید، میتوانید این پیام را نادیده بگیرید.",
"emails.verification.thanks": "سپاس فراوان،",
+ "emails.verification.buttonText": "آدرس ایمیل را تایید کنید",
"emails.verification.signature": "تیم {{user}}",
"emails.magicSession.subject": "ورود به حساب کاربری",
"emails.magicSession.hello": "سلام،",
@@ -20,12 +21,14 @@
"emails.recovery.body": "برای بازیابی گذرواژهتان پیوند زیر را دنبال کنید.",
"emails.recovery.footer": "اگر شما درخواست بازیابی گذرواژه ندادهاید، میتوانید این پیام را نادیده بگیرید.",
"emails.recovery.thanks": "سپاس فراوان،",
+ "emails.recovery.buttonText": "بازنشانی رمز عبور",
"emails.recovery.signature": "تیم {{user}}",
"emails.invitation.subject": "دعوت به تیم %s در %s",
"emails.invitation.hello": "سلام،",
"emails.invitation.body": "این ایمیل برای شما فرستاده شدهاست زیرا {{owner}} میخواهد شما را به تیم {{team}} در پروژهی {{project}} بیفزاید.",
"emails.invitation.footer": "اگر علاقه ندارید، میتوانید این پیام را نادیده بگیرید.",
"emails.invitation.thanks": "سپاس فراوان،",
+ "emails.invitation.buttonText": "دعوت را به {{team}} بپذیرید",
"emails.invitation.signature": "تیم {{user}}",
"locale.country.unknown": "ناشناخته",
"countries.af": "افغانستان",
diff --git a/app/config/locale/translations/fr.json b/app/config/locale/translations/fr.json
index 1b60cb1910..3af7193764 100644
--- a/app/config/locale/translations/fr.json
+++ b/app/config/locale/translations/fr.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Suivez ce lien pour vérifier votre adresse e-mail.",
"emails.verification.footer": "Si vous n'avez pas demandé à vérifier cette adresse, vous pouvez ignorer ce message.",
"emails.verification.thanks": "Merci,",
+ "emails.verification.buttonText": "Confirmez l'adresse e-mail",
"emails.verification.signature": "Équipe {{project}}",
"emails.magicSession.subject": "Connexion",
"emails.magicSession.hello": "Bonjour,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Suivez ce lien pour réinitialiser votre mot de passe pour {{project}}.",
"emails.recovery.footer": "Si vous n'avez pas demandé à réinitialiser votre mot de passe, vous pouvez ignorer ce message.",
"emails.recovery.thanks": "Merci,",
+ "emails.recovery.buttonText": "Réinitialisation du mot de passe",
"emails.recovery.signature": "L'équipe {{project}}",
"emails.invitation.subject": "Invitation à l'équipe %s de %s",
"emails.invitation.hello": "Bonjour,",
"emails.invitation.body": "Cet e-mail vous a été envoyé parce que {{owner}} souhaite vous inviter à devenir membre de l'équipe {{team}} pour {{project}}.",
"emails.invitation.footer": "Si vous n'êtes pas intéressé, vous pouvez ignorer ce message.",
"emails.invitation.thanks": "Merci,",
+ "emails.invitation.buttonText": "Accepter l'invitation à {{team}}",
"emails.invitation.signature": "L'équipe {{project}}",
"locale.country.unknown": "Inconnu",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ga.json b/app/config/locale/translations/ga.json
index 3ed68ad8c3..c486e77126 100644
--- a/app/config/locale/translations/ga.json
+++ b/app/config/locale/translations/ga.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Lean an nasc seo chun do ríomhphost a fhíorú.",
"emails.verification.footer": "Mura ndearna tú iarratas an seoladh seo a fhíoru, déan neamhaird den teachtaireacht seo.",
"emails.verification.thanks": "Go raibh maith agat,",
+ "emails.verification.buttonText": "Deimhnigh seoladh ríomhphoist",
"emails.verification.signature": "{{project}} foireann",
"emails.magicSession.subject": "Logáil isteach",
"emails.magicSession.hello": "Haigh,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Lean an nasc seo chun do pasfhocal {{project}} a athshocrú.",
"emails.recovery.footer": "Mura ndearna tú iarratas do pasfhocal a athshocrú, déan neamhaird den teachtaireacht seo.",
"emails.recovery.thanks": "Go raibh maith agat,",
+ "emails.recovery.buttonText": "Athshocraigh focal faire",
"emails.recovery.signature": "{{project}} foireann",
"emails.invitation.subject": "Cuireadh do %s foireann ag %s",
"emails.invitation.hello": "Haigh,",
"emails.invitation.body": "Seoladh an ríomhphost seo chugat mar ba mhaith le {{owner}} cuireadh a thabhairt duit bheith mar bhall den fhoireann {{team}} ag obair ar {{project}}.",
"emails.invitation.footer": "Is cuma leat? Déan neamhaird den teachtaireacht seo.",
"emails.invitation.thanks": "Go raibh maith agat,",
+ "emails.invitation.buttonText": "Glac le cuireadh chuig {{team}}",
"emails.invitation.signature": "{{project}} foireann",
"locale.country.unknown": "Neamhaithnid",
"countries.af": "An Afganastáin",
diff --git a/app/config/locale/translations/gu.json b/app/config/locale/translations/gu.json
index 54378caa9e..8d5d2fb8d6 100644
--- a/app/config/locale/translations/gu.json
+++ b/app/config/locale/translations/gu.json
@@ -8,6 +8,7 @@
"emails.verification.body": "તમારું ઇમેઇલ સરનામું ચકાસવા માટે આ લિંકને અનુસરો.",
"emails.verification.footer": "જો તમે આ સરનામાંની ચકાસણી કરવાનું ન કહ્યું હોય, તો તમે આ સંદેશને અવગણી શકો છો.",
"emails.verification.thanks": "આભાર,",
+ "emails.verification.buttonText": "ઇમેઇલ સરનામું ખાતરી કરો",
"emails.verification.signature": "{{project}} ટીમ",
"emails.magicSession.subject": "પ્રવેશ કરો",
"emails.magicSession.hello": "નમસ્કાર,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "તમારો {{project}} પાસવર્ડ ફરીથી સેટ કરવા માટે આ લિંકને અનુસરો.",
"emails.recovery.footer": "જો તમે તમારો પાસવર્ડ ફરીથી સેટ કરવાનું ન કહ્યું હોય, તો તમે આ સંદેશને અવગણી શકો છો.",
"emails.recovery.thanks": "આભાર,",
+ "emails.recovery.buttonText": "પાસવર્ડ રીસેટ કરો",
"emails.recovery.signature": "{{project}} ટીમ",
"emails.invitation.subject": "%s ટીમને %s પર આમંત્રણ",
"emails.invitation.hello": "નમસ્કાર,",
"emails.invitation.body": "આ મેઇલ તમને મોકલવામાં આવ્યો હતો કારણ કે {{owner}} તમને {{project}} માં {{team}} ટીમના સભ્ય બનવા માટે આમંત્રિત કરવા માંગતા હતો.",
"emails.invitation.footer": "જો તમને રસ નથી, તો તમે આ સંદેશને અવગણી શકો છો.",
"emails.invitation.thanks": "આભાર,",
+ "emails.invitation.buttonText": "{{team}} નું આમંત્રણ સ્વીકારો",
"emails.invitation.signature": "{{project}} ટીમ",
"locale.country.unknown": "અજાણ",
"countries.af": "અફઘાનિસ્તાન",
diff --git a/app/config/locale/translations/he.json b/app/config/locale/translations/he.json
index b3d4dea2a8..8e5279e5e4 100644
--- a/app/config/locale/translations/he.json
+++ b/app/config/locale/translations/he.json
@@ -8,6 +8,7 @@
"emails.verification.body": "לחץ על קישור זה כדי לאמת את כתובת הדוא\"ל שלך.",
"emails.verification.footer": "אם לא ביקשת לאמת כתובת זו, תוכל להתעלם מהודעה זו.",
"emails.verification.thanks": "תודה,",
+ "emails.verification.buttonText": "אשר כתובת דוא\"ל",
"emails.verification.signature": "צוות {{project}}",
"emails.magicSession.subject": "כניסה למערכת",
"emails.magicSession.hello": "שלום,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "עקוב אחר קישור זה כדי לאפס את סיסמתך ב-{{project}}.",
"emails.recovery.footer": "אם לא ביקשת לאפס את הסיסמה, תוכל להתעלם מהודעה זו.",
"emails.recovery.thanks": "תודה,",
+ "emails.recovery.buttonText": "סיסמא איפוס",
"emails.recovery.signature": "צוות {{project}}",
"emails.invitation.subject": "הזמנה לצוות %s ב- %s",
"emails.invitation.hello": "שלום,",
"emails.invitation.body": "דואר זה נשלח אליך מכיוון ש {{owner}} רצה להזמין אותך להיות חבר בצוות {{team}} ב-{{project}}.",
"emails.invitation.footer": "אם אינך מעוניין, תוכל להתעלם מהודעה זו.",
"emails.invitation.thanks": "תודה,",
+ "emails.invitation.buttonText": "אשר הזמנה ל-{{team}}",
"emails.invitation.signature": "צוות {{project}}",
"locale.country.unknown": "לא ידוע",
"countries.af": "אפגניסטן",
diff --git a/app/config/locale/translations/hi.json b/app/config/locale/translations/hi.json
index 1c4d531d60..ef71e287cd 100644
--- a/app/config/locale/translations/hi.json
+++ b/app/config/locale/translations/hi.json
@@ -8,6 +8,7 @@
"emails.verification.body": "इस लिंक के माध्यम से अपने ईमेल को सत्यापित कीजिये।",
"emails.verification.footer": "यदि आप इस पते को सत्यापित नहीं करना चाहते हैं, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.verification.thanks": "धन्यवाद,",
+ "emails.verification.buttonText": "ईमेल पता सत्यापित करें",
"emails.verification.signature": "{{project}} टीम",
"emails.magicSession.subject": "लॉग इन",
"emails.magicSession.hello": "नमस्ते,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "इस लिंक के माध्यम से अपना {{project}} पासवर्ड रीसेट करें।",
"emails.recovery.footer": "यदि आप अपना पासवर्ड रीसेट नहीं करना चाहते हैं, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.recovery.thanks": "धन्यवाद,",
+ "emails.recovery.buttonText": "पासवर्ड रीसेट करें",
"emails.recovery.signature": "{{project}} टीम",
"emails.invitation.subject": "%s टीम का यहाँ %s पर आमंत्रण",
"emails.invitation.hello": "नमस्ते,",
"emails.invitation.body": "यह मेल आपको इसलिए भेजा गया है क्योंकि {{owner}} आपको {{team}} टीम का सदस्य बनाना चाहते है, जो {{project}} से जुड़ा हुआ है।",
"emails.invitation.footer": "यदि आप इसमें रूचि नहीं रखते, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.invitation.thanks": "धन्यवाद,",
+ "emails.invitation.buttonText": "{{team}} का निमंत्रण स्वीकार करें",
"emails.invitation.signature": "{{project}} टीम",
"locale.country.unknown": "अज्ञात",
"countries.af": "अफ़ग़ानिस्तान",
diff --git a/app/config/locale/translations/hr.json b/app/config/locale/translations/hr.json
index e5bf4719a9..8331d67422 100644
--- a/app/config/locale/translations/hr.json
+++ b/app/config/locale/translations/hr.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Slijedite ovu poveznicu da biste potvrdili svoju adresu e-pošte.",
"emails.verification.footer": "Ukoliko niste zatražili potvrdu ove adrese, možete zanemariti ovu poruku.",
"emails.verification.thanks": "Hvala,",
+ "emails.verification.buttonText": "Potvrdi adresu e-pošte",
"emails.verification.signature": "{{project}} tim",
"emails.magicSession.subject": "Prijavite se",
"emails.magicSession.hello": "Pozdrav,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Slijedite ovu poveznicu za ponovno postavljanje {{project}} lozinke.",
"emails.recovery.footer": "Ako niste zatražili ponovno postavljanje Vaše lozinke, možete zanemariti ovu poruku.",
"emails.recovery.thanks": "Hvala,",
+ "emails.recovery.buttonText": "Resetiraj lozinku",
"emails.recovery.signature": "{{project}} tim",
"emails.invitation.subject": "Pozivnica za %s tim na %s",
"emails.invitation.hello": "Pozdrav,",
"emails.invitation.body": "Ova poruka Vam je poslana jer Vas je {{owner}} htio pozvati da postanete član {{team}} tima na {{project}}.",
"emails.invitation.footer": "Ukoliko niste zainteresirani, možete zanemariti ovu poruku.",
"emails.invitation.thanks": "Hvala,",
+ "emails.invitation.buttonText": "Prihvati pozivnicu za {{team}}",
"emails.invitation.signature": "{{project}} tim",
"locale.country.unknown": "Nepoznato",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/hu.json b/app/config/locale/translations/hu.json
index 589cb61859..c21701a509 100644
--- a/app/config/locale/translations/hu.json
+++ b/app/config/locale/translations/hu.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Kattints a linkre, hogy megerősítsd az email címedet.",
"emails.verification.footer": "Ha nem te kérted a címed megerősítését, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.verification.thanks": "Köszönettel,",
+ "emails.verification.buttonText": "E-mail-cím megerősítése",
"emails.verification.signature": "a {{project}} csapat",
"emails.magicSession.subject": "Bejelentkezés",
"emails.magicSession.hello": "Szia,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Kattints a linkre a {{project}} jelszavad visszaállításához.",
"emails.recovery.footer": "Ha nem te kezdeményezted a jelszavad visszaállítását, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.recovery.thanks": "Köszönettel,",
+ "emails.recovery.buttonText": "Jelszó visszaállítása",
"emails.recovery.signature": "a {{project}} csapat",
"emails.invitation.subject": "Meghívó a(z) %s csapatba, a(z) %s projektbe",
"emails.invitation.hello": "Szia,",
"emails.invitation.body": "Ezt a levelet azért kaptad, mert {{owner}} meghívott, hogy légy a {{team}} csapat tagja a {{project}} projektben.",
"emails.invitation.footer": "Ha nem érdekel a lehetőség, nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.invitation.thanks": "Köszönettel,",
+ "emails.invitation.buttonText": "Elfogadni meghívást a {{team}-re",
"emails.invitation.signature": "a {{project}} csapat",
"locale.country.unknown": "Ismeretlen",
"countries.af": "Afganisztán",
diff --git a/app/config/locale/translations/id.json b/app/config/locale/translations/id.json
index c28b15f15d..836941f79a 100644
--- a/app/config/locale/translations/id.json
+++ b/app/config/locale/translations/id.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Ikuti tautan ini untuk memverifikasi alamat email Anda.",
"emails.verification.footer": "Jika Anda tidak meminta untuk memverifikasi alamat email ini, Anda dapat mengabaikan pesan ini.",
"emails.verification.thanks": "Terima kasih,",
+ "emails.verification.buttonText": "Konfirmasi alamat email",
"emails.verification.signature": "Tim {{project}}",
"emails.magicSession.subject": "Masuk",
"emails.magicSession.hello": "Hai,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Ikuti tautan ini untuk menyetel ulang kata sandi {{project}} Anda.",
"emails.recovery.footer": "Jika Anda tidak meminta untuk menyetel ulang kata sandi, Anda dapat mengabaikan pesan ini.",
"emails.recovery.thanks": "Terima kasih,",
+ "emails.recovery.buttonText": "Atur ulang kata sandi",
"emails.recovery.signature": "Tim {{project}}",
"emails.invitation.subject": "Undangan ke Tim %s di %s",
"emails.invitation.hello": "Halo,",
"emails.invitation.body": "Email ini dikirimkan kepada Anda karena {{owner}} ingin mengundang Anda untuk menjadi anggota tim {{team}} di {{project}}.",
"emails.invitation.footer": "Jika Anda tidak tertarik, Anda dapat mengabaikan pesan ini.",
"emails.invitation.thanks": "Terima kasih,",
+ "emails.invitation.buttonText": "Terima undangan ke {{team}}",
"emails.invitation.signature": "Tim {{project}}",
"locale.country.unknown": "Tidak diketahui",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/it.json b/app/config/locale/translations/it.json
index 8d45de9903..f0e290b481 100644
--- a/app/config/locale/translations/it.json
+++ b/app/config/locale/translations/it.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Clicca questo link per verificare il tuo indirizzo email.",
"emails.verification.footer": "Se non hai richiesto la verifica dell’indirizzo email, puoi ignorare questo messaggio.",
"emails.verification.thanks": "Grazie,",
+ "emails.verification.buttonText": "Confermare l'indirizzo email",
"emails.verification.signature": "Il team {{project}}",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Ciao,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Clicca questo link per reimpostare la tua password di {{project}}.",
"emails.recovery.footer": "Se non hai richiesto la reimpostazione della password, puoi ignorare questo messaggio.",
"emails.recovery.thanks": "Grazie,",
+ "emails.recovery.buttonText": "Reimposta password",
"emails.recovery.signature": "Il team {{project}}",
"emails.invitation.subject": "Invito al Team %s per %s",
"emails.invitation.hello": "Ciao,",
"emails.invitation.body": "Hai ricevuto questa email perché {{owner}} ti ha invitato a diventare un membro del team {{team}} di {{project}}.",
"emails.invitation.footer": "Ignora questo messaggio se non sei interessatə.",
"emails.invitation.thanks": "Grazie,",
+ "emails.invitation.buttonText": "Accetta invito a {{team}}",
"emails.invitation.signature": "Il team {{project}}",
"locale.country.unknown": "Sconosciuto",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ja.json b/app/config/locale/translations/ja.json
index 76d9a0cb1f..f3ad8fe1ed 100644
--- a/app/config/locale/translations/ja.json
+++ b/app/config/locale/translations/ja.json
@@ -8,6 +8,7 @@
"emails.verification.body": "メールアドレスを有効化するためには下記リンクをクリックして下さい。",
"emails.verification.footer": "このメールに心当たりが無い場合は破棄をお願いいたします。",
"emails.verification.thanks": "ご利用いただきありがとうございます。、",
+ "emails.verification.buttonText": "メールアドレスを確認する",
"emails.verification.signature": "{{project}}チーム",
"emails.magicSession.subject": "ログイン",
"emails.magicSession.hello": "こんにちは、",
@@ -20,12 +21,14 @@
"emails.recovery.body": "パスワードをリセットするためには下記リンクをクリックしてください。",
"emails.recovery.footer": "このメールに心当たりが無い場合は破棄をお願いいたします。",
"emails.recovery.thanks": "ご利用いただきありがとうございます。、",
+ "emails.recovery.buttonText": "パスワードをリセット",
"emails.recovery.signature": "{{project}}チーム",
"emails.invitation.subject": "%sチームへの招待が%sから来ました。",
"emails.invitation.hello": "こんにちは、",
"emails.invitation.body": "{{owner}}さんが{{project}}の{{team}}チームにあなたを招待しています。",
"emails.invitation.footer": "このメールに心当たりが無い場合は破棄をお願いいたします。",
"emails.invitation.thanks": "ご利用いただきありがとうございます。、",
+ "emails.invitation.buttonText": "{{team}}への招待を承諾する",
"emails.invitation.signature": "{{project}}チーム",
"locale.country.unknown": "不明",
"countries.af": "アフガニスタン",
diff --git a/app/config/locale/translations/jv.json b/app/config/locale/translations/jv.json
index 889e968b4d..71d4f4b24a 100644
--- a/app/config/locale/translations/jv.json
+++ b/app/config/locale/translations/jv.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Klik link iki kanggo verifikasi alamat email sampeyan.",
"emails.verification.footer": "Yen sampeyan ora njaluk verifikasi alamat iki, sampeyan iso nglirwakake pesen iki.",
"emails.verification.thanks": "Matur nuwun,",
+ "emails.verification.buttonText": "Konfirmasi alamat email",
"emails.verification.signature": "Tim {{project}}",
"emails.magicSession.subject": "Masuk",
"emails.magicSession.hello": "Hai,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Klik link iki kanggo setel ulang sandi {{project}}.",
"emails.recovery.footer": "Yen sampeyan ora njaluk setel ulang sandi, sampeyan iso nglirwakake pesen iki.",
"emails.recovery.thanks": "Matur nuwun,",
+ "emails.recovery.buttonText": "Reset sandhi",
"emails.recovery.signature": "Tim {{project}}",
"emails.invitation.subject": "Undangan ke Tim %s di %s",
"emails.invitation.hello": "Halo,",
"emails.invitation.body": "Email iki dikirim menyang sampeyan amarga {{owner}} pengin ngajak sampeyan dadi anggota tim {{team}} di {{project}}.",
"emails.invitation.footer": "Yen sampeyan ora tertarik, sampeyan iso nglirwakake pesen iki.",
"emails.invitation.thanks": "Matur nuwun,",
+ "emails.invitation.buttonText": "Tampa undhangan menyang {{team}}",
"emails.invitation.signature": "Tim {{project}}",
"locale.country.unknown": "Ora dingerteni",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/kn.json b/app/config/locale/translations/kn.json
index ba57c21155..ed35a7947f 100644
--- a/app/config/locale/translations/kn.json
+++ b/app/config/locale/translations/kn.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ನಿಮ್ಮ ಇಮೇಲ್ ವಿಳಾಸ ಪರಿಶೀಲನೆಗೆ ಈ ಲಿಂಕನ್ನು ಅನುಸರಿಸಿ",
"emails.verification.footer": "ನೀವು ಇಮೇಲ್ ವಿಳಾಸ ಪರಿಶೀಲನೆಗೆ ಕೇಳದಿದ್ದರೆ, ಈ ಸಂದೇಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ",
"emails.verification.thanks": "ಧನ್ಯವಾದಗಳು,",
+ "emails.verification.buttonText": "ಇಮೇಲ್ ವಿಳಾಸವನ್ನು ದೃಢೀಕರಿಸಿ",
"emails.verification.signature": "{{project}} ತಂಡ",
"emails.magicSession.subject": "ಲಾಗಿನ್",
"emails.magicSession.hello": "ನಮಸ್ಕಾರ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "ನಿಮ್ಮ {{project}} ಗುಪ್ತಪದವನ್ನು ಮರುಹೊಂದಿಸಲು ಈ ಲಿಂಕನ್ನು ಅನುಸರಿಸಿ",
"emails.recovery.footer": "ನೀವು ಗುಪ್ತಪದವನ್ನು ಮರುಹೊಂದಿಸಲು ಕೇಳದಿದ್ದರೆ, ಈ ಸಂದೇಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ",
"emails.recovery.thanks": "ಧನ್ಯವಾದಗಳು,",
+ "emails.recovery.buttonText": "ಗುಪ್ತಪದವನ್ನು ಮರುಸೆಟ್ ಮಾಡಿ",
"emails.recovery.signature": "{{project}} ತಂಡ",
"emails.invitation.subject": "%s ತಂಡಕ್ಕೆ %s ರಲ್ಲಿ ಆಹ್ವಾನ",
"emails.invitation.hello": "ನಮಸ್ಕಾರ,",
"emails.invitation.body": "ಈ ಇಮೇಲ್ ನಿಮಗೆ ಬಂದಿದೆ ಏಕೆಂದರೆ {{owner}} ನಿಮ್ಮನ್ನು {{team}} ತಂಡದ {{project}}ರಲ್ಲಿ ಸದಸ್ಯ ಆಗಲಿಕ್ಕೆ ಆಹ್ವಾನಿಸಿದ್ದಾರೆ",
"emails.invitation.footer": "ನಿಮಗೆ ಆಸಕ್ತಿಯಿಲ್ಲದಿದ್ದರೆ, ಈ ಸಂದೇಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ",
"emails.invitation.thanks": "ಧನ್ಯವಾದಗಳು,",
+ "emails.invitation.buttonText": "{{team}} ಗೆ ಆಹ್ವಾನವನ್ನು ಸ್ವೀಕರಿಸಿ",
"emails.invitation.signature": "{{project}} ತಂಡ",
"locale.country.unknown": "Unknown",
"countries.af": "ಅಫ್ಘಾನಿಸ್ತಾನ",
diff --git a/app/config/locale/translations/ko.json b/app/config/locale/translations/ko.json
index c33c961130..0bc425aeae 100644
--- a/app/config/locale/translations/ko.json
+++ b/app/config/locale/translations/ko.json
@@ -8,6 +8,7 @@
"emails.verification.body": "이메일 인증을 위해 링크를 클릭하여주세요.",
"emails.verification.footer": "이메일 인증을 부탁하지 않으셨다면 이 메시지를 무시하여주세요.",
"emails.verification.thanks": "감사합니다、",
+ "emails.verification.buttonText": "이메일 주소를 확인합니다",
"emails.verification.signature": "{{project}} 팀",
"emails.magicSession.subject": "로그인",
"emails.magicSession.hello": "안녕하세요、",
@@ -20,12 +21,14 @@
"emails.recovery.body": "{{project}}의 비밀번호 재설정을 위해 링크를 클릭하여주세요.",
"emails.recovery.footer": "비밀번호 재설정 신청을 하지 않으셨다면 이 메세지를 무시하여주세요.",
"emails.recovery.thanks": "감사합니다、",
+ "emails.recovery.buttonText": "비밀번호 재설정",
"emails.recovery.signature": "{{project}} 팀",
"emails.invitation.subject": "초대장 %s 팀 - %s",
"emails.invitation.hello": "안녕하세요、",
"emails.invitation.body": "{{owner}}님이 귀하를 {{project}}의 {{team}} 팀으로 초대합니다.",
"emails.invitation.footer": "팀에 합류할 의사가 없으시면 이 메세지를 무시하여주세요.",
"emails.invitation.thanks": "감사합니다、",
+ "emails.invitation.buttonText": "{{team}} 초대를 수락하기",
"emails.invitation.signature": "{{project}} 팀",
"locale.country.unknown": "알려지지 않은",
"countries.af": "아프가니스탄",
diff --git a/app/config/locale/translations/la.json b/app/config/locale/translations/la.json
index bebef26854..fe3e7930e2 100644
--- a/app/config/locale/translations/la.json
+++ b/app/config/locale/translations/la.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Sequere hanc nexum ut quin inscriptionem tuum.",
"emails.verification.footer": "Si verificationem huius inscriptionis non postulasti, nuntium hunc ignorare potes.",
"emails.verification.thanks": "Gratias,",
+ "emails.verification.buttonText": "Confirma inscriptionem electronicam",
"emails.verification.signature": "{{project}} Team",
"emails.magicSession.subject": "Log in",
"emails.magicSession.hello": "Salve ibi,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Sequere hanc conjunctionem ut recipias project password {{project}}",
"emails.recovery.footer": "Si tesseram tuam recuperare non petis, nuntium hunc ignorare potes",
"emails.recovery.thanks": "Gratias,",
+ "emails.recovery.buttonText": "Reset password",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Invitatio pro %s in quadrigis %s",
"emails.invitation.hello": "Salve ibi,",
"emails.invitation.body": "Haec inscriptio ad te missa est quia dominus incepto {{owner}} te invitare vult ut membrum {{team}} quadrigis fias ad {{project}}",
"emails.invitation.footer": "Si non quaero, potes hunc nuntium ignorare",
"emails.invitation.thanks": "Gratias,",
+ "emails.invitation.buttonText": "Accipe invitare ad {{team}}",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Ignotum",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/lb.json b/app/config/locale/translations/lb.json
index 91b52e4a18..8fe4b346e7 100644
--- a/app/config/locale/translations/lb.json
+++ b/app/config/locale/translations/lb.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Follegt dëse Link fir Är E -Mail Adress z'iwwerpréiwen.",
"emails.verification.footer": "Wann Dir net gefrot hutt dës Adress z'iwwerpréiwen, kënnt Dir dëse Message ignoréieren.",
"emails.verification.thanks": "Merci,",
+ "emails.verification.buttonText": "E-Mail-Adress bestätegen",
"emails.verification.signature": "{{project}} équipe",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Hey,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Follegt dëse Link fir Äert {{project}} Passwuert zréckzesetzen.",
"emails.recovery.footer": "Wann Dir net gefrot hutt Äert Passwuert zréckzesetzen, kënnt Dir dëse Message ignoréieren.",
"emails.recovery.thanks": "Merci,",
+ "emails.recovery.buttonText": "Passwuert zrécksetzen",
"emails.recovery.signature": "{{project}} équipe",
"emails.invitation.subject": "Invitatioun un %s équipe bei %s",
"emails.invitation.hello": "Hallo,",
"emails.invitation.body": "Dës E -Mail gouf un Iech geschéckt well {{owner}} Iech invitéiere wëllt fir Member vum {{team}} Team bei {{project}} ze ginn.",
"emails.invitation.footer": "Wann Dir net interesséiert sidd, kënnt Dir dëse Message ignoréieren.",
"emails.invitation.thanks": "Merci,",
+ "emails.invitation.buttonText": "Invitatioun bei {{team}} akzeptéieren",
"emails.invitation.signature": "{{project}} équipe",
"locale.country.unknown": "Onbekannt",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/lt.json b/app/config/locale/translations/lt.json
index 94c874ce82..2439428b02 100644
--- a/app/config/locale/translations/lt.json
+++ b/app/config/locale/translations/lt.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Spauskite šią nuorodą, kad patvirtintumėte savo el. paštą.",
"emails.verification.footer": "Jei neprašėte patvirtinti šio el. pašto, galite ignoruoti šį pranešimą.",
"emails.verification.thanks": "Ačiū,",
+ "emails.verification.buttonText": "Patvirtinti el. pašto adresą",
"emails.verification.signature": "{{project}} komanda",
"emails.magicSession.subject": "Prisijungti",
"emails.magicSession.hello": "Labas,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Spauskite šią nuorodą, kad atkurtumėte projekto {{project}} slaptažodį.",
"emails.recovery.footer": "Jei neprašėte atkurti savo slaptažodzio, galite ignoruoti šį pranešimą.",
"emails.recovery.thanks": "Ačiū,",
+ "emails.recovery.buttonText": "Atstatyti slaptažodį",
"emails.recovery.signature": "{{project}} komanda",
"emails.invitation.subject": "Pakvietimas į %s komandą %s projekte",
"emails.invitation.hello": "Labas,",
"emails.invitation.body": "Šis el. laiškas buvo atsiųstas jums, nes {{owner}} norėjo jus pakviesti tapti projekto {{project}} dalimi {{team}} komandoje.",
"emails.invitation.footer": "Jei jūsų tai nedomina, galite ignoruoti šį pranešimą.",
"emails.invitation.thanks": "Ačiū,",
+ "emails.invitation.buttonText": "Priimti kvietimą į {{team}}",
"emails.invitation.signature": "{{project}} komanda",
"locale.country.unknown": "Nežinoma",
"countries.af": "Afganistanas",
diff --git a/app/config/locale/translations/lv.json b/app/config/locale/translations/lv.json
index b4a396367c..59edfce7a6 100644
--- a/app/config/locale/translations/lv.json
+++ b/app/config/locale/translations/lv.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Sekojiet saitei, lai apstiprinātu savu e-pasta adresi.",
"emails.verification.footer": "Ja Jūs nepieprasījāt šīs adreses apstiprinājumu, lūdzu, ignorējiet šo ziņu.",
"emails.verification.thanks": "Paldies,",
+ "emails.verification.buttonText": "Apstiprināt e-pasta adresi",
"emails.verification.signature": "{{project}} komanda",
"emails.magicSession.subject": "Ieiet",
"emails.magicSession.hello": "Sveicināti,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Sekojiet saitei, lai atjauninātu {{project}} paroli.",
"emails.recovery.footer": "Ja Jūs nepieprasījāt paroles atjaunināšanu, lūdzu, ignorējiet šo ziņu.",
"emails.recovery.thanks": "Paldies,",
+ "emails.recovery.buttonText": "Atiestatīt paroli",
"emails.recovery.signature": "{{project}} komanda",
"emails.invitation.subject": "Ielūgums piebiedroties %s komandai %s projektā.",
"emails.invitation.hello": "Labdien,",
"emails.invitation.body": "Šis e-pasts tika nosūtīts Jums, jo {{owner}} vēlējās Jūs ielūgt kļūt par {{team}} komandas biedru {{project}} projektā.",
"emails.invitation.footer": "Ja Jūs neesat ieinteresēts, lūdzu, ignorējiet šo ziņu.",
"emails.invitation.thanks": "Paldies,",
+ "emails.invitation.buttonText": "Pieņemt ielūgumu uz {{team}}",
"emails.invitation.signature": "{{project}} komanda",
"locale.country.unknown": "Nav zināms",
"countries.af": "Afganistāna",
diff --git a/app/config/locale/translations/ml.json b/app/config/locale/translations/ml.json
index 1b57d87865..bd13f92fa8 100644
--- a/app/config/locale/translations/ml.json
+++ b/app/config/locale/translations/ml.json
@@ -8,6 +8,7 @@
"emails.verification.body": "നിങ്ങളുടെ ഇമെയിൽ വിലാസം സ്ഥിരീകരിക്കുന്നതിനായി ഈ ലിങ്ക് പിന്തുടരുക.",
"emails.verification.footer": "ഈ വിലാസം സ്ഥിരീകരിക്കാന് നിങ്ങൾ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, നിങ്ങൾക്ക് ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.",
"emails.verification.thanks": "നന്ദി,",
+ "emails.verification.buttonText": "ഇമെയിൽ വിലാസം സ്ഥിരീകരിക്കുക",
"emails.verification.signature": "{{project}} ടീം",
"emails.magicSession.subject": "ലോഗിൻ",
"emails.magicSession.hello": "നമസ്കാരം,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "നിങ്ങളുടെ {{Project}} രഹസ്യവാക്ക് പുനക്രമീകരിക്കുന്നതിന് ഈ ലിങ്ക് പിന്തുടരുക.",
"emails.recovery.footer": "നിങ്ങളുടെ രഹസ്യവാക്ക് പുനക്രമീകരിക്കാന് നിങ്ങൾ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.",
"emails.recovery.thanks": "നന്ദി,",
+ "emails.recovery.buttonText": "പാസ്വേഡ് റീസെറ്റ് ചെയ്യുക",
"emails.recovery.signature": "{{project}} ടീം",
"emails.invitation.subject": "%s -ലെ %s ടീമിലേക്കുള്ള ക്ഷണം",
"emails.invitation.hello": "നമസ്കാരം,",
"emails.invitation.body": "നിങ്ങളെ {{project}} -ലെ {{team}} ടീമിലെ അംഗമാകുവാന് ക്ഷണിക്കാൻ {{owner}} ആഗ്രഹിക്കുന്നതിനാലാണ് ഈ മെയിൽ നിങ്ങൾക്ക് അയക്കുന്നത്.",
"emails.invitation.footer": "നിങ്ങൾക്ക് താൽപ്പര്യമില്ലെങ്കിൽ, ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.",
"emails.invitation.thanks": "നന്ദി,",
+ "emails.invitation.buttonText": "{{team}} ലേക്കുള്ള ക്ഷണം സ്വീകരിക്കുക",
"emails.invitation.signature": "{{project}} ടീം",
"locale.country.unknown": "Unknown",
"countries.af": "അഫ്ഗാനിസ്ഥാൻ",
diff --git a/app/config/locale/translations/mr.json b/app/config/locale/translations/mr.json
index 6550d1c1ba..881afdfe71 100644
--- a/app/config/locale/translations/mr.json
+++ b/app/config/locale/translations/mr.json
@@ -8,6 +8,7 @@
"emails.verification.body": "आपला ईमेल पत्ता सत्यापित करण्यासाठी या दुव्याचे अनुसरण करा.",
"emails.verification.footer": "आपण या पत्त्याची पडताळणी करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.verification.thanks": "धन्यवाद,",
+ "emails.verification.buttonText": "ईमेल पत्ता सत्यापित करा",
"emails.verification.signature": "{{project}} संघ",
"emails.magicSession.subject": "लॉगिन करा",
"emails.magicSession.hello": "नमस्कार ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "आपला {{project}}चे पासवर्ड रीसेट करण्यासाठी या लिंकचे अनुसरण करा",
"emails.recovery.footer": "आपण आपला पासवर्ड रीसेट करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.recovery.thanks": "धन्यवाद,",
+ "emails.recovery.buttonText": "पासवर्ड रीसेट करा",
"emails.recovery.signature": "{{project}} संघ",
"emails.invitation.subject": "%s संघ %s येथे सामील होण्यासाठी आमंत्रण",
"emails.invitation.hello": "नमस्कार,",
"emails.invitation.body": "हा मेल तुम्हाला पाठवला होता कारण {{owner}} तुम्हाला {{project}} येथे {{team}} टीमचे सदस्य होण्यासाठी आमंत्रित करू इच्छित होते.",
"emails.invitation.footer": "आपल्याला स्वारस्य नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.invitation.thanks": "धन्यवाद,",
+ "emails.invitation.buttonText": "{{team}} साठी आमंत्रण स्वीकारा",
"emails.invitation.signature": "{{project}} संघ",
"locale.country.unknown": "अज्ञात",
"countries.af": "अफगानिस्तान",
diff --git a/app/config/locale/translations/ms.json b/app/config/locale/translations/ms.json
index a02c36b075..448307550e 100644
--- a/app/config/locale/translations/ms.json
+++ b/app/config/locale/translations/ms.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Tekan pautan ini untuk mengesahkan alamat email anda.",
"emails.verification.footer": "Sekiranya anda tidak membuat permintaan untuk mengesahkan email ini, sila abaikan mesej ini.",
"emails.verification.thanks": "Terima kasih,",
+ "emails.verification.buttonText": "Sahkan alamat email",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "Log masuk",
"emails.magicSession.hello": "Hey,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Tekan pautan ini untuk menetapkan semula kata laluan {{project}}.",
"emails.recovery.footer": "Sekiranya anda tidak membuat permintaan menetap semula kata laluan, sila abaikan mesej ini.",
"emails.recovery.thanks": "Terima kasih,",
+ "emails.recovery.buttonText": "Tetapkan semula kata laluan",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Jemputan ke pasukan %s di %s",
"emails.invitation.hello": "Hello,",
"emails.invitation.body": "Anda menerima mel ini kerana {{owner}} ingin menjemput anda untuk menjadi ahli pasukan {{team}} di {{project}}.",
"emails.invitation.footer": "Sekiranya anda tidak berminat, sila abaikan mesej ini.",
"emails.invitation.thanks": "Terima kasih,",
+ "emails.invitation.buttonText": "Terima jemputan ke {{team}}",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Tidak Diketahui",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/nb.json b/app/config/locale/translations/nb.json
index daf18abc1c..cc95bacf9e 100644
--- a/app/config/locale/translations/nb.json
+++ b/app/config/locale/translations/nb.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Følg denne lenken for å bekrefte din e-postadresse.",
"emails.verification.footer": "Dersom du ikke ba om å bekrefte e-postadressen, kan du se bort fra denne meldingen.",
"emails.verification.thanks": "Takk,",
+ "emails.verification.buttonText": "Bekreft e-postadresse",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "Pålogging",
"emails.magicSession.hello": "Hei,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Følg denne lenken for å nullstille ditt {{project}} passord.",
"emails.recovery.footer": "Dersom du ikke ba om å nullstille passordet ditt, kan du se bort fra denne meldingen.",
"emails.recovery.thanks": "Takk,",
+ "emails.recovery.buttonText": "Tilbakestill passord",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Invitasjon til %s Team ved %s",
"emails.invitation.hello": "Hei,",
"emails.invitation.body": "Denne meldingen ble sendt til deg fordi {{owner}} ønsket å invitere deg til å bli medlem av {{team}} team ved {{project}}.",
"emails.invitation.footer": "Dersom du ikke er interessert, kan du se bort fra denne meldingen.",
"emails.invitation.thanks": "Takk,",
+ "emails.invitation.buttonText": "Godta invitasjon til {{team}}",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Ukjent",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ne.json b/app/config/locale/translations/ne.json
index 4f05a9b5ba..f1ba841fed 100644
--- a/app/config/locale/translations/ne.json
+++ b/app/config/locale/translations/ne.json
@@ -8,6 +8,7 @@
"emails.verification.body": "इमेल ठेगाना प्रमाणित गर्नको लागी यो लिंकमा जानुहोस।",
"emails.verification.footer": "यदि तपाइँले आफ्नो खाता प्रमाणित गर्न सोध्नु भएको छैन भने तपाइँले यो सन्देश लाई बेवास्ता गर्न सक्नुहुन्छ।",
"emails.verification.thanks": "धन्यवाद,",
+ "emails.verification.buttonText": "इमेल ठेगाना पुष्टि गर्नुहोस्",
"emails.verification.signature": "{{project}} समूह",
"emails.magicSession.subject": "लगइन",
"emails.magicSession.hello": "नमस्ते,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "{{project}}को पासवर्ड रिसेट गर्नको लागी यो लिंकमा जानुहोस।",
"emails.recovery.footer": "यदि तपाइँले आफ्नो पासवर्ड रिसेट गर्न सोध्नु भएको छैन भने तपाइँले यो सन्देश लाई बेवास्ता गर्न सक्नुहुन्छ।",
"emails.recovery.thanks": "धन्यवाद,",
+ "emails.recovery.buttonText": "रिसेट पासवर्ड",
"emails.recovery.signature": "{{project}} समूह",
"emails.invitation.subject": "%s समूहको लागि %s मा निमन्त्रणा",
"emails.invitation.hello": "नमस्ते,",
"emails.invitation.body": "{{owner}}ले तपाइँलाई {{project}}मा {{team}}को सदस्य बन्न आमन्त्रित गर्न चाहनु भएको छ। त्येसैले तपाइँलाई यो सन्देश पठाइएको हो।",
"emails.invitation.footer": "यदि तपाइँ इच्छुक हुनुहुन्न भने, तपाइँले यो सन्देशलाई बेवास्ता गर्न सक्नुहुन्छ।",
"emails.invitation.thanks": "धन्यवाद,",
+ "emails.invitation.buttonText": "{{team}} मा निमन्त्रणा स्वीकार गर्नुहोस्",
"emails.invitation.signature": "{{project}} समूह",
"locale.country.unknown": "अज्ञात",
"countries.af": "अफगानिस्तान",
diff --git a/app/config/locale/translations/nl.json b/app/config/locale/translations/nl.json
index cae82a9a37..4f71f67199 100644
--- a/app/config/locale/translations/nl.json
+++ b/app/config/locale/translations/nl.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Volg deze link om uw e-mail te verifieren",
"emails.verification.footer": "Als u geen aanvraag voor verificatie heeft gemaakt, kan u deze mail negeren",
"emails.verification.thanks": "Bedankt,",
+ "emails.verification.buttonText": "Bevestig e-mailadres",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Hoi,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Volg deze link om het wachtwoord van uw project {{project}} te wijzigen",
"emails.recovery.footer": "Als u geen aanvraag heeft gemaakt om uw wachtwoord te wijzigen, kan u deze mail negeren",
"emails.recovery.thanks": "Bedankt,",
+ "emails.recovery.buttonText": "Wachtwoord opnieuw instellen",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Uitnodiging van %s Team uit %s",
"emails.invitation.hello": "Hallo,",
"emails.invitation.body": "U ontvangt deze mail want u was uitgenodig door {{owner}} om lid van het {{team}} team te worden in {{project}} ",
"emails.invitation.footer": "Als u niet geintereseerd bent, kan u deze mail negeren.",
"emails.invitation.thanks": "Bedankt,",
+ "emails.invitation.buttonText": "Uitnodiging voor {{team}} accepteren",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Onbekend",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/nn.json b/app/config/locale/translations/nn.json
index 44be0f9845..646a57904c 100644
--- a/app/config/locale/translations/nn.json
+++ b/app/config/locale/translations/nn.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Følg denne lenkja for å bekrefta din e-postadresse.",
"emails.verification.footer": "Om du ikkje bad om å bekrefta e-postadressa, kan du ignorera denne meldinga.",
"emails.verification.thanks": "Takk,",
+ "emails.verification.buttonText": "Stadfest e-postadresse",
"emails.verification.signature": "{{project}} team",
"emails.magicSession.subject": "Pålogging",
"emails.magicSession.hello": "Hei,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Følg denne lenkja for å nullstilla ditt {{project}} passord.",
"emails.recovery.footer": "Om du ikkje ba om å nullstilla passordet ditt, kan du ignorera denne meldinga.",
"emails.recovery.thanks": "Takk,",
+ "emails.recovery.buttonText": "Nullstill passord",
"emails.recovery.signature": "{{project}} team",
"emails.invitation.subject": "Innbyding til %s Team ved %s",
"emails.invitation.hello": "Hallo,",
"emails.invitation.body": "Denne meldinga ble sendt til deg fordi {{owner}} ynskja å invitera deg til å bli medlem av {{team}} team i {{project}}.",
"emails.invitation.footer": "Om du ikkje er interessert, kan du ignorera denne meldinga.",
"emails.invitation.thanks": "Takk,",
+ "emails.invitation.buttonText": "Godta invitasjon til {{team}}",
"emails.invitation.signature": "{{project}} team",
"locale.country.unknown": "Ukjend",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/or.json b/app/config/locale/translations/or.json
index efd516f23a..a8e08b8043 100644
--- a/app/config/locale/translations/or.json
+++ b/app/config/locale/translations/or.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ଆପଣଙ୍କର ଇମେଲ୍ ଠିକଣା ଯାଞ୍ଚ କରିବାକୁ ଏହି ଲିଙ୍କ୍ ଅନୁସରଣ କରନ୍ତୁ |",
"emails.verification.footer": "ଯଦି ଆପଣ ଏହି ଠିକଣା ଯାଞ୍ଚ କରିବାକୁ କହି ନାହାଁନ୍ତି, ତେବେ ଆପଣ ଏହି ସନ୍ଦେଶକୁ ଉପେକ୍ଷା କରିପାରିବେ |",
"emails.verification.thanks": "ଧନ୍ୟବାଦ,",
+ "emails.verification.buttonText": "ଇମେଲ ଠିକଣା ନିଶ୍ଚିତ କରନ୍ତୁ",
"emails.verification.signature": "{{project}} ଦଳ",
"emails.magicSession.subject": "ଲଗଇନ୍ କରନ୍ତୁ",
"emails.magicSession.hello": "ନମସ୍କାର,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "ଆପଣଙ୍କର {{project}} ପାସୱାର୍ଡ ପୁନଃ ସେଟ୍ କରିବାକୁ ଏହି ଲିଙ୍କକୁ ଅନୁସରଣ କରନ୍ତୁ |",
"emails.recovery.footer": "ଯଦି ଆପଣ ଆପଣଙ୍କର ପାସୱାର୍ଡ ପୁନଃ ସେଟ୍ କରିବାକୁ କହି ନାହାଁନ୍ତି, ତେବେ ଆପଣ ଏହି ସନ୍ଦେଶକୁ ଉପେକ୍ଷା କରିପାରିବେ |",
"emails.recovery.thanks": "ଧନ୍ୟବାଦ,",
+ "emails.recovery.buttonText": "ପାସୱାର୍ଡ ପୁନଃସେଟ୍ କରନ୍ତୁ",
"emails.recovery.signature": "{{project}} ଦଳ",
"emails.invitation.subject": "%s ରେ %s ଦଳକୁ ନିମନ୍ତ୍ରଣ |",
"emails.invitation.hello": "ନମସ୍କାର,",
"emails.invitation.body": "ଏହି ମେଲ୍ ଆପଣଙ୍କୁ ପଠାଯାଇଥିଲା କାରଣ {{owner}} ଆପଣଙ୍କୁ {{project} ରେ {{team}} ଦଳର ସଦସ୍ୟ ହେବାକୁ ଆମନ୍ତ୍ରଣ କରିବାକୁ ଚାହୁଁଥିଲେ |",
"emails.invitation.footer": "ଯଦି ଆପଣ ଆଗ୍ରହୀ ନୁହଁନ୍ତି, ଆପଣ ଏହି ସନ୍ଦେଶକୁ ଅଣଦେଖା କରିପାରିବେ |",
"emails.invitation.thanks": "ଧନ୍ୟବାଦ,",
+ "emails.invitation.buttonText": "{{team}} ପାଇଁ ଆମନ୍ତ୍ରଣ ଗ୍ରହଣ କରନ୍ତୁ",
"emails.invitation.signature": "{{project}} ଦଳ",
"locale.country.unknown": "ଅଜ୍ଞାତ",
"countries.af": "ଆଫଗାନିସ୍ତାନ",
diff --git a/app/config/locale/translations/pl.json b/app/config/locale/translations/pl.json
index ee5811fb59..75bc3a24f9 100644
--- a/app/config/locale/translations/pl.json
+++ b/app/config/locale/translations/pl.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Przejdź do tego linku, aby zweryfikować swój adres e-mail.",
"emails.verification.footer": "Jeśli to nie Ty prosiłeś o zweryfikowanie tego adresu, zignoruj tę wiadomość.",
"emails.verification.thanks": "Dziękujemy,",
+ "emails.verification.buttonText": "Potwierdź adres e-mail",
"emails.verification.signature": "Zespół {{project}}",
"emails.magicSession.subject": "Logowanie",
"emails.magicSession.hello": "Cześć,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Przejdź do tego linku, aby zresetować hasło dla {{project}}.",
"emails.recovery.footer": "Jeśli to nie Ty prosiłeś o zresetowanie swojego hasła, zignoruj tę wiadomość.",
"emails.recovery.thanks": "Dziękujemy,",
+ "emails.recovery.buttonText": "Zresetuj hasło",
"emails.recovery.signature": "Zespół {{project}}",
"emails.invitation.subject": "Zaproszenie do zespołu %s w %s",
"emails.invitation.hello": "Cześć,",
"emails.invitation.body": "Otrzymujesz tę wiadomość, ponieważ {{owner}} zaprasza Cię do grona członków zespołu {{team}} w projekcie {{project}}.",
"emails.invitation.footer": "Jeśli nie jesteś zainteresowany, zignoruj tę wiadomość.",
"emails.invitation.thanks": "Dziękujemy,",
+ "emails.invitation.buttonText": "Zaakceptuj zaproszenie do {{team}}",
"emails.invitation.signature": "Zespół {{project}}",
"locale.country.unknown": "Nieznany",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/pt-br.json b/app/config/locale/translations/pt-br.json
index a53ca79813..7e3af1d3f1 100644
--- a/app/config/locale/translations/pt-br.json
+++ b/app/config/locale/translations/pt-br.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Clique neste link para verificar o seu endereço de e-mail.",
"emails.verification.footer": "Se você não solicitou a verificação deste e-mail, ignore essa mensagem.",
"emails.verification.thanks": "Muito obrigado,",
+ "emails.verification.buttonText": "Confirmar endereço de e-mail",
"emails.verification.signature": "Time {{project}}",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Olá,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Clique neste link para redefinir sua senha do {{project}}.",
"emails.recovery.footer": "Se você não solicitou a redefinição da sua senha, você pode ignorar essa mensagem.",
"emails.recovery.thanks": "Muito obrigado,",
+ "emails.recovery.buttonText": "Redefinir senha",
"emails.recovery.signature": "Time {{project}}",
"emails.invitation.subject": "Convite para o Time %s em %s",
"emails.invitation.hello": "Olá,",
"emails.invitation.body": "Este e-mail foi enviado porque {{owner}} deseja convidar você a se tornar membro do Time {{team}} em {{project}}.",
"emails.invitation.footer": "Caso não tenha interesse, ignore essa mensagem.",
"emails.invitation.thanks": "Muito obrigado,",
+ "emails.invitation.buttonText": "Aceitar convite para {{team}}",
"emails.invitation.signature": "Time {{project}}",
"locale.country.unknown": "Desconhecido",
"countries.af": "Afeganistão",
diff --git a/app/config/locale/translations/pt-pt.json b/app/config/locale/translations/pt-pt.json
index d85dca9300..c13ce558bf 100644
--- a/app/config/locale/translations/pt-pt.json
+++ b/app/config/locale/translations/pt-pt.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Siga esta ligação para verificar o seu endereço de correio electrónico.",
"emails.verification.footer": "Se não pediu para verificar este endereço, pode ignorar esta mensagem.",
"emails.verification.thanks": "Obrigado,",
+ "emails.verification.buttonText": "Confirmar endereço de email",
"emails.verification.signature": "Equipa {{project}}",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Olá ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Utilize este link para redefinir a palavra-passe do seu projecto {{project}}",
"emails.recovery.footer": "Se não pediu para redefinir a sua palavra-passe, pode ignorar esta mensagem.",
"emails.recovery.thanks": "Obrigado,",
+ "emails.recovery.buttonText": "Repor palavra-passe",
"emails.recovery.signature": "Equipa {{project}}",
"emails.invitation.subject": "Convite à equipa de %s às %s",
"emails.invitation.hello": "Olá,",
"emails.invitation.body": "Este correio foi-lhe enviado porque {{owner}} queria convidá-lo a tornar-se membro da equipa {{team}} da {{project}}.",
"emails.invitation.footer": "Se não estiver interessado, pode ignorar esta mensagem.",
"emails.invitation.thanks": "Obrigado,",
+ "emails.invitation.buttonText": "Aceitar convite para o {{team}}",
"emails.invitation.signature": "Equipa {{project}}",
"locale.country.unknown": "Desconhecido",
"countries.af": "Afeganistão",
diff --git a/app/config/locale/translations/ro.json b/app/config/locale/translations/ro.json
index 04cb22dd6b..88499ce3f6 100644
--- a/app/config/locale/translations/ro.json
+++ b/app/config/locale/translations/ro.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Click pe acest link pentru a valida adresa de email.",
"emails.verification.footer": "Dacă nu ai cerut validarea adresei de email, poți ignora acest mesaj.",
"emails.verification.thanks": "Mulțumim,",
+ "emails.verification.buttonText": "Confirmă adresa de email",
"emails.verification.signature": "Echipa {{project}}",
"emails.magicSession.subject": "Login",
"emails.magicSession.hello": "Bună ziua,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Click aici pentru a reseta parola pentru {{project}}",
"emails.recovery.footer": "Dacă nu ai cerut să îți schimbi parola, ignoră acest mesaj.",
"emails.recovery.thanks": "Mulțumim,",
+ "emails.recovery.buttonText": "Resetează parola",
"emails.recovery.signature": "Echipa {{project}}",
"emails.invitation.subject": "Invitatie catre %s Echipa la %s",
"emails.invitation.hello": "Bună ziua,",
"emails.invitation.body": "Acest email a fost trimis pentru că {{owner}} a vrut ca tu să devii membru al echipei {{team}} la {{project}}.",
"emails.invitation.footer": "Dacă nu esti interesat, poți ignora acest email.",
"emails.invitation.thanks": "Mulțumim,",
+ "emails.invitation.buttonText": "Acceptă invitația la {{team}}",
"emails.invitation.signature": "Echipa {{project}}",
"locale.country.unknown": "Necunoscut",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ru.json b/app/config/locale/translations/ru.json
index 029aa06ee7..f61337de80 100644
--- a/app/config/locale/translations/ru.json
+++ b/app/config/locale/translations/ru.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Перейдите по ссылке, чтобы подтвердить свой адрес электронной почты.",
"emails.verification.footer": "Если вы не запрашивали подтверждение этого адреса, проигнорируйте это сообщение.",
"emails.verification.thanks": "Спасибо,",
+ "emails.verification.buttonText": "Подтвердить адрес электронной почты",
"emails.verification.signature": "команда {{project}}",
"emails.magicSession.subject": "Логин",
"emails.magicSession.hello": "Здравствуйте,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Перейдите по этой ссылке для того чтобы сбросить свой пароль для проекта {{project}}",
"emails.recovery.footer": "Если вы не запрашивали сброс пароля, проигнорируйте это сообщение.",
"emails.recovery.thanks": "Спасибо,",
+ "emails.recovery.buttonText": "Сбросить пароль",
"emails.recovery.signature": "команда {{project}}",
"emails.invitation.subject": "Приглашение в команду %s по проекту %s",
"emails.invitation.hello": "Здравствуйте,",
"emails.invitation.body": "Это письмо отправлено вам, потому что {{owner}} приглашает стать членом команды {{team}} в проекте {{project}}.",
"emails.invitation.footer": "Если вы не заинтересованы, проигнорируйте это сообщение.",
"emails.invitation.thanks": "Спасибо,",
+ "emails.invitation.buttonText": "Принять приглашение в {{team}}",
"emails.invitation.signature": "команда {{project}}",
"locale.country.unknown": "Неизвестно",
"countries.af": "Афганистан",
diff --git a/app/config/locale/translations/sa.json b/app/config/locale/translations/sa.json
index 7aa8c90d77..b3326110d1 100644
--- a/app/config/locale/translations/sa.json
+++ b/app/config/locale/translations/sa.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ई-पत्रनिर्णायनार्थमिदं संयोगसूत्रमनुसरतु।",
"emails.verification.footer": "यदि अस्य संकेतस्य निर्णायनं नेष्यते तर्हि वात्र्तामिमामुपेक्षताम्।",
"emails.verification.thanks": "धन्यवादः,",
+ "emails.verification.buttonText": "ईमेल-पत्त्रं सुनिश्चित करें",
"emails.verification.signature": "{{project}} गणः",
"emails.magicSession.subject": "संप्रवेशः",
"emails.magicSession.hello": "अयि,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "{{project}} कूटशब्दपुनयाेजनाय संयोगमेनमनुसरतु।",
"emails.recovery.footer": "यदि कूटशब्दस्य पुनयाेजनं नेष्यते तर्हि वात्र्तामिमामुपेक्षताम्।",
"emails.recovery.thanks": "धन्यवादः,",
+ "emails.recovery.buttonText": "गुप्तशब्दं पुनः स्थापित करें",
"emails.recovery.signature": "{{project}} गणः",
"emails.invitation.subject": "गणस्य आमन्त्रणम् %s इति %s",
"emails.invitation.hello": "अयि भो,",
"emails.invitation.body": "{{owner}} {{team}} गणे {{project}} मध्ये भवद्योगदानमच्छितीति हेतोः पत्रमदिं भवत्सकाशं प्रेषतिम्।",
"emails.invitation.footer": "यदि भवदनिच्छा तर्हि वात्र्तामिमामुपेक्षताम्।",
"emails.invitation.thanks": "धन्यवादः,",
+ "emails.invitation.buttonText": "{{team}} निमन्त्रणं स्वीकुरुत",
"emails.invitation.signature": "{{project}} गणः",
"locale.country.unknown": "अज्ञातम् ",
"countries.af": "आफगानिस्थानम्",
diff --git a/app/config/locale/translations/sd.json b/app/config/locale/translations/sd.json
index 3f1f7678db..26c89a1770 100644
--- a/app/config/locale/translations/sd.json
+++ b/app/config/locale/translations/sd.json
@@ -8,6 +8,7 @@
"emails.verification.body": "پنھنجي اي ميل ايڊريس جي تصديق ڪرڻ لاءِ ھن لنڪ تي عمل ڪريو.",
"emails.verification.footer": "جيڪڏھن توھان نه پ askيا ھئا ھن ايڊريس جي تصديق ڪرڻ لاءِ ، توھان نظر انداز ڪري سگھوٿا ھن پيغام کي.",
"emails.verification.thanks": "مهرباني,",
+ "emails.verification.buttonText": "اي ميل پتو تصديق ڪريو",
"emails.verification.signature": "{{project}} ٽيم",
"emails.magicSession.subject": "لاگ ان",
"emails.magicSession.hello": "هي ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "ھن لنڪ تي عمل ڪريو پنھنجو {{project}} پاسورڊ ري سيٽ ڪرڻ لاءِ.",
"emails.recovery.footer": "جيڪڏھن توھان نه پ پيو ھو پنھنجي پاسورڊ کي ري سيٽ ڪرڻ لاءِ ، توھان نظر انداز ڪري سگھوٿا ھن پيغام کي.",
"emails.recovery.thanks": "مهرباني,",
+ "emails.recovery.buttonText": "پاسورڊ ري سيٽ ڪريو",
"emails.recovery.signature": "{{project}} ٽيم",
"emails.invitation.subject": "%s ٽيم %s تيجي دعوت",
"emails.invitation.hello": "هيلو,",
"emails.invitation.body": "ھي اي ميل توھان ڏانھن موڪليو ويو آھي {اڪاڻ ته {{owner}} توھان کي دعوت ڏيڻ چاھي ٿو ته توھان {{team}} ٽيم جو ميمبر بڻجي {{project}} تي.",
"emails.invitation.footer": "جيڪڏھن توھان دلچسپي نٿا رکو ، توھان نظر انداز ڪري سگھوٿا ھن پيغام کي.",
"emails.invitation.thanks": "مهرباني,",
+ "emails.invitation.buttonText": "{{team}} جي دعوت قبول ڪريو",
"emails.invitation.signature": "{{project}} ٽيم",
"locale.country.unknown": "نامعلوم",
"countries.af": "افغانستان",
diff --git a/app/config/locale/translations/si.json b/app/config/locale/translations/si.json
index 536e8d3604..e2053407ea 100644
--- a/app/config/locale/translations/si.json
+++ b/app/config/locale/translations/si.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ඔබගේ විද්යුත් තැපැල් ලිපිනය සත්යාපනය කිරීමට මෙම සම්බන්ධකය අනුගමනය කරන්න.",
"emails.verification.footer": "මෙම ලිපිනය සත්යාපනය කරන ලෙස ඔබ ඉල්ලුවේ නැත්නම්, ඔබට මෙම පණිවිඩය නොසලකා හැරිය හැක.",
"emails.verification.thanks": "ස්තුතියි,",
+ "emails.verification.buttonText": "ඊමේල් ලිපිනය තහවුරු කරන්න",
"emails.verification.signature": "{{project}} කණ්ඩායම",
"emails.magicSession.subject": "ප්රවේශ වන්න",
"emails.magicSession.hello": "හේයි,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "ඔබගේ {{project}} මුරපදය නැවත සැකසීමට මෙම සම්බන්ධකය අනුගමනය කරන්න.",
"emails.recovery.footer": "ඔබගේ මුරපදය නැවත සකසන ලෙස ඔබ ඉල්ලුවේ නැත්නම්, ඔබට මෙම පණිවිඩය නොසලකා හැරිය හැක.",
"emails.recovery.thanks": "ස්තුතියි,",
+ "emails.recovery.buttonText": "මුරපදය යළි පිහිටුවන්න",
"emails.recovery.signature": "{{project}} කණ්ඩායම",
"emails.invitation.subject": "%s කණ්ඩායමට ආරාධනා %s හි",
"emails.invitation.hello": "ආයුබෝවන්,",
"emails.invitation.body": "මෙම තැපැල් ඔබට එව්වේ, {{owner}} හට {{project}} හි {{team}} කණ්ඩායමේ සාමාජිකයෙකු වීමට ඔබට ආරාධනා කිරීමට අවශ්ය වූ බැවිනි.",
"emails.invitation.footer": "ඔබ උනන්දුවක් නොදක්වන්නේ නම්, ඔබට මෙම පණිවිඩය නොසලකා හැරිය හැක.",
"emails.invitation.thanks": "ස්තුතියි,",
+ "emails.invitation.buttonText": "{{team}} සඳහා ආරාධනය පිළිගෙනින්න",
"emails.invitation.signature": "{{project}} කණ්ඩායම",
"locale.country.unknown": "නොදන්නා",
"countries.af": "ඇෆ්ගනිස්ථානය",
diff --git a/app/config/locale/translations/sk.json b/app/config/locale/translations/sk.json
index 93c12c0881..1b41d8031d 100644
--- a/app/config/locale/translations/sk.json
+++ b/app/config/locale/translations/sk.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Použi tento link pre overenie svojej emailovej adresy.",
"emails.verification.footer": "Ak si nepožiadal o overenie tejto adresy, môžeš túto správu ignorovať.",
"emails.verification.thanks": "Ďakujeme.,",
+ "emails.verification.buttonText": "Potvrďte e-mailovú adresu",
"emails.verification.signature": "{{project}} tím",
"emails.magicSession.subject": "Prihlásenie",
"emails.magicSession.hello": "Ahoj,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Použi tento link pre obnovenie svojho {{project}} hesla.",
"emails.recovery.footer": "Ak si nepožiadal o obnovu svojho hesla, túto správu môžeš ignorovať.",
"emails.recovery.thanks": "Ďakujeme,",
+ "emails.recovery.buttonText": "Obnoviť heslo",
"emails.recovery.signature": "{{project}} tím",
"emails.invitation.subject": "Pozvánka do %s Tímu v %s",
"emails.invitation.hello": "Ahoj,",
"emails.invitation.body": "Tento email ti bol zaslaný, pretože {{owner}} ťa pozval, aby si sa stal členom {{team}} tímu v projekte {{project}}.",
"emails.invitation.footer": "Ak nemáš záujem, môžeš túto správu ignorovať.",
"emails.invitation.thanks": "Ďakujeme,",
+ "emails.invitation.buttonText": "Prijať pozvánku do {{team}}",
"emails.invitation.signature": "{{project}} tím",
"locale.country.unknown": "Neznámy",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/sn.json b/app/config/locale/translations/sn.json
index d17a98ff42..9fcadfaa82 100644
--- a/app/config/locale/translations/sn.json
+++ b/app/config/locale/translations/sn.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Tevedza chinongedzo ichi kuti uratidze kuti kero iyi ndeyako.",
"emails.verification.footer": "Kana usina kukumbira kuti uratidze kuti kero iyi ndeyako, unogona kufuratira meseji iyi.",
"emails.verification.thanks": "Ndatenda,",
+ "emails.verification.buttonText": "Simbisa kero yeemail",
"emails.verification.signature": "Chikwata che{{project}}",
"emails.magicSession.subject": "Pinda",
"emails.magicSession.hello": "Hesi,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Baya chinongedzo ichi kuti uchinje pasiwedhi yako ye{{project}}.",
"emails.recovery.footer": "Kana usina kukumbira kuchinja pasiwedhi yako, unogona kufuratira meseji iyi.",
"emails.recovery.thanks": "Ndatenda,",
+ "emails.recovery.buttonText": "Gadzirisa password",
"emails.recovery.signature": "Chikwata che{{project}}",
"emails.invitation.subject": "Kukokwa kuchikwata che%s ku%s",
"emails.invitation.hello": "Mhoro,",
"emails.invitation.body": "Tsamba iyi yatumirwa kwauri nekuti {{owner}} anga achida kuti uve nhengo yechikwata che{{team}} pachirongwa che{{project}}.",
"emails.invitation.footer": "Kana usiri kufarira kuve nhengo yechikwata ichi, unogona kufuratira meseji iyi.",
"emails.invitation.thanks": "Ndatenda,",
+ "emails.invitation.buttonText": "Gamuchira kukokwa ku {{team}}",
"emails.invitation.signature": "Chikwata che{{project}}",
"locale.country.unknown": "Haizivikanwe",
"countries.af": "Afuganisitani",
diff --git a/app/config/locale/translations/sv.json b/app/config/locale/translations/sv.json
index 8997fd53f8..9bff513f0c 100644
--- a/app/config/locale/translations/sv.json
+++ b/app/config/locale/translations/sv.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Klicka på denna länk för att verifiera din email",
"emails.verification.footer": "Om du inte bad om att verifiera den här e-postadressen kan du ignorera detta mail.",
"emails.verification.thanks": "Tack,",
+ "emails.verification.buttonText": "Bekräfta e-postadress",
"emails.verification.signature": "{{project}} teamet",
"emails.magicSession.subject": "Logga in",
"emails.magicSession.hello": "Hej,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Klicka på denna länk för att återställa lösenordet på {{project}}",
"emails.recovery.footer": "Om du inte bad om att återställa ditt lösenord kan du ignorera detta mail.",
"emails.recovery.thanks": "Tack,",
+ "emails.recovery.buttonText": "Återställ lösenord",
"emails.recovery.signature": "{{project}} teamet",
"emails.invitation.subject": "Inbjudan till %s teamet på %s",
"emails.invitation.hello": "Hej,",
"emails.invitation.body": "Detta mail skickades till dig eftersom {{owner}} ville bjuda in dig att bli medlem i teamet {{team}} på {{project}}.",
"emails.invitation.footer": "Om du inte är intresserad kan du ignorera detta mail.",
"emails.invitation.thanks": "Tack,",
+ "emails.invitation.buttonText": "Acceptera inbjudan till {{team}}",
"emails.invitation.signature": "{{project}} teamet",
"locale.country.unknown": "Okänt",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/ta.json b/app/config/locale/translations/ta.json
index f0695867a9..4afcbe9b63 100644
--- a/app/config/locale/translations/ta.json
+++ b/app/config/locale/translations/ta.json
@@ -8,6 +8,7 @@
"emails.verification.body": "உங்கள் மின்னஞ்சல் முகவரியைச் சரிபார்க்க இந்த இணைப்பைப் பின்தொடரவும்.",
"emails.verification.footer": "இந்த முகவரியைச் சரிபார்க்கும்படி உங்களிடம் கேட்கப்படவில்லை என்றால், இந்தச் செய்தியை நீங்கள் புறக்கணிக்கலாம்.",
"emails.verification.thanks": "நன்றி,",
+ "emails.verification.buttonText": "மின்னஞ்சல் முகவரியை உறுதிப்படுத்தவும்",
"emails.verification.signature": "{{project}} குழு ",
"emails.magicSession.subject": "உள்நுழைய",
"emails.magicSession.hello": "ஏய்,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "மீட்டமைக்க இந்த இணைப்பைப் பின்தொடரவும் {{project}} கடவுச்சொல்.",
"emails.recovery.footer": "உங்கள் கடவுச்சொல்லை மீட்டமைக்கும்படி உங்களிடம் கேட்கப்படவில்லை என்றால், இந்தச் செய்தியை நீங்கள் புறக்கணிக்கலாம்.",
"emails.recovery.thanks": "நன்றி,",
+ "emails.recovery.buttonText": "கடவுச்சொல்லை மீட்டமைக்கவும்",
"emails.recovery.signature": "{{project}} குழு",
"emails.invitation.subject": "அழைப்பிதழ் %s குழு %s ",
"emails.invitation.hello": "வணக்கம்,",
"emails.invitation.body": "{{project}} இல் {{team}} குழுவில் உறுப்பினராக உங்களை {{owner}} அழைக்க விரும்புவதால், இந்த அஞ்சல் உங்களுக்கு அனுப்பப்பட்டது.",
"emails.invitation.footer": "உங்களுக்கு ஆர்வம் இல்லை என்றால், இந்த செய்தியை நீங்கள் புறக்கணிக்கலாம்.",
"emails.invitation.thanks": "நன்றி,",
+ "emails.invitation.buttonText": "{{team}} அழைப்பை ஏற்கவும்",
"emails.invitation.signature": "{{project}} குழு",
"locale.country.unknown": "அறியவில்லை",
"countries.af": "ஆப்கானித்தான்",
diff --git a/app/config/locale/translations/te.json b/app/config/locale/translations/te.json
index 870b0b82a2..4073fc72d9 100644
--- a/app/config/locale/translations/te.json
+++ b/app/config/locale/translations/te.json
@@ -8,6 +8,7 @@
"emails.verification.body": "ఈ లింక్ ద్వారా ఇమెయిల్ ని ధృవీకరించండి",
"emails.verification.footer": "మీరు ఈ చిరునామాను ధృవీకరించమని అడగనట్లయితే, మీరు ఈ సందేశాన్ని విస్మరించవచ్చు",
"emails.verification.thanks": "ధన్యవాదాలు,",
+ "emails.verification.buttonText": "ఇమెయిల్ చిరునామాను నిర్ధారించండి",
"emails.verification.signature": "{{project}} జట్",
"emails.magicSession.subject": "లాగిన్",
"emails.magicSession.hello": "నమస్కారము,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "మీ {{project}} పాస్వర్డ్ ని రీసెట్ చేయడానికి ఈ లింక్ ని అనుసరించండి",
"emails.recovery.footer": "మీరు మీ పాస్వర్డ్ ని రీసెట్ చేయమని అడగనట్లయితే, మీరు ఈ సందేశాన్ని విస్మరించవచ్చు",
"emails.recovery.thanks": "ధన్యవాదాల,",
+ "emails.recovery.buttonText": "పాస్వర్డ్ను రీసెట్ చేయండి",
"emails.recovery.signature": "{{project}} జట్",
"emails.invitation.subject": "%s వద్ద %s బృందానికి ఆహ్వానం",
"emails.invitation.hello": "నమస్కారమ,",
"emails.invitation.body": "{{owner}} మిమ్మల్ని {{project}} లో {{team}} బృందంలో సభ్యునిగా ఉండమని ఆహ్వానించాలనుకుంటున్నందున ఈ మెయిల్ మీకు పంపబడింది.",
"emails.invitation.footer": "మీకు ఆసక్తి లేకుంటే, మీరు ఈ సందేశాన్ని విస్మరించవచ్చు.",
"emails.invitation.thanks": "ధన్యవాదాల,",
+ "emails.invitation.buttonText": "{{team}} కు ఆహ్వానాన్ని ఆమోదించండి",
"emails.invitation.signature": "{{project}} జట్",
"locale.country.unknown": "తెలియని",
"countries.af": "ఆఫ్ఘనిస్తాన్",
diff --git a/app/config/locale/translations/th.json b/app/config/locale/translations/th.json
index 5a53b16055..4003ece666 100644
--- a/app/config/locale/translations/th.json
+++ b/app/config/locale/translations/th.json
@@ -8,6 +8,7 @@
"emails.verification.body": "กดเข้าไปที่ลิงก์นี้เพื่อยืนยันอีเมลของท่าน",
"emails.verification.footer": "หากท่านไม่ได้ต้องการที่จะยืนยันอีเมลนี้ ท่านสามารถเพิกเฉยข้อความนี้ได้",
"emails.verification.thanks": "ขอบคุณ",
+ "emails.verification.buttonText": "ยืนยันที่อยู่อีเมล",
"emails.verification.signature": "ทีม {{project}}",
"emails.magicSession.subject": "เข้าสู่ระบบ",
"emails.magicSession.hello": "เรียนผู้ใช้งาน",
@@ -20,12 +21,14 @@
"emails.recovery.body": "กดเข้าไปที่ลิงก์นี้เพื่อรีเซ็ตรหัสผ่านสำหรับโปรเจกต์ {{project}} ของท่าน",
"emails.recovery.footer": "หากท่านไม่ได้ต้องการที่จะรีเซ็ตรหัสผ่านของท่าน ท่านสามารถเพิกเฉยข้อความนี้ได้",
"emails.recovery.thanks": "ขอบคุณ",
+ "emails.recovery.buttonText": "รีเซ็ตรหัสผ่าน",
"emails.recovery.signature": "ทีม {{project}}",
"emails.invitation.subject": "เรียนเชิญเข้าร่วม ทีม %s จากโปรเจกต์ %s",
"emails.invitation.hello": "สวัสดี",
"emails.invitation.body": "ท่านได้รับอีเมลฉบับนี้เนื่องจาก {{owner}} ต้องการที่จะเชิญชวนคุณเข้าร่วมเป็นส่วนหนึ่งของ ทีม {{team}} จากโปรเจกต์ {{project}}",
"emails.invitation.footer": "หากท่านไม่ได้สนใจที่จะเข้าร่วม ท่านสามารถเพิกเฉยข้อความนี้ได้",
"emails.invitation.thanks": "ขอบคุณ",
+ "emails.invitation.buttonText": "ยอมรับคำเชิญเข้าร่วม {{team}}",
"emails.invitation.signature": "ทีม {{project}}",
"locale.country.unknown": "ไม่ทราบ",
"countries.af": "อัฟกานิสถาน",
diff --git a/app/config/locale/translations/tl.json b/app/config/locale/translations/tl.json
index 6d0be01095..27ea6c088f 100644
--- a/app/config/locale/translations/tl.json
+++ b/app/config/locale/translations/tl.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Sundin ang link na ito upang ma-verify ang iyong email address.",
"emails.verification.footer": "Kung hindi mo hiningi na i-verify ang address na ito, maaari mong balewalain ang mensahe na ito.",
"emails.verification.thanks": "Salamat,",
+ "emails.verification.buttonText": "Kumpirmahin ang email address",
"emails.verification.signature": "Pangkat ng {{project}}",
"emails.magicSession.subject": "Mag log in",
"emails.magicSession.hello": "Kamusta ,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Sundin ang link na ito upang i-reset ang password ng iyong {{project}}.",
"emails.recovery.footer": "Kung hindi mo hiningi na i-reset ang iyong password, maaari mong balewalain ang mensahe na ito.",
"emails.recovery.thanks": "Salamat,",
+ "emails.recovery.buttonText": "I-reset ang password",
"emails.recovery.signature": "Pangkat ng {{project}}",
"emails.invitation.subject": "Imbitasyon para sa Pangkat %s sa %s",
"emails.invitation.hello": "Kamusta,",
"emails.invitation.body": "Ipinadala sa iyo ang mail na ito dahil gusto kang imbitahan ni {{owner}} na maging miyembro ng Pangkat {{team}} sa ilalim ng proyektong {{project}}.",
"emails.invitation.footer": "Kung ikaw ay hindi interesado, maaari mong balewalain ang mensaheng ito.",
"emails.invitation.thanks": "Salamat,",
+ "emails.invitation.buttonText": "Tanggapin ang paanyaya sa {{team}}",
"emails.invitation.signature": "Pangkat ng {{project}}",
"locale.country.unknown": "Hindi kilala",
"countries.af": "Apganistan",
diff --git a/app/config/locale/translations/tr.json b/app/config/locale/translations/tr.json
index 115050c2e2..a7183152b6 100644
--- a/app/config/locale/translations/tr.json
+++ b/app/config/locale/translations/tr.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Eposta adresini doğrulamak için bu bağlantıyı kullanın.",
"emails.verification.footer": "Eğer bu eposta adresini doğrulamak isteyen siz değilseniz devam etmeyin.",
"emails.verification.thanks": "Teşekkürler,",
+ "emails.verification.buttonText": "E-posta adresini doğrula",
"emails.verification.signature": "{{project}} takımı",
"emails.magicSession.subject": "Giriş",
"emails.magicSession.hello": "Merhaba,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "{{project}} şifrenizi sıfırlamak için bu bağlantıyı kullanın.",
"emails.recovery.footer": "Eğer şifre sıfırlama talebinde bulunmadıysanız devam etmeyin.",
"emails.recovery.thanks": "Teşekkürler,",
+ "emails.recovery.buttonText": "Şifreyi sıfırla",
"emails.recovery.signature": "{{project}} takımı",
"emails.invitation.subject": "%s üzerinde %s Takımına Davet",
"emails.invitation.hello": "Merhaba,",
"emails.invitation.body": "Bu epostayı aldınız, çünkü {{owner}} sizi {{project}} üzerinde {{team}} takımının üyesi olmaya davet etti.",
"emails.invitation.footer": "Eğer ilgilenmiyorsanız devam etmeyin.",
"emails.invitation.thanks": "Teşekkürler,",
+ "emails.invitation.buttonText": "{{team}}'e daveti kabul et",
"emails.invitation.signature": "{{project}} takımı",
"locale.country.unknown": "Bilinmeyen",
"countries.af": "Afganistan",
diff --git a/app/config/locale/translations/uk.json b/app/config/locale/translations/uk.json
index 3f66bd1c58..daa003754d 100644
--- a/app/config/locale/translations/uk.json
+++ b/app/config/locale/translations/uk.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Перейдіть за цим посиланням, щоб підтвердити свою електронну адресу.",
"emails.verification.footer": "Якщо ви не запитували підтвердження цієї адреси, ви можете ігнорувати це повідомлення.",
"emails.verification.thanks": "Дякуємо,",
+ "emails.verification.buttonText": "Підтвердити адресу електронної пошти",
"emails.verification.signature": "команда {{project}}",
"emails.magicSession.subject": "Логін",
"emails.magicSession.hello": "Вітаємо,",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Перейдіть за цим посиланням для того щоб скинути свій пароль для проекту {{project}}",
"emails.recovery.footer": "Якщо ви не запитували скидання паролю, проігноруйте це повідомлення.",
"emails.recovery.thanks": "Дякуємо,",
+ "emails.recovery.buttonText": "Скинути пароль",
"emails.recovery.signature": "команда {{project}}",
"emails.invitation.subject": "Запрошення до %s Команди у %s",
"emails.invitation.hello": "Вітаємо,",
"emails.invitation.body": "Цей лист був надісланий вам тому що {{owner}} запрошує вас стати членом команди {{team}} у проекті {{project}}.",
"emails.invitation.footer": "Якщо ви не зацікавлені, проігноруйте це повідомлення.",
"emails.invitation.thanks": "Дякуємо,",
+ "emails.invitation.buttonText": "Прийняти запрошення до {{team}}",
"emails.invitation.signature": "команда {{project}}",
"locale.country.unknown": "Невідомо",
"countries.af": "Афганістан",
diff --git a/app/config/locale/translations/ur.json b/app/config/locale/translations/ur.json
index 9d6aa47762..8823e0da2e 100644
--- a/app/config/locale/translations/ur.json
+++ b/app/config/locale/translations/ur.json
@@ -8,6 +8,7 @@
"emails.verification.body": "براہ کرم اپنے ای میل کی تصدیق کے لیے درج ذیل لنک پر عمل کریں۔",
"emails.verification.footer": "اگر آپ نے اس پتے کی تصدیق کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.verification.thanks": "شکریہ،",
+ "emails.verification.buttonText": "ای میل پتہ کی تصدیق کریں",
"emails.verification.signature": "ٹیم۔ {{project}}",
"emails.magicSession.subject": "اگ ان کریں",
"emails.magicSession.hello": "خوش آمدید،",
@@ -20,13 +21,15 @@
"emails.recovery.body": "{{project}} کا پاس ورڈ تبدیل کرنے کے لیے درج ذیل لنک پر عمل کریں",
"emails.recovery.footer": "اگر آپ نے اپنا پاس ورڈ دوبارہ ترتیب دینے کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.recovery.thanks": "شکریہ،",
+ "emails.recovery.buttonText": "پاس ورڈ ری سیٹ کریں",
"emails.recovery.signature": "ٹیم۔ {{project}}",
"emails.invitation.subject": "%s پر %s ٹیم کو دعوت",
"emails.invitation.hello": "خوش آمدید،",
"emails.invitation.body": "یہ پیغام آپ کو اس لیے بھیجا گیا تھا کہ {{owner}} نے آپ کو {{project}} میں {{team}} ٹیم کا رکن بننے کی دعوت بھیجی",
"emails.invitation.footer": "اگر آپ دلچسپی نہیں رکھتے تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.invitation.thanks": "شکریہ،",
- "emails.invitation.signature": "ٹیم۔ {{project}",
+ "emails.invitation.buttonText": "{{team}} کی دعوت قبول کریں",
+ "emails.invitation.signature": "ٹیم۔ {{project}}",
"locale.country.unknown": "نامعلوم",
"countries.af": "افغانستان",
"countries.ao": "انگولا",
diff --git a/app/config/locale/translations/vi.json b/app/config/locale/translations/vi.json
index 76a545a1d4..e9168d9ab8 100644
--- a/app/config/locale/translations/vi.json
+++ b/app/config/locale/translations/vi.json
@@ -8,6 +8,7 @@
"emails.verification.body": "Nhấn vào đường dẫn sau để xác minh địa chỉ email của bạn.",
"emails.verification.footer": "Nếu bạn không yêu cầu xác minh tài khoản, bạn có thể bỏ qua email này.",
"emails.verification.thanks": "Cảm ơn",
+ "emails.verification.buttonText": "Xác nhận địa chỉ email",
"emails.verification.signature": "Nhóm {{project}}",
"emails.magicSession.subject": "Đăng nhập",
"emails.magicSession.hello": "Chào",
@@ -20,12 +21,14 @@
"emails.recovery.body": "Nhấn vào đường dẫn sau để thiết lập lại mật khẩu {{project}} của bạn.",
"emails.recovery.footer": "Nếu bạn không yêu cầu thiết lập lại mật khẩu, bạn có thể bỏ qua email này.",
"emails.recovery.thanks": "Cảm ơn",
+ "emails.recovery.buttonText": "Đặt lại mật khẩu",
"emails.recovery.signature": "Nhóm {{project}}",
"emails.invitation.subject": "Lời mời tham gia nhóm %s tại %s",
"emails.invitation.hello": "Xin chào",
"emails.invitation.body": "Email này được gửi cho bạn vì {{owner}} muốn mời bạn trở thành một thành viên của nhóm {{team}} tại {{project}}.",
"emails.invitation.footer": "Nếu bạn không quan tâm, bạn có thể bỏ qua email này.",
"emails.invitation.thanks": "Cảm ơn",
+ "emails.invitation.buttonText": "Chấp nhận lời mời vào {{team}}",
"emails.invitation.signature": "Nhóm {{project}}",
"locale.country.unknown": "Không xác định",
"countries.af": "Afghanistan",
diff --git a/app/config/locale/translations/zh-cn.json b/app/config/locale/translations/zh-cn.json
index 5e35a89bfe..554b506e9e 100644
--- a/app/config/locale/translations/zh-cn.json
+++ b/app/config/locale/translations/zh-cn.json
@@ -8,6 +8,7 @@
"emails.verification.body": "点此链接验证您的电子邮件地址。",
"emails.verification.footer": "如果您没有要求验证此地址,则可忽略此消息。",
"emails.verification.thanks": "谢谢、",
+ "emails.verification.buttonText": "确认邮箱地址",
"emails.verification.signature": "{{project}} 团队",
"emails.magicSession.subject": "登录",
"emails.magicSession.hello": "你好、",
@@ -20,12 +21,14 @@
"emails.recovery.body": "点此链接重置您的 {{project}} 密码。",
"emails.recovery.footer": "如果您没有要求重置密码,则可以忽略此消息。",
"emails.recovery.thanks": "谢谢、",
+ "emails.recovery.buttonText": "重置密码",
"emails.recovery.signature": "{{project}} 团队",
"emails.invitation.subject": "邀请 %s 团队在 %s",
"emails.invitation.hello": "你好、",
"emails.invitation.body": "这封邮件发送给您是因为 {{owner}} 想邀请您成为 {{team}} 团队在 {{project}}.",
"emails.invitation.footer": "如果您不感兴趣,可以忽略此消息。",
"emails.invitation.thanks": "谢谢、",
+ "emails.invitation.buttonText": "接受加入 {{team}} 的邀请",
"emails.invitation.signature": "{{project}} 团队",
"locale.country.unknown": "未知",
"countries.af": "阿富汗",
diff --git a/app/config/locale/translations/zh-tw.json b/app/config/locale/translations/zh-tw.json
index 146dd0a401..bb9868d679 100644
--- a/app/config/locale/translations/zh-tw.json
+++ b/app/config/locale/translations/zh-tw.json
@@ -8,6 +8,7 @@
"emails.verification.body": "按照此連結驗證您的電子郵件地址。",
"emails.verification.footer": "如果您沒有要求驗證此地址,則可以忽略此消息。",
"emails.verification.thanks": "謝謝、",
+ "emails.verification.buttonText": "確認電子郵件地址",
"emails.verification.signature": "{{project}} 團隊",
"emails.magicSession.subject": "登入",
"emails.magicSession.hello": "嗨、",
@@ -20,12 +21,14 @@
"emails.recovery.body": "按照此連結重置您的 {{project}} 密碼。",
"emails.recovery.footer": "如果您沒有要求重置密碼,則可以忽略此消息。",
"emails.recovery.thanks": "謝謝、",
+ "emails.recovery.buttonText": "重設密碼",
"emails.recovery.signature": "{{project}} 團隊",
"emails.invitation.subject": "邀請 %s 團隊在 %s",
"emails.invitation.hello": "您好、",
"emails.invitation.body": "發送這封郵件給您是因為 {{owner}} 想邀請您成為 {{team}} 團隊在 {{project}}。",
"emails.invitation.footer": "如果您不感興趣,可以忽略此消息。",
"emails.invitation.thanks": "謝謝、",
+ "emails.invitation.buttonText": "接受加入 {{team}} 的邀請",
"emails.invitation.signature": "{{project}} 團隊",
"locale.country.unknown": "未知",
"countries.af": "阿富汗",
diff --git a/app/config/platforms.php b/app/config/platforms.php
index f08401e8fa..96d5426515 100644
--- a/app/config/platforms.php
+++ b/app/config/platforms.php
@@ -134,7 +134,7 @@ return [
[
'key' => 'react-native',
'name' => 'React Native',
- 'version' => '0.9.1',
+ 'version' => '0.10.0',
'url' => 'https://github.com/appwrite/sdk-for-react-native',
'package' => 'https://npmjs.com/package/react-native-appwrite',
'enabled' => true,
@@ -217,7 +217,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
- 'version' => '8.0.0',
+ 'version' => '8.1.0',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
diff --git a/app/config/specs/open-api3-1.7.x-client.json b/app/config/specs/open-api3-1.7.x-client.json
index bbb78c6c66..11fd80fda8 100644
--- a/app/config/specs/open-api3-1.7.x-client.json
+++ b/app/config/specs/open-api3-1.7.x-client.json
@@ -4666,7 +4666,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -6595,7 +6595,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
diff --git a/app/config/specs/open-api3-1.7.x-console.json b/app/config/specs/open-api3-1.7.x-console.json
index 90ef137fc2..48440caac4 100644
--- a/app/config/specs/open-api3-1.7.x-console.json
+++ b/app/config/specs/open-api3-1.7.x-console.json
@@ -8071,7 +8071,7 @@
"model": "#\/components\/schemas\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -8151,7 +8151,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Documents List",
@@ -8242,7 +8242,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -8335,7 +8335,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8520,7 +8520,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -9767,6 +9767,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -9792,7 +9793,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -10395,6 +10397,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -10420,7 +10423,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -25446,12 +25450,33 @@
"Temporary Redirect 307",
"Permanent Redirect 308"
]
+ },
+ "resourceId": {
+ "type": "string",
+ "description": "ID of parent resource.",
+ "x-example": ""
+ },
+ "resourceType": {
+ "type": "string",
+ "description": "Type of parent resource.",
+ "x-example": "site",
+ "enum": [
+ "site",
+ "function"
+ ],
+ "x-enum-name": "ProxyResourceType",
+ "x-enum-keys": [
+ "Site",
+ "Function"
+ ]
}
},
"required": [
"domain",
"url",
- "statusCode"
+ "statusCode",
+ "resourceId",
+ "resourceType"
]
}
}
@@ -25936,6 +25961,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -25961,7 +25987,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -26580,6 +26607,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -26605,7 +26633,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -29364,7 +29393,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -34846,6 +34876,17 @@
"default": ""
},
"in": "query"
+ },
+ {
+ "name": "providerReference",
+ "description": "Git reference (branch, tag, commit) to get contents from",
+ "required": false,
+ "schema": {
+ "type": "string",
+ "x-example": "",
+ "default": ""
+ },
+ "in": "query"
}
]
}
diff --git a/app/config/specs/open-api3-1.7.x-server.json b/app/config/specs/open-api3-1.7.x-server.json
index 1ae9328864..4a6a4f3b4f 100644
--- a/app/config/specs/open-api3-1.7.x-server.json
+++ b/app/config/specs/open-api3-1.7.x-server.json
@@ -7552,7 +7552,7 @@
"model": "#\/components\/schemas\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -7634,7 +7634,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Documents List",
@@ -7726,7 +7726,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -7820,7 +7820,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8008,7 +8008,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -8844,6 +8844,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -8869,7 +8870,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -9244,6 +9246,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -9269,7 +9272,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -17490,6 +17494,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -17515,7 +17520,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -17906,6 +17912,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -17931,7 +17938,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -20646,7 +20654,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json
index b6e1971407..e004ad35c9 100644
--- a/app/config/specs/open-api3-latest-console.json
+++ b/app/config/specs/open-api3-latest-console.json
@@ -8072,7 +8072,7 @@
"model": "#\/components\/schemas\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -8152,7 +8152,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Documents List",
@@ -8262,7 +8262,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -8356,7 +8356,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8542,7 +8542,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Document",
diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json
index 90b49ae65c..042398d8f3 100644
--- a/app/config/specs/open-api3-latest-server.json
+++ b/app/config/specs/open-api3-latest-server.json
@@ -7553,7 +7553,7 @@
"model": "#\/components\/schemas\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -7635,7 +7635,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Documents List",
@@ -7746,7 +7746,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -7841,7 +7841,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8030,7 +8030,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Document",
diff --git a/app/config/specs/swagger2-1.7.x-client.json b/app/config/specs/swagger2-1.7.x-client.json
index 92132151b4..0e83cb4691 100644
--- a/app/config/specs/swagger2-1.7.x-client.json
+++ b/app/config/specs/swagger2-1.7.x-client.json
@@ -4809,7 +4809,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -6729,7 +6729,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
diff --git a/app/config/specs/swagger2-1.7.x-console.json b/app/config/specs/swagger2-1.7.x-console.json
index e53a0dfb0b..9b2696efe5 100644
--- a/app/config/specs/swagger2-1.7.x-console.json
+++ b/app/config/specs/swagger2-1.7.x-console.json
@@ -8200,7 +8200,7 @@
"model": "#\/definitions\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -8284,7 +8284,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Documents List",
@@ -8372,7 +8372,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -8463,7 +8463,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8638,7 +8638,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -9835,6 +9835,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -9860,7 +9861,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -10466,6 +10468,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -10491,7 +10494,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -25696,12 +25700,35 @@
"Temporary Redirect 307",
"Permanent Redirect 308"
]
+ },
+ "resourceId": {
+ "type": "string",
+ "description": "ID of parent resource.",
+ "default": null,
+ "x-example": ""
+ },
+ "resourceType": {
+ "type": "string",
+ "description": "Type of parent resource.",
+ "default": null,
+ "x-example": "site",
+ "enum": [
+ "site",
+ "function"
+ ],
+ "x-enum-name": "ProxyResourceType",
+ "x-enum-keys": [
+ "Site",
+ "Function"
+ ]
}
},
"required": [
"domain",
"url",
- "statusCode"
+ "statusCode",
+ "resourceId",
+ "resourceType"
]
}
}
@@ -26203,6 +26230,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -26228,7 +26256,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -26850,6 +26879,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -26875,7 +26905,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -29604,7 +29635,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -35063,6 +35095,15 @@
"x-example": "",
"default": "",
"in": "query"
+ },
+ {
+ "name": "providerReference",
+ "description": "Git reference (branch, tag, commit) to get contents from",
+ "required": false,
+ "type": "string",
+ "x-example": "",
+ "default": "",
+ "in": "query"
}
]
}
diff --git a/app/config/specs/swagger2-1.7.x-server.json b/app/config/specs/swagger2-1.7.x-server.json
index 083290bcc0..aba8aa5032 100644
--- a/app/config/specs/swagger2-1.7.x-server.json
+++ b/app/config/specs/swagger2-1.7.x-server.json
@@ -7671,7 +7671,7 @@
"model": "#\/definitions\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -7757,7 +7757,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Documents List",
@@ -7846,7 +7846,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -7938,7 +7938,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8116,7 +8116,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
@@ -8927,6 +8927,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -8952,7 +8953,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -9340,6 +9342,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -9365,7 +9368,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -17792,6 +17796,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -17817,7 +17822,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -18221,6 +18227,7 @@
"dart-3.1",
"dart-3.3",
"dart-3.5",
+ "dart-3.8",
"dotnet-6.0",
"dotnet-7.0",
"dotnet-8.0",
@@ -18246,7 +18253,8 @@
"static-1",
"flutter-3.24",
"flutter-3.27",
- "flutter-3.29"
+ "flutter-3.29",
+ "flutter-3.32"
],
"x-enum-name": null,
"x-enum-keys": []
@@ -20935,7 +20943,8 @@
"png",
"webp",
"heic",
- "avif"
+ "avif",
+ "gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json
index 85836ff2b8..b124a3cf0a 100644
--- a/app/config/specs/swagger2-latest-console.json
+++ b/app/config/specs/swagger2-latest-console.json
@@ -3466,7 +3466,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3591,7 +3590,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3722,7 +3720,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3785,7 +3782,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -4272,7 +4268,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -4355,7 +4350,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -4446,7 +4440,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8064,7 +8057,6 @@
"scope": "documents.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8146,7 +8138,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8201,7 +8192,7 @@
"model": "#\/definitions\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -8285,7 +8276,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Documents List",
@@ -8392,7 +8383,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -8484,7 +8475,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8594,7 +8585,6 @@
"scope": "documents.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8660,7 +8650,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Document",
@@ -8684,7 +8674,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8808,7 +8797,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8905,7 +8893,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -16267,7 +16254,6 @@
"rate-key": "url:{url},ip:{ip}",
"scope": "functions.read",
"platforms": [
- "server",
"server"
],
"packaging": false,
@@ -16421,7 +16407,6 @@
"scope": "execution.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -16495,7 +16480,6 @@
"scope": "execution.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -16612,7 +16596,6 @@
"scope": "execution.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17199,8 +17182,7 @@
"scope": "graphql",
"platforms": [
"server",
- "client",
- "server"
+ "client"
],
"packaging": false,
"auth": {
@@ -17273,8 +17255,7 @@
"scope": "graphql",
"platforms": [
"server",
- "client",
- "server"
+ "client"
],
"packaging": false,
"auth": {
@@ -18608,7 +18589,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18660,7 +18640,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18712,7 +18691,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18764,7 +18742,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18816,7 +18793,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18868,7 +18844,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18920,7 +18895,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -18972,7 +18946,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -23361,8 +23334,7 @@
"platforms": [
"server",
"client",
- "console",
- "server"
+ "console"
],
"packaging": false,
"auth": {
@@ -23512,8 +23484,7 @@
"platforms": [
"server",
"client",
- "console",
- "server"
+ "console"
],
"packaging": false,
"auth": {
@@ -32714,7 +32685,6 @@
"rate-key": "url:{url},ip:{ip}",
"scope": "sites.read",
"platforms": [
- "server",
"server"
],
"packaging": false,
@@ -33983,7 +33953,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34066,7 +34035,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34156,7 +34124,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34226,7 +34193,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34315,7 +34281,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34385,7 +34350,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34464,7 +34428,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34671,7 +34634,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34898,7 +34860,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -34973,7 +34934,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35063,7 +35023,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35125,7 +35084,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35200,7 +35158,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35332,7 +35289,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35415,7 +35371,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35528,7 +35483,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35598,7 +35552,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -35684,7 +35637,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json
index b0a58b264d..d9779cceb2 100644
--- a/app/config/specs/swagger2-latest-server.json
+++ b/app/config/specs/swagger2-latest-server.json
@@ -3142,7 +3142,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3269,7 +3268,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3402,7 +3400,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3467,7 +3464,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -3956,7 +3952,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -4041,7 +4036,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -4134,7 +4128,6 @@
"scope": "avatars.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -7533,7 +7526,6 @@
"scope": "documents.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -7617,7 +7609,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -7672,7 +7663,7 @@
"model": "#\/definitions\/documentList"
}
],
- "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -7758,7 +7749,7 @@
"tags": [
"databases"
],
- "description": "Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Documents List",
@@ -7866,7 +7857,7 @@
"tags": [
"databases"
],
- "description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nUpdate all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
"responses": {
"200": {
"description": "Documents List",
@@ -7959,7 +7950,7 @@
"tags": [
"databases"
],
- "description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nBulk delete documents using queries, if no queries are passed then all documents are deleted.",
"responses": {
"200": {
"description": "Documents List",
@@ -8070,7 +8061,6 @@
"scope": "documents.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8138,7 +8128,7 @@
"tags": [
"databases"
],
- "description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
+ "description": "**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.\n\nCreate or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"201": {
"description": "Document",
@@ -8162,7 +8152,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8288,7 +8277,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -8387,7 +8375,6 @@
"scope": "documents.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -14951,7 +14938,6 @@
"rate-key": "url:{url},ip:{ip}",
"scope": "functions.read",
"platforms": [
- "server",
"server"
],
"packaging": false,
@@ -15107,7 +15093,6 @@
"scope": "execution.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -15183,7 +15168,6 @@
"scope": "execution.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -15302,7 +15286,6 @@
"scope": "execution.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -15819,8 +15802,7 @@
"scope": "graphql",
"platforms": [
"server",
- "client",
- "server"
+ "client"
],
"packaging": false,
"auth": {
@@ -15895,8 +15877,7 @@
"scope": "graphql",
"platforms": [
"server",
- "client",
- "server"
+ "client"
],
"packaging": false,
"auth": {
@@ -17254,7 +17235,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17308,7 +17288,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17362,7 +17341,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17416,7 +17394,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17470,7 +17447,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17524,7 +17500,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17578,7 +17553,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -17632,7 +17606,6 @@
"scope": "locale.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -22066,8 +22039,7 @@
"platforms": [
"server",
"client",
- "console",
- "server"
+ "console"
],
"packaging": false,
"auth": {
@@ -22220,8 +22192,7 @@
"platforms": [
"server",
"client",
- "console",
- "server"
+ "console"
],
"packaging": false,
"auth": {
@@ -23794,7 +23765,6 @@
"rate-key": "url:{url},ip:{ip}",
"scope": "sites.read",
"platforms": [
- "server",
"server"
],
"packaging": false,
@@ -25000,7 +24970,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25085,7 +25054,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25177,7 +25145,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25249,7 +25216,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25340,7 +25306,6 @@
"scope": "files.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25412,7 +25377,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25493,7 +25457,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25702,7 +25665,6 @@
"scope": "files.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25783,7 +25745,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25860,7 +25821,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -25952,7 +25912,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26016,7 +25975,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26093,7 +26051,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26157,7 +26114,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26242,7 +26198,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26357,7 +26312,6 @@
"scope": "teams.read",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26429,7 +26383,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
@@ -26517,7 +26470,6 @@
"scope": "teams.write",
"platforms": [
"client",
- "server",
"server"
],
"packaging": false,
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index 2bb009cf61..e3ce2eb057 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -3229,6 +3229,7 @@ App::post('/v1/account/recovery')
->setParam('{{hello}}', $locale->getText("emails.recovery.hello"))
->setParam('{{footer}}', $locale->getText("emails.recovery.footer"))
->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks"))
+ ->setParam('{{buttonText}}', $locale->getText("emails.recovery.buttonText"))
->setParam('{{signature}}', $locale->getText("emails.recovery.signature"));
$body = $message->render();
@@ -3484,6 +3485,7 @@ App::post('/v1/account/verification')
->setParam('{{hello}}', $locale->getText("emails.verification.hello"))
->setParam('{{footer}}', $locale->getText("emails.verification.footer"))
->setParam('{{thanks}}', $locale->getText("emails.verification.thanks"))
+ ->setParam('{{buttonText}}', $locale->getText("emails.verification.buttonText"))
->setParam('{{signature}}', $locale->getText("emails.verification.signature"));
$body = $message->render();
diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php
index 5527a6bd18..3d6f791665 100644
--- a/app/controllers/api/projects.php
+++ b/app/controllers/api/projects.php
@@ -2275,6 +2275,7 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
->setParam('{{footer}}', $localeObj->getText("emails.{$type}.footer"))
->setParam('{{body}}', $localeObj->getText('emails.' . $type . '.body'), escapeHtml: false)
->setParam('{{thanks}}', $localeObj->getText("emails.{$type}.thanks"))
+ ->setParam('{{buttonText}}', $localeObj->getText("emails.{$type}.buttonText"))
->setParam('{{signature}}', $localeObj->getText("emails.{$type}.signature"))
->setParam('{{direction}}', $localeObj->getText('settings.direction'));
$message = $message->render();
diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php
index 26c789ce27..98a5b105a3 100644
--- a/app/controllers/api/storage.php
+++ b/app/controllers/api/storage.php
@@ -18,6 +18,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Buckets;
use Appwrite\Utopia\Database\Validator\Queries\Files;
use Appwrite\Utopia\Response;
use Utopia\App;
+use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
@@ -953,12 +954,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
// NOTE: this is only for the sdk generator and is not used in the action below and is utilised in `resources.php` for `resourceToken`.
->param('token', '', new Text(512), 'File token for accessing this file.', true)
+ ->inject('request')
->inject('response')
->inject('dbForProject')
->inject('resourceToken')
->inject('deviceForFiles')
->inject('deviceForLocal')
- ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal) {
+ ->inject('project')
+ ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project) {
if (!\extension_loaded('imagick')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
@@ -1035,8 +1038,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
}
+ $startTime = \microtime(true);
+
$source = $deviceForFiles->read($path);
+ $downloadTime = \microtime(true) - $startTime;
+
if (!empty($cipher)) { // Decrypt
$source = OpenSSL::decrypt(
$source,
@@ -1048,6 +1055,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
);
}
+ $decryptionTime = \microtime(true) - $startTime - $downloadTime;
+
switch ($algorithm) {
case Compression::ZSTD:
$compressor = new Zstd();
@@ -1059,6 +1068,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
break;
}
+ $decompressionTime = \microtime(true) - $startTime - $downloadTime - $decryptionTime;
+
try {
$image = new Image($source);
} catch (ImagickException $e) {
@@ -1089,6 +1100,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$data = $image->output($output, $quality);
+ $renderingTime = \microtime(true) - $startTime - $downloadTime - $decryptionTime - $decompressionTime;
+
+ $totalTime = \microtime(true) - $startTime;
+
+ Console::info("File preview rendered,project=" . $project->getId() . ",bucket=" . $bucketId . ",file=" . $file->getId() . ",uri=" . $request->getURI() . ",total=" . $totalTime . ",rendering=" . $renderingTime . ",decryption=" . $decryptionTime . ",decompression=" . $decompressionTime . ",download=" . $downloadTime);
+
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
//Do not update transformedAt if it's a console user
diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php
index e72ea7bc92..1dcf20e519 100644
--- a/app/controllers/api/teams.php
+++ b/app/controllers/api/teams.php
@@ -666,6 +666,7 @@ App::post('/v1/teams/:teamId/memberships')
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
+ ->setParam('{{buttonText}}', $locale->getText("emails.invitation.buttonText"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"));
$body = $message->render();
diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php
index 0b580170e1..3376f4857c 100644
--- a/app/controllers/api/users.php
+++ b/app/controllers/api/users.php
@@ -649,6 +649,8 @@ App::get('/v1/users')
$total = $dbForProject->count('users', $filterQueries, APP_LIMIT_COUNT);
} catch (OrderException $e) {
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
+ } catch (QueryException $e) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$response->dynamic(new Document([
'users' => $users,
diff --git a/app/controllers/general.php b/app/controllers/general.php
index f8f392a716..8002278fcd 100644
--- a/app/controllers/general.php
+++ b/app/controllers/general.php
@@ -56,7 +56,7 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
-function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey)
+function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey)
{
$host = $request->getHostname() ?? '';
if (!empty($previewHostname)) {
@@ -118,6 +118,11 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$project->setAttribute('accessedAt', DateTime::now());
Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
}
+
+ /**
+ * Set projectId to update the Error hook logger, since x-appwrite-project is not available when executing custom domain function
+ */
+ $log->addTag('projectId', $project->getId());
}
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
@@ -787,13 +792,13 @@ App::init()
->inject('swooleRequest')
->inject('request')
->inject('response')
+ ->inject('log')
->inject('console')
->inject('project')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('locale')
->inject('localeCodes')
- ->inject('clients')
->inject('geodb')
->inject('queueForStatsUsage')
->inject('queueForEvents')
@@ -804,7 +809,9 @@ App::init()
->inject('previewHostname')
->inject('devKey')
->inject('apiKey')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey) {
+ ->inject('httpReferrer')
+ ->inject('httpReferrerSafe')
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe) {
/*
* Appwrite Router
*/
@@ -812,7 +819,7 @@ App::init()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
- if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
+ if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -936,42 +943,9 @@ App::init()
$locale->setDefault($localeParam);
}
- $referrer = $request->getReferer();
- $origin = \parse_url($request->getOrigin($referrer), PHP_URL_HOST);
- $protocol = \parse_url($request->getOrigin($referrer), PHP_URL_SCHEME);
- $port = \parse_url($request->getOrigin($referrer), PHP_URL_PORT);
-
- $refDomainOrigin = 'localhost';
- $validator = new Hostname($clients);
- if ($validator->isValid($origin)) {
- $refDomainOrigin = $origin;
- } elseif (!empty($origin)) {
- // Auto-allow domains with linked rule
- if (System::getEnv('_APP_RULES_FORMAT') === 'md5') {
- $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? '')));
- } else {
- $rule = Authorization::skip(
- fn () => $dbForPlatform->find('rules', [
- Query::equal('domain', [$origin]),
- Query::limit(1)
- ])
- )[0] ?? new Document();
- }
-
- if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getSequence()) {
- $refDomainOrigin = $origin;
- }
- }
-
- $refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
-
- $refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
- ? $refDomain
- : (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
-
+ $origin = \parse_url($request->getOrigin($httpReferrer), PHP_URL_HOST);
$selfDomain = new Domain($request->getHostname());
$endDomain = new Domain((string)$origin);
-
Config::setParam(
'domainVerification',
($selfDomain->getRegisterable() === $endDomain->getRegisterable()) &&
@@ -1045,7 +1019,7 @@ App::init()
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
- ->addHeader('Access-Control-Allow-Origin', $refDomain)
+ ->addHeader('Access-Control-Allow-Origin', $httpReferrerSafe)
->addHeader('Access-Control-Allow-Credentials', 'true');
if (!$devKey->isEmpty()) {
@@ -1081,6 +1055,7 @@ App::init()
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
&& $route->getLabel('origin', false) !== '*'
&& empty($request->getHeader('x-appwrite-key', ''))
+ && \parse_url($httpReferrerSafe, PHP_URL_HOST) === 'localhost'
) {
throw new AppwriteException(AppwriteException::GENERAL_UNKNOWN_ORIGIN, $originValidator->getDescription());
}
@@ -1091,6 +1066,7 @@ App::options()
->inject('swooleRequest')
->inject('request')
->inject('response')
+ ->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1103,7 +1079,7 @@ App::options()
->inject('project')
->inject('devKey')
->inject('apiKey')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey) {
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey) {
/*
* Appwrite Router
*/
@@ -1111,7 +1087,7 @@ App::options()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
- if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
+ if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1284,7 +1260,12 @@ App::error()
$log->addTag('url', $request->getURI());
$log->addTag('verboseType', get_class($error));
$log->addTag('code', $error->getCode());
- $log->addTag('projectId', $project->getId());
+
+ $tags = $log->getTags();
+ if (!isset($tags['projectId'])) {
+ $log->addTag('projectId', $project->getId());
+ }
+
$log->addTag('hostname', $request->getHostname());
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
@@ -1402,6 +1383,7 @@ App::get('/robots.txt')
->inject('swooleRequest')
->inject('request')
->inject('response')
+ ->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1412,7 +1394,7 @@ App::get('/robots.txt')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('apiKey')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1420,7 +1402,7 @@ App::get('/robots.txt')
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
} else {
- if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
+ if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1434,6 +1416,7 @@ App::get('/humans.txt')
->inject('swooleRequest')
->inject('request')
->inject('response')
+ ->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1444,7 +1427,7 @@ App::get('/humans.txt')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('apiKey')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1452,7 +1435,7 @@ App::get('/humans.txt')
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
} else {
- if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
+ if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php
index f99ebbce07..76fe177b0b 100644
--- a/app/controllers/shared/api.php
+++ b/app/controllers/shared/api.php
@@ -22,6 +22,7 @@ use Utopia\Abuse\Abuse;
use Utopia\App;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
+use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
@@ -563,7 +564,7 @@ App::init()
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
);
- $timestamp = 60 * 60 * 24 * 30;
+ $timestamp = 60 * 60 * 24 * 180; // Temporarily increase the TTL to 180 day to ensure files in the cache are still fetched.
$data = $cache->load($key, $timestamp);
if (!empty($data) && !$cacheLog->isEmpty()) {
@@ -797,6 +798,12 @@ App::shutdown()
}
if (!empty($queueForDatabase->getType())) {
+ Console::info("Triggering database event: \n" . \json_encode([
+ 'projectId' => $project->getId(),
+ 'databaseId' => $queueForDatabase->getDatabase()?->getId(),
+ 'collectionId' => $queueForDatabase->getCollection()?->getId(),
+ 'documentId' => $queueForDatabase->getDocument()?->getId(),
+ ]));
$queueForDatabase->trigger();
}
@@ -824,6 +831,10 @@ App::shutdown()
$resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user);
}
+ $cache = new Cache(
+ new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
+ );
+
$key = $request->cacheIdentifier();
$signature = md5($data['payload']);
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
@@ -841,12 +852,11 @@ App::shutdown()
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
$cacheLog->setAttribute('accessedAt', $now);
Authorization::skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog));
+ // Overwrite the file every APP_CACHE_UPDATE seconds to update the file modified time that is used in the TTL checks in cache->load()
+ $cache->save($key, $data['payload']);
}
if ($signature !== $cacheLog->getAttribute('signature')) {
- $cache = new Cache(
- new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
- );
$cache->save($key, $data['payload']);
}
}
diff --git a/app/init/registers.php b/app/init/registers.php
index 415730f936..3dc0e22dba 100644
--- a/app/init/registers.php
+++ b/app/init/registers.php
@@ -36,7 +36,8 @@ App::setMode(System::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
if (!App::isProduction()) {
// Allow specific domains to skip public domain validation in dev environment
// Useful for existing tests involving webhooks
- PublicDomain::allow(['request-catcher']);
+ PublicDomain::allow(['request-catcher-sms']);
+ PublicDomain::allow(['request-catcher-webhook']);
}
$register->set('logger', function () {
// Register error logger
diff --git a/app/init/resources.php b/app/init/resources.php
index 5e035b2663..2c5c13b723 100644
--- a/app/init/resources.php
+++ b/app/init/resources.php
@@ -945,3 +945,52 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
}
return new Document([]);
}, ['project', 'dbForProject', 'request']);
+
+App::setResource('httpReferrer', function (Request $request): string {
+ $referrer = $request->getReferer();
+ return $referrer;
+}, ['request']);
+
+App::setResource('httpReferrerSafe', function (Request $request, string $httpReferrer, array $clients, Database $dbForPlatform, Document $project, App $utopia): string {
+ $origin = \parse_url($request->getOrigin($httpReferrer), PHP_URL_HOST);
+ $protocol = \parse_url($request->getOrigin($httpReferrer), PHP_URL_SCHEME);
+ $port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
+ $referrer = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
+
+ // Safe if route is publicly accessible
+ $route = $utopia->getRoute();
+ if ($route->getLabel('origin', false)) {
+ return $referrer;
+ }
+
+ // Safe if added as web platform
+ $validator = new Hostname($clients);
+ if ($validator->isValid($origin)) {
+ return $referrer;
+ }
+
+ // Safe if rule with same project ID exists
+ if (!empty($origin)) {
+ if (System::getEnv('_APP_RULES_FORMAT') === 'md5') {
+ $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? '')));
+ } else {
+ $rule = Authorization::skip(
+ fn () => $dbForPlatform->find('rules', [
+ Query::equal('domain', [$origin]),
+ Query::limit(1)
+ ])
+ )[0] ?? new Document();
+ }
+
+ if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getSequence()) {
+ return $referrer;
+ }
+ }
+
+ // Unsafe; Localhost is always safe for ease of local development
+ $origin = 'localhost';
+ $protocol = \parse_url($request->getOrigin($httpReferrer), PHP_URL_SCHEME);
+ $port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
+ $referrer = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
+ return $referrer;
+}, ['request', 'httpReferrer', 'clients', 'dbForPlatform', 'project', 'utopia']);
diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml
index e3699662a4..89facfe0f1 100644
--- a/app/views/install/compose.phtml
+++ b/app/views/install/compose.phtml
@@ -864,7 +864,7 @@ $image = $this->getParam('image', '');
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
- image: openruntimes/executor:0.7.20
+ image: openruntimes/executor:0.7.22
networks:
- appwrite
- runtimes
diff --git a/app/worker.php b/app/worker.php
index e57aae91d2..845914c923 100644
--- a/app/worker.php
+++ b/app/worker.php
@@ -18,9 +18,7 @@ use Appwrite\Event\StatsUsage;
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Executor\Executor;
-use Swoole\Process;
use Swoole\Runtime;
-use Swoole\Timer;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
@@ -484,15 +482,8 @@ $worker
});
$worker->workerStart()
- ->action(function () use ($worker, $workerName) {
- Console::info("Worker $workerName started");
-
- Process::signal(SIGTERM, function () use ($worker, $workerName) {
- Console::info("Stopping worker $workerName.");
-
- $worker->stop();
- Timer::clearAll();
- });
+ ->action(function () use ($workerName) {
+ Console::info("Worker $workerName started");
});
$worker->start();
diff --git a/bin/doctor b/bin/doctor
index 92b3cf6bf8..b2a4547156 100755
--- a/bin/doctor
+++ b/bin/doctor
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php doctor $@
+php /usr/src/code/app/cli.php doctor $@
\ No newline at end of file
diff --git a/bin/install b/bin/install
index 126d5373bf..e669e91e6b 100755
--- a/bin/install
+++ b/bin/install
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php install $@
+php /usr/src/code/app/cli.php install $@
\ No newline at end of file
diff --git a/bin/maintenance b/bin/maintenance
index 70273feb61..099551cb32 100644
--- a/bin/maintenance
+++ b/bin/maintenance
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php maintenance $@
+php /usr/src/code/app/cli.php maintenance $@
\ No newline at end of file
diff --git a/bin/migrate b/bin/migrate
index 32bf7ee2f4..28ebbd19e7 100755
--- a/bin/migrate
+++ b/bin/migrate
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php migrate $@
+php /usr/src/code/app/cli.php migrate $@
\ No newline at end of file
diff --git a/bin/queue-count-failed b/bin/queue-count-failed
index 93a6b3136c..ca8f2b4291 100644
--- a/bin/queue-count-failed
+++ b/bin/queue-count-failed
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php queue-count --type=failed $@
+php /usr/src/code/app/cli.php queue-count --type=failed $@
\ No newline at end of file
diff --git a/bin/queue-count-processing b/bin/queue-count-processing
index 18e89664bd..325d86111d 100644
--- a/bin/queue-count-processing
+++ b/bin/queue-count-processing
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php queue-count --type=processing $@
+php /usr/src/code/app/cli.php queue-count --type=processing $@
\ No newline at end of file
diff --git a/bin/queue-count-success b/bin/queue-count-success
index b38bfa2159..34fc54b4c1 100644
--- a/bin/queue-count-success
+++ b/bin/queue-count-success
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php queue-count --type=success $@
+php /usr/src/code/app/cli.php queue-count --type=success $@
\ No newline at end of file
diff --git a/bin/queue-retry b/bin/queue-retry
index 2224a66b3b..f9473e6b07 100644
--- a/bin/queue-retry
+++ b/bin/queue-retry
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php queue-retry $@
+php /usr/src/code/app/cli.php queue-retry $@
\ No newline at end of file
diff --git a/bin/realtime b/bin/realtime
index debd4baf2a..e43dc269e0 100644
--- a/bin/realtime
+++ b/bin/realtime
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/realtime.php $@
+php /usr/src/code/app/realtime.php $@
\ No newline at end of file
diff --git a/bin/schedule-executions b/bin/schedule-executions
index 5d503e374c..f239cad206 100644
--- a/bin/schedule-executions
+++ b/bin/schedule-executions
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php schedule-executions $@
+php /usr/src/code/app/cli.php schedule-executions $@
\ No newline at end of file
diff --git a/bin/schedule-functions b/bin/schedule-functions
index beca1a0420..10edbe8226 100644
--- a/bin/schedule-functions
+++ b/bin/schedule-functions
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php schedule-functions $@
+php /usr/src/code/app/cli.php schedule-functions $@
\ No newline at end of file
diff --git a/bin/schedule-messages b/bin/schedule-messages
index 3f17a279b5..fa7219f6ea 100644
--- a/bin/schedule-messages
+++ b/bin/schedule-messages
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php schedule-messages $@
+php /usr/src/code/app/cli.php schedule-messages $@
\ No newline at end of file
diff --git a/bin/screenshot b/bin/screenshot
index aef15eb96f..4d8ceb998f 100755
--- a/bin/screenshot
+++ b/bin/screenshot
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php screenshot $@
\ No newline at end of file
+php /usr/src/code/app/cli.php screenshot $@
\ No newline at end of file
diff --git a/bin/sdks b/bin/sdks
index 3180813ea1..ab73414829 100644
--- a/bin/sdks
+++ b/bin/sdks
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php sdks $@
+php /usr/src/code/app/cli.php sdks $@
\ No newline at end of file
diff --git a/bin/specs b/bin/specs
index 52875a1675..e77d1487d4 100644
--- a/bin/specs
+++ b/bin/specs
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php specs $@
+php /usr/src/code/app/cli.php specs $@
\ No newline at end of file
diff --git a/bin/ssl b/bin/ssl
index 0cc12375d0..83dcf6a026 100755
--- a/bin/ssl
+++ b/bin/ssl
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php ssl $@
+php /usr/src/code/app/cli.php ssl $@
\ No newline at end of file
diff --git a/bin/stats-resources b/bin/stats-resources
index 9cc67fb4a6..3104bab896 100644
--- a/bin/stats-resources
+++ b/bin/stats-resources
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php stats-resources $@
+php /usr/src/code/app/cli.php stats-resources $@
\ No newline at end of file
diff --git a/bin/test b/bin/test
index c3b0d9b74c..a2153fc536 100755
--- a/bin/test
+++ b/bin/test
@@ -1,3 +1,3 @@
#!/bin/sh
-exec /usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
+/usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
\ No newline at end of file
diff --git a/bin/upgrade b/bin/upgrade
index fd1f35b65a..ce32b9ca30 100755
--- a/bin/upgrade
+++ b/bin/upgrade
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php upgrade $@
+php /usr/src/code/app/cli.php upgrade $@
\ No newline at end of file
diff --git a/bin/vars b/bin/vars
index 238d004675..19e3f1ebf2 100644
--- a/bin/vars
+++ b/bin/vars
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/cli.php vars $@
+php /usr/src/code/app/cli.php vars $@
\ No newline at end of file
diff --git a/bin/worker-audits b/bin/worker-audits
index 9bf81b93e2..3df65d65e8 100644
--- a/bin/worker-audits
+++ b/bin/worker-audits
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php audits $@
+php /usr/src/code/app/worker.php audits $@
\ No newline at end of file
diff --git a/bin/worker-builds b/bin/worker-builds
index 7ddf5792de..3400111cb5 100644
--- a/bin/worker-builds
+++ b/bin/worker-builds
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php builds $@
+php /usr/src/code/app/worker.php builds $@
\ No newline at end of file
diff --git a/bin/worker-certificates b/bin/worker-certificates
index 958627bc33..901688c4c8 100755
--- a/bin/worker-certificates
+++ b/bin/worker-certificates
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php certificates $@
+php /usr/src/code/app/worker.php certificates $@
\ No newline at end of file
diff --git a/bin/worker-databases b/bin/worker-databases
index 235c16927c..61e09aa9f1 100644
--- a/bin/worker-databases
+++ b/bin/worker-databases
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php databases $@
+php /usr/src/code/app/worker.php databases $@
diff --git a/bin/worker-deletes b/bin/worker-deletes
index c9711a4e66..7c9793e6cb 100644
--- a/bin/worker-deletes
+++ b/bin/worker-deletes
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php deletes $@
+php /usr/src/code/app/worker.php deletes $@
\ No newline at end of file
diff --git a/bin/worker-functions b/bin/worker-functions
index e82506d0e2..4757b1b72a 100644
--- a/bin/worker-functions
+++ b/bin/worker-functions
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php functions $@
+php /usr/src/code/app/worker.php functions $@
\ No newline at end of file
diff --git a/bin/worker-mails b/bin/worker-mails
index ffb4f7ea77..fee8a96da7 100644
--- a/bin/worker-mails
+++ b/bin/worker-mails
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php mails $@
+php /usr/src/code/app/worker.php mails $@
\ No newline at end of file
diff --git a/bin/worker-messaging b/bin/worker-messaging
index 6f39348419..e6edf80f06 100644
--- a/bin/worker-messaging
+++ b/bin/worker-messaging
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php messaging $@
+php /usr/src/code/app/worker.php messaging $@
\ No newline at end of file
diff --git a/bin/worker-migrations b/bin/worker-migrations
index 2728d9d22c..32d4aef468 100644
--- a/bin/worker-migrations
+++ b/bin/worker-migrations
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php migrations $@
+php /usr/src/code/app/worker.php migrations $@
\ No newline at end of file
diff --git a/bin/worker-stats-resources b/bin/worker-stats-resources
index 70bfacbe52..9c5d2bebff 100644
--- a/bin/worker-stats-resources
+++ b/bin/worker-stats-resources
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php stats-resources $@
+php /usr/src/code/app/worker.php stats-resources $@
\ No newline at end of file
diff --git a/bin/worker-stats-usage b/bin/worker-stats-usage
index e6dd849a48..2c267d805e 100644
--- a/bin/worker-stats-usage
+++ b/bin/worker-stats-usage
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php stats-usage $@
+php /usr/src/code/app/worker.php stats-usage $@
\ No newline at end of file
diff --git a/bin/worker-webhooks b/bin/worker-webhooks
index 63fc13e3c5..93f8027a81 100644
--- a/bin/worker-webhooks
+++ b/bin/worker-webhooks
@@ -1,3 +1,3 @@
#!/bin/sh
-exec php /usr/src/code/app/worker.php webhooks $@
+php /usr/src/code/app/worker.php webhooks $@
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 18507e04f1..073e667cdb 100644
--- a/composer.json
+++ b/composer.json
@@ -67,7 +67,7 @@
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.8.*",
"utopia-php/preloader": "0.2.*",
- "utopia-php/queue": "0.11.*",
+ "utopia-php/queue": "0.12.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.18.*",
"utopia-php/swoole": "0.8.*",
diff --git a/composer.lock b/composer.lock
index d5c2380af9..985f2187b8 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "1557e469b3074a6478a0b2fd522e1a2a",
+ "content-hash": "beacba1fc087db3ab9f9d718b28c5876",
"packages": [
{
"name": "adhocore/jwt",
@@ -67,6 +67,99 @@
],
"time": "2025-02-18T01:00:50+00:00"
},
+ {
+ "name": "appwrite-labs/php-amqplib",
+ "version": "0.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/appwrite-labs/php-amqplib.git",
+ "reference": "bd380cbd63c8c0f063a3893b7a0b889d40876861"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/appwrite-labs/php-amqplib/zipball/bd380cbd63c8c0f063a3893b7a0b889d40876861",
+ "reference": "bd380cbd63c8c0f063a3893b7a0b889d40876861",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "ext-sockets": "*",
+ "php": "^7.2||^8.0",
+ "phpseclib/phpseclib": "^2.0|^3.0"
+ },
+ "conflict": {
+ "php": "7.4.0 - 7.4.1"
+ },
+ "replace": {
+ "php-amqplib/php-amqplib": "self.version",
+ "videlalvaro/php-amqplib": "self.version"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "nategood/httpful": "^0.2.20",
+ "phpunit/phpunit": "^7.5|^9.5",
+ "squizlabs/php_codesniffer": "^3.6",
+ "swoole/ide-helper": "^5.0"
+ },
+ "suggest": {
+ "ext-swoole": "For Swoole coroutine support"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpAmqpLib\\": "PhpAmqpLib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-2.1-or-later"
+ ],
+ "authors": [
+ {
+ "name": "Appwrite Labs",
+ "email": "team@appwrite.io",
+ "role": "Fork Maintainer"
+ },
+ {
+ "name": "Alvaro Videla",
+ "role": "Original Maintainer"
+ },
+ {
+ "name": "Raúl Araya",
+ "email": "nubeiro@gmail.com",
+ "role": "Maintainer"
+ },
+ {
+ "name": "Luke Bakken",
+ "email": "luke@bakken.io",
+ "role": "Maintainer"
+ },
+ {
+ "name": "Ramūnas Dronga",
+ "email": "github@ramuno.lt",
+ "role": "Maintainer"
+ }
+ ],
+ "description": "Fork of php-amqplib with Swoole coroutine support. A pure PHP implementation of the AMQP protocol tested against RabbitMQ.",
+ "homepage": "https://github.com/appwrite-labs/php-amqplib/",
+ "keywords": [
+ "async",
+ "coroutine",
+ "message",
+ "queue",
+ "rabbitmq",
+ "swoole"
+ ],
+ "support": {
+ "source": "https://github.com/appwrite-labs/php-amqplib/tree/0.1.1"
+ },
+ "time": "2025-06-24T18:12:57+00:00"
+ },
{
"name": "appwrite/appwrite",
"version": "11.1.0",
@@ -1463,16 +1556,16 @@
},
{
"name": "open-telemetry/sem-conv",
- "version": "1.32.0",
+ "version": "1.32.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sem-conv.git",
- "reference": "16585cc0dbc3032a318e274043454679430d2ebf"
+ "reference": "94daa85ea61a8e2b7e1b0af6be0e875bedda7c22"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/16585cc0dbc3032a318e274043454679430d2ebf",
- "reference": "16585cc0dbc3032a318e274043454679430d2ebf",
+ "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/94daa85ea61a8e2b7e1b0af6be0e875bedda7c22",
+ "reference": "94daa85ea61a8e2b7e1b0af6be0e875bedda7c22",
"shasum": ""
},
"require": {
@@ -1516,7 +1609,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-05T03:58:53+00:00"
+ "time": "2025-06-24T02:32:27+00:00"
},
{
"name": "paragonie/constant_time_encoding",
@@ -1635,87 +1728,6 @@
},
"time": "2020-10-15T08:29:30+00:00"
},
- {
- "name": "php-amqplib/php-amqplib",
- "version": "v3.7.3",
- "source": {
- "type": "git",
- "url": "https://github.com/php-amqplib/php-amqplib.git",
- "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/9f50fe69a9f1a19e2cb25596a354d705de36fe59",
- "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "ext-sockets": "*",
- "php": "^7.2||^8.0",
- "phpseclib/phpseclib": "^2.0|^3.0"
- },
- "conflict": {
- "php": "7.4.0 - 7.4.1"
- },
- "replace": {
- "videlalvaro/php-amqplib": "self.version"
- },
- "require-dev": {
- "ext-curl": "*",
- "nategood/httpful": "^0.2.20",
- "phpunit/phpunit": "^7.5|^9.5",
- "squizlabs/php_codesniffer": "^3.6"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "PhpAmqpLib\\": "PhpAmqpLib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "LGPL-2.1-or-later"
- ],
- "authors": [
- {
- "name": "Alvaro Videla",
- "role": "Original Maintainer"
- },
- {
- "name": "Raúl Araya",
- "email": "nubeiro@gmail.com",
- "role": "Maintainer"
- },
- {
- "name": "Luke Bakken",
- "email": "luke@bakken.io",
- "role": "Maintainer"
- },
- {
- "name": "Ramūnas Dronga",
- "email": "github@ramuno.lt",
- "role": "Maintainer"
- }
- ],
- "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
- "homepage": "https://github.com/php-amqplib/php-amqplib/",
- "keywords": [
- "message",
- "queue",
- "rabbitmq"
- ],
- "support": {
- "issues": "https://github.com/php-amqplib/php-amqplib/issues",
- "source": "https://github.com/php-amqplib/php-amqplib/tree/v3.7.3"
- },
- "time": "2025-02-18T20:11:13+00:00"
- },
{
"name": "php-http/discovery",
"version": "1.20.0",
@@ -1878,16 +1890,16 @@
},
{
"name": "phpseclib/phpseclib",
- "version": "3.0.45",
+ "version": "3.0.46",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "bd81b90d5963c6b9d87de50357585375223f4dd8"
+ "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/bd81b90d5963c6b9d87de50357585375223f4dd8",
- "reference": "bd81b90d5963c6b9d87de50357585375223f4dd8",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6",
+ "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6",
"shasum": ""
},
"require": {
@@ -1968,7 +1980,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/3.0.45"
+ "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46"
},
"funding": [
{
@@ -1984,7 +1996,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-22T22:54:43+00:00"
+ "time": "2025-06-26T16:29:55+00:00"
},
{
"name": "psr/container",
@@ -2327,21 +2339,20 @@
},
{
"name": "ramsey/uuid",
- "version": "4.8.1",
+ "version": "4.9.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
+ "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0",
+ "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
- "ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
},
@@ -2400,9 +2411,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.8.1"
+ "source": "https://github.com/ramsey/uuid/tree/4.9.0"
},
- "time": "2025-06-01T06:28:46+00:00"
+ "time": "2025-06-25T14:20:11+00:00"
},
{
"name": "spomky-labs/otphp",
@@ -2548,16 +2559,16 @@
},
{
"name": "symfony/http-client",
- "version": "v7.3.0",
+ "version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
- "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9"
+ "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/57e4fb86314015a695a750ace358d07a7e37b8a9",
- "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9",
+ "url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64",
+ "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64",
"shasum": ""
},
"require": {
@@ -2569,6 +2580,7 @@
},
"conflict": {
"amphp/amp": "<2.5",
+ "amphp/socket": "<1.1",
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.4"
},
@@ -2581,7 +2593,6 @@
"require-dev": {
"amphp/http-client": "^4.2.1|^5.0",
"amphp/http-tunnel": "^1.0|^2.0",
- "amphp/socket": "^1.1",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
@@ -2623,7 +2634,7 @@
"http"
],
"support": {
- "source": "https://github.com/symfony/http-client/tree/v7.3.0"
+ "source": "https://github.com/symfony/http-client/tree/v7.3.1"
},
"funding": [
{
@@ -2639,7 +2650,7 @@
"type": "tidelift"
}
],
- "time": "2025-05-02T08:23:16+00:00"
+ "time": "2025-06-28T07:58:39+00:00"
},
{
"name": "symfony/http-client-contracts",
@@ -2961,16 +2972,16 @@
},
{
"name": "tbachert/spi",
- "version": "v1.0.3",
+ "version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/Nevay/spi.git",
- "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a"
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Nevay/spi/zipball/506a79c98e1a51522e76ee921ccb6c62d52faf3a",
- "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a",
+ "url": "https://api.github.com/repos/Nevay/spi/zipball/e7078767866d0a9e0f91d3f9d42a832df5e39002",
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002",
"shasum": ""
},
"require": {
@@ -2988,7 +2999,7 @@
"extra": {
"class": "Nevay\\SPI\\Composer\\Plugin",
"branch-alias": {
- "dev-main": "0.2.x-dev"
+ "dev-main": "1.0.x-dev"
},
"plugin-optional": true
},
@@ -3007,9 +3018,9 @@
],
"support": {
"issues": "https://github.com/Nevay/spi/issues",
- "source": "https://github.com/Nevay/spi/tree/v1.0.3"
+ "source": "https://github.com/Nevay/spi/tree/v1.0.5"
},
- "time": "2025-04-02T19:38:14+00:00"
+ "time": "2025-06-29T15:42:06+00:00"
},
{
"name": "thecodingmachine/safe",
@@ -3494,16 +3505,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.71.7",
+ "version": "0.71.8",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "aa0116b2380125907fc18c82662be8e74c54091f"
+ "reference": "7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/aa0116b2380125907fc18c82662be8e74c54091f",
- "reference": "aa0116b2380125907fc18c82662be8e74c54091f",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e",
+ "reference": "7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e",
"shasum": ""
},
"require": {
@@ -3544,9 +3555,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.71.7"
+ "source": "https://github.com/utopia-php/database/tree/0.71.8"
},
- "time": "2025-06-17T23:59:10+00:00"
+ "time": "2025-06-26T14:48:17+00:00"
},
{
"name": "utopia-php/detector",
@@ -3943,16 +3954,16 @@
},
{
"name": "utopia-php/messaging",
- "version": "0.18.0",
+ "version": "0.18.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
- "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6"
+ "reference": "5d1245207a61d7ca065daddad7ac5f1d5640152f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c151aa5d4d475c788ca15c210b5b2017e21c41d6",
- "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6",
+ "url": "https://api.github.com/repos/utopia-php/messaging/zipball/5d1245207a61d7ca065daddad7ac5f1d5640152f",
+ "reference": "5d1245207a61d7ca065daddad7ac5f1d5640152f",
"shasum": ""
},
"require": {
@@ -3988,9 +3999,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
- "source": "https://github.com/utopia-php/messaging/tree/0.18.0"
+ "source": "https://github.com/utopia-php/messaging/tree/0.18.1"
},
- "time": "2025-05-15T05:00:03+00:00"
+ "time": "2025-06-26T18:26:07+00:00"
},
{
"name": "utopia-php/migration",
@@ -4100,16 +4111,16 @@
},
{
"name": "utopia-php/platform",
- "version": "0.7.8",
+ "version": "0.7.9",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/platform.git",
- "reference": "e3a4536c46f10988b1a446ec6b8dd8a9914be854"
+ "reference": "b061f523513b071ef7168e6dc1441364eb73f308"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/platform/zipball/e3a4536c46f10988b1a446ec6b8dd8a9914be854",
- "reference": "e3a4536c46f10988b1a446ec6b8dd8a9914be854",
+ "url": "https://api.github.com/repos/utopia-php/platform/zipball/b061f523513b071ef7168e6dc1441364eb73f308",
+ "reference": "b061f523513b071ef7168e6dc1441364eb73f308",
"shasum": ""
},
"require": {
@@ -4118,7 +4129,7 @@
"php": ">=8.0",
"utopia-php/cli": "0.15.*",
"utopia-php/framework": "0.33.*",
- "utopia-php/queue": "0.11.*"
+ "utopia-php/queue": "^0.12.0"
},
"require-dev": {
"laravel/pint": "1.*",
@@ -4144,9 +4155,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/platform/issues",
- "source": "https://github.com/utopia-php/platform/tree/0.7.8"
+ "source": "https://github.com/utopia-php/platform/tree/0.7.9"
},
- "time": "2025-05-30T10:05:43+00:00"
+ "time": "2025-06-24T20:21:05+00:00"
},
{
"name": "utopia-php/pools",
@@ -4255,21 +4266,21 @@
},
{
"name": "utopia-php/queue",
- "version": "0.11.1",
+ "version": "0.12.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/queue.git",
- "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6"
+ "reference": "3a7603ee712c592bfc54af4a76f0426c428b5574"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/queue/zipball/498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
- "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
+ "url": "https://api.github.com/repos/utopia-php/queue/zipball/3a7603ee712c592bfc54af4a76f0426c428b5574",
+ "reference": "3a7603ee712c592bfc54af4a76f0426c428b5574",
"shasum": ""
},
"require": {
+ "appwrite-labs/php-amqplib": "^0.1",
"php": ">=8.3",
- "php-amqplib/php-amqplib": "^3.7",
"utopia-php/cli": "0.15.*",
"utopia-php/fetch": "0.4.*",
"utopia-php/framework": "0.33.*",
@@ -4315,9 +4326,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/queue/issues",
- "source": "https://github.com/utopia-php/queue/tree/0.11.1"
+ "source": "https://github.com/utopia-php/queue/tree/0.12.0"
},
- "time": "2025-05-30T11:50:34+00:00"
+ "time": "2025-06-24T18:58:38+00:00"
},
{
"name": "utopia-php/registry",
@@ -4811,16 +4822,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
- "version": "0.41.8",
+ "version": "0.41.9",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
- "reference": "93ffb24b25b376ca4423e3a5caf6f916673af4b2"
+ "reference": "61037c1ed9262308cab49c1d760f3278036ab694"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/93ffb24b25b376ca4423e3a5caf6f916673af4b2",
- "reference": "93ffb24b25b376ca4423e3a5caf6f916673af4b2",
+ "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/61037c1ed9262308cab49c1d760f3278036ab694",
+ "reference": "61037c1ed9262308cab49c1d760f3278036ab694",
"shasum": ""
},
"require": {
@@ -4856,9 +4867,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
- "source": "https://github.com/appwrite/sdk-generator/tree/0.41.8"
+ "source": "https://github.com/appwrite/sdk-generator/tree/0.41.9"
},
- "time": "2025-06-18T13:20:45+00:00"
+ "time": "2025-06-27T10:16:17+00:00"
},
{
"name": "doctrine/annotations",
@@ -7256,16 +7267,16 @@
},
{
"name": "symfony/console",
- "version": "v7.3.0",
+ "version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44"
+ "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44",
- "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44",
+ "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101",
+ "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101",
"shasum": ""
},
"require": {
@@ -7330,7 +7341,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.0"
+ "source": "https://github.com/symfony/console/tree/v7.3.1"
},
"funding": [
{
@@ -7346,7 +7357,7 @@
"type": "tidelift"
}
],
- "time": "2025-05-24T10:34:04+00:00"
+ "time": "2025-06-27T19:55:54+00:00"
},
{
"name": "symfony/filesystem",
diff --git a/docker-compose.yml b/docker-compose.yml
index 0b653af8c2..f5ac47a832 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -323,7 +323,8 @@ services:
depends_on:
- redis
- mariadb
- - request-catcher
+ - request-catcher-sms
+ - request-catcher-webhook
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
@@ -951,7 +952,7 @@ services:
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
- image: openruntimes/executor:0.7.20
+ image: openruntimes/executor:0.7.22
restart: unless-stopped
networks:
- appwrite
@@ -1075,15 +1076,24 @@ services:
networks:
- appwrite
- request-catcher: # used mainly for dev tests
+ request-catcher-webhook: # used mainly for dev tests (mock HTTP webhook)
image: appwrite/requestcatcher:1.0.0
- container_name: appwrite-requestcatcher
+ container_name: appwrite-requestcatcher-webhook
<<: *x-logging
ports:
- "9504:5000"
networks:
- appwrite
+ request-catcher-sms: # used mainly for dev tests (mock SMS auth secret)
+ image: appwrite/requestcatcher:1.0.0
+ container_name: appwrite-requestcatcher-sms
+ <<: *x-logging
+ ports:
+ - "9507:5000"
+ networks:
+ - appwrite
+
adminer:
image: adminer
container_name: appwrite-adminer
diff --git a/docs/examples/1.7.x/console-cli/examples/proxy/create-redirect-rule.md b/docs/examples/1.7.x/console-cli/examples/proxy/create-redirect-rule.md
index f975ce686e..ec9098a748 100644
--- a/docs/examples/1.7.x/console-cli/examples/proxy/create-redirect-rule.md
+++ b/docs/examples/1.7.x/console-cli/examples/proxy/create-redirect-rule.md
@@ -1,4 +1,6 @@
appwrite proxy createRedirectRule \
--domain '' \
--url https://example.com \
- --statusCode 301
+ --statusCode 301 \
+ --resourceId \
+ --resourceType site
diff --git a/docs/examples/1.7.x/console-cli/examples/vcs/get-repository-contents.md b/docs/examples/1.7.x/console-cli/examples/vcs/get-repository-contents.md
index 7d378d7efa..3ba8d75c91 100644
--- a/docs/examples/1.7.x/console-cli/examples/vcs/get-repository-contents.md
+++ b/docs/examples/1.7.x/console-cli/examples/vcs/get-repository-contents.md
@@ -2,3 +2,4 @@ appwrite vcs getRepositoryContents \
--installationId \
--providerRepositoryId \
+
diff --git a/docs/references/databases/create-documents.md b/docs/references/databases/create-documents.md
index a02d7c8bf1..7f60c138ea 100644
--- a/docs/references/databases/create-documents.md
+++ b/docs/references/databases/create-documents.md
@@ -1 +1,3 @@
+**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.
+
Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
\ No newline at end of file
diff --git a/docs/references/databases/delete-documents.md b/docs/references/databases/delete-documents.md
index a7b05503de..b4e255c69f 100644
--- a/docs/references/databases/delete-documents.md
+++ b/docs/references/databases/delete-documents.md
@@ -1 +1,3 @@
+**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.
+
Bulk delete documents using queries, if no queries are passed then all documents are deleted.
\ No newline at end of file
diff --git a/docs/references/databases/update-documents.md b/docs/references/databases/update-documents.md
index 5f560c6435..9ab8373d36 100644
--- a/docs/references/databases/update-documents.md
+++ b/docs/references/databases/update-documents.md
@@ -1 +1,3 @@
+**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.
+
Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.
\ No newline at end of file
diff --git a/docs/references/databases/upsert-document.md b/docs/references/databases/upsert-document.md
index a67694cfa6..1980141d22 100644
--- a/docs/references/databases/upsert-document.md
+++ b/docs/references/databases/upsert-document.md
@@ -1 +1,3 @@
+**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.
+
Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
\ No newline at end of file
diff --git a/docs/references/databases/upsert-documents.md b/docs/references/databases/upsert-documents.md
index f46254bd7b..2e2dc461ba 100644
--- a/docs/references/databases/upsert-documents.md
+++ b/docs/references/databases/upsert-documents.md
@@ -1 +1,3 @@
-Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
+**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions.
+
+Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
\ No newline at end of file
diff --git a/docs/references/vcs/get-repository-contents.md b/docs/references/vcs/get-repository-contents.md
index ab5ef7f8da..176b4203d3 100644
--- a/docs/references/vcs/get-repository-contents.md
+++ b/docs/references/vcs/get-repository-contents.md
@@ -1 +1 @@
-Get a list of files and directories from a GitHub repository connected to your project. This endpoint returns the contents of a specified repository path, including file names, sizes, and whether each item is a file or directory. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.
+Get a list of files and directories from a GitHub repository connected to your project. This endpoint returns the contents of a specified repository path, including file names, sizes, and whether each item is a file or directory. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.
\ No newline at end of file
diff --git a/docs/sdks/cli/CHANGELOG.md b/docs/sdks/cli/CHANGELOG.md
index fa4d35e687..c2c93b0c09 100644
--- a/docs/sdks/cli/CHANGELOG.md
+++ b/docs/sdks/cli/CHANGELOG.md
@@ -1 +1,61 @@
-# Change Log
\ No newline at end of file
+# Change Log
+
+## 8.1.0
+
+* Add multi-region support to `init` command
+* Update `init` command to clear previous configuration in `appwrite.json`
+* Update localConfig to store multi-region endpoint
+* Fix throw error when creating unknown attribute instead of timing out
+* Fix equal comparison of large numbers and BigNumber instances using proper equality checks
+* Fix duplication of reasons when comparing localConfig with remoteConfig
+* Fix `firstOrNull()` to `firstOrNull` in types generation for dart
+* Refactor to use `isCloud()` method consistently
+
+## 8.0.2
+
+* Add Type generation fixes:
+ * Properly handle enum attributes in dart, java and kotlin
+ * Fix initialisation of null attributes in dart's fromMap method
+ * Fix relationships and enums in swift
+
+## 8.0.1
+
+* Add `resourceId` and `resourceType` attributes to `createRedirectRule`
+* Add `providerReference` to vcs command for getting repository contents
+* Add warning comment to `bulk updateDocuments` method
+* Fix type generation for enums in Typescript and PHP language
+
+## 8.0.0
+
+* Add `types` command to generate language specific typings for collections. Currently supports - `php`, `swift`, `dart`, `js`, `ts`, `kotlin` and `java`
+* Update bulk operation docs to include experiment feature warnings
+* Remove assistant service and commands
+
+## 7.0.0
+
+* Add `sites` command
+* Add `tokens` command
+* Add `devKeys` support to `projects` command
+* Add `init site`, `pull site` and `push site` commands
+* Add bulk operation methods like `createDocuments`, `deleteDocuments` etc.
+* Add new upsert methods: `upsertDocument` and `upsertDocuments`
+* Update GET requests to not include content-type header
+
+## 6.2.3
+
+* Fix hot swapping error in `python-ml` function
+
+## 6.2.2
+
+* Fix GitHub builds by adding `qemu-system` package
+* Fix attribute creation timed out
+
+## 6.2.1
+
+* Add `listOrganizations` method to `organizations` service and fix init project command
+
+## 6.2.0
+
+* Add specifications support to CLI
+* Update package version
+* Fix: Missed specifications param when updating a function
\ No newline at end of file
diff --git a/docs/sdks/react-native/CHANGELOG.md b/docs/sdks/react-native/CHANGELOG.md
index 1bc7d89373..56e176f08f 100644
--- a/docs/sdks/react-native/CHANGELOG.md
+++ b/docs/sdks/react-native/CHANGELOG.md
@@ -1,5 +1,18 @@
# Change log
+## 0.10.0
+
+* Add generate file URL methods like`getFilePreviewURL`, `getFileViewURL` etc.
+* Update (breaking) existing methods like `getFilePreview` to download the image instead of returning URLs
+
+## 0.9.2
+
+* Fix `devKeys` by removing credentials from requests when the key is set
+
+## 0.9.1
+
+* Add `setDevkey` and `upsertDocument` methods
+
## 0.9.0
* Add `token` param to `getFilePreview` and `getFileView` for File tokens usage
diff --git a/src/Appwrite/Event/Database.php b/src/Appwrite/Event/Database.php
index be73614dc1..70051f9055 100644
--- a/src/Appwrite/Event/Database.php
+++ b/src/Appwrite/Event/Database.php
@@ -61,6 +61,16 @@ class Database extends Event
return $this;
}
+ /**
+ * Returns set database for this event.
+ *
+ * @return null|Document
+ */
+ public function getDatabase(): ?Document
+ {
+ return $this->database;
+ }
+
/**
* Set the table for this database event.
*
diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php
index 37e9d87d26..66f3508104 100644
--- a/src/Appwrite/GraphQL/Types/Mapper.php
+++ b/src/Appwrite/GraphQL/Types/Mapper.php
@@ -226,7 +226,7 @@ class Mapper
];
if (!$rule['required']) {
- $fields[$escapedKey]['defaultValue'] = $rule['default'];
+ $fields[$escapedKey]['defaultValue'] = $rule['default'] ?? null;
}
}
diff --git a/src/Appwrite/Platform/Action.php b/src/Appwrite/Platform/Action.php
index 72c41582ea..e5a7cf7984 100644
--- a/src/Appwrite/Platform/Action.php
+++ b/src/Appwrite/Platform/Action.php
@@ -3,7 +3,10 @@
namespace Appwrite\Platform;
use Swoole\Coroutine as Co;
+use Utopia\CLI\Console;
use Utopia\Database\Database;
+use Utopia\Database\DateTime;
+use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Platform\Action as UtopiaAction;
@@ -16,6 +19,12 @@ class Action extends UtopiaAction
*/
protected mixed $logError;
+ protected array $filters = [
+ 'subQueryKeys', 'subQueryWebhooks', 'subQueryPlatforms', 'subQueryProjectVariables', 'subQueryBlocks', 'subQueryDevKeys', // Project
+ 'subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships', 'subQueryTargets', 'subQueryTopicTargets',// Users
+ 'subQueryVariables', // Sites
+ ];
+
/**
* Foreach Document
* Call provided callback for each document in the collection
@@ -87,4 +96,57 @@ class Action extends UtopiaAction
$latestDocument = $results[array_key_last($results)];
}
}
+
+ public function disableSubqueries()
+ {
+ $filters = $this->filters;
+
+ foreach ($filters as $filter) {
+ Database::addFilter(
+ $filter,
+ function (mixed $value) {
+ return;
+ },
+ function (mixed $value, Document $document, Database $database) {
+ return [];
+ }
+ );
+ }
+ }
+
+ /**
+ * Dump Log Message
+ *
+ * Logs messages to console with timestamp, method context, and project details.
+ * Supports multiple log types: success, error, log, warning, and info (default).
+ *
+ * @param string $method The calling method name
+ * @param string $log The log message
+ * @param string $type The log type (success, error, log, warning, info)
+ * @param Document|null $project The project document for context
+ * @param string $collectionId The collection identifier
+ * @return void
+ */
+ public function dump(string $method, string $log, string $type = 'info', ?Document $project = null, string $collectionId = ''): void
+ {
+ if (empty($project)) {
+ $project = new Document([]);
+ }
+ switch ($type) {
+ case 'success':
+ Console::success("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
+ break;
+ case 'error':
+ Console::error("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
+ break;
+ case 'log':
+ Console::log("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
+ break;
+ case 'warning':
+ Console::warning("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
+ break;
+ default:
+ Console::info("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
+ }
+ }
}
diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php
index fe4a267cd7..e58f2b8664 100644
--- a/src/Appwrite/Platform/Modules/Compute/Base.php
+++ b/src/Appwrite/Platform/Modules/Compute/Base.php
@@ -6,6 +6,7 @@ use Appwrite\Event\Build;
use Appwrite\Extend\Exception;
use Utopia\Database\Database;
use Utopia\Database\Document;
+use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -226,6 +227,73 @@ class Base extends Action
]))
);
+ if (!empty($commitDetails['commitHash'])) {
+ $domain = "commit-" . substr($commitDetails['commitHash'], 0, 16) . ".{$sitesDomain}";
+ $ruleId = md5($domain);
+ try {
+ Authorization::skip(
+ fn () => $dbForPlatform->createDocument('rules', new Document([
+ '$id' => $ruleId,
+ 'projectId' => $project->getId(),
+ 'projectInternalId' => $project->getSequence(),
+ 'domain' => $domain,
+ 'type' => 'deployment',
+ 'trigger' => 'deployment',
+ 'deploymentId' => $deployment->getId(),
+ 'deploymentInternalId' => $deployment->getSequence(),
+ 'deploymentResourceType' => 'site',
+ 'deploymentResourceId' => $site->getId(),
+ 'deploymentResourceInternalId' => $site->getSequence(),
+ 'deploymentVcsProviderBranch' => $providerBranch,
+ 'status' => 'verified',
+ 'certificateId' => '',
+ 'search' => implode(' ', [$ruleId, $domain]),
+ 'owner' => 'Appwrite',
+ 'region' => $project->getAttribute('region')
+ ]))
+ );
+ } catch (Duplicate $err) {
+ // Ignore, rule already exists; will be updated by builds worker
+ }
+ }
+
+ // VCS branch preview
+ if (!empty($providerBranch)) {
+ $branchPrefix = substr($providerBranch, 0, 16);
+ if (strlen($providerBranch) > 16) {
+ $remainingChars = substr($providerBranch, 16);
+ $branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7);
+ }
+ $resourceProjectHash = substr(hash('sha256', $site->getId() . $project->getId()), 0, 7);
+ $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}";
+ $ruleId = md5($domain);
+ try {
+ Authorization::skip(
+ fn () => $dbForPlatform->createDocument('rules', new Document([
+ '$id' => $ruleId,
+ 'projectId' => $project->getId(),
+ 'projectInternalId' => $project->getSequence(),
+ 'domain' => $domain,
+ 'type' => 'deployment',
+ 'trigger' => 'deployment',
+ 'deploymentId' => $deployment->getId(),
+ 'deploymentInternalId' => $deployment->getSequence(),
+ 'deploymentResourceType' => 'site',
+ 'deploymentResourceId' => $site->getId(),
+ 'deploymentResourceInternalId' => $site->getSequence(),
+ 'deploymentVcsProviderBranch' => $providerBranch,
+ 'status' => 'verified',
+ 'certificateId' => '',
+ 'search' => implode(' ', [$ruleId, $domain]),
+ 'owner' => 'Appwrite',
+ 'region' => $project->getAttribute('region')
+ ]))
+ );
+ } catch (Duplicate $err) {
+ // Ignore, rule already exists; will be updated by builds worker
+ }
+ }
+
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($site)
diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php
index 16a94dc00c..114a24ef22 100644
--- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php
+++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php
@@ -57,7 +57,7 @@ class Get extends Action
->param('type', '', new WhiteList(['rules']), 'Resource type.')
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Databases/Workers/Databases.php b/src/Appwrite/Platform/Modules/Databases/Workers/Databases.php
index 2576765445..7e5e9eb19f 100644
--- a/src/Appwrite/Platform/Modules/Databases/Workers/Databases.php
+++ b/src/Appwrite/Platform/Modules/Databases/Workers/Databases.php
@@ -64,6 +64,14 @@ class Databases extends Action
$collection = new Document($payload['table'] ?? $payload['collection'] ?? []);
$database = new Document($payload['database'] ?? []);
+ Console::info("Processing database operation: \n" . \json_encode([
+ 'type' => $type,
+ 'projectId' => $project->getId(),
+ 'databaseId' => $database->getId(),
+ 'collectionId' => $collection->getId(),
+ 'documentId' => $document->getId(),
+ ], JSON_PRETTY_PRINT));
+
$log->addTag('projectId', $project->getId());
$log->addTag('type', $type);
@@ -82,6 +90,14 @@ class Databases extends Action
DATABASE_TYPE_DELETE_INDEX => $this->deleteIndex($database, $collection, $document, $project, $dbForPlatform, $dbForProject, $queueForRealtime),
default => throw new Exception('No database operation for type: ' . \strval($type)),
};
+
+ Console::info("Finished processing database operation: \n" . \json_encode([
+ 'type' => $type,
+ 'projectId' => $project->getId(),
+ 'databaseId' => $database->getId(),
+ 'collectionId' => $collection->getId(),
+ 'documentId' => $document->getId(),
+ ], JSON_PRETTY_PRINT));
}
/**
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php
index 007cea0252..f64a960507 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php
@@ -87,7 +87,7 @@ class Create extends Action
->inject('deviceForLocal')
->inject('queueForBuilds')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Delete.php
index 912e12bdc1..9e314d05c6 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Delete.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Delete.php
@@ -62,7 +62,7 @@ class Delete extends Action
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('deviceForFunctions')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
index 1993db4cf5..fd22248fa3 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
@@ -61,7 +61,7 @@ class Get extends Action
->inject('dbForProject')
->inject('deviceForFunctions')
->inject('deviceForBuilds')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php
index 0a07440dff..28861f71f1 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php
@@ -62,7 +62,7 @@ class Create extends Action
->inject('queueForEvents')
->inject('queueForBuilds')
->inject('deviceForFunctions')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Get.php
index e9c5240f5c..a79da7f908 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Get.php
@@ -49,7 +49,7 @@ class Get extends Action
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Status/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Status/Update.php
index 4c924a64d1..e6b45b27de 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Status/Update.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Status/Update.php
@@ -59,7 +59,7 @@ class Update extends Action
->inject('project')
->inject('queueForEvents')
->inject('executor')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
index f1bd4b71e4..4d93c8e8cd 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
@@ -75,7 +75,7 @@ class Create extends Base
->inject('project')
->inject('queueForBuilds')
->inject('gitHub')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Vcs/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Vcs/Create.php
index 48f3894bb2..0ad9852722 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Vcs/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Vcs/Create.php
@@ -72,7 +72,7 @@ class Create extends Base
->inject('queueForEvents')
->inject('queueForBuilds')
->inject('gitHub')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php
index 2ffcfc5d11..996df299d0 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php
@@ -57,7 +57,7 @@ class XList extends Action
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php
index bbdbf8ab45..d502a78e07 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php
@@ -94,7 +94,7 @@ class Create extends Base
->inject('queueForFunctions')
->inject('geodb')
->inject('executor')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php
index 8a3d5f2a49..9c818cfacc 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php
@@ -62,7 +62,7 @@ class Delete extends Base
->inject('dbForProject')
->inject('dbForPlatform')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php
index 659682ab55..42d78f8ca8 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php
@@ -52,7 +52,7 @@ class Get extends Base
->param('executionId', '', new UID(), 'Execution ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php
index 91683c915b..46a41e6517 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php
@@ -58,7 +58,7 @@ class XList extends Base
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php
index c644c681d8..21a74f9a81 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php
@@ -114,7 +114,7 @@ class Create extends Base
->inject('dbForPlatform')
->inject('request')
->inject('gitHub')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php
index 91da68538c..72d5589252 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php
@@ -61,7 +61,7 @@ class Delete extends Base
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php
index 23e2fc3b91..8846329d27 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php
@@ -62,7 +62,7 @@ class Update extends Base
->inject('dbForProject')
->inject('queueForEvents')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Get.php
index 9ce6560fd0..e8da162b8a 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Get.php
@@ -49,7 +49,7 @@ class Get extends Base
->param('functionId', '', new UID(), 'Function ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php
index 2bfe8b1344..aaff953af0 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php
@@ -104,7 +104,7 @@ class Update extends Base
->inject('dbForPlatform')
->inject('gitHub')
->inject('executor')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php
index cd0eba2c50..4b03a5b6cc 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php
@@ -56,7 +56,7 @@ class XList extends Base
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Runtimes/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Runtimes/XList.php
index bfccff0479..0690d1a139 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Runtimes/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Runtimes/XList.php
@@ -47,7 +47,7 @@ class XList extends Base
]
))
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Response $response)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php
index 39186e7ab7..4c059b09d0 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php
@@ -48,7 +48,7 @@ class XList extends Base
))
->inject('response')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Response $response, array $plan)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Templates/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Templates/Get.php
index 237898f6fa..f66322839b 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Templates/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Templates/Get.php
@@ -49,7 +49,7 @@ class Get extends Base
))
->param('templateId', '', new Text(128), 'Template ID.')
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $templateId, Response $response)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php
index 05b54a75d0..86e7f21362 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php
@@ -53,7 +53,7 @@ class XList extends Base
->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true)
->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true)
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(array $runtimes, array $usecases, int $limit, int $offset, Response $response)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php
index 947da4cd37..acb6995d6f 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php
@@ -55,7 +55,7 @@ class Get extends Base
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $functionId, string $range, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php
index e64fe9a600..6a4ded4db7 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php
@@ -52,7 +52,7 @@ class XList extends Base
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $range, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php
index ee892fe1ed..815d364dad 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php
@@ -65,7 +65,7 @@ class Create extends Base
->inject('dbForProject')
->inject('dbForPlatform')
->inject('project')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php
index dda1f97f6b..35f9618edb 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php
@@ -57,7 +57,7 @@ class Delete extends Base
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Get.php
index 98119c4a66..3955b854e9 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Get.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Get.php
@@ -53,7 +53,7 @@ class Get extends Base
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $functionId, string $variableId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php
index 7a6acf88e3..639b1c74d5 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php
@@ -61,7 +61,7 @@ class Update extends Base
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/XList.php
index 9c02cfe07c..29465b7572 100644
--- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/XList.php
+++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/XList.php
@@ -53,7 +53,7 @@ class XList extends Base
->param('functionId', '', new UID(), 'Function unique ID.', false)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $functionId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
index bbe1e1f004..0369879a94 100644
--- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
+++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
@@ -75,7 +75,7 @@ class Builds extends Action
->inject('log')
->inject('executor')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
@@ -209,6 +209,9 @@ class Builds extends Action
Executor $executor,
array $plan
): void {
+ $startTime = DateTime::now();
+ $durationStart = \microtime(true);
+
$resourceKey = match ($resource->getCollection()) {
'functions' => 'functionId',
'sites' => 'siteId',
@@ -260,9 +263,6 @@ class Builds extends Action
->setParam($resourceKey, $resource->getId())
->setParam('deploymentId', $deployment->getId());
- $startTime = DateTime::now();
- $durationStart = \microtime(true);
-
if ($deployment->getAttribute('status') === 'canceled') {
Console::info('Build has been canceled');
return;
@@ -747,6 +747,13 @@ class Builds extends Action
if ($separator !== false) {
$logs = \substr($logs, 0, $separator);
$insideSeparation = true;
+
+ $leftover = \substr($logs, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_START}'));
+ $separator = \strpos($leftover, '{APPWRITE_DETECTION_SEPARATOR_END}');
+ if ($separator !== false) {
+ $logs .= \substr($leftover, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_END}'));
+ $insideSeparation = false;
+ }
}
} else {
$separator = \strpos($logs, '{APPWRITE_DETECTION_SEPARATOR_END}');
@@ -810,9 +817,6 @@ class Builds extends Action
throw $err;
}
- $endTime = DateTime::now();
- $durationEnd = \microtime(true);
-
$buildSizeLimit = (int)System::getEnv('_APP_COMPUTE_BUILD_SIZE_LIMIT', '2000000000');
if (isset($plan['buildSize'])) {
$buildSizeLimit = $plan['buildSize'] * 1000 * 1000;
@@ -821,10 +825,6 @@ class Builds extends Action
throw new \Exception('Build size should be less than ' . number_format($buildSizeLimit / (1000 * 1000), 2) . ' MBs.');
}
- /** Update the build document */
- $deployment->setAttribute('buildStartedAt', DateTime::format((new \DateTime())->setTimestamp(floor($response['startTime']))));
- $deployment->setAttribute('buildEndedAt', $endTime);
- $deployment->setAttribute('buildDuration', \intval(\ceil($durationEnd - $durationStart)));
$deployment->setAttribute('buildPath', $response['path']);
$deployment->setAttribute('buildSize', $response['size']);
$deployment->setAttribute('totalSize', $deployment->getAttribute('buildSize', 0) + $deployment->getAttribute('sourceSize', 0));
@@ -836,18 +836,10 @@ class Builds extends Action
// Separate logs for SSR detection
$detectionLogs = '';
- $separator = \strpos($logs, '{APPWRITE_DETECTION_SEPARATOR_START}');
- if ($separator !== false) {
- $detectionLogs = \substr($logs, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR}'));
- $separatorEnd = \strpos($detectionLogs, '{APPWRITE_DETECTION_SEPARATOR_END}');
- $logs .= \substr($detectionLogs, $separatorEnd + strlen('{APPWRITE_DETECTION_SEPARATOR_END}'));
- $detectionLogs = \substr($detectionLogs, 0, $separatorEnd);
- $logs = \substr($logs, 0, $separator);
- }
-
- if ($resource->getCollection() === 'sites') {
- $date = \date('H:i:s');
- $logs .= "[90m[$date] [90m[[0mappwrite[90m][97m Screenshot capturing started. [0m\n";
+ if (\str_contains($logs, '{APPWRITE_DETECTION_SEPARATOR_START}')) {
+ [$logsBefore, $detectionLogsStart] = \explode('{APPWRITE_DETECTION_SEPARATOR_START}', $logs, 2);
+ [$detectionLogs, $logsAfter] = \explode('{APPWRITE_DETECTION_SEPARATOR_END}', $detectionLogsStart, 2);
+ $logs = ($logsBefore ?? '') . ($logsAfter ?? '');
}
$deployment->setAttribute('buildLogs', $logs);
@@ -877,16 +869,24 @@ class Builds extends Action
}
}
- $deployment->setAttribute('buildLogs', $logs);
-
- $this->afterBuildSuccess($dbForProject, $deployment);
-
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
-
$queueForRealtime
->setPayload($deployment->getArrayCopy())
->trigger();
+ $this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment);
+ $logs = $deployment->getAttribute('buildLogs', '');
+
+ if ($resource->getCollection() === 'sites') {
+ $date = \date('H:i:s');
+ $logs .= "[90m[$date] [90m[[0mappwrite[90m][97m Screenshot capturing started. [0m\n";
+ $deployment->setAttribute('buildLogs', $logs);
+ $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
+ $queueForRealtime
+ ->setPayload($deployment->getArrayCopy())
+ ->trigger();
+ }
+
/** Screenshot site */
if ($resource->getCollection() === 'sites') {
try {
@@ -1032,6 +1032,7 @@ class Builds extends Action
$date = \date('H:i:s');
$logs .= "[90m[$date] [90m[[0mappwrite[90m][97m Screenshot capturing finished. [0m\n";
+ $deployment->setAttribute('buildLogs', $logs);
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
$queueForRealtime
@@ -1046,6 +1047,7 @@ class Builds extends Action
$date = \date('H:i:s');
$logs .= "[90m[$date] [90m[[0mappwrite[90m][33m Screenshot capturing failed. Deployment will continue. [0m\n";
+ $deployment->setAttribute('buildLogs', $logs);
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
}
}
@@ -1189,6 +1191,15 @@ class Builds extends Action
}
}
+ $endTime = DateTime::now();
+ $durationEnd = \microtime(true);
+ $deployment->setAttribute('buildEndedAt', $endTime);
+ $deployment->setAttribute('buildDuration', \intval(\ceil($durationEnd - $durationStart)));
+ $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
+ $queueForRealtime
+ ->setPayload($deployment->getArrayCopy())
+ ->trigger();
+
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
Console::info('Build has been canceled');
return;
@@ -1223,16 +1234,12 @@ class Builds extends Action
$message = "[31m" . $message;
}
- $separator = \strpos($message, '{APPWRITE_DETECTION_SEPARATOR_START}');
- if ($separator !== false) {
- $error = \substr($message, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_START}'));
- $message = \substr($message, 0, $separator);
- $message .= "\n[31m" . $error;
- }
+ $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_START}', '', $message);
+ $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_END}', '', $message);
// Combine with previous logs if deployment got past build process
$previousLogs = '';
- if (!empty($deployment->getAttribute('buildEndedAt', ''))) {
+ if (!is_null($deployment->getAttribute('buildSize', null))) {
$previousLogs = $deployment->getAttribute('buildLogs', '');
if (!empty($previousLogs)) {
$message = $previousLogs . "\n" . $message;
@@ -1317,12 +1324,14 @@ class Builds extends Action
/**
* Hook to run after build success
*
+ * @param Realtime $queueForRealtime
* @param Database $dbForProject
* @param Document $deployment
* @return void
*/
- protected function afterBuildSuccess(Database $dbForProject, Document &$deployment): void
+ protected function afterBuildSuccess(Realtime $queueForRealtime, Database $dbForProject, Document &$deployment): void
{
+ assert($queueForRealtime instanceof Realtime);
assert($dbForProject instanceof Database);
assert($deployment instanceof Document);
}
diff --git a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Create.php b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Create.php
index 54ff189c20..9332453eea 100644
--- a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Create.php
+++ b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Create.php
@@ -57,7 +57,7 @@ class Create extends Action
->inject('user')
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $projectId, string $name, ?string $expire, Document $user, Response $response, Database $dbForPlatform)
diff --git a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Delete.php b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Delete.php
index eac42be5f0..2bfea6c55b 100644
--- a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Delete.php
+++ b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Delete.php
@@ -49,7 +49,7 @@ class Delete extends Action
->param('keyId', '', new UID(), 'Key unique ID.')
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $projectId, string $keyId, Response $response, Database $dbForPlatform)
diff --git a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Get.php b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Get.php
index 6255976de4..29cda90f66 100644
--- a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Get.php
+++ b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Get.php
@@ -49,7 +49,7 @@ class Get extends Action
->param('keyId', '', new UID(), 'Key unique ID.')
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $projectId, string $keyId, Response $response, Database $dbForPlatform)
diff --git a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Update.php b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Update.php
index 33b91eb0b6..b13bc535dd 100644
--- a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Update.php
+++ b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/Update.php
@@ -52,7 +52,7 @@ class Update extends Action
->param('expire', null, new DatetimeValidator(), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.')
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $projectId, string $keyId, string $name, ?string $expire, Response $response, Database $dbForPlatform)
{
diff --git a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/XList.php b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/XList.php
index 73e79a783a..209387018b 100644
--- a/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/XList.php
+++ b/src/Appwrite/Platform/Modules/Projects/Http/DevKeys/XList.php
@@ -53,7 +53,7 @@ class XList extends Action
->param('queries', [], new DevKeys(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', DevKeys::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $projectId, ?array $queries, Response $response, Database $dbForPlatform)
diff --git a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/API/Create.php b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/API/Create.php
index 33eb5313a0..4efe8176f6 100644
--- a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/API/Create.php
+++ b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/API/Create.php
@@ -66,7 +66,7 @@ class Create extends Action
->inject('queueForCertificates')
->inject('queueForEvents')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $domain, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform)
diff --git a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Function/Create.php b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Function/Create.php
index 0b68b80aa3..1c8fe7b04d 100644
--- a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Function/Create.php
+++ b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Function/Create.php
@@ -71,7 +71,7 @@ class Create extends Action
->inject('queueForEvents')
->inject('dbForPlatform')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $domain, string $functionId, string $branch, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Redirect/Create.php b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Redirect/Create.php
index 60e8759e5c..580d92bc74 100644
--- a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Redirect/Create.php
+++ b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Redirect/Create.php
@@ -74,7 +74,7 @@ class Create extends Action
->inject('queueForEvents')
->inject('dbForPlatform')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $domain, string $url, int $statusCode, string $resourceId, string $resourceType, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Site/Create.php b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Site/Create.php
index 7c2a640cdf..7a5a1f4952 100644
--- a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Site/Create.php
+++ b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Site/Create.php
@@ -71,7 +71,7 @@ class Create extends Action
->inject('queueForEvents')
->inject('dbForPlatform')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $domain, string $siteId, string $branch, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php
index 62c5998c9b..65a0fcf143 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php
@@ -86,7 +86,7 @@ class Create extends Action
->inject('deviceForLocal')
->inject('queueForBuilds')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Delete.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Delete.php
index 8717d04fc2..dfc0f0c976 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Delete.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Delete.php
@@ -62,7 +62,7 @@ class Delete extends Action
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('deviceForSites')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
index d3a2f0b814..5a87ce453f 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
@@ -60,7 +60,7 @@ class Get extends Action
->inject('dbForProject')
->inject('deviceForSites')
->inject('deviceForBuilds')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php
index 739c701a2e..22a7a47390 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php
@@ -65,7 +65,7 @@ class Create extends Action
->inject('queueForEvents')
->inject('queueForBuilds')
->inject('deviceForSites')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Get.php
index d280231159..d583c62fb1 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Get.php
@@ -49,7 +49,7 @@ class Get extends Action
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $deploymentId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Status/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Status/Update.php
index 046ddd1ac8..a447e54f8d 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Status/Update.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Status/Update.php
@@ -57,7 +57,7 @@ class Update extends Action
->inject('project')
->inject('queueForEvents')
->inject('executor')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
index 5de688fbf8..a2040d830b 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
@@ -77,7 +77,7 @@ class Create extends Base
->inject('queueForEvents')
->inject('queueForBuilds')
->inject('gitHub')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php
index eb6fdf4094..ddad5d793a 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php
@@ -72,7 +72,7 @@ class Create extends Base
->inject('queueForEvents')
->inject('queueForBuilds')
->inject('gitHub')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php
index 306f756d87..a1a79ec155 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php
@@ -57,7 +57,7 @@ class XList extends Action
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, array $queries, string $search, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Frameworks/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Frameworks/XList.php
index cf2bb8c62b..a042fd6e7c 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Frameworks/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Frameworks/XList.php
@@ -46,7 +46,7 @@ class XList extends Base
]
))
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Response $response)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Logs/Delete.php b/src/Appwrite/Platform/Modules/Sites/Http/Logs/Delete.php
index 2d87321086..0f53985039 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Logs/Delete.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Logs/Delete.php
@@ -55,7 +55,7 @@ class Delete extends Base
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $logId, Response $response, Database $dbForProject, Event $queueForEvents)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Logs/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Logs/Get.php
index 2ef7d75539..935e790113 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Logs/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Logs/Get.php
@@ -50,7 +50,7 @@ class Get extends Base
->param('logId', '', new UID(), 'Log ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $logId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php
index 7e2c587797..f9bee3e425 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php
@@ -57,7 +57,7 @@ class XList extends Base
->param('queries', [], new Logs(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, array $queries, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php
index 6dd1865047..9be95441cb 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php
@@ -89,7 +89,7 @@ class Create extends Base
->inject('project')
->inject('queueForEvents')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Delete.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Delete.php
index 37666215e5..ed9b059c33 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Delete.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Delete.php
@@ -58,7 +58,7 @@ class Delete extends Base
->inject('dbForProject')
->inject('queueForDeletes')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php
index a45c2a1243..bb6bd4f632 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php
@@ -60,7 +60,7 @@ class Update extends Base
->inject('dbForProject')
->inject('queueForEvents')
->inject('dbForPlatform')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Get.php
index 88ff5f1d51..d86d98ef71 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Get.php
@@ -49,7 +49,7 @@ class Get extends Base
->param('siteId', '', new UID(), 'Site ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php
index 85f1ee8845..80354d5067 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php
@@ -97,7 +97,7 @@ class Update extends Base
->inject('dbForPlatform')
->inject('gitHub')
->inject('executor')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php
index 0a3b257f59..988a2d2e20 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php
@@ -56,7 +56,7 @@ class XList extends Base
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(array $queries, string $search, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php
index 2a9447f8c6..a76f067114 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php
@@ -48,7 +48,7 @@ class XList extends Base
))
->inject('response')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Response $response, array $plan)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Templates/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Templates/Get.php
index a4066fb787..633ef31e68 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Templates/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Templates/Get.php
@@ -49,7 +49,7 @@ class Get extends Base
))
->param('templateId', '', new Text(128), 'Template ID.')
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $templateId, Response $response)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Templates/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Templates/XList.php
index 414ecc9987..4fe00f3edf 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Templates/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Templates/XList.php
@@ -53,7 +53,7 @@ class XList extends Base
->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true)
->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true)
->inject('response')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php
index f8df836085..af96c10457 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php
@@ -55,7 +55,7 @@ class Get extends Base
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php
index e37d3e792e..d36cc56ae5 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php
@@ -52,7 +52,7 @@ class XList extends Base
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $range, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Create.php
index 88da635fe4..ef504fe663 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Create.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Create.php
@@ -62,7 +62,7 @@ class Create extends Base
->inject('response')
->inject('dbForProject')
->inject('project')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $key, string $value, bool $secret, Response $response, Database $dbForProject, Document $project)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Delete.php
index ea927be367..be0addb34c 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Delete.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Delete.php
@@ -54,7 +54,7 @@ class Delete extends Base
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $variableId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Get.php
index 1c25f9e701..11eb546092 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Get.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Get.php
@@ -53,7 +53,7 @@ class Get extends Base
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $siteId, string $variableId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php
index 698992f79f..3cf2e2f85f 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php
@@ -58,7 +58,7 @@ class Update extends Base
->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only sites can read them during build and runtime.', true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/XList.php
index 15e21296a5..51ab355c75 100644
--- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/XList.php
+++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/XList.php
@@ -53,7 +53,7 @@ class XList extends Base
->param('siteId', '', new UID(), 'Site unique ID.', false)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php
index dc1e5232b6..fe7a0187e9 100644
--- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php
+++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php
@@ -65,7 +65,7 @@ class Create extends Action
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void
diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php
index 628d9b768f..231164d6ee 100644
--- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php
+++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php
@@ -55,7 +55,7 @@ class XList extends Action
->param('queries', [], new FileTokens(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', FileTokens::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $bucketId, string $fileId, array $queries, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Delete.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Delete.php
index fcac9a6b24..c36df367ee 100644
--- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Delete.php
+++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Delete.php
@@ -58,7 +58,7 @@ class Delete extends Action
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $tokenId, Response $response, Database $dbForProject, Event $queueForEvents)
diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Get.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Get.php
index 66b9c1b5cb..4da9e125f2 100644
--- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Get.php
+++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Get.php
@@ -50,7 +50,7 @@ class Get extends Action
->param('tokenId', '', new UID(), 'Token ID.')
->inject('response')
->inject('dbForProject')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $tokenId, Response $response, Database $dbForProject)
diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php
index c341831c0d..7a15708011 100644
--- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php
+++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php
@@ -61,7 +61,7 @@ class Update extends Action
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $tokenId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents)
diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php
index b543555477..20eeb0826e 100644
--- a/src/Appwrite/Platform/Tasks/Doctor.php
+++ b/src/Appwrite/Platform/Tasks/Doctor.php
@@ -34,7 +34,7 @@ class Doctor extends Action
$this
->desc('Validate server health')
->inject('register')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Registry $register): void
diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php
index c7b1f72453..c3b4e33593 100644
--- a/src/Appwrite/Platform/Tasks/Install.php
+++ b/src/Appwrite/Platform/Tasks/Install.php
@@ -31,7 +31,7 @@ class Install extends Action
->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true)
->param('interactive', 'Y', new Text(1), 'Run an interactive session', true)
->param('no-start', false, new Boolean(true), 'Run an interactive session', true)
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void
diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php
index ddc8c3cb6f..e6def793b5 100644
--- a/src/Appwrite/Platform/Tasks/Maintenance.php
+++ b/src/Appwrite/Platform/Tasks/Maintenance.php
@@ -29,7 +29,7 @@ class Maintenance extends Action
->inject('console')
->inject('queueForCertificates')
->inject('queueForDeletes')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Database $dbForPlatform, Document $console, Certificate $queueForCertificates, Delete $queueForDeletes): void
diff --git a/src/Appwrite/Platform/Tasks/QueueRetry.php b/src/Appwrite/Platform/Tasks/QueueRetry.php
index f8099dcb00..442fa39823 100644
--- a/src/Appwrite/Platform/Tasks/QueueRetry.php
+++ b/src/Appwrite/Platform/Tasks/QueueRetry.php
@@ -24,7 +24,7 @@ class QueueRetry extends Action
->param('name', '', new Text(100), 'Queue name')
->param('limit', 0, new Wildcard(), 'jobs limit', true)
->inject('publisher')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php
index 07749400d6..ea73af541c 100644
--- a/src/Appwrite/Platform/Tasks/SDKs.php
+++ b/src/Appwrite/Platform/Tasks/SDKs.php
@@ -46,7 +46,7 @@ class SDKs extends Action
->param('git', null, new Nullable(new WhiteList(['yes', 'no'])), 'Should we use git push?', optional: true)
->param('production', null, new Nullable(new WhiteList(['yes', 'no'])), 'Should we push to production?', optional: true)
->param('message', null, new Nullable(new Text(256)), 'Commit Message', optional: true)
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(?string $selectedPlatform, ?string $selectedSDK, ?string $version, ?string $git, ?string $production, ?string $message): void
diff --git a/src/Appwrite/Platform/Tasks/SSL.php b/src/Appwrite/Platform/Tasks/SSL.php
index ae1c93a360..651cb4de11 100644
--- a/src/Appwrite/Platform/Tasks/SSL.php
+++ b/src/Appwrite/Platform/Tasks/SSL.php
@@ -24,7 +24,7 @@ class SSL extends Action
->param('domain', System::getEnv('_APP_DOMAIN', ''), new Hostname(), 'Domain to generate certificate for. If empty, main domain will be used.', true)
->param('skip-check', true, new Boolean(true), 'If DNS and renew check should be skipped. Defaults to true, and when true, all jobs will result in certificate generation attempt.', true)
->inject('queueForCertificates')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $domain, bool|string $skipCheck, Certificate $queueForCertificates): void
diff --git a/src/Appwrite/Platform/Tasks/Screenshot.php b/src/Appwrite/Platform/Tasks/Screenshot.php
index 3a9c9a64f5..5a4d8a76b7 100644
--- a/src/Appwrite/Platform/Tasks/Screenshot.php
+++ b/src/Appwrite/Platform/Tasks/Screenshot.php
@@ -21,7 +21,7 @@ class Screenshot extends Action
$this
->desc('Create Site template screenshot')
->param('templateId', '', new Text(128), 'Template ID.')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $templateId): void
diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php
index a0b5056b0f..b64dd61f86 100644
--- a/src/Appwrite/Platform/Tasks/StatsResources.php
+++ b/src/Appwrite/Platform/Tasks/StatsResources.php
@@ -45,7 +45,7 @@ class StatsResources extends Action
->inject('dbForPlatform')
->inject('logError')
->inject('queueForStatsResources')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue): void
@@ -53,11 +53,14 @@ class StatsResources extends Action
$this->logError = $logError;
$this->dbForPlatform = $dbForPlatform;
+ $this->disableSubqueries();
+
Console::title("Stats resources V1");
Console::success('Stats resources: started');
$interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600');
+
Console::loop(function () use ($queue) {
Authorization::disable();
Authorization::setDefaultStatus(false);
diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php
index dfd10d347e..d6159d2718 100644
--- a/src/Appwrite/Platform/Tasks/Upgrade.php
+++ b/src/Appwrite/Platform/Tasks/Upgrade.php
@@ -23,7 +23,7 @@ class Upgrade extends Install
->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true)
->param('interactive', 'Y', new Text(1), 'Run an interactive session', true)
->param('no-start', false, new Boolean(true), 'Run an interactive session', true)
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void
diff --git a/src/Appwrite/Platform/Tasks/Vars.php b/src/Appwrite/Platform/Tasks/Vars.php
index 70ae550ef9..542b5bdc9f 100644
--- a/src/Appwrite/Platform/Tasks/Vars.php
+++ b/src/Appwrite/Platform/Tasks/Vars.php
@@ -18,7 +18,7 @@ class Vars extends Action
{
$this
->desc('List all the server environment variables')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(): void
diff --git a/src/Appwrite/Platform/Workers/Audits.php b/src/Appwrite/Platform/Workers/Audits.php
index 9d4bbbc408..04b562a219 100644
--- a/src/Appwrite/Platform/Workers/Audits.php
+++ b/src/Appwrite/Platform/Workers/Audits.php
@@ -45,7 +45,7 @@ class Audits extends Action
->inject('message')
->inject('getProjectDB')
->inject('project')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
$this->lastTriggeredTime = time();
}
diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php
index 8ed96c76a2..2f41001b58 100644
--- a/src/Appwrite/Platform/Workers/Deletes.php
+++ b/src/Appwrite/Platform/Workers/Deletes.php
@@ -495,7 +495,7 @@ class Deletes extends Action
* @throws Authorization
* @throws DatabaseException
*/
- private function deleteProject(Database $dbForPlatform, callable $getProjectDB, Device $deviceForFiles, Device $deviceForSites, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, Document $document): void
+ protected function deleteProject(Database $dbForPlatform, callable $getProjectDB, Device $deviceForFiles, Device $deviceForSites, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, Document $document): void
{
$projectInternalId = $document->getSequence();
$projectId = $document->getId();
diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php
index 8b3347775a..2c9ca16b0c 100644
--- a/src/Appwrite/Platform/Workers/Functions.php
+++ b/src/Appwrite/Platform/Workers/Functions.php
@@ -53,7 +53,7 @@ class Functions extends Action
->inject('log')
->inject('executor')
->inject('isResourceBlocked')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
public function action(
diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php
index 3a15182e51..4e8b5e085c 100644
--- a/src/Appwrite/Platform/Workers/Mails.php
+++ b/src/Appwrite/Platform/Workers/Mails.php
@@ -29,7 +29,7 @@ class Mails extends Action
->inject('message')
->inject('register')
->inject('log')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php
index 2ee107a319..668993fdae 100644
--- a/src/Appwrite/Platform/Workers/Messaging.php
+++ b/src/Appwrite/Platform/Workers/Messaging.php
@@ -72,7 +72,7 @@ class Messaging extends Action
->inject('dbForProject')
->inject('deviceForFiles')
->inject('queueForStatsUsage')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
@@ -426,7 +426,7 @@ class Messaging extends Action
$credentials = $provider->getAttribute('credentials');
return match ($provider->getAttribute('provider')) {
- 'mock' => new Mock('username', 'password'),
+ 'mock' => (new Mock('username', 'password'))->setEndpoint('http://request-catcher-sms:5000/'),
'twilio' => new Twilio(
$credentials['accountSid'] ?? '',
$credentials['authToken'] ?? '',
diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php
index 66f45004ea..f224a6e806 100644
--- a/src/Appwrite/Platform/Workers/Migrations.php
+++ b/src/Appwrite/Platform/Workers/Migrations.php
@@ -69,7 +69,7 @@ class Migrations extends Action
->inject('logError')
->inject('queueForRealtime')
->inject('deviceForImports')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
diff --git a/src/Appwrite/Platform/Workers/StatsResources.php b/src/Appwrite/Platform/Workers/StatsResources.php
index c68465f8df..98c9d01a87 100644
--- a/src/Appwrite/Platform/Workers/StatsResources.php
+++ b/src/Appwrite/Platform/Workers/StatsResources.php
@@ -49,7 +49,7 @@ class StatsResources extends Action
->inject('getLogsDB')
->inject('dbForPlatform')
->inject('logError')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
diff --git a/src/Appwrite/Platform/Workers/StatsUsage.php b/src/Appwrite/Platform/Workers/StatsUsage.php
index 59b5a15ada..3610381d5a 100644
--- a/src/Appwrite/Platform/Workers/StatsUsage.php
+++ b/src/Appwrite/Platform/Workers/StatsUsage.php
@@ -119,7 +119,7 @@ class StatsUsage extends Action
->inject('getProjectDB')
->inject('getLogsDB')
->inject('register')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
$this->lastTriggeredTime = time();
}
diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php
index 2ce39f8aaa..3ffc3f0aad 100644
--- a/src/Appwrite/Platform/Workers/Webhooks.php
+++ b/src/Appwrite/Platform/Workers/Webhooks.php
@@ -38,7 +38,7 @@ class Webhooks extends Action
->inject('queueForStatsUsage')
->inject('log')
->inject('plan')
- ->callback([$this, 'action']);
+ ->callback($this->action(...));
}
/**
diff --git a/src/Appwrite/SDK/Specification/Format/Swagger2.php b/src/Appwrite/SDK/Specification/Format/Swagger2.php
index ffd193d772..88f8c24647 100644
--- a/src/Appwrite/SDK/Specification/Format/Swagger2.php
+++ b/src/Appwrite/SDK/Specification/Format/Swagger2.php
@@ -141,6 +141,7 @@ class Swagger2 extends Format
$sdkPlatforms[] = APP_PLATFORM_CLIENT;
}
+ $sdkPlatforms = array_values(array_unique($sdkPlatforms));
$namespace = $sdk->getNamespace() ?? 'default';
$desc ??= '';
diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php
index 15411f18ab..df4c5fd8f5 100644
--- a/src/Executor/Executor.php
+++ b/src/Executor/Executor.php
@@ -64,7 +64,8 @@ class Executor
string $destination = '',
array $variables = [],
string $command = null,
- string $outputDirectory = ''
+ string $outputDirectory = '',
+ string $runtimeEntrypoint = ''
) {
$runtimeId = "$projectId-$deploymentId-build";
$route = "/runtimes";
@@ -87,7 +88,8 @@ class Executor
'memory' => $memory,
'version' => $version,
'timeout' => $timeout,
- 'outputDirectory' => $outputDirectory
+ 'outputDirectory' => $outputDirectory,
+ 'runtimeEntrypoint' => $runtimeEntrypoint
];
@@ -186,9 +188,9 @@ class Executor
array $headers,
float $cpus,
int $memory,
- string $runtimeEntrypoint = null,
bool $logging,
- int $requestTimeout = null
+ string $runtimeEntrypoint = '',
+ ?int $requestTimeout = null
) {
if (empty($headers['host'])) {
$headers['host'] = System::getEnv('_APP_DOMAIN', '');
diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php
index 620409bb39..bce6e7206f 100644
--- a/tests/e2e/General/HTTPTest.php
+++ b/tests/e2e/General/HTTPTest.php
@@ -60,7 +60,7 @@ class HTTPTest extends Scope
'origin' => 'http://localhost',
]));
- $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals(200, $response['headers']['status-code'], "Simple GET /robots.txt HTTP request failed: " . \json_encode($response));
$this->assertStringContainsString('# robotstxt.org/', $response['body']);
}
diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php
index ea27318390..c2b4896814 100644
--- a/tests/e2e/Scopes/ProjectCustom.php
+++ b/tests/e2e/Scopes/ProjectCustom.php
@@ -144,7 +144,7 @@ trait ProjectCustom
'teams.*',
'users.*'
],
- 'url' => 'http://request-catcher:5000/webhook',
+ 'url' => 'http://request-catcher-webhook:5000/',
'security' => false,
]);
diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php
index 2fa6416bf7..2ee0d0198e 100644
--- a/tests/e2e/Scopes/Scope.php
+++ b/tests/e2e/Scopes/Scope.php
@@ -13,6 +13,9 @@ abstract class Scope extends TestCase
use Retryable;
use Async;
+ public const REQUEST_TYPE_WEBHOOK = 'webhook';
+ public const REQUEST_TYPE_SMS = 'sms';
+
protected ?Client $client = null;
protected string $endpoint = 'http://localhost/v1';
@@ -37,18 +40,55 @@ abstract class Scope extends TestCase
if ($limit === 1) {
return end($emails);
} else {
- $lastEmails = array_slice($emails, -1 * $limit);
- return $lastEmails;
+ return array_slice($emails, -1 * $limit);
}
}
return [];
}
- protected function assertLastRequest(callable $probe, $timeoutMs = 20_000, $waitMs = 500): array
+ protected function extractQueryParamsFromEmailLink(string $html): array
{
- $this->assertEventually(function () use (&$request, $probe) {
- $request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
+ foreach (['/join-us?', '/verification?', '/recovery?'] as $prefix) {
+ $linkStart = strpos($html, $prefix);
+ if ($linkStart !== false) {
+ $hrefStart = strrpos(substr($html, 0, $linkStart), 'href="');
+ if ($hrefStart === false) {
+ continue;
+ }
+
+ $hrefStart += 6;
+ $hrefEnd = strpos($html, '"', $hrefStart);
+ if ($hrefEnd === false || $hrefStart >= $hrefEnd) {
+ continue;
+ }
+
+ $link = substr($html, $hrefStart, $hrefEnd - $hrefStart);
+ $link = strtok($link, '#'); // Remove `#title`
+ $queryStart = strpos($link, '?');
+ if ($queryStart === false) {
+ continue;
+ }
+
+ $queryString = substr($link, $queryStart + 1);
+ parse_str(html_entity_decode($queryString), $queryParams);
+ return $queryParams;
+ }
+ }
+
+ return [];
+ }
+
+ protected function assertLastRequest(callable $probe, string $type, $timeoutMs = 20_000, $waitMs = 500): array
+ {
+ $hostname = match ($type) {
+ 'webhook' => 'request-catcher-webhook',
+ 'sms' => 'request-catcher-sms',
+ default => throw new \Exception('Invalid request catcher type.'),
+ };
+
+ $this->assertEventually(function () use (&$request, $probe, $hostname) {
+ $request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true);
$request['data'] = json_decode($request['data'], true);
call_user_func($probe, $request);
@@ -57,11 +97,16 @@ abstract class Scope extends TestCase
return $request;
}
+ /**
+ * @deprecated Use assertLastRequest instead. Used only historically in webhook tests
+ */
protected function getLastRequest(): array
{
+ $hostname = 'request-catcher-webhook';
+
sleep(2);
- $request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
+ $request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true);
$request['data'] = json_decode($request['data'], true);
return $request;
diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php
index b114a54c30..b63055072c 100644
--- a/tests/e2e/Services/Account/AccountCustomClientTest.php
+++ b/tests/e2e/Services/Account/AccountCustomClientTest.php
@@ -926,17 +926,18 @@ class AccountCustomClientTest extends Scope
$this->assertEquals($name, $lastEmail['to'][0]['name']);
$this->assertEquals('Account Verification', $lastEmail['subject']);
- $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
- $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0);
- $this->assertNotFalse($expireTime);
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $verification = $tokens['secret'];
+ $expectedExpire = DateTime::format(new \DateTime($response['body']['expire']));
+ $this->assertEquals($expectedExpire, $tokens['expire']);
- $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0);
+ // Secret check
+ $this->assertArrayHasKey('secret', $tokens);
+ $this->assertNotEmpty($tokens['secret']);
- $this->assertNotFalse($secretTest);
-
- $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0);
-
- $this->assertNotFalse($userIDTest);
+ // User ID check
+ $this->assertArrayHasKey('userId', $tokens);
+ $this->assertNotEmpty($tokens['userId']);
/**
* Test for FAILURE
@@ -1228,19 +1229,25 @@ class AccountCustomClientTest extends Scope
$this->assertEquals($name, $lastEmail['to'][0]['name']);
$this->assertEquals('Password Reset', $lastEmail['subject']);
- $recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
- $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0);
+ // Secret check
+ $this->assertArrayHasKey('secret', $tokens);
+ $this->assertNotEmpty($tokens['secret']);
+ $this->assertNotFalse($response['body']['secret']);
- $this->assertNotFalse($expireTime);
+ // User ID check
+ $this->assertArrayHasKey('userId', $tokens);
+ $this->assertNotEmpty($tokens['userId']);
+ $this->assertNotFalse($response['body']['userId']);
- $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0);
-
- $this->assertNotFalse($secretTest);
-
- $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0);
-
- $this->assertNotFalse($userIDTest);
+ // Expire check
+ $this->assertArrayHasKey('expire', $tokens);
+ $this->assertNotEmpty($tokens['expire']);
+ $this->assertEquals(
+ DateTime::format(new \DateTime($response['body']['expire'])),
+ $tokens['expire']
+ );
/**
* Test for FAILURE
@@ -1278,7 +1285,7 @@ class AccountCustomClientTest extends Scope
$this->assertEquals(404, $response['headers']['status-code']);
- $data['recovery'] = $recovery;
+ $data['recovery'] = $tokens['secret'];
return $data;
}
@@ -1433,7 +1440,7 @@ class AccountCustomClientTest extends Scope
$this->assertEquals('otpuser2@appwrite.io', $lastEmail['to'][0]['address']);
$this->assertEquals('OTP for ' . $this->getProject()['name'] . ' Login', $lastEmail['subject']);
- // FInd 6 concurrent digits in email text - OTP
+ // Find 6 concurrent digits in email text - OTP
preg_match_all("/\b\d{6}\b/", $lastEmail['text'], $matches);
$code = ($matches[0] ?? [])[0] ?? '';
@@ -2204,14 +2211,13 @@ class AccountCustomClientTest extends Scope
$userId = $response['body']['userId'];
$smsRequest = $this->assertLastRequest(function (array $request) use ($number) {
- $this->assertEquals('http://request-catcher:5000/mock-sms', $request['url']);
$this->assertEquals('Appwrite Mock Message Sender', $request['headers']['User-Agent']);
$this->assertEquals('username', $request['headers']['X-Username']);
$this->assertEquals('password', $request['headers']['X-Key']);
$this->assertEquals('POST', $request['method']);
$this->assertEquals('+123456789', $request['data']['from']);
$this->assertEquals($number, $request['data']['to']);
- });
+ }, Scope::REQUEST_TYPE_SMS);
$data['token'] = $smsRequest['data']['message'];
$data['id'] = $userId;
@@ -2555,13 +2561,21 @@ class AccountCustomClientTest extends Scope
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
+ $this->assertNotEmpty($response['body']['$createdAt']);
$this->assertEmpty($response['body']['secret']);
$this->assertTrue((new DatetimeValidator())->isValid($response['body']['expire']));
- $smsRequest = $this->assertLastRequest(function ($request) {
+ $tokenCreatedAt = $response['body']['$createdAt'];
+
+ $smsRequest = $this->assertLastRequest(function ($request) use ($tokenCreatedAt) {
$this->assertArrayHasKey('data', $request);
- $this->assertArrayHasKey('message', $request['data']);
- });
+ $this->assertArrayHasKey('time', $request);
+ $this->assertArrayHasKey('message', $request['data'], "Last request missing message: " . \json_encode($request));
+
+ // Ensure we are not using token from last sms login
+ $tokenRecievedAt = $request['time'];
+ $this->assertGreaterThan($tokenCreatedAt, $tokenRecievedAt);
+ }, Scope::REQUEST_TYPE_SMS);
/**
* Test for FAILURE
diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
index 33b3b1dc88..0d138566fd 100644
--- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
@@ -957,10 +957,8 @@ class RealtimeConsoleClientTest extends Scope
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertArrayHasKey('buildLogs', $response['data']['payload']);
- if (!empty($response['data']['payload']['buildEndedAt'])) {
- $this->assertNotEmpty($response['data']['payload']['buildEndedAt']);
+ if (!empty($response['data']['payload']['buildSize'])) {
$this->assertNotEmpty($response['data']['payload']['buildStartedAt']);
- $this->assertNotEmpty($response['data']['payload']['buildDuration']);
$this->assertNotEmpty($response['data']['payload']['buildPath']);
$this->assertNotEmpty($response['data']['payload']['buildSize']);
$this->assertNotEmpty($response['data']['payload']['totalSize']);
@@ -984,6 +982,13 @@ class RealtimeConsoleClientTest extends Scope
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertEquals("ready", $response['data']['payload']['status']);
+ $response = json_decode($client->receive(), true);
+ $this->assertContains("functions.{$functionId}.deployments.{$deploymentId}.update", $response['data']['events']);
+ $this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
+ $this->assertNotEmpty($response['data']['payload']['buildDuration']);
+ $this->assertNotEmpty($response['data']['payload']['buildEndedAt']);
+
$client->close();
}
}
diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
index 6d6c0d18a4..dbb3b016be 100644
--- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
@@ -426,7 +426,8 @@ class RealtimeCustomClientTest extends Scope
$this->assertContains("users.*", $response['data']['events']);
$lastEmail = $this->getLastEmail();
- $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $verification = $tokens['secret'];
/**
* Test Account Verification Complete
@@ -623,7 +624,8 @@ class RealtimeCustomClientTest extends Scope
$response = json_decode($client->receive(), true);
$lastEmail = $this->getLastEmail();
- $recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $recovery = $tokens['secret'];
$this->assertArrayHasKey('type', $response);
$this->assertArrayHasKey('data', $response);
diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php
index 1858fd50ad..5c8e94feb1 100644
--- a/tests/e2e/Services/Teams/TeamsBaseClient.php
+++ b/tests/e2e/Services/Teams/TeamsBaseClient.php
@@ -223,8 +223,10 @@ trait TeamsBaseClient
$this->assertEquals($email, $lastEmail['to'][0]['address']);
$this->assertEquals($name, $lastEmail['to'][0]['name']);
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
- $this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
- $this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
+
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $this->assertEquals($teamName, $tokens['teamName']);
+ $this->assertEquals($response['body']['teamId'], $tokens['teamId']);
/**
* Test with UserId
@@ -288,8 +290,10 @@ trait TeamsBaseClient
$this->assertEquals($secondEmail, $lastEmail['to'][0]['address']);
$this->assertEquals($secondName, $lastEmail['to'][0]['name']);
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
- $this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
- $this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
+
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $this->assertEquals($teamName, $tokens['teamName']);
+ $this->assertEquals($response['body']['teamId'], $tokens['teamId']);
// test for resending invitation
$response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([
@@ -305,9 +309,10 @@ trait TeamsBaseClient
$this->assertEquals(201, $response['headers']['status-code']);
$lastEmail = $this->getLastEmail();
- $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
- $userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20);
- $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
+ $membershipUid = $tokens['membershipId'];
+ $userUid = $tokens['userId'];
+ $secret = $tokens['secret'];
/**
* Test for FAILURE
@@ -338,11 +343,11 @@ trait TeamsBaseClient
$this->assertEquals(400, $response['headers']['status-code']);
return [
- 'teamUid' => $teamUid,
- 'teamName' => $teamName,
- 'secret' => $secret,
- 'membershipUid' => $membershipUid,
- 'userUid' => $userUid,
+ 'teamUid' => $tokens['teamId'],
+ 'teamName' => $tokens['teamName'],
+ 'secret' => $tokens['secret'],
+ 'membershipUid' => $tokens['membershipId'],
+ 'userUid' => $tokens['userId'],
'email' => $email,
'name' => $name
];
@@ -600,10 +605,11 @@ trait TeamsBaseClient
$this->assertEquals(201, $response['headers']['status-code']);
$lastEmail = $this->getLastEmail();
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
- $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
- $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
- $userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20);
+ $secret = $tokens['secret'];
+ $membershipUid = $tokens['membershipId'];
+ $userUid = $tokens['userId'];
$response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', [
'origin' => 'http://localhost',
diff --git a/tests/e2e/Services/Teams/TeamsCustomClientTest.php b/tests/e2e/Services/Teams/TeamsCustomClientTest.php
index 7286bb0827..e30dacac74 100644
--- a/tests/e2e/Services/Teams/TeamsCustomClientTest.php
+++ b/tests/e2e/Services/Teams/TeamsCustomClientTest.php
@@ -6,6 +6,7 @@ use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
+use Utopia\CLI\Console;
class TeamsCustomClientTest extends Scope
{
@@ -152,11 +153,14 @@ class TeamsCustomClientTest extends Scope
$this->assertEquals(201, $response['headers']['status-code']);
$email = $this->getLastEmail();
+ Console::log(json_encode([
+ 'testTeamsInviteHTMLInjection' => $email
+ ], JSON_PRETTY_PRINT));
+
$encoded = 'http://localhost:5000/join-us\"></a><h1>INJECTED</h1>?';
$this->assertStringNotContainsString('INJECTED
', $email['html']);
$this->assertStringContainsString($encoded, $email['html']);
- $this->assertStringContainsString($encoded, $email['text']);
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/'.$response['body']['$id'], array_merge([
'content-type' => 'application/json',
diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php
index b26f964479..fe9a4ed366 100644
--- a/tests/e2e/Services/Webhooks/WebhooksBase.php
+++ b/tests/e2e/Services/Webhooks/WebhooksBase.php
@@ -1271,7 +1271,10 @@ trait WebhooksBase
$lastEmail = $this->getLastEmail();
- $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+ // `$isAppUser` — no email expected;
+ $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html'] ?? '');
+
+ $secret = $tokens['secret'] ?? '';
$membershipId = $team['body']['$id'];
$webhook = $this->getLastRequest();
diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
index a170492551..bcc4ede30a 100644
--- a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
+++ b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
@@ -894,9 +894,9 @@ class WebhooksCustomClientTest extends Scope
$url = $webhook['url'];
$signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true));
- $this->assertEquals($webhook['method'], 'POST');
- $this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
- $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
+ $this->assertEquals('POST', $webhook['method']);
+ $this->assertEquals('application/json', $webhook['headers']['Content-Type']);
+ $this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
$this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('teams.*.memberships.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('teams.*.memberships.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
@@ -919,8 +919,8 @@ class WebhooksCustomClientTest extends Scope
$this->assertNotEmpty($webhook['data']['userId']);
$this->assertNotEmpty($webhook['data']['teamId']);
$this->assertCount(2, $webhook['data']['roles']);
- $this->assertEquals(true, (new DatetimeValidator())->isValid($webhook['data']['joined']));
- $this->assertEquals(true, $webhook['data']['confirm']);
+ $this->assertTrue((new DatetimeValidator())->isValid($webhook['data']['joined']));
+ $this->assertTrue($webhook['data']['confirm']);
/**
* Test for FAILURE