From b2bae294b6302307e517f1af79b6096190872df6 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 14:20:32 +0200 Subject: [PATCH 01/40] add languages method to locale endpoint --- app/config/languages.php | 936 ++++++++++++++++++++++++ app/controllers/api/locale.php | 16 + docs/references/locale/get-languages.md | 1 + 3 files changed, 953 insertions(+) create mode 100644 app/config/languages.php create mode 100644 docs/references/locale/get-languages.md diff --git a/app/config/languages.php b/app/config/languages.php new file mode 100644 index 000000000..5f0434b4d --- /dev/null +++ b/app/config/languages.php @@ -0,0 +1,936 @@ + "aa", + "name" => "Afar", + "nativeName" => "Afar" + ], + [ + "code" => "ab", + "name" => "Abkhazian", + "nativeName" => "Аҧсуа" + ], + [ + "code" => "af", + "name" => "Afrikaans", + "nativeName" => "Afrikaans" + ], + [ + "code" => "ak", + "name" => "Akan", + "nativeName" => "Akana" + ], + [ + "code" => "am", + "name" => "Amharic", + "nativeName" => "አማርኛ" + ], + [ + "code" => "an", + "name" => "Aragonese", + "nativeName" => "Aragonés" + ], + [ + "code" => "ar", + "name" => "Arabic", + "nativeName" => "العربية" + ], + [ + "code" => "as", + "name" => "Assamese", + "nativeName" => "অসমীয়া" + ], + [ + "code" => "av", + "name" => "Avar", + "nativeName" => "Авар" + ], + [ + "code" => "ay", + "name" => "Aymara", + "nativeName" => "Aymar" + ], + [ + "code" => "az", + "name" => "Azerbaijani", + "nativeName" => "Azərbaycanca / آذربايجان" + ], + [ + "code" => "ba", + "name" => "Bashkir", + "nativeName" => "Башҡорт" + ], + [ + "code" => "be", + "name" => "Belarusian", + "nativeName" => "Беларуская" + ], + [ + "code" => "bg", + "name" => "Bulgarian", + "nativeName" => "Български" + ], + [ + "code" => "bh", + "name" => "Bihari", + "nativeName" => "भोजपुरी" + ], + [ + "code" => "bi", + "name" => "Bislama", + "nativeName" => "Bislama" + ], + [ + "code" => "bm", + "name" => "Bambara", + "nativeName" => "Bamanankan" + ], + [ + "code" => "bn", + "name" => "Bengali", + "nativeName" => "বাংলা" + ], + [ + "code" => "bo", + "name" => "Tibetan", + "nativeName" => "བོད་ཡིག / Bod skad" + ], + [ + "code" => "br", + "name" => "Breton", + "nativeName" => "Brezhoneg" + ], + [ + "code" => "bs", + "name" => "Bosnian", + "nativeName" => "Bosanski" + ], + [ + "code" => "ca", + "name" => "Catalan", + "nativeName" => "Català" + ], + [ + "code" => "ce", + "name" => "Chechen", + "nativeName" => "Нохчийн" + ], + [ + "code" => "ch", + "name" => "Chamorro", + "nativeName" => "Chamoru" + ], + [ + "code" => "co", + "name" => "Corsican", + "nativeName" => "Corsu" + ], + [ + "code" => "cr", + "name" => "Cree", + "nativeName" => "Nehiyaw" + ], + [ + "code" => "cs", + "name" => "Czech", + "nativeName" => "Česky" + ], + [ + "code" => "cu", + "name" => "Old Church Slavonic / Old Bulgarian", + "nativeName" => "словѣньскъ / slověnĭskŭ" + ], + [ + "code" => "cv", + "name" => "Chuvash", + "nativeName" => "Чăваш" + ], + [ + "code" => "cy", + "name" => "Welsh", + "nativeName" => "Cymraeg" + ], + [ + "code" => "da", + "name" => "Danish", + "nativeName" => "Dansk" + ], + [ + "code" => "de", + "name" => "German", + "nativeName" => "Deutsch" + ], + [ + "code" => "dv", + "name" => "Divehi", + "nativeName" => "ދިވެހިބަސް" + ], + [ + "code" => "dz", + "name" => "Dzongkha", + "nativeName" => "ཇོང་ཁ" + ], + [ + "code" => "ee", + "name" => "Ewe", + "nativeName" => "Ɛʋɛ" + ], + [ + "code" => "el", + "name" => "Greek", + "nativeName" => "Ελληνικά" + ], + [ + "code" => "en", + "name" => "English", + "nativeName" => "English" + ], + [ + "code" => "eo", + "name" => "Esperanto", + "nativeName" => "Esperanto" + ], + [ + "code" => "es", + "name" => "Spanish", + "nativeName" => "Español" + ], + [ + "code" => "et", + "name" => "Estonian", + "nativeName" => "Eesti" + ], + [ + "code" => "eu", + "name" => "Basque", + "nativeName" => "Euskara" + ], + [ + "code" => "fa", + "name" => "Persian", + "nativeName" => "فارسی" + ], + [ + "code" => "ff", + "name" => "Peul", + "nativeName" => "Fulfulde" + ], + [ + "code" => "fi", + "name" => "Finnish", + "nativeName" => "Suomi" + ], + [ + "code" => "fj", + "name" => "Fijian", + "nativeName" => "Na Vosa Vakaviti" + ], + [ + "code" => "fo", + "name" => "Faroese", + "nativeName" => "Føroyskt" + ], + [ + "code" => "fr", + "name" => "French", + "nativeName" => "Français" + ], + [ + "code" => "fy", + "name" => "West Frisian", + "nativeName" => "Frysk" + ], + [ + "code" => "ga", + "name" => "Irish", + "nativeName" => "Gaeilge" + ], + [ + "code" => "gd", + "name" => "Scottish Gaelic", + "nativeName" => "Gàidhlig" + ], + [ + "code" => "gl", + "name" => "Galician", + "nativeName" => "Galego" + ], + [ + "code" => "gn", + "name" => "Guarani", + "nativeName" => "Avañe'ẽ" + ], + [ + "code" => "gu", + "name" => "Gujarati", + "nativeName" => "ગુજરાતી" + ], + [ + "code" => "gv", + "name" => "Manx", + "nativeName" => "Gaelg" + ], + [ + "code" => "ha", + "name" => "Hausa", + "nativeName" => "هَوُسَ" + ], + [ + "code" => "he", + "name" => "Hebrew", + "nativeName" => "עברית" + ], + [ + "code" => "hi", + "name" => "Hindi", + "nativeName" => "हिन्दी" + ], + [ + "code" => "ho", + "name" => "Hiri Motu", + "nativeName" => "Hiri Motu" + ], + [ + "code" => "hr", + "name" => "Croatian", + "nativeName" => "Hrvatski" + ], + [ + "code" => "ht", + "name" => "Haitian", + "nativeName" => "Krèyol ayisyen" + ], + [ + "code" => "hu", + "name" => "Hungarian", + "nativeName" => "Magyar" + ], + [ + "code" => "hy", + "name" => "Armenian", + "nativeName" => "Հայերեն" + ], + [ + "code" => "hz", + "name" => "Herero", + "nativeName" => "Otsiherero" + ], + [ + "code" => "ia", + "name" => "Interlingua", + "nativeName" => "Interlingua" + ], + [ + "code" => "id", + "name" => "Indonesian", + "nativeName" => "Bahasa Indonesia" + ], + [ + "code" => "ie", + "name" => "Interlingue", + "nativeName" => "Interlingue" + ], + [ + "code" => "ig", + "name" => "Igbo", + "nativeName" => "Igbo" + ], + [ + "code" => "ii", + "name" => "Sichuan Yi", + "nativeName" => "ꆇꉙ / 四川彝语" + ], + [ + "code" => "ik", + "name" => "Inupiak", + "nativeName" => "Iñupiak" + ], + [ + "code" => "io", + "name" => "Ido", + "nativeName" => "Ido" + ], + [ + "code" => "is", + "name" => "Icelandic", + "nativeName" => "Íslenska" + ], + [ + "code" => "it", + "name" => "Italian", + "nativeName" => "Italiano" + ], + [ + "code" => "iu", + "name" => "Inuktitut", + "nativeName" => "ᐃᓄᒃᑎᑐᑦ" + ], + [ + "code" => "ja", + "name" => "Japanese", + "nativeName" => "日本語" + ], + [ + "code" => "jv", + "name" => "Javanese", + "nativeName" => "Basa Jawa" + ], + [ + "code" => "ka", + "name" => "Georgian", + "nativeName" => "ქართული" + ], + [ + "code" => "kg", + "name" => "Kongo", + "nativeName" => "KiKongo" + ], + [ + "code" => "ki", + "name" => "Kikuyu", + "nativeName" => "Gĩkũyũ" + ], + [ + "code" => "kj", + "name" => "Kuanyama", + "nativeName" => "Kuanyama" + ], + [ + "code" => "kk", + "name" => "Kazakh", + "nativeName" => "Қазақша" + ], + [ + "code" => "kl", + "name" => "Greenlandic", + "nativeName" => "Kalaallisut" + ], + [ + "code" => "km", + "name" => "Cambodian", + "nativeName" => "ភាសាខ្មែរ" + ], + [ + "code" => "kn", + "name" => "Kannada", + "nativeName" => "ಕನ್ನಡ" + ], + [ + "code" => "ko", + "name" => "Korean", + "nativeName" => "한국어" + ], + [ + "code" => "kr", + "name" => "Kanuri", + "nativeName" => "Kanuri" + ], + [ + "code" => "ks", + "name" => "Kashmiri", + "nativeName" => "कश्मीरी / كشميري" + ], + [ + "code" => "ku", + "name" => "Kurdish", + "nativeName" => "Kurdî / كوردی" + ], + [ + "code" => "kv", + "name" => "Komi", + "nativeName" => "Коми" + ], + [ + "code" => "kw", + "name" => "Cornish", + "nativeName" => "Kernewek" + ], + [ + "code" => "ky", + "name" => "Kirghiz", + "nativeName" => "Kırgızca / Кыргызча" + ], + [ + "code" => "la", + "name" => "Latin", + "nativeName" => "Latina" + ], + [ + "code" => "lb", + "name" => "Luxembourgish", + "nativeName" => "Lëtzebuergesch" + ], + [ + "code" => "lg", + "name" => "Ganda", + "nativeName" => "Luganda" + ], + [ + "code" => "li", + "name" => "Limburgian", + "nativeName" => "Limburgs" + ], + [ + "code" => "ln", + "name" => "Lingala", + "nativeName" => "Lingála" + ], + [ + "code" => "lo", + "name" => "Laotian", + "nativeName" => "ລາວ / Pha xa lao" + ], + [ + "code" => "lt", + "name" => "Lithuanian", + "nativeName" => "Lietuvių" + ], + [ + "code" => "lu", + "name" => "Luba-Katanga", + "nativeName" => "Tshiluba" + ], + [ + "code" => "lv", + "name" => "Latvian", + "nativeName" => "Latviešu" + ], + [ + "code" => "mg", + "name" => "Malagasy", + "nativeName" => "Malagasy" + ], + [ + "code" => "mh", + "name" => "Marshallese", + "nativeName" => "Kajin Majel / Ebon" + ], + [ + "code" => "mi", + "name" => "Maori", + "nativeName" => "Māori" + ], + [ + "code" => "mk", + "name" => "Macedonian", + "nativeName" => "Македонски" + ], + [ + "code" => "ml", + "name" => "Malayalam", + "nativeName" => "മലയാളം" + ], + [ + "code" => "mn", + "name" => "Mongolian", + "nativeName" => "Монгол" + ], + [ + "code" => "mo", + "name" => "Moldovan", + "nativeName" => "Moldovenească" + ], + [ + "code" => "mr", + "name" => "Marathi", + "nativeName" => "मराठी" + ], + [ + "code" => "ms", + "name" => "Malay", + "nativeName" => "Bahasa Melayu" + ], + [ + "code" => "mt", + "name" => "Maltese", + "nativeName" => "bil-Malti" + ], + [ + "code" => "my", + "name" => "Burmese", + "nativeName" => "မြန်မာစာ" + ], + [ + "code" => "na", + "name" => "Nauruan", + "nativeName" => "Dorerin Naoero" + ], + [ + "code" => "nb", + "name" => "Norwegian Bokmål", + "nativeName" => "Norsk bokmål" + ], + [ + "code" => "nd", + "name" => "North Ndebele", + "nativeName" => "Sindebele" + ], + [ + "code" => "ne", + "name" => "Nepali", + "nativeName" => "नेपाली" + ], + [ + "code" => "ng", + "name" => "Ndonga", + "nativeName" => "Oshiwambo" + ], + [ + "code" => "nl", + "name" => "Dutch", + "nativeName" => "Nederlands" + ], + [ + "code" => "nn", + "name" => "Norwegian Nynorsk", + "nativeName" => "Norsk nynorsk" + ], + [ + "code" => "no", + "name" => "Norwegian", + "nativeName" => "Norsk" + ], + [ + "code" => "nr", + "name" => "South Ndebele", + "nativeName" => "isiNdebele" + ], + [ + "code" => "nv", + "name" => "Navajo", + "nativeName" => "Diné bizaad" + ], + [ + "code" => "ny", + "name" => "Chichewa", + "nativeName" => "Chi-Chewa" + ], + [ + "code" => "oc", + "name" => "Occitan", + "nativeName" => "Occitan" + ], + [ + "code" => "oj", + "name" => "Ojibwa", + "nativeName" => "ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin" + ], + [ + "code" => "om", + "name" => "Oromo", + "nativeName" => "Oromoo" + ], + [ + "code" => "or", + "name" => "Oriya", + "nativeName" => "ଓଡ଼ିଆ" + ], + [ + "code" => "os", + "name" => "Ossetian / Ossetic", + "nativeName" => "Иронау" + ], + [ + "code" => "pa", + "name" => "Panjabi / Punjabi", + "nativeName" => "ਪੰਜਾਬੀ / पंजाबी / پنجابي" + ], + [ + "code" => "pi", + "name" => "Pali", + "nativeName" => "Pāli / पाऴि" + ], + [ + "code" => "pl", + "name" => "Polish", + "nativeName" => "Polski" + ], + [ + "code" => "ps", + "name" => "Pashto", + "nativeName" => "پښتو" + ], + [ + "code" => "pt", + "name" => "Portuguese", + "nativeName" => "Português" + ], + [ + "code" => "qu", + "name" => "Quechua", + "nativeName" => "Runa Simi" + ], + [ + "code" => "rm", + "name" => "Raeto Romance", + "nativeName" => "Rumantsch" + ], + [ + "code" => "rn", + "name" => "Kirundi", + "nativeName" => "Kirundi" + ], + [ + "code" => "ro", + "name" => "Romanian", + "nativeName" => "Română" + ], + [ + "code" => "ru", + "name" => "Russian", + "nativeName" => "Русский" + ], + [ + "code" => "rw", + "name" => "Rwandi", + "nativeName" => "Kinyarwandi" + ], + [ + "code" => "sa", + "name" => "Sanskrit", + "nativeName" => "संस्कृतम्" + ], + [ + "code" => "sc", + "name" => "Sardinian", + "nativeName" => "Sardu" + ], + [ + "code" => "sd", + "name" => "Sindhi", + "nativeName" => "सिनधि" + ], + [ + "code" => "se", + "name" => "Northern Sami", + "nativeName" => "Sámegiella" + ], + [ + "code" => "sg", + "name" => "Sango", + "nativeName" => "Sängö" + ], + [ + "code" => "sh", + "name" => "Serbo-Croatian", + "nativeName" => "Srpskohrvatski / Српскохрватски" + ], + [ + "code" => "si", + "name" => "Sinhalese", + "nativeName" => "සිංහල" + ], + [ + "code" => "sk", + "name" => "Slovak", + "nativeName" => "Slovenčina" + ], + [ + "code" => "sl", + "name" => "Slovenian", + "nativeName" => "Slovenščina" + ], + [ + "code" => "sm", + "name" => "Samoan", + "nativeName" => "Gagana Samoa" + ], + [ + "code" => "sn", + "name" => "Shona", + "nativeName" => "chiShona" + ], + [ + "code" => "so", + "name" => "Somalia", + "nativeName" => "Soomaaliga" + ], + [ + "code" => "sq", + "name" => "Albanian", + "nativeName" => "Shqip" + ], + [ + "code" => "sr", + "name" => "Serbian", + "nativeName" => "Српски" + ], + [ + "code" => "ss", + "name" => "Swati", + "nativeName" => "SiSwati" + ], + [ + "code" => "st", + "name" => "Southern Sotho", + "nativeName" => "Sesotho" + ], + [ + "code" => "su", + "name" => "Sundanese", + "nativeName" => "Basa Sunda" + ], + [ + "code" => "sv", + "name" => "Swedish", + "nativeName" => "Svenska" + ], + [ + "code" => "sw", + "name" => "Swahili", + "nativeName" => "Kiswahili" + ], + [ + "code" => "ta", + "name" => "Tamil", + "nativeName" => "தமிழ்" + ], + [ + "code" => "te", + "name" => "Telugu", + "nativeName" => "తెలుగు" + ], + [ + "code" => "tg", + "name" => "Tajik", + "nativeName" => "Тоҷикӣ" + ], + [ + "code" => "th", + "name" => "Thai", + "nativeName" => "ไทย / Phasa Thai" + ], + [ + "code" => "ti", + "name" => "Tigrinya", + "nativeName" => "ትግርኛ" + ], + [ + "code" => "tk", + "name" => "Turkmen", + "nativeName" => "Туркмен / تركمن" + ], + [ + "code" => "tl", + "name" => "Tagalog / Filipino", + "nativeName" => "Tagalog" + ], + [ + "code" => "tn", + "name" => "Tswana", + "nativeName" => "Setswana" + ], + [ + "code" => "to", + "name" => "Tonga", + "nativeName" => "Lea Faka-Tonga" + ], + [ + "code" => "tr", + "name" => "Turkish", + "nativeName" => "Türkçe" + ], + [ + "code" => "ts", + "name" => "Tsonga", + "nativeName" => "Xitsonga" + ], + [ + "code" => "tt", + "name" => "Tatar", + "nativeName" => "Tatarça" + ], + [ + "code" => "tw", + "name" => "Twi", + "nativeName" => "Twi" + ], + [ + "code" => "ty", + "name" => "Tahitian", + "nativeName" => "Reo Mā`ohi" + ], + [ + "code" => "ug", + "name" => "Uyghur", + "nativeName" => "Uyƣurqə / ئۇيغۇرچە" + ], + [ + "code" => "uk", + "name" => "Ukrainian", + "nativeName" => "Українська" + ], + [ + "code" => "ur", + "name" => "Urdu", + "nativeName" => "اردو" + ], + [ + "code" => "uz", + "name" => "Uzbek", + "nativeName" => "Ўзбек" + ], + [ + "code" => "ve", + "name" => "Venda", + "nativeName" => "Tshivenḓa" + ], + [ + "code" => "vi", + "name" => "Vietnamese", + "nativeName" => "Tiếng Việt" + ], + [ + "code" => "vo", + "name" => "Volapük", + "nativeName" => "Volapük" + ], + [ + "code" => "wa", + "name" => "Walloon", + "nativeName" => "Walon" + ], + [ + "code" => "wo", + "name" => "Wolof", + "nativeName" => "Wollof" + ], + [ + "code" => "xh", + "name" => "Xhosa", + "nativeName" => "isiXhosa" + ], + [ + "code" => "yi", + "name" => "Yiddish", + "nativeName" => "ייִדיש" + ], + [ + "code" => "yo", + "name" => "Yoruba", + "nativeName" => "Yorùbá" + ], + [ + "code" => "za", + "name" => "Zhuang", + "nativeName" => "Cuengh / Tôô / 壮语" + ], + [ + "code" => "zh", + "name" => "Chinese", + "nativeName" => "中文" + ], + [ + "code" => "zu", + "name" => "Zulu", + "nativeName" => "isiZulu" + ] +]; diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 8f4f2e327..72da12222 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -165,3 +165,19 @@ $utopia->get('/v1/locale/currencies') $response->json($currencies); } ); + + +$utopia->get('/v1/locale/languages') + ->desc('List Languages') + ->label('scope', 'locale.read') + ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) + ->label('sdk.namespace', 'locale') + ->label('sdk.method', 'getLanguages') + ->label('sdk.description', '/docs/references/locale/get-languages.md') + ->action( + function () use ($response) { + $currencies = include __DIR__.'/../../config/languages.php'; + + $response->json($currencies); + } + ); \ No newline at end of file diff --git a/docs/references/locale/get-languages.md b/docs/references/locale/get-languages.md new file mode 100644 index 000000000..b9d8302f9 --- /dev/null +++ b/docs/references/locale/get-languages.md @@ -0,0 +1 @@ +List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language. \ No newline at end of file From a331eb769ae2c31e1a5e601351a7715cf8e0d9bf Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 14:20:56 +0200 Subject: [PATCH 02/40] fix typo in getCurrencies description --- docs/references/locale/get-currencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/references/locale/get-currencies.md b/docs/references/locale/get-currencies.md index e6c525cc9..0bd698d6b 100644 --- a/docs/references/locale/get-currencies.md +++ b/docs/references/locale/get-currencies.md @@ -1 +1 @@ -List of all currencies, including currency symol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language. \ No newline at end of file +List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language. \ No newline at end of file From 65f63bb769abba65b07413b2d6890c151c9becca Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 14:31:48 +0200 Subject: [PATCH 03/40] refactor variables to languages --- app/controllers/api/locale.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 72da12222..64978ac35 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -176,8 +176,8 @@ $utopia->get('/v1/locale/languages') ->label('sdk.description', '/docs/references/locale/get-languages.md') ->action( function () use ($response) { - $currencies = include __DIR__.'/../../config/languages.php'; + $languages = include __DIR__.'/../../config/languages.php'; - $response->json($currencies); + $response->json($languages); } ); \ No newline at end of file From d01373d8d4d48b92092c976849581c0ea332e4ab Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 15:07:05 +0200 Subject: [PATCH 04/40] add e2e tests for locale/languages --- tests/e2e/Services/Locale/LocaleBase.php | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/e2e/Services/Locale/LocaleBase.php b/tests/e2e/Services/Locale/LocaleBase.php index 5a3df45b2..863ab1757 100644 --- a/tests/e2e/Services/Locale/LocaleBase.php +++ b/tests/e2e/Services/Locale/LocaleBase.php @@ -183,6 +183,35 @@ trait LocaleBase return []; } + public function testGetLanguages():array + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/locale/langauges', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertIsArray($response['body']); + $this->assertCount(184, $response['body']); + + $this->assertEquals($response['body'][0]['code'], 'aa'); + $this->assertEquals($response['body'][0]['name'], 'Afar'); + $this->assertEquals($response['body'][0]['nativeName'], 'Afar'); + + $this->assertEquals($response['body'][183]['code'], 'zu'); + $this->assertEquals($response['body'][183]['name'], 'Zulu'); + $this->assertEquals($response['body'][183]['nativeName'], 'isiZulu'); + + /** + * Test for FAILURE + */ + + return []; + } + public function testLangaugaes(): array { /** From b86ef1a0259cdc1a30a6a6efd5e96c159be4868b Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 15:16:56 +0200 Subject: [PATCH 05/40] fix typo on e2e tests --- tests/e2e/Services/Locale/LocaleBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Locale/LocaleBase.php b/tests/e2e/Services/Locale/LocaleBase.php index 863ab1757..d07f8e67f 100644 --- a/tests/e2e/Services/Locale/LocaleBase.php +++ b/tests/e2e/Services/Locale/LocaleBase.php @@ -188,7 +188,7 @@ trait LocaleBase /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/locale/langauges', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/locale/languages', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); From ea2130774f9f62f51e3c622a3f9a35d3a032165d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 24 May 2020 15:28:42 +0200 Subject: [PATCH 06/40] update array length in e2e test --- tests/e2e/Services/Locale/LocaleBase.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/Services/Locale/LocaleBase.php b/tests/e2e/Services/Locale/LocaleBase.php index d07f8e67f..20fb91b25 100644 --- a/tests/e2e/Services/Locale/LocaleBase.php +++ b/tests/e2e/Services/Locale/LocaleBase.php @@ -195,15 +195,15 @@ trait LocaleBase $this->assertEquals($response['headers']['status-code'], 200); $this->assertIsArray($response['body']); - $this->assertCount(184, $response['body']); + $this->assertCount(185, $response['body']); $this->assertEquals($response['body'][0]['code'], 'aa'); $this->assertEquals($response['body'][0]['name'], 'Afar'); $this->assertEquals($response['body'][0]['nativeName'], 'Afar'); - $this->assertEquals($response['body'][183]['code'], 'zu'); - $this->assertEquals($response['body'][183]['name'], 'Zulu'); - $this->assertEquals($response['body'][183]['nativeName'], 'isiZulu'); + $this->assertEquals($response['body'][184]['code'], 'zu'); + $this->assertEquals($response['body'][184]['name'], 'Zulu'); + $this->assertEquals($response['body'][184]['nativeName'], 'isiZulu'); /** * Test for FAILURE From 1c7cb37efe9d1512ea338f0e9948649ccf63611c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 07:18:02 +0300 Subject: [PATCH 07/40] Added a new team page --- app/controllers/web/console.php | 18 +++++++++++++++--- app/views/console/users/index.phtml | 2 +- .../console/users/{view.phtml => user.phtml} | 6 +++--- public/scripts/routes.js | 18 ++++++++++++++---- 4 files changed, 33 insertions(+), 11 deletions(-) rename app/views/console/users/{view.phtml => user.phtml} (98%) diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index 480c4ff9b..fcf483735 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -277,14 +277,26 @@ $utopia->get('/console/users') ->setParam('body', $page); }); -$utopia->get('/console/users/view') +$utopia->get('/console/users/user') ->desc('Platform console project user') ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { - $page = new View(__DIR__.'/../../views/console/users/view.phtml'); + $page = new View(__DIR__.'/../../views/console/users/user.phtml'); $layout - ->setParam('title', APP_NAME.' - View User') + ->setParam('title', APP_NAME.' - User') + ->setParam('body', $page); + }); + +$utopia->get('/console/users/team') + ->desc('Platform console project team') + ->label('permission', 'public') + ->label('scope', 'console') + ->action(function () use ($layout) { + $page = new View(__DIR__.'/../../views/console/users/team.phtml'); + + $layout + ->setParam('title', APP_NAME.' - Team') ->setParam('body', $page); }); diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index f4b6282bc..1968016c5 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -107,7 +107,7 @@ $providers = $this->getParam('providers', []); User Avatar - + ----- diff --git a/app/views/console/users/view.phtml b/app/views/console/users/user.phtml similarity index 98% rename from app/views/console/users/view.phtml rename to app/views/console/users/user.phtml index 8089fde0c..18ca82134 100644 --- a/app/views/console/users/view.phtml +++ b/app/views/console/users/user.phtml @@ -30,7 +30,7 @@
    -
  • +
  • General

-
  • +
  • Devices

  • -
  • +
  • Activity

    Date: Sun, 7 Jun 2020 07:18:19 +0300 Subject: [PATCH 08/40] New team page routes --- public/dist/scripts/app-all.js | 2 +- public/dist/scripts/app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index 8acc3d90d..a6cf4fb16 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -2532,7 +2532,7 @@ return slf.renderToken(tokens,idx,opts);} md.renderer.rules.strong_open=renderEm;md.renderer.rules.strong_close=renderEm;return md;},true);})(window);(function(window){"use strict";window.ls.container.set('rtl',function(){var rtlStock="^ا^ب^ت^ث^ج^ح^خ^د^ذ^ر^ز^س^ش^ص^ض^ط^ظ^ع^غ^ف^ق^ك^ل^م^ن^ه^و^ي^א^ב^ג^ד^ה^ו^ז^ח^ט^י^כ^ך^ל^מ^ם^נ^ן^ס^ע^פ^ף^צ^ץ^ק^ר^ש^ת^";var special=["\n"," "," ","״",'"',"_","'","!","@","#","$","^","&","%","*","(",")","+","=","-","[","]","\\","/","{","}","|",":","<",">","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;iUnknown + +
    + + + +
    +
      +
    • +

      General

      + + + +
      +
      + + +
      +
      + User Avatar + +
      +
      + + Verified + + + Unverified + +
      +
      +
      +
      + +

      Members

      + + +
      +
      + +
      + +
      + +
        +
      • +
      + +
      +
      + + +
      +
      + +
      +
      + + +
      +
      +
      +
      +
    • +
    • +

      Devices

      + +
      + + + +
      +
      +
        +
      • +
        + + + + +
        + + + + on + +
        + + / +
        +
      • +
      +
      + +
      + + +
      +
      +
      + +
    • +
    • +

      Activity

      + +
      + + + + +
      +
    • +
    +
    + \ No newline at end of file From 9083ea0cdca94082797df7e979cb418f45d7fe7b Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 08:57:04 +0300 Subject: [PATCH 10/40] Updated routes --- app/controllers/web/console.php | 2 +- app/views/console/users/index.phtml | 31 ++--------------------------- public/dist/scripts/app-all.js | 2 +- public/dist/scripts/app.js | 2 +- public/scripts/routes.js | 8 ++++---- 5 files changed, 9 insertions(+), 36 deletions(-) diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index fcf483735..d90966ba7 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -289,7 +289,7 @@ $utopia->get('/console/users/user') ->setParam('body', $page); }); -$utopia->get('/console/users/team') +$utopia->get('/console/users/teams/team') ->desc('Platform console project team') ->label('permission', 'public') ->label('scope', 'console') diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index 1968016c5..993d4f967 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -253,36 +253,9 @@ $providers = $this->getParam('providers', []); Collection Avatar - + + diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index a6cf4fb16..3f80fda24 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -2532,7 +2532,7 @@ return slf.renderToken(tokens,idx,opts);} md.renderer.rules.strong_open=renderEm;md.renderer.rules.strong_close=renderEm;return md;},true);})(window);(function(window){"use strict";window.ls.container.set('rtl',function(){var rtlStock="^ا^ب^ت^ث^ج^ح^خ^د^ذ^ر^ز^س^ش^ص^ض^ط^ظ^ع^غ^ف^ق^ك^ل^م^ن^ه^و^ي^א^ב^ג^ד^ה^ו^ז^ח^ט^י^כ^ך^ל^מ^ם^נ^ן^ס^ע^פ^ף^צ^ץ^ק^ר^ש^ת^";var special=["\n"," "," ","״",'"',"_","'","!","@","#","$","^","&","%","*","(",")","+","=","-","[","]","\\","/","{","}","|",":","<",">","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i @@ -468,10 +468,10 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false); data-event="submit" data-loading="Sending invitation, please wait..." data-success="alert,trigger,reset" - data-success-param-alert-text="Invitation Sent Successfully" + data-success-param-alert-text="Invitation sent successfully" data-success-param-trigger-events="teams.createMembership" data-failure="alert" - data-failure-param-alert-text="Failed to Send Invite" + data-failure-param-alert-text="Failed to send invite" data-failure-param-alert-classname="error"> diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 15c1b658e..c10fdad43 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -33,10 +33,6 @@
  • General

    - -
    @@ -72,24 +68,22 @@
  • -
    -
    + - -
    -
    + +
    diff --git a/app/views/console/users/user.phtml b/app/views/console/users/user.phtml index 18ca82134..d256c4e2b 100644 --- a/app/views/console/users/user.phtml +++ b/app/views/console/users/user.phtml @@ -113,10 +113,10 @@ data-event="submit" data-param-user-id="{{router.params.id}}" data-success="alert,trigger" - data-success-param-alert-text="Blocked User Successfully" + data-success-param-alert-text="Blocked user successfully" data-success-param-trigger-events="users.update" data-failure="alert" - data-failure-param-alert-text="Failed to Block User" + data-failure-param-alert-text="Failed to block user" data-failure-param-alert-classname="error"> @@ -132,10 +132,10 @@ data-event="submit" data-param-user-id="{{router.params.id}}" data-success="alert,trigger" - data-success-param-alert-text="Activated User Successfully" + data-success-param-alert-text="Activated user successfully" data-success-param-trigger-events="users.update" data-failure="alert" - data-failure-param-alert-text="Failed to Activate User" + data-failure-param-alert-text="Failed to activate user" data-failure-param-alert-classname="error"> diff --git a/app/views/home/auth/join.phtml b/app/views/home/auth/join.phtml index 5996ff77b..e5c0f6e72 100644 --- a/app/views/home/auth/join.phtml +++ b/app/views/home/auth/join.phtml @@ -12,7 +12,7 @@ data-param-secret="{{router.params.secret}}" data-success="redirect,alert,trigger" data-success-param-redirect-url="/console?project={{router.params.project}}" - data-success-param-alert-text="Joined Team Successfully" + data-success-param-alert-text="Joined team successfully" data-success-param-trigger-events="teams.updateMembershipStatus" data-failure="redirect,alert" data-success-param-redirect-url="/console" From 2afb5776c01c177f670f933991a25f6843b57d12 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 10:48:06 +0300 Subject: [PATCH 12/40] Added option to update team name --- app/views/console/users/index.phtml | 4 +- app/views/console/users/team.phtml | 171 +++++----------------------- 2 files changed, 28 insertions(+), 147 deletions(-) diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index 993d4f967..c3ae2ee3e 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -253,9 +253,7 @@ $providers = $this->getParam('providers', []); Collection Avatar - - - + diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index c10fdad43..285c8957f 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -30,28 +30,37 @@
      -
    • +
    • General

      - -
      + +
      -
      - User Avatar + -
      -
      - - Verified - - - Unverified - -
      -
      -
      + + + + + +
      + + +

      Members

      @@ -66,6 +75,7 @@
      • +
      • Created:
      Delete Team
      - -
      -
      - - -
      -
      -
      -
      -
    • -
    • -

      Devices

      - -
      - - - -
      -
      -
        -
      • -
        - - - - -
        - - - - on - -
        - - / -
        -
      • -
      -
      - -
      - - -
      -
      -
      - -
    • -
    • -

      Activity

      - -
      - - - -
    • +
    \ No newline at end of file From 950a66f294884d5226ca8b053288cc4f4320cab8 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 11:09:05 +0300 Subject: [PATCH 13/40] #380 added option to delete team from the console --- app/views/console/users/team.phtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 285c8957f..23140221c 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -81,13 +81,15 @@
    From fb2663745d47ec59cf6144fbfda67162edaf5c2a Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 12:29:51 +0300 Subject: [PATCH 14/40] Updated Team UI --- CHANGES.md | 5 +- app/controllers/api/teams.php | 23 ++++---- app/views/console/settings/index.phtml | 2 +- app/views/console/users/team.phtml | 74 ++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6fcb7b9cd..5ea597b6a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,8 +2,11 @@ ## Features -- New route in Locale API to fetch a list of languages +- Added a new route in Locale API to fetch a list of languages - Added Google Fonts to Appwrite for offline availability +- Added option to delete team from the console +- Added option to view team members from the console +- Added option to join a user to any team from the console ## Bug Fixes diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index fad09b695..89f1ff0df 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -371,8 +371,12 @@ $utopia->get('/v1/teams/:teamId/memberships') ->label('sdk.method', 'getMemberships') ->label('sdk.description', '/docs/references/teams/get-team-members.md') ->param('teamId', '', function () { return new UID(); }, 'Team unique ID.') + ->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true) ->action( - function ($teamId) use ($response, $projectDB) { + function ($teamId, $search, $limit, $offset, $orderType) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { @@ -380,8 +384,12 @@ $utopia->get('/v1/teams/:teamId/memberships') } $memberships = $projectDB->getCollection([ - 'limit' => 50, - 'offset' => 0, + 'limit' => $limit, + 'offset' => $offset, + 'orderField' => 'joined', + 'orderType' => $orderType, + 'orderCast' => 'int', + 'search' => $search, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, 'teamId='.$teamId, @@ -408,15 +416,8 @@ $utopia->get('/v1/teams/:teamId/memberships') ])); } - usort($users, function ($a, $b) { - if ($a['joined'] === 0 || $b['joined'] === 0) { - return $b['joined'] - $a['joined']; - } + $response->json(['sum' => $projectDB->getSum(), 'memberships' => $users]); - return $a['joined'] - $b['joined']; - }); - - $response->json($users); } ); diff --git a/app/views/console/settings/index.phtml b/app/views/console/settings/index.phtml index 34ac7bcca..a52c74fd4 100644 --- a/app/views/console/settings/index.phtml +++ b/app/views/console/settings/index.phtml @@ -383,7 +383,7 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false); data-success-param-trigger-events="teams.getMemberships">
    -
      +
      • Members +
        +
        +

        No Memberships Found

        + +

        Create your first team member to get started

        +
        + +
        +
        results found
        + +
        + + + + + + + + + + + + + + + + + +
        NameMembersCreated
        + Collection Avatar + + +
        +
        +
        + +
        + + + + + + +
        + +
        +
        +
    From 0e6f36d78de295f41f96f40adf3e7b5eae6a8da0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 7 Jun 2020 15:29:12 +0300 Subject: [PATCH 15/40] Added invite form --- app/views/console/users/team.phtml | 34 +++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 45d98ebdd..c31afd222 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -110,7 +110,39 @@
    -
    + + +
    Date: Mon, 8 Jun 2020 07:38:39 +0300 Subject: [PATCH 16/40] Updated Console SDK --- app/sdks/client-web/README.md | 2 +- .../examples/account/create-o-auth2session.md | 2 +- app/sdks/client-web/src/sdk.js | 45 +- app/sdks/client-web/src/sdk.min.js | 8 +- app/sdks/client-web/types/index.d.ts | 29 +- app/sdks/console-web/README.md | 2 +- .../examples/account/create-o-auth2session.md | 2 +- .../docs/examples/projects/update-o-auth2.md | 2 +- app/sdks/console-web/src/sdk.js | 45 +- app/sdks/console-web/src/sdk.min.js | 8 +- app/sdks/console-web/types/index.d.ts | 29 +- public/dist/scripts/app-all.js | 39 +- public/dist/scripts/app-dep.js | 36 +- public/dist/scripts/app.js | 3 +- public/scripts/dependencies/appwrite.js | 490 ++++++++++++++---- 15 files changed, 546 insertions(+), 196 deletions(-) diff --git a/app/sdks/client-web/README.md b/app/sdks/client-web/README.md index e59480b4a..093783ab4 100644 --- a/app/sdks/client-web/README.md +++ b/app/sdks/client-web/README.md @@ -1,7 +1,7 @@ # Appwrite Web SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-js.svg?v=1) -![Version](https://img.shields.io/badge/api%20version-0.6.1-blue.svg?v=1) +![Version](https://img.shields.io/badge/api%20version-0.6.2-blue.svg?v=1) Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Web SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. diff --git a/app/sdks/client-web/docs/examples/account/create-o-auth2session.md b/app/sdks/client-web/docs/examples/account/create-o-auth2session.md index 5cc825a27..0c7430741 100644 --- a/app/sdks/client-web/docs/examples/account/create-o-auth2session.md +++ b/app/sdks/client-web/docs/examples/account/create-o-auth2session.md @@ -5,7 +5,7 @@ sdk .setProject('5df5acd0d48c2') // Your project ID ; -let promise = sdk.account.createOAuth2Session('bitbucket'); +let promise = sdk.account.createOAuth2Session('amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/client-web/src/sdk.js b/app/sdks/client-web/src/sdk.js index 0d7a7deaa..a423ae9cf 100644 --- a/app/sdks/client-web/src/sdk.js +++ b/app/sdks/client-web/src/sdk.js @@ -276,10 +276,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -522,7 +522,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -563,7 +563,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -772,7 +772,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -1168,7 +1168,10 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -1942,10 +1945,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -1954,6 +1961,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -1969,8 +1992,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/client-web/src/sdk.min.js b/app/sdks/client-web/src/sdk.min.js index 113a3402b..bef842f31 100644 --- a/app/sdks/client-web/src/sdk.min.js +++ b/app/sdks/client-web/src/sdk.min.js @@ -148,8 +148,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"')} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload.name=name} return http.put(path,{'content-type':'application/json',},payload)},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload.search=search} +if(limit){payload.limit=limit} +if(offset){payload.offset=offset} +if(orderType){payload.orderType=orderType} +return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} if(email===undefined){throw new Error('Missing required parameter: "email"')} if(roles===undefined){throw new Error('Missing required parameter: "roles"')} if(url===undefined){throw new Error('Missing required parameter: "url"')} diff --git a/app/sdks/client-web/types/index.d.ts b/app/sdks/client-web/types/index.d.ts index f2bc108bc..2715af9f8 100644 --- a/app/sdks/client-web/types/index.d.ts +++ b/app/sdks/client-web/types/index.d.ts @@ -64,10 +64,10 @@ declare namespace Appwrite { * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -170,7 +170,7 @@ declare namespace Appwrite { * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -186,7 +186,7 @@ declare namespace Appwrite { * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -276,7 +276,7 @@ declare namespace Appwrite { * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -431,7 +431,10 @@ declare namespace Appwrite { /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -758,10 +761,14 @@ declare namespace Appwrite { * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships(teamId: string): Promise; + getMemberships(teamId: string, search: string, limit: number, offset: number, orderType: string): Promise; /** * Create Team Membership @@ -772,8 +779,8 @@ declare namespace Appwrite { * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/console-web/README.md b/app/sdks/console-web/README.md index 8d44e2769..68b7e8ff9 100644 --- a/app/sdks/console-web/README.md +++ b/app/sdks/console-web/README.md @@ -1,7 +1,7 @@ # Appwrite Console SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-console.svg?v=1) -![Version](https://img.shields.io/badge/api%20version-0.6.1-blue.svg?v=1) +![Version](https://img.shields.io/badge/api%20version-0.6.2-blue.svg?v=1) Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Console SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. diff --git a/app/sdks/console-web/docs/examples/account/create-o-auth2session.md b/app/sdks/console-web/docs/examples/account/create-o-auth2session.md index bea25a368..4a3523693 100644 --- a/app/sdks/console-web/docs/examples/account/create-o-auth2session.md +++ b/app/sdks/console-web/docs/examples/account/create-o-auth2session.md @@ -6,7 +6,7 @@ sdk .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key ; -let promise = sdk.account.createOAuth2Session('bitbucket'); +let promise = sdk.account.createOAuth2Session('amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/console-web/docs/examples/projects/update-o-auth2.md b/app/sdks/console-web/docs/examples/projects/update-o-auth2.md index 4a82548a6..479c5e9d3 100644 --- a/app/sdks/console-web/docs/examples/projects/update-o-auth2.md +++ b/app/sdks/console-web/docs/examples/projects/update-o-auth2.md @@ -6,7 +6,7 @@ sdk .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key ; -let promise = sdk.projects.updateOAuth2('[PROJECT_ID]', 'bitbucket'); +let promise = sdk.projects.updateOAuth2('[PROJECT_ID]', 'amazon'); promise.then(function (response) { console.log(response); // Success diff --git a/app/sdks/console-web/src/sdk.js b/app/sdks/console-web/src/sdk.js index 86e219cde..08f0501f2 100644 --- a/app/sdks/console-web/src/sdk.js +++ b/app/sdks/console-web/src/sdk.js @@ -312,10 +312,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -558,7 +558,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -599,7 +599,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -810,7 +810,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -1421,7 +1421,10 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -3753,10 +3756,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -3765,6 +3772,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -3780,8 +3803,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/app/sdks/console-web/src/sdk.min.js b/app/sdks/console-web/src/sdk.min.js index b43f612ff..f0951f503 100644 --- a/app/sdks/console-web/src/sdk.min.js +++ b/app/sdks/console-web/src/sdk.min.js @@ -319,8 +319,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"')} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload.name=name} return http.put(path,{'content-type':'application/json',},payload)},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload)},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload.search=search} +if(limit){payload.limit=limit} +if(offset){payload.offset=offset} +if(orderType){payload.orderType=orderType} +return http.get(path,{'content-type':'application/json',},payload)},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"')} if(email===undefined){throw new Error('Missing required parameter: "email"')} if(roles===undefined){throw new Error('Missing required parameter: "roles"')} if(url===undefined){throw new Error('Missing required parameter: "url"')} diff --git a/app/sdks/console-web/types/index.d.ts b/app/sdks/console-web/types/index.d.ts index 08f42c7cf..65da15001 100644 --- a/app/sdks/console-web/types/index.d.ts +++ b/app/sdks/console-web/types/index.d.ts @@ -85,10 +85,10 @@ declare namespace Appwrite { * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -191,7 +191,7 @@ declare namespace Appwrite { * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -207,7 +207,7 @@ declare namespace Appwrite { * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -297,7 +297,7 @@ declare namespace Appwrite { * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -522,7 +522,10 @@ declare namespace Appwrite { /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data @@ -1402,10 +1405,14 @@ declare namespace Appwrite { * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships(teamId: string): Promise; + getMemberships(teamId: string, search: string, limit: number, offset: number, orderType: string): Promise; /** * Create Team Membership @@ -1416,8 +1423,8 @@ declare namespace Appwrite { * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index 3f80fda24..1293d3589 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -18,8 +18,7 @@ request.setRequestHeader(key,headers[key]);}} request.onload=function(){if(4===request.readyState&&399>=request.status){let data=request.response;let contentType=this.getResponseHeader('content-type')||'';contentType=contentType.substring(0,contentType.indexOf(';'));switch(contentType){case'application/json':data=JSON.parse(data);break;} let cookieFallback=this.getResponseHeader('X-Fallback-Cookies')||'';if(window.localStorage&&cookieFallback){window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');window.localStorage.setItem('cookieFallback',cookieFallback);} resolve(data);}else{reject(new Error(request.statusText));}};if(progress){request.addEventListener('progress',progress);request.upload.addEventListener('progress',progress,false);} -request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let iframe=function(method,url,params){let form=document.createElement('form');form.setAttribute('method',method);form.setAttribute('action',config.endpoint+url);for(let key in params){if(params.hasOwnProperty(key)){let hiddenField=document.createElement("input");hiddenField.setAttribute("type","hidden");hiddenField.setAttribute("name",key);hiddenField.setAttribute("value",params[key]);form.appendChild(hiddenField);}} -document.body.appendChild(form);return form.submit();};let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} @@ -52,12 +51,10 @@ return http.put(path,{'content-type':'application/json',},payload);},getSessions if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account/sessions';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} -return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success,failure){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} -if(success===undefined){throw new Error('Missing required parameter: "success"');} -if(failure===undefined){throw new Error('Missing required parameter: "failure"');} +return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success='https://appwrite.io/auth/oauth2/success',failure='https://appwrite.io/auth/oauth2/failure'){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} let path='/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}','g'),provider);let payload={};if(success){payload['success']=success;} if(failure){payload['failure']=failure;} -payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');window.location=config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} let path='/account/sessions/{sessionId}'.replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createVerification:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/account/verification';let payload={};if(url){payload['url']=url;} return http.post(path,{'content-type':'application/json',},payload);},updateVerification:function(userId,secret){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} @@ -68,26 +65,26 @@ return http.put(path,{'content-type':'application/json',},payload);}};let avatar let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';let payload={};if(url){payload['url']=url;} -return http.get(path,{'content-type':'application/json',},payload);},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/flags/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/image';let payload={};if(url){payload['url']=url;} if(width){payload['width']=width;} if(height){payload['height']=height;} -return http.get(path,{'content-type':'application/json',},payload);},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} let path='/avatars/qr';let payload={};if(text){payload['text']=text;} if(size){payload['size']=size;} if(margin){payload['margin']=margin;} if(download){payload['download']=download;} -return http.get(path,{'content-type':'application/json',},payload);}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} if(limit){payload['limit']=limit;} if(offset){payload['offset']=offset;} if(orderType){payload['orderType']=orderType;} @@ -141,7 +138,8 @@ if(read){payload['read']=read;} if(write){payload['write']=write;} return http.patch(path,{'content-type':'application/json',},payload);},deleteDocument:function(collectionId,documentId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} if(documentId===undefined){throw new Error('Missing required parameter: "documentId"');} -let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} +let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getCollectionLogs:function(collectionId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} +let path='/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}','g'),collectionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} let path='/projects';let payload={};if(name){payload['name']=name;} if(teamId){payload['teamId']=teamId;} @@ -259,7 +257,7 @@ if(httpUser){payload['httpUser']=httpUser;} if(httpPass){payload['httpPass']=httpPass;} return http.put(path,{'content-type':'application/json',},payload);},deleteTask:function(projectId,taskId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} if(taskId===undefined){throw new Error('Missing required parameter: "taskId"');} -let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='monthly'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} +let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='last30'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/usage'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(range){payload['range']=range;} return http.get(path,{'content-type':'application/json',},payload);},listWebhooks:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/webhooks'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createWebhook:function(projectId,name,events,url,security,httpUser='',httpPass=''){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} @@ -327,8 +325,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"');} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload['name']=name;} return http.put(path,{'content-type':'application/json',},payload);},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload['search']=search;} +if(limit){payload['limit']=limit;} +if(offset){payload['offset']=offset;} +if(orderType){payload['orderType']=orderType;} +return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} if(email===undefined){throw new Error('Missing required parameter: "email"');} if(roles===undefined){throw new Error('Missing required parameter: "roles"');} if(url===undefined){throw new Error('Missing required parameter: "url"');} @@ -366,7 +368,7 @@ if(sessionId===undefined){throw new Error('Missing required parameter: "sessionI let path='/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}','g'),userId).replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},updateStatus:function(userId,status){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(status===undefined){throw new Error('Missing required parameter: "status"');} let path='/users/{userId}/status'.replace(new RegExp('{userId}','g'),userId);let payload={};if(status){payload['status']=status;} -return http.patch(path,{'content-type':'application/json',},payload);}};return{setEndpoint:setEndpoint,setProject:setProject,setKey:setKey,setLocale:setLocale,setMode:setMode,account:account,avatars:avatars,database:database,locale:locale,projects:projects,storage:storage,teams:teams,users:users};};if(typeof module!=="undefined"){module.exports=window.Appwrite;}})((typeof window!=="undefined")?window:{});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart=f()}})(function(){var define,module,exports;return(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=50)?'...':'';return $value.substring(0,50)+postfix;;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} +return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';} +return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} return annotate(number,maxPlaces,forcePlaces,abbr);} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} diff --git a/public/dist/scripts/app-dep.js b/public/dist/scripts/app-dep.js index 22e19c4fa..f9d07fdc0 100644 --- a/public/dist/scripts/app-dep.js +++ b/public/dist/scripts/app-dep.js @@ -18,8 +18,7 @@ request.setRequestHeader(key,headers[key]);}} request.onload=function(){if(4===request.readyState&&399>=request.status){let data=request.response;let contentType=this.getResponseHeader('content-type')||'';contentType=contentType.substring(0,contentType.indexOf(';'));switch(contentType){case'application/json':data=JSON.parse(data);break;} let cookieFallback=this.getResponseHeader('X-Fallback-Cookies')||'';if(window.localStorage&&cookieFallback){window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');window.localStorage.setItem('cookieFallback',cookieFallback);} resolve(data);}else{reject(new Error(request.statusText));}};if(progress){request.addEventListener('progress',progress);request.upload.addEventListener('progress',progress,false);} -request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let iframe=function(method,url,params){let form=document.createElement('form');form.setAttribute('method',method);form.setAttribute('action',config.endpoint+url);for(let key in params){if(params.hasOwnProperty(key)){let hiddenField=document.createElement("input");hiddenField.setAttribute("type","hidden");hiddenField.setAttribute("name",key);hiddenField.setAttribute("value",params[key]);form.appendChild(hiddenField);}} -document.body.appendChild(form);return form.submit();};let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +request.onerror=function(){reject(new Error("Network Error"));};request.send(params);})};return{'get':function(path,headers={},params={}){return call('GET',path+((Object.keys(params).length>0)?'?'+buildQuery(params):''),headers,{});},'post':function(path,headers={},params={},progress=null){return call('POST',path,headers,params,progress);},'put':function(path,headers={},params={},progress=null){return call('PUT',path,headers,params,progress);},'patch':function(path,headers={},params={},progress=null){return call('PATCH',path,headers,params,progress);},'delete':function(path,headers={},params={},progress=null){return call('DELETE',path,headers,params,progress);},'addGlobalParam':addGlobalParam,'addGlobalHeader':addGlobalHeader}}(window.document);let account={get:function(){let path='/account';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(email,password,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} @@ -52,12 +51,10 @@ return http.put(path,{'content-type':'application/json',},payload);},getSessions if(password===undefined){throw new Error('Missing required parameter: "password"');} let path='/account/sessions';let payload={};if(email){payload['email']=email;} if(password){payload['password']=password;} -return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success,failure){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} -if(success===undefined){throw new Error('Missing required parameter: "success"');} -if(failure===undefined){throw new Error('Missing required parameter: "failure"');} +return http.post(path,{'content-type':'application/json',},payload);},deleteSessions:function(){let path='/account/sessions';let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createOAuth2Session:function(provider,success='https://appwrite.io/auth/oauth2/success',failure='https://appwrite.io/auth/oauth2/failure'){if(provider===undefined){throw new Error('Missing required parameter: "provider"');} let path='/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}','g'),provider);let payload={};if(success){payload['success']=success;} if(failure){payload['failure']=failure;} -payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');window.location=config.endpoint+path+((query)?'?'+query:'');},deleteSession:function(sessionId){if(sessionId===undefined){throw new Error('Missing required parameter: "sessionId"');} let path='/account/sessions/{sessionId}'.replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},createVerification:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/account/verification';let payload={};if(url){payload['url']=url;} return http.post(path,{'content-type':'application/json',},payload);},updateVerification:function(userId,secret){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} @@ -68,26 +65,26 @@ return http.put(path,{'content-type':'application/json',},payload);}};let avatar let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';let payload={};if(url){payload['url']=url;} -return http.get(path,{'content-type':'application/json',},payload);},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/flags/{code}'.replace(new RegExp('{code}','g'),code);let payload={};if(width){payload['width']=width;} if(height){payload['height']=height;} if(quality){payload['quality']=quality;} -return http.get(path,{'content-type':'application/json',},payload);},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getImage:function(url,width=400,height=400){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/image';let payload={};if(url){payload['url']=url;} if(width){payload['width']=width;} if(height){payload['height']=height;} -return http.get(path,{'content-type':'application/json',},payload);},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');},getQR:function(text,size=400,margin=1,download=0){if(text===undefined){throw new Error('Missing required parameter: "text"');} let path='/avatars/qr';let payload={};if(text){payload['text']=text;} if(size){payload['size']=size;} if(margin){payload['margin']=margin;} if(download){payload['download']=download;} -return http.get(path,{'content-type':'application/json',},payload);}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} +payload['project']=config.project;payload['key']=config.key;let query=Object.keys(payload).map(key=>key+'='+encodeURIComponent(payload[key])).join('&');return config.endpoint+path+((query)?'?'+query:'');}};let database={listCollections:function(search='',limit=25,offset=0,orderType='ASC'){let path='/database/collections';let payload={};if(search){payload['search']=search;} if(limit){payload['limit']=limit;} if(offset){payload['offset']=offset;} if(orderType){payload['orderType']=orderType;} @@ -141,7 +138,8 @@ if(read){payload['read']=read;} if(write){payload['write']=write;} return http.patch(path,{'content-type':'application/json',},payload);},deleteDocument:function(collectionId,documentId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} if(documentId===undefined){throw new Error('Missing required parameter: "documentId"');} -let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} +let path='/database/collections/{collectionId}/documents/{documentId}'.replace(new RegExp('{collectionId}','g'),collectionId).replace(new RegExp('{documentId}','g'),documentId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getCollectionLogs:function(collectionId){if(collectionId===undefined){throw new Error('Missing required parameter: "collectionId"');} +let path='/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}','g'),collectionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(){let path='/projects';let payload={};return http.get(path,{'content-type':'application/json',},payload);},create:function(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId=''){if(name===undefined){throw new Error('Missing required parameter: "name"');} if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} let path='/projects';let payload={};if(name){payload['name']=name;} if(teamId){payload['teamId']=teamId;} @@ -259,7 +257,7 @@ if(httpUser){payload['httpUser']=httpUser;} if(httpPass){payload['httpPass']=httpPass;} return http.put(path,{'content-type':'application/json',},payload);},deleteTask:function(projectId,taskId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} if(taskId===undefined){throw new Error('Missing required parameter: "taskId"');} -let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='monthly'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} +let path='/projects/{projectId}/tasks/{taskId}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{taskId}','g'),taskId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(projectId,range='last30'){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/usage'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(range){payload['range']=range;} return http.get(path,{'content-type':'application/json',},payload);},listWebhooks:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} let path='/projects/{projectId}/webhooks'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createWebhook:function(projectId,name,events,url,security,httpUser='',httpPass=''){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');} @@ -327,8 +325,12 @@ let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payloa if(name===undefined){throw new Error('Missing required parameter: "name"');} let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(name){payload['name']=name;} return http.put(path,{'content-type':'application/json',},payload);},delete:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} -let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}'.replace(new RegExp('{teamId}','g'),teamId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getMemberships:function(teamId,search='',limit=25,offset=0,orderType='ASC'){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} +let path='/teams/{teamId}/memberships'.replace(new RegExp('{teamId}','g'),teamId);let payload={};if(search){payload['search']=search;} +if(limit){payload['limit']=limit;} +if(offset){payload['offset']=offset;} +if(orderType){payload['orderType']=orderType;} +return http.get(path,{'content-type':'application/json',},payload);},createMembership:function(teamId,email,roles,url,name=''){if(teamId===undefined){throw new Error('Missing required parameter: "teamId"');} if(email===undefined){throw new Error('Missing required parameter: "email"');} if(roles===undefined){throw new Error('Missing required parameter: "roles"');} if(url===undefined){throw new Error('Missing required parameter: "url"');} @@ -366,7 +368,7 @@ if(sessionId===undefined){throw new Error('Missing required parameter: "sessionI let path='/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}','g'),userId).replace(new RegExp('{sessionId}','g'),sessionId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},updateStatus:function(userId,status){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(status===undefined){throw new Error('Missing required parameter: "status"');} let path='/users/{userId}/status'.replace(new RegExp('{userId}','g'),userId);let payload={};if(status){payload['status']=status;} -return http.patch(path,{'content-type':'application/json',},payload);}};return{setEndpoint:setEndpoint,setProject:setProject,setKey:setKey,setLocale:setLocale,setMode:setMode,account:account,avatars:avatars,database:database,locale:locale,projects:projects,storage:storage,teams:teams,users:users};};if(typeof module!=="undefined"){module.exports=window.Appwrite;}})((typeof window!=="undefined")?window:{});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart=f()}})(function(){var define,module,exports;return(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=50)?'...':'';return $value.substring(0,50)+postfix;;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} +return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';} +return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} return annotate(number,maxPlaces,forcePlaces,abbr);} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} diff --git a/public/scripts/dependencies/appwrite.js b/public/scripts/dependencies/appwrite.js index 590b45116..08f0501f2 100644 --- a/public/scripts/dependencies/appwrite.js +++ b/public/scripts/dependencies/appwrite.js @@ -286,28 +286,6 @@ } }(window.document); - let iframe = function(method, url, params) { - let form = document.createElement('form'); - - form.setAttribute('method', method); - form.setAttribute('action', config.endpoint + url); - - for(let key in params) { - if(params.hasOwnProperty(key)) { - let hiddenField = document.createElement("input"); - hiddenField.setAttribute("type", "hidden"); - hiddenField.setAttribute("name", key); - hiddenField.setAttribute("value", params[key]); - - form.appendChild(hiddenField); - } - } - - document.body.appendChild(form); - - return form.submit(); - }; - let account = { /** @@ -334,10 +312,10 @@ * * Use this endpoint to allow a new user to register a new account in your * project. After the user registration completes successfully, you can use - * the [/account/verfication](/docs/account#createVerification) route to start - * verifying the user email address. To allow your new user to login to his - * new account, you need to create a new [account - * session](/docs/account#createSession). + * the [/account/verfication](/docs/client/account#createVerification) route + * to start verifying the user email address. To allow your new user to login + * to his new account, you need to create a new [account + * session](/docs/client/account#createSession). * * @param {string} email * @param {string} password @@ -580,7 +558,7 @@ * When the user clicks the confirmation link he is redirected back to your * app password reset URL with the secret key and email address values * attached to the URL query string. Use the query string params to submit a - * request to the [PUT /account/recovery](/docs/account#updateRecovery) + * request to the [PUT /account/recovery](/docs/client/account#updateRecovery) * endpoint to complete the process. * * @param {string} email @@ -621,7 +599,7 @@ * Use this endpoint to complete the user account password reset. Both the * **userId** and **secret** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the [POST - * /account/recovery](/docs/account#createRecovery) endpoint. + * /account/recovery](/docs/client/account#createRecovery) endpoint. * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -768,21 +746,13 @@ * @param {string} success * @param {string} failure * @throws {Error} - * @return {string} + * @return {Promise} */ - createOAuth2Session: function(provider, success, failure) { + createOAuth2Session: function(provider, success = 'https://appwrite.io/auth/oauth2/success', failure = 'https://appwrite.io/auth/oauth2/failure') { if(provider === undefined) { throw new Error('Missing required parameter: "provider"'); } - if(success === undefined) { - throw new Error('Missing required parameter: "success"'); - } - - if(failure === undefined) { - throw new Error('Missing required parameter: "failure"'); - } - let path = '/account/sessions/oauth2/{provider}'.replace(new RegExp('{provider}', 'g'), provider); let payload = {}; @@ -800,8 +770,8 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - - return config.endpoint + path + ((query) ? '?' + query : ''); + + window.location = config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -840,7 +810,7 @@ * should redirect the user back for your app and allow you to complete the * verification process by verifying both the **userId** and **secret** * parameters. Learn more about how to [complete the verification - * process](/docs/account#updateAccountVerification). + * process](/docs/client/account#updateAccountVerification). * * Please note that in order to avoid a [Redirect * Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -926,7 +896,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getBrowser: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -949,10 +919,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -968,7 +941,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getCreditCard: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -991,10 +964,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1005,7 +981,7 @@ * * @param {string} url * @throws {Error} - * @return {Promise} + * @return {string} */ getFavicon: function(url) { if(url === undefined) { @@ -1020,10 +996,13 @@ payload['url'] = url; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1038,7 +1017,7 @@ * @param {number} height * @param {number} quality * @throws {Error} - * @return {Promise} + * @return {string} */ getFlag: function(code, width = 100, height = 100, quality = 100) { if(code === undefined) { @@ -1061,10 +1040,13 @@ payload['quality'] = quality; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1079,7 +1061,7 @@ * @param {number} width * @param {number} height * @throws {Error} - * @return {Promise} + * @return {string} */ getImage: function(url, width = 400, height = 400) { if(url === undefined) { @@ -1102,10 +1084,13 @@ payload['height'] = height; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); }, /** @@ -1119,7 +1104,7 @@ * @param {number} margin * @param {number} download * @throws {Error} - * @return {Promise} + * @return {string} */ getQR: function(text, size = 400, margin = 1, download = 0) { if(text === undefined) { @@ -1146,10 +1131,13 @@ payload['download'] = download; } - return http - .get(path, { - 'content-type': 'application/json', - }, payload); + payload['project'] = config.project; + + payload['key'] = config.key; + + let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); + + return config.endpoint + path + ((query) ? '?' + query : ''); } }; @@ -1203,9 +1191,9 @@ * Create a new Collection. * * @param {string} name - * @param {array} read - * @param {array} write - * @param {array} rules + * @param {string[]} read + * @param {string[]} write + * @param {string[]} rules * @throws {Error} * @return {Promise} */ @@ -1284,9 +1272,9 @@ * * @param {string} collectionId * @param {string} name - * @param {array} read - * @param {array} write - * @param {array} rules + * @param {string[]} read + * @param {string[]} write + * @param {string[]} rules * @throws {Error} * @return {Promise} */ @@ -1367,7 +1355,7 @@ * modes](/docs/admin). * * @param {string} collectionId - * @param {array} filters + * @param {string[]} filters * @param {number} offset * @param {number} limit * @param {string} orderField @@ -1433,12 +1421,15 @@ /** * Create Document * - * Create a new Document. + * Create a new Document. Before using this route, you should create a new + * collection resource using either a [server + * integration](/docs/server/database?sdk=nodejs#createCollection) API or + * directly from your database console. * * @param {string} collectionId * @param {object} data - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @param {string} parentDocument * @param {string} parentProperty * @param {string} parentPropertyType @@ -1533,8 +1524,8 @@ * @param {string} collectionId * @param {string} documentId * @param {object} data - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -1610,6 +1601,272 @@ .delete(path, { 'content-type': 'application/json', }, payload); + }, + + /** + * Get Collection Logs + * + * + * @param {string} collectionId + * @throws {Error} + * @return {Promise} + */ + getCollectionLogs: function(collectionId) { + if(collectionId === undefined) { + throw new Error('Missing required parameter: "collectionId"'); + } + + let path = '/database/collections/{collectionId}/logs'.replace(new RegExp('{collectionId}', 'g'), collectionId); + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + } + }; + + let health = { + + /** + * Get HTTP + * + * Check the Appwrite HTTP server is up and responsive. + * + * @throws {Error} + * @return {Promise} + */ + get: function() { + let path = '/health'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Anti virus + * + * Check the Appwrite Anti Virus server is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getAntiVirus: function() { + let path = '/health/anti-virus'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Cache + * + * Check the Appwrite in-memory cache server is up and connection is + * successful. + * + * @throws {Error} + * @return {Promise} + */ + getCache: function() { + let path = '/health/cache'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get DB + * + * Check the Appwrite database server is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getDB: function() { + let path = '/health/db'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Certificate Queue + * + * Get the number of certificates that are waiting to be issued against + * [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue + * server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueCertificates: function() { + let path = '/health/queue/certificates'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Functions Queue + * + * + * @throws {Error} + * @return {Promise} + */ + getQueueFunctions: function() { + let path = '/health/queue/functions'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Logs Queue + * + * Get the number of logs that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueLogs: function() { + let path = '/health/queue/logs'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Tasks Queue + * + * Get the number of tasks that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueTasks: function() { + let path = '/health/queue/tasks'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Usage Queue + * + * Get the number of usage stats that are waiting to be processed in the + * Appwrite internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueUsage: function() { + let path = '/health/queue/usage'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Webhooks Queue + * + * Get the number of webhooks that are waiting to be processed in the Appwrite + * internal queue server. + * + * @throws {Error} + * @return {Promise} + */ + getQueueWebhooks: function() { + let path = '/health/queue/webhooks'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Local Storage + * + * Check the Appwrite local storage device is up and connection is successful. + * + * @throws {Error} + * @return {Promise} + */ + getStorageLocal: function() { + let path = '/health/storage/local'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); + }, + + /** + * Get Time + * + * Check the Appwrite server time is synced with Google remote NTP server. We + * use this technology to smoothly handle leap seconds with no disruptive + * events. The [Network Time + * Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is + * used by hundreds of millions of computers and devices to synchronize their + * clocks over the Internet. If your computer sets its own clock, it likely + * uses NTP. + * + * @throws {Error} + * @return {Promise} + */ + getTime: function() { + let path = '/health/time'; + + let payload = {}; + + return http + .get(path, { + 'content-type': 'application/json', + }, payload); } }; @@ -1640,7 +1897,7 @@ }, /** - * List Countries + * List Continents * * List of all continents. You can use the locale header to get the data in a * supported language. @@ -2142,7 +2399,7 @@ * * @param {string} projectId * @param {string} name - * @param {array} scopes + * @param {string[]} scopes * @throws {Error} * @return {Promise} */ @@ -2212,7 +2469,7 @@ * @param {string} projectId * @param {string} keyId * @param {string} name - * @param {array} scopes + * @param {string[]} scopes * @throws {Error} * @return {Promise} */ @@ -2542,7 +2799,7 @@ * @param {number} security * @param {string} httpMethod * @param {string} httpUrl - * @param {array} httpHeaders + * @param {string[]} httpHeaders * @param {string} httpUser * @param {string} httpPass * @throws {Error} @@ -2663,7 +2920,7 @@ * @param {number} security * @param {string} httpMethod * @param {string} httpUrl - * @param {array} httpHeaders + * @param {string[]} httpHeaders * @param {string} httpUser * @param {string} httpPass * @throws {Error} @@ -2781,10 +3038,11 @@ * * * @param {string} projectId + * @param {string} range * @throws {Error} * @return {Promise} */ - getUsage: function(projectId, range = 'monthly') { + getUsage: function(projectId, range = 'last30') { if(projectId === undefined) { throw new Error('Missing required parameter: "projectId"'); } @@ -2832,7 +3090,7 @@ * * @param {string} projectId * @param {string} name - * @param {array} events + * @param {string[]} events * @param {string} url * @param {number} security * @param {string} httpUser @@ -2930,7 +3188,7 @@ * @param {string} projectId * @param {string} webhookId * @param {string} name - * @param {array} events + * @param {string[]} events * @param {string} url * @param {number} security * @param {string} httpUser @@ -3077,8 +3335,8 @@ * read and write arguments. * * @param {File} file - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -3149,8 +3407,8 @@ * to update this resource. * * @param {string} fileId - * @param {array} read - * @param {array} write + * @param {string[]} read + * @param {string[]} write * @throws {Error} * @return {Promise} */ @@ -3235,7 +3493,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); }, @@ -3290,7 +3548,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); }, @@ -3323,7 +3581,7 @@ payload['key'] = config.key; let query = Object.keys(payload).map(key => key + '=' + encodeURIComponent(payload[key])).join('&'); - + return config.endpoint + path + ((query) ? '?' + query : ''); } }; @@ -3380,7 +3638,7 @@ * project. * * @param {string} name - * @param {array} roles + * @param {string[]} roles * @throws {Error} * @return {Promise} */ @@ -3498,10 +3756,14 @@ * for this list of resources. * * @param {string} teamId + * @param {string} search + * @param {number} limit + * @param {number} offset + * @param {string} orderType * @throws {Error} * @return {Promise} */ - getMemberships: function(teamId) { + getMemberships: function(teamId, search = '', limit = 25, offset = 0, orderType = 'ASC') { if(teamId === undefined) { throw new Error('Missing required parameter: "teamId"'); } @@ -3510,6 +3772,22 @@ let payload = {}; + if(search) { + payload['search'] = search; + } + + if(limit) { + payload['limit'] = limit; + } + + if(offset) { + payload['offset'] = offset; + } + + if(orderType) { + payload['orderType'] = orderType; + } + return http .get(path, { 'content-type': 'application/json', @@ -3525,8 +3803,8 @@ * * Use the 'URL' parameter to redirect the user from the invitation email back * to your app. When the user is redirected, use the [Update Team Membership - * Status](/docs/teams#updateMembershipStatus) endpoint to allow the user to - * accept the invitation to the team. + * Status](/docs/client/teams#updateMembershipStatus) endpoint to allow the + * user to accept the invitation to the team. * * Please note that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) @@ -3535,7 +3813,7 @@ * * @param {string} teamId * @param {string} email - * @param {array} roles + * @param {string[]} roles * @param {string} url * @param {string} name * @throws {Error} @@ -3922,10 +4200,7 @@ throw new Error('Missing required parameter: "sessionId"'); } - let path = '/users/{userId}/sessions/{sessionId}' - .replace(new RegExp('{userId}', 'g'), userId) - .replace(new RegExp('{sessionId}', 'g'), sessionId) - ; + let path = '/users/{userId}/sessions/{sessionId}'.replace(new RegExp('{userId}', 'g'), userId).replace(new RegExp('{sessionId}', 'g'), sessionId); let payload = {}; @@ -3978,6 +4253,7 @@ account: account, avatars: avatars, database: database, + health: health, locale: locale, projects: projects, storage: storage, From 591ff738ee309a0fa1ffbe3263e2411d0a292885 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 07:40:13 +0300 Subject: [PATCH 17/40] Added roles tooltip --- app/views/console/users/team.phtml | 123 +++++++++++++++++------------ public/scripts/filters.js | 7 ++ 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index c31afd222..b6e54838a 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -1,7 +1,7 @@
    @@ -34,7 +34,7 @@

    General

    -
    +
    @@ -67,13 +67,13 @@
    + data-name="project-members">

    No Memberships Found

    @@ -81,94 +81,113 @@

    Create your first team member to get started

    -
    -
    results found
    +
    +
    members found
    -
    - - - - - - - - - - - - - - - - - -
    NameMembersCreated
    - Collection Avatar - - -
    +
    +
      +
    • + + + + + + + + + User Avatar + +
      +    + + +
      +   Pending Approval +
    • +
    - diff --git a/public/scripts/filters.js b/public/scripts/filters.js index 6f08193df..54d0fe806 100644 --- a/public/scripts/filters.js +++ b/public/scripts/filters.js @@ -406,6 +406,13 @@ window.ls.filter return $value.substring(0, 50) + postfix; ; }) + .add("arraySentence", function($value) { + if(!Array.isArray($value)) { + return ''; + } + + return $value.join(", ").replace(/,\s([^,]+)$/, ' and $1'); + }) ; function abbreviate(number, maxPlaces, forcePlaces, forceLetter) { From 157b91b63b8949f6177d303eefe7995cad43fdb1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 08:42:01 +0300 Subject: [PATCH 18/40] Fixed team member count --- CHANGES.md | 1 + app/controllers/api/teams.php | 8 +++++--- app/views/console/users/team.phtml | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5ea597b6a..530963517 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ ## Bug Fixes - Fixed output of /v1/health/queue/certificates returning wrong data +- Fixed bug where team members count was wrong in some cases ## Security diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 89f1ff0df..35b5be4c1 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -584,9 +584,11 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId') throw new Exception('Failed to remove membership from DB', 500); } - $team = $projectDB->updateDocument(array_merge($team->getArrayCopy(), [ - 'sum' => $team->getAttribute('sum', 0) - 1, - ])); + if ($membership->getAttribute('confirm')) { // Count only confirmed members + $team = $projectDB->updateDocument(array_merge($team->getArrayCopy(), [ + 'sum' => $team->getAttribute('sum', 0) - 1, + ])); + } if (false === $team) { throw new Exception('Failed saving team to DB', 500); diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index b6e54838a..1ce7f40ac 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -82,7 +82,7 @@
    -
    members found
    +
    memberships found
      @@ -153,7 +153,7 @@
      - +  
      From 0060dfe7151b14dc7d357c3c48cde94d9ef37775 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:01:11 +0300 Subject: [PATCH 19/40] Fix for tests --- app/views/console/users/team.phtml | 4 ++-- tests/e2e/Services/Teams/TeamsBaseClient.php | 9 +++++---- tests/e2e/Services/Teams/TeamsBaseServer.php | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index 1ce7f40ac..d4050c9e7 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -75,10 +75,10 @@ data-scope="sdk" data-name="project-members"> -
      +

      No Memberships Found

      -

      Create your first team member to get started

      +

      Add your first team member to get started

      diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 0b91f862d..05394a391 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -22,10 +22,11 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertNotEmpty($response['body'][0]['$id']); - $this->assertEquals($this->getUser()['name'], $response['body'][0]['name']); - $this->assertEquals($this->getUser()['email'], $response['body'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['roles'][0]); + $this->assertIsInt($response['body']['sum']); + $this->assertNotEmpty($response['body']['memberships'][0]['$id']); + $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); + $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); + $this->assertEquals('owner', $response['body'][0]['roles']['memberships'][0]); /** * Test for FAILURE diff --git a/tests/e2e/Services/Teams/TeamsBaseServer.php b/tests/e2e/Services/Teams/TeamsBaseServer.php index 6b00a6559..8de0f2ede 100644 --- a/tests/e2e/Services/Teams/TeamsBaseServer.php +++ b/tests/e2e/Services/Teams/TeamsBaseServer.php @@ -22,7 +22,7 @@ trait TeamsBaseServer ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']); + $this->assertEquals(0, $response['body']['sum']); /** * Test for FAILURE From ee7f6ce9763caa0c361b29e99455658569e0129a Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:11:39 +0300 Subject: [PATCH 20/40] Test fix --- tests/e2e/Services/Teams/TeamsBaseClient.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 05394a391..db9ecdf15 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -26,7 +26,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['memberships'][0]['$id']); $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['roles']['memberships'][0]); + $this->assertEquals('owner', $response['body'][0]['memberships']['roles'][0]); /** * Test for FAILURE @@ -234,6 +234,8 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']); + var_dump($response); + return []; } } \ No newline at end of file From 38fae2bd874621aebcdd952d1e1a603a2e92ce4c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 11:23:03 +0300 Subject: [PATCH 21/40] Fixed test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index db9ecdf15..ec4676fe6 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -26,7 +26,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['memberships'][0]['$id']); $this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']); $this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']); - $this->assertEquals('owner', $response['body'][0]['memberships']['roles'][0]); + $this->assertEquals('owner', $response['body']['memberships'][0]['roles'][0]); /** * Test for FAILURE From 4f62cdc6dee556790b270ed85da34071bbb223fc Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 12:03:08 +0300 Subject: [PATCH 22/40] Fixed test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index ec4676fe6..6d6df372a 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -232,7 +232,7 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']); + $this->assertCount(1, $response['body']['memberships']); var_dump($response); From 7d5ee934ee757ee4a7a16e0c029b5499b441229c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 19:15:13 +0300 Subject: [PATCH 23/40] Added link to user page --- app/views/console/users/team.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml index d4050c9e7..435785ae5 100644 --- a/app/views/console/users/team.phtml +++ b/app/views/console/users/team.phtml @@ -103,13 +103,13 @@ - + User Avatar
      -    +   
      From 26a133a3f87c603cb12d32e5b8f7f4de86618dac Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 8 Jun 2020 19:15:35 +0300 Subject: [PATCH 24/40] Allowed admin to auto-add new member to a team --- app/controllers/api/teams.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 35b5be4c1..e235c3536 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -215,7 +215,7 @@ $utopia->post('/v1/teams/:teamId/memberships') ->param('roles', [], function () { return new ArrayList(new Text(128)); }, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions).') ->param('url', '', function () use ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.') // TODO add our own built-in confirm page ->action( - function ($teamId, $email, $name, $roles, $url) use ($response, $register, $project, $user, $audit, $projectDB) { + function ($teamId, $email, $name, $roles, $url) use ($response, $register, $project, $user, $audit, $projectDB, $mode) { $name = (empty($name)) ? $email : $name; $team = $projectDB->getDocument($teamId); @@ -285,7 +285,7 @@ $utopia->post('/v1/teams/:teamId/memberships') } } - if (!$isOwner) { + if (!$isOwner && (APP_MODE_ADMIN !== $mode)) { throw new Exception('User is not allowed to send invitations for this team', 401); } @@ -302,11 +302,18 @@ $utopia->post('/v1/teams/:teamId/memberships') 'roles' => $roles, 'invited' => time(), 'joined' => 0, - 'confirm' => false, + 'confirm' => (APP_MODE_ADMIN === $mode), 'secret' => Auth::hash($secret), ]); - $membership = $projectDB->createDocument($membership->getArrayCopy()); + if(APP_MODE_ADMIN === $mode) { // Allow admin to create membership + Authorization::disable(); + $membership = $projectDB->createDocument($membership->getArrayCopy()); + Authorization::reset(); + } + else { + $membership = $projectDB->createDocument($membership->getArrayCopy()); + } if (false === $membership) { throw new Exception('Failed saving membership to DB', 500); @@ -334,7 +341,9 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - $mail->send(); + if(APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + $mail->send(); + } } catch (\Exception $error) { throw new Exception('Error sending mail: ' . $error->getMessage(), 500); } From 98846adfc978c1725a19e577f4faef88678406f2 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 9 Jun 2020 07:27:09 +0300 Subject: [PATCH 25/40] Fixed test --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index e235c3536..a88f8ee2d 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -341,7 +341,7 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - if(APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + if(!APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode $mail->send(); } } catch (\Exception $error) { From 50e7fc43c90bcd85eea546db4b0be9e77aaa3bd1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 10 Jun 2020 21:55:22 +0300 Subject: [PATCH 26/40] Fixed test --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a88f8ee2d..ded2445fa 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -341,7 +341,7 @@ $utopia->post('/v1/teams/:teamId/memberships') $mail->AltBody = strip_tags($body->render()); try { - if(!APP_MODE_ADMIN === $mode) { // No need in comfirmation when in admin mode + if(APP_MODE_ADMIN !== $mode) { // No need in comfirmation when in admin mode $mail->send(); } } catch (\Exception $error) { From f54b662bdb147fdbe699166fa6ae0fd699dc2445 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 10 Jun 2020 21:55:56 +0300 Subject: [PATCH 27/40] Removed debug log --- tests/e2e/Services/Teams/TeamsBaseClient.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 6d6df372a..ceb0d86e5 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -234,8 +234,6 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - var_dump($response); - return []; } } \ No newline at end of file From 69f944ec46f1c5e01f8a2cf7210cc523a81d5b8e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Thu, 11 Jun 2020 10:57:12 +0300 Subject: [PATCH 28/40] Removed gravatar upload button --- app/views/console/account/index.phtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/console/account/index.phtml b/app/views/console/account/index.phtml index 8843636ea..0e3224337 100644 --- a/app/views/console/account/index.phtml +++ b/app/views/console/account/index.phtml @@ -24,13 +24,13 @@
      User Avatar -
      + - Upload + -
      + - (via gravatar.com ) +
      @@ -57,7 +57,7 @@
      - +
      @@ -85,7 +85,7 @@
      -