1
0
Fork 0
mirror of synced 2024-05-20 20:52:36 +12:00

Merge branch 'master' into some-typos-fixes

This commit is contained in:
Dmitriy Danilov 2021-11-28 09:22:19 -05:00 committed by GitHub
commit 3eabd83309
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 5866 additions and 28638 deletions

View file

@ -1,8 +1,6 @@
app/db/SQL
node_modules
storage
public/scripts
public/styles
.git
.idea
.cd .babelrc

34
.gitattributes vendored
View file

@ -1,10 +1,42 @@
; app/* linguist-detectable=false
; app/* linguist-detectable=false
; app/*/* linguist-detectable=false
; app/*/*/* linguist-detectable=false
; app/*/*/*/* linguist-detectable=false
; app/*/*/*/*/* linguist-detectable=false
app/config/* linguist-detectable=false
app/config/* linguist-detectable=false
app/config/*/* linguist-detectable=false
app/config/*/*/* linguist-detectable=false
app/config/*/*/*/* linguist-detectable=false
app/views/* linguist-detectable=false
app/views/* linguist-detectable=false
app/views/*/* linguist-detectable=false
app/views/*/*/* linguist-detectable=false
app/views/*/*/*/* linguist-detectable=false
app/controllers/* linguist-detectable=false
app/controllers/* linguist-detectable=false
app/controllers/*/* linguist-detectable=false
app/controllers/*/*/* linguist-detectable=false
app/controllers/*/*/*/* linguist-detectable=false
app/controllers/*/*/*/*/* linguist-detectable=false
; app/workers/* linguist-detectable=false
; app/workers/* linguist-detectable=false
; app/workers/*/* linguist-detectable=false
; app/workers/*/*/* linguist-detectable=false
; app/workers/*/*/*/* linguist-detectable=false
; src/Appwrite/Auth/* linguist-detectable=false
; src/Appwrite/Auth/*/* linguist-detectable=false
; src/Appwrite/Auth/*/*/* linguist-detectable=false
src/* linguist-detectable=false
src/* linguist-detectable=false
src/*/* linguist-detectable=false
src/*/*/* linguist-detectable=false
src/*/*/*/* linguist-detectable=false
src/*/*/*/*/* linguist-detectable=false
tests/* linguist-detectable=false
tests/*/* linguist-detectable=false
tests/*/*/* linguist-detectable=false
tests/*/*/*/* linguist-detectable=false
tests/*/*/*/*/* linguist-detectable=false
tests/*/*/*/*/* linguist-detectable=false
tests/*/*/*/*/*/* linguist-detectable=false

View file

@ -37,6 +37,7 @@ body:
label: "🎲 Appwrite version"
description: "What version of Appwrite are you running?"
options:
- Version 0.11.x
- Version 0.10.x
- Version 0.9.x
- Version 0.8.x

View file

@ -12,6 +12,18 @@ RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM node:16-alpine as node
WORKDIR /usr/local/src/
COPY package-lock.json /usr/local/src/
COPY package.json /usr/local/src/
COPY gulpfile.js /usr/local/src/
COPY public /usr/local/src/public
RUN npm ci
RUN npm run build
FROM php:8.0-cli-alpine as compile
ARG DEBUG=false
@ -195,6 +207,7 @@ RUN \
WORKDIR /usr/src/code
COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor
COPY --from=node /usr/local/src/public/dist /usr/src/code/public/dist
COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/yasd.so* /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=redis /usr/local/lib/php/extensions/no-debug-non-zts-20200930/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=imagick /usr/local/lib/php/extensions/no-debug-non-zts-20200930/imagick.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
@ -205,7 +218,8 @@ COPY --from=maxmind /usr/local/lib/php/extensions/no-debug-non-zts-20200930/maxm
COPY ./app /usr/src/code/app
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./public /usr/src/code/public
COPY ./public/fonts /usr/src/code/public/fonts
COPY ./public/images /usr/src/code/public/images
COPY ./src /usr/src/code/src
# Set Volumes

View file

@ -102,7 +102,6 @@ Getting started with Appwrite is as easy as creating a new project, choosing you
* [Getting Started for Android](https://appwrite.io/docs/getting-started-for-android)
* [Getting Started for Server](https://appwrite.io/docs/getting-started-for-server)
* [Getting Started for CLI](https://appwrite.io/docs/command-line)
* Getting Started for iOS (Coming soon...)
### Services
@ -139,8 +138,9 @@ Below is a list of currently supported platforms and languages. If you wish to h
* ✅   [.NET](https://github.com/appwrite/sdk-for-dotnet) - **Experimental** (Maintained by the Appwrite Team)
#### Community
* ✅   [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/))
* ✅   [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/))
* ✅   [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (Maintained by [fenix-hub @GodotNuts](https://github.com/fenix-hub))
Looking for more SDKs? - Help us by contributing a pull request to our [SDK Generator](https://github.com/appwrite/sdk-generator)!
## Contributing

View file

@ -1,24 +1,24 @@
{
"settings.inspire": "\"هنر خردمند بودن، هنر دانستن چیزی است که باید از آن غافل شد.\"",
"settings.inspire": "\"هنر خردمند بودن این است که بدانید چه چیزی را نادیده بگیرید.\"",
"settings.locale": "fa",
"settings.direction": "rtl",
"emails.sender": "تیم %s",
"emails.verification.subject": "تأیید حساب",
"emails.verification.hello": "سلام {{name}}",
"emails.verification.body": "برای تأیید حساب‌تان پیوند زیر را دنبال کنید.",
"emails.verification.footer": "اگر شما درخواست تأیید حساب نداده‌اید، می‌توانید این ایمیل را نادیده بگیرید.",
"emails.verification.body": "برای تأیید ایمیل‌تان پیوند زیر را دنبال کنید.",
"emails.verification.footer": "اگر شما درخواست تأیید حساب نداده‌اید، می‌توانید این پیام را نادیده بگیرید.",
"emails.verification.thanks": "سپاس فراوان",
"emails.verification.signature": "تیم {{name}}",
"emails.magicSession.subject": "ورود به حساب کاربری",
"emails.magicSession.hello": "سلام،",
"emails.magicSession.body": "برای ورود به حساب‌تان پیوند زیر را دنبال کنید.",
"emails.magicSession.footer": "اگر شما درخواست ورود به حساب کاربری نداد‌ه‌اید، می‌توانید این ایمیل را نادیده بگیرید.",
"emails.magicSession.footer": "اگر شما درخواست ورود به حساب کاربری با استفاده از این ایمیل را نداد‌ه‌اید، می‌توانید این پیام را نادیده بگیرید.",
"emails.magicSession.thanks": "سپاس فراوان",
"emails.magicSession.signature": "تیم {{name}}",
"emails.recovery.subject": "بازیابی گذرواژه",
"emails.recovery.hello": "سلام {{name}}",
"emails.recovery.body": "برای بازیابی گذرواژه‌تان پیوند زیر را دنبال کنید.",
"emails.recovery.footer": "اگر شما درخواست بازیابی گذرواژه نداده‌اید، می‌توانید این ایمیل را نادیده بگیرید.",
"emails.recovery.footer": "اگر شما درخواست بازیابی گذرواژه نداده‌اید، می‌توانید این پیام را نادیده بگیرید.",
"emails.recovery.thanks": "سپاس فراوان",
"emails.recovery.signature": "تیم {{name}}",
"emails.invitation.subject": "دعوت به تیم %s در %s",

View file

@ -28,205 +28,205 @@
"emails.invitation.thanks": "Go raibh maith agat",
"emails.invitation.signature": "{{project}} foireann",
"locale.country.unknown": "Neamhaithnid",
"countries.af": "Afghanistan",
"countries.ao": "Angola",
"countries.al": "Albania",
"countries.ad": "Andorra",
"countries.ae": "United Arab Emirates",
"countries.ar": "Argentina",
"countries.am": "Armenia",
"countries.ag": "Antigua and Barbuda",
"countries.au": "Australia",
"countries.at": "Austria",
"countries.az": "Azerbaijan",
"countries.bi": "Burundi",
"countries.be": "Belgium",
"countries.bj": "Benin",
"countries.bf": "Burkina Faso",
"countries.bd": "Bangladesh",
"countries.bg": "Bulgaria",
"countries.bh": "Bahrain",
"countries.bs": "Bahamas",
"countries.ba": "Bosnia and Herzegovina",
"countries.by": "Belarus",
"countries.bz": "Belize",
"countries.bo": "Bolivia",
"countries.br": "Brazil",
"countries.bb": "Barbados",
"countries.bn": "Brunei",
"countries.bt": "Bhutan",
"countries.bw": "Botswana",
"countries.cf": "Central African Republic",
"countries.ca": "Canada",
"countries.ch": "Switzerland",
"countries.cl": "Chile",
"countries.cn": "China",
"countries.ci": "Ivory Coast",
"countries.cm": "Cameroon",
"countries.cd": "DR Congo",
"countries.cg": "Republic of the Congo",
"countries.co": "Colombia",
"countries.km": "Comoros",
"countries.af": "An Afganastáin",
"countries.ao": "Angóla",
"countries.al": "Albáin",
"countries.ad": "Andóra",
"countries.ae": "Aontas na nÉimíríochtaí Arabacha",
"countries.ar": "Airgintín",
"countries.am": "Airméin",
"countries.ag": "Antigua agus Barbúda",
"countries.au": "Astráil",
"countries.at": "Ostair",
"countries.az": "Asarbaiseáin",
"countries.bi": "An Bhurúin",
"countries.be": "An Bheilg",
"countries.bj": "Beinin",
"countries.bf": "Buircíne Fasó",
"countries.bd": "An Bhanglaidéis",
"countries.bg": "An Bhulgáir",
"countries.bh": "Bairéin",
"countries.bs": "Na Bahámaí",
"countries.ba": "An Bhoisnia agus an Heirseagaivéin",
"countries.by": "An Bhealarúis",
"countries.bz": "An Bheilís",
"countries.bo": "An Bholaiv",
"countries.br": "An Bhrasaíl",
"countries.bb": "Barbadós",
"countries.bn": "Brúiné",
"countries.bt": "An Bhútáin",
"countries.bw": "An Bhotsuáin",
"countries.cf": "Poblacht na hAfraice Láir",
"countries.ca": "Ceanada",
"countries.ch": "An Eilvéis",
"countries.cl": "An tSile",
"countries.cn": "An tSín",
"countries.ci": "Poblacht Côte dIvoire",
"countries.cm": "Camarún",
"countries.cd": "Poblacht Dhaonlathach an Chongó",
"countries.cg": "Poblacht an Chongó",
"countries.co": "An Cholóim",
"countries.km": "Oileáin Chomóra",
"countries.cv": "Cape Verde",
"countries.cr": "Costa Rica",
"countries.cu": "Cuba",
"countries.cy": "Cyprus",
"countries.cz": "Czechia",
"countries.de": "Germany",
"countries.cr": "Cósta Ríce",
"countries.cu": "Cúba",
"countries.cy": "An Chipir",
"countries.cz": "An tSeicia",
"countries.de": "An Ghearmáin",
"countries.dj": "Djibouti",
"countries.dm": "Dominica",
"countries.dk": "Denmark",
"countries.do": "Dominican Republic",
"countries.dz": "Algeria",
"countries.ec": "Ecuador",
"countries.eg": "Egypt",
"countries.er": "Eritrea",
"countries.es": "Spain",
"countries.ee": "Estonia",
"countries.et": "Ethiopia",
"countries.fi": "Finland",
"countries.fj": "Fiji",
"countries.fr": "France",
"countries.fm": "Micronesia",
"countries.ga": "Gabon",
"countries.gb": "United Kingdom",
"countries.ge": "Georgia",
"countries.gh": "Ghana",
"countries.gn": "Guinea",
"countries.gm": "Gambia",
"countries.gw": "Guinea-Bissau",
"countries.gq": "Equatorial Guinea",
"countries.gr": "Greece",
"countries.gd": "Grenada",
"countries.gt": "Guatemala",
"countries.gy": "Guyana",
"countries.hn": "Honduras",
"countries.hr": "Croatia",
"countries.ht": "Haiti",
"countries.hu": "Hungary",
"countries.id": "Indonesia",
"countries.dm": "Doiminice",
"countries.dk": "An Danmhairg",
"countries.do": "An Phoblacht Dhoiminiceach",
"countries.dz": "An Ailgéir",
"countries.ec": "Eacuadór",
"countries.eg": "An Éigipt",
"countries.er": "An Eiritré",
"countries.es": "An Spáinn",
"countries.ee": "An Eastóin",
"countries.et": "An Aetóip",
"countries.fi": "An Fhionlainn",
"countries.fj": "Fidsí",
"countries.fr": "An Fhrainc",
"countries.fm": "An Mhicrinéis",
"countries.ga": "An Ghabúin",
"countries.gb": "An Ríocht Aontaithe",
"countries.ge": "An tSeoirsia",
"countries.gh": "Gána",
"countries.gn": "An Ghuine",
"countries.gm": "An Ghaimbia",
"countries.gw": "Guine Bissau",
"countries.gq": "An Ghuine Mheánchiorclach",
"countries.gr": "An Ghréig",
"countries.gd": "Greanáda",
"countries.gt": "Guatamala",
"countries.gy": "An Ghuáin",
"countries.hn": "Hondúras",
"countries.hr": "An Chróit",
"countries.ht": "Háítí",
"countries.hu": "An Ungáir",
"countries.id": "An Indinéis",
"countries.in": "India",
"countries.ie": "Ireland",
"countries.ir": "Iran",
"countries.iq": "Iraq",
"countries.is": "Iceland",
"countries.il": "Israel",
"countries.it": "Italy",
"countries.jm": "Jamaica",
"countries.jo": "Jordan",
"countries.jp": "Japan",
"countries.kz": "Kazakhstan",
"countries.ke": "Kenya",
"countries.kg": "Kyrgyzstan",
"countries.kh": "Cambodia",
"countries.ki": "Kiribati",
"countries.kn": "Saint Kitts and Nevis",
"countries.kr": "South Korea",
"countries.kw": "Kuwait",
"countries.ie": "Éire",
"countries.ir": "An Iaráin",
"countries.iq": "An Iaráic",
"countries.is": "An Íoslainn",
"countries.il": "Iosrael",
"countries.it": "An Iodáil",
"countries.jm": "Iamáice",
"countries.jo": "An Iordáin",
"countries.jp": "An tSeapáin",
"countries.kz": "An Chasacstáin",
"countries.ke": "An Chéinia",
"countries.kg": "An Chirgeastáin",
"countries.kh": "An Chambóid",
"countries.ki": "Ciribeas",
"countries.kn": "San Críostóir-Nimheas",
"countries.kr": "An Chóiré Theas",
"countries.kw": "Cuáit",
"countries.la": "Laos",
"countries.lb": "Lebanon",
"countries.lr": "Liberia",
"countries.ly": "Libya",
"countries.lb": "An Liobáin",
"countries.lr": "An Libéir",
"countries.ly": "An Libia",
"countries.lc": "Saint Lucia",
"countries.li": "Liechtenstein",
"countries.lk": "Sri Lanka",
"countries.ls": "Lesotho",
"countries.lt": "Lithuania",
"countries.lu": "Luxembourg",
"countries.lv": "Latvia",
"countries.ma": "Morocco",
"countries.mc": "Monaco",
"countries.md": "Moldova",
"countries.li": "Lichtinstéin",
"countries.lk": "Srí Lanca",
"countries.ls": "Leosóta",
"countries.lt": "An Liotuáin",
"countries.lu": "Lucsamburg",
"countries.lv": "An Laitvia",
"countries.ma": "Maracó",
"countries.mc": "Monacó",
"countries.md": "An Mholdóiv",
"countries.mg": "Madagascar",
"countries.mv": "Maldives",
"countries.mx": "Mexico",
"countries.mh": "Marshall Islands",
"countries.mk": "Macedonia",
"countries.ml": "Mali",
"countries.mt": "Malta",
"countries.mm": "Myanmar",
"countries.me": "Montenegro",
"countries.mn": "Mongolia",
"countries.mz": "Mozambique",
"countries.mr": "Mauritania",
"countries.mu": "Mauritius",
"countries.mw": "Malawi",
"countries.my": "Malaysia",
"countries.na": "Namibia",
"countries.mv": "Oileáin Mhaildíve",
"countries.mx": "Meicsiceo",
"countries.mh": "Oileáin Marshall",
"countries.mk": "An Mhacadóin",
"countries.ml": "Mailí",
"countries.mt": "Málta",
"countries.mm": "Maenmar",
"countries.me": "Montainéagró",
"countries.mn": "An Mhongóil",
"countries.mz": "Mósaimbíc",
"countries.mr": "An Mháratáin",
"countries.mu": "Oileán Mhuirís",
"countries.mw": "Malávach",
"countries.my": "An Mhalaeisia",
"countries.na": "An Namaib",
"countries.ne": "Niger",
"countries.ng": "Nigeria",
"countries.ni": "Nicaragua",
"countries.nl": "Netherlands",
"countries.no": "Norway",
"countries.np": "Nepal",
"countries.nr": "Nauru",
"countries.nz": "New Zealand",
"countries.om": "Oman",
"countries.pk": "Pakistan",
"countries.ng": "An Nigéir",
"countries.ni": "Nicearagua",
"countries.nl": "An Ísiltír",
"countries.no": "An Iorua",
"countries.np": "Neipeal",
"countries.nr": "Nárú",
"countries.nz": "An Nua-Shéalainn",
"countries.om": "Óman",
"countries.pk": "An Phacastáin",
"countries.pa": "Panama",
"countries.pe": "Peru",
"countries.ph": "Philippines",
"countries.pw": "Palau",
"countries.pg": "Papua New Guinea",
"countries.pl": "Poland",
"countries.kp": "North Korea",
"countries.pt": "Portugal",
"countries.py": "Paraguay",
"countries.qa": "Qatar",
"countries.ro": "Romania",
"countries.ru": "Russia",
"countries.rw": "Rwanda",
"countries.sa": "Saudi Arabia",
"countries.sd": "Sudan",
"countries.sn": "Senegal",
"countries.sg": "Singapore",
"countries.sb": "Solomon Islands",
"countries.sl": "Sierra Leone",
"countries.sv": "El Salvador",
"countries.sm": "San Marino",
"countries.so": "Somalia",
"countries.rs": "Serbia",
"countries.ss": "South Sudan",
"countries.st": "São Tomé and Príncipe",
"countries.sr": "Suriname",
"countries.sk": "Slovakia",
"countries.si": "Slovenia",
"countries.se": "Sweden",
"countries.sz": "Swaziland",
"countries.sc": "Seychelles",
"countries.sy": "Syria",
"countries.td": "Chad",
"countries.tg": "Togo",
"countries.th": "Thailand",
"countries.tj": "Tajikistan",
"countries.tm": "Turkmenistan",
"countries.tl": "Timor-Leste",
"countries.pe": "Peiriú",
"countries.ph": "Na hOileáin Fhilipíneacha",
"countries.pw": "Oileáin Palau",
"countries.pg": "Nua-Ghuine Phapua",
"countries.pl": "An Pholainn",
"countries.kp": "An Chóiré Thuaidh",
"countries.pt": "An Phortaingéil",
"countries.py": "Paragua",
"countries.qa": "Catar",
"countries.ro": "An Rómáin",
"countries.ru": "An Rúis",
"countries.rw": "Ruanda",
"countries.sa": "An Araib Shádach",
"countries.sd": "An tSúdáin",
"countries.sn": "An tSeineagáil",
"countries.sg": "Singeapór",
"countries.sb": "Oileáin Sholaimh",
"countries.sl": "Siarra Leon",
"countries.sv": "An tSalvadóir",
"countries.sm": "San Mairíne",
"countries.so": "An tSomáil",
"countries.rs": "An tSeirbia",
"countries.ss": "An tSúdáin Theas",
"countries.st": "São Tomé agus Príncipe",
"countries.sr": "Suranam",
"countries.sk": "An tSlóvaic",
"countries.si": "An tSlóivéin",
"countries.se": "An tSualainn",
"countries.sz": "An tSuasalainn",
"countries.sc": "Na Séiséil",
"countries.sy": "An tSiria",
"countries.td": "Sead",
"countries.tg": "Tóga",
"countries.th": "An Téalainn",
"countries.tj": "An Táidsíceastáin",
"countries.tm": "An Tuircméanastáin",
"countries.tl": "Tíomór Thoir",
"countries.to": "Tonga",
"countries.tt": "Trinidad and Tobago",
"countries.tn": "Tunisia",
"countries.tr": "Turkey",
"countries.tv": "Tuvalu",
"countries.tz": "Tanzania",
"countries.tt": "Oileán na Tríonóide agus Tobága",
"countries.tn": "An Túinéis",
"countries.tr": "An Tuirc",
"countries.tv": "Túvalú",
"countries.tz": "An Tansáin",
"countries.ug": "Uganda",
"countries.ua": "Ukraine",
"countries.uy": "Uruguay",
"countries.us": "United States",
"countries.uz": "Uzbekistan",
"countries.va": "Vatican City",
"countries.vc": "Saint Vincent and the Grenadines",
"countries.ve": "Venezuela",
"countries.vn": "Vietnam",
"countries.vu": "Vanuatu",
"countries.ws": "Samoa",
"countries.ye": "Yemen",
"countries.za": "South Africa",
"countries.zm": "Zambia",
"countries.zw": "Zimbabwe",
"continents.af": "Africa",
"continents.an": "Antarctica",
"continents.as": "Asia",
"continents.eu": "Europe",
"continents.na": "North America",
"continents.oc": "Oceania",
"continents.sa": "South America"
"countries.ua": "An Úcráin",
"countries.uy": "Uragua",
"countries.us": "Na Stáit Aontaithe",
"countries.uz": "An Úisbéiceastáin",
"countries.va": "Cathair na Vatacáine",
"countries.vc": "San Uinseann agus na Greanáidíní",
"countries.ve": "Veiniséala",
"countries.vn": "Vítneam",
"countries.vu": "Vanuatú",
"countries.ws": "Samó",
"countries.ye": "Éimin",
"countries.za": "An Afraic Theas",
"countries.zm": "An tSaimbia",
"countries.zw": "An tSiombáib",
"continents.af": "An Afraic",
"continents.an": "Antartaice",
"continents.as": "An Áise",
"continents.eu": "An Eoraip",
"continents.na": "Meiriceá Thuaidh",
"continents.oc": "An Aigéine",
"continents.sa": "Meiriceá Theas"
}

View file

@ -1,30 +1,30 @@
{
"settings.inspire": "\"बुद्धिमान होने की कला यह जानने की कला है कि क्या अनदेखा करना चाहिए |\"",
"settings.inspire": "\"बुद्धिमान होने की कला यह जानने की कला है कि क्या अनदेखा किया जाए |\"",
"settings.locale": "hi",
"settings.direction": "ltr",
"emails.sender": "%s टीम",
"emails.verification.subject": "खाता सत्यापन",
"emails.verification.subject": "अकाउंट वेरिफिकेशन ",
"emails.verification.hello": "नमस्ते {{name}}",
"emails.verification.body": "इस लिंक के माध्यम से ईमेल सत्यापित कीजिये।",
"emails.verification.footer": "यदि आपने इस पते को सत्यापित करने के लिए नहीं कहा है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.verification.body": "इस लिंक के माध्यम से अपने ईमेल को सत्यापित कीजिये।",
"emails.verification.footer": "यदि आपने इस पते को सत्यापित नहीं करना चाहते है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.verification.thanks": "धन्यवाद",
"emails.verification.signature": "{{project}} टीम",
"emails.magicSession.subject": "लॉग इन",
"emails.magicSession.hello": "नमस्ते,",
"emails.magicSession.body": "इस लिंक के माध्यम से लॉग इन करें।",
"emails.magicSession.footer": "यदि आपने इस ईमेल का उपयोग करके लॉगिन करने के लिए नहीं कहा है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.magicSession.body": "इस लिंक के माध्यम से लॉग-इन करें।",
"emails.magicSession.footer": "यदि आप इस ईमेल द्वारा लॉगिन नहीं करना चाहते है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.magicSession.thanks": "धन्यवाद",
"emails.magicSession.signature": "{{project}} टीम",
"emails.recovery.subject": "पासवर्ड रीसेट",
"emails.recovery.hello": "नमस्ते {{name}}",
"emails.recovery.body": "इस लिंक के माध्यम से अपना {{project}} पासवर्ड रीसेट करें।",
"emails.recovery.footer": "यदि आपने अपना पासवर्ड रीसेट करने के लिए नहीं कहा है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.recovery.footer": "यदि आप अपना पासवर्ड रिसेट नहीं करना चाहते है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.recovery.thanks": "धन्यवाद",
"emails.recovery.signature": "{{project}} टीम",
"emails.invitation.subject": "%s टीम क %s पर आमंत्रण",
"emails.invitation.subject": "%s टीम का यहाँ %s पर आमंत्रण",
"emails.invitation.hello": "नमस्ते",
"emails.invitation.body": "यह मेल आपको इसलिए भेजा गया था क्योंकि {{owner}} आपको {{team}} टीम का सदस्य बनने के लिए आमंत्रित करना चाहते थे जो {{project}} से जुड़ा है।",
"emails.invitation.footer": "यदि यह आपके लिए आवश्यक नहीं है, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.invitation.body": "यह मेल आपको इसलिए भेजा गया था क्योंकि {{owner}} आपको {{team}} टीम का सदस्य बनाना चाहते थे, जो {{project}} से जुड़ा हुआ है।",
"emails.invitation.footer": "यदि आप इसमे रूचि नहीं रखते, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।",
"emails.invitation.thanks": "धन्यवाद",
"emails.invitation.signature": "{{project}} टीम",
"locale.country.unknown": "अज्ञात",

View file

@ -3,30 +3,30 @@
"settings.locale": "hu",
"settings.direction": "ltr",
"emails.sender": "%s Csapat",
"emails.verification.subject": "",
"emails.verification.hello": "",
"emails.verification.body": "",
"emails.verification.footer": "",
"emails.verification.thanks": "",
"emails.verification.signature": "",
"emails.magicSession.subject": "",
"emails.magicSession.hello": "",
"emails.magicSession.body": "",
"emails.magicSession.footer": "",
"emails.magicSession.thanks": "",
"emails.magicSession.signature": "",
"emails.recovery.subject": "",
"emails.recovery.hello": "",
"emails.recovery.body": "",
"emails.recovery.footer": "",
"emails.recovery.thanks": "",
"emails.recovery.signature": "",
"emails.invitation.subject": "",
"emails.invitation.hello": "",
"emails.invitation.body": "",
"emails.invitation.footer": "",
"emails.invitation.thanks": "",
"emails.invitation.signature": "",
"emails.verification.subject": "Fiók Megerősítése",
"emails.verification.hello": "Szia {{name}}",
"emails.verification.body": "Kattints a linkre, hogy megerősítsd az email címedet.",
"emails.verification.footer": "Ha nem te kérted a címed megerősítését, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.verification.thanks": "Köszönettel",
"emails.verification.signature": "a {{project}} csapat",
"emails.magicSession.subject": "Bejelentkezés",
"emails.magicSession.hello": "Szia,",
"emails.magicSession.body": "Kattints a linkre a bejelentkezéshez.",
"emails.magicSession.footer": "Ha nem te szerettél volna bejelentkezni ezzel az email címmel, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.magicSession.thanks": "Köszönettel",
"emails.magicSession.signature": "a {{project}} csapat",
"emails.recovery.subject": "Jelszó Visszaállítása",
"emails.recovery.hello": "Hahó, {{name}}",
"emails.recovery.body": "Kattints a linkre a {{project}} jelszavad visszaállításához.",
"emails.recovery.footer": "Ha nem te kezdeményezted a jelszavad visszaállítását, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.recovery.thanks": "Köszönettel",
"emails.recovery.signature": "a {{project}} csapat",
"emails.invitation.subject": "Meghívó a(z) %s csapatba, a(z) %s projektbe",
"emails.invitation.hello": "Szia",
"emails.invitation.body": "Ezt a levelet azért kaptad, mert {{owner}} meghívott, hogy légy a {{team}} csapat tagja a {{project}} projektben.",
"emails.invitation.footer": "Ha nem érdekel a lehetőség, nyugodtan hagyd figyelmen kívül ezt az üzenetet.",
"emails.invitation.thanks": "Köszönettel",
"emails.invitation.signature": "a {{project}} csapat",
"locale.country.unknown": "Ismeretlen",
"countries.af": "Afganisztán",
"countries.ao": "Angola",

View file

@ -3,30 +3,30 @@
"settings.locale": "jv",
"settings.direction": "ltr",
"emails.sender": "Tim %s",
"emails.verification.subject": "",
"emails.verification.hello": "",
"emails.verification.body": "",
"emails.verification.footer": "",
"emails.verification.thanks": "",
"emails.verification.signature": "",
"emails.magicSession.subject": "",
"emails.magicSession.hello": "",
"emails.magicSession.body": "",
"emails.magicSession.footer": "",
"emails.magicSession.thanks": "",
"emails.magicSession.signature": "",
"emails.recovery.subject": "",
"emails.recovery.hello": "",
"emails.recovery.body": "",
"emails.recovery.footer": "",
"emails.recovery.thanks": "",
"emails.recovery.signature": "",
"emails.invitation.subject": "",
"emails.invitation.hello": "",
"emails.invitation.body": "",
"emails.invitation.footer": "",
"emails.invitation.thanks": "",
"emails.invitation.signature": "",
"emails.verification.subject": "Verifikasi Akun",
"emails.verification.hello": "Hai {{name}}",
"emails.verification.body": "Klik link iki kanggo verifikasi alamat email sampeyan.",
"emails.verification.footer": "Yen sampeyan ora njaluk verifikasi alamat iki, sampeyan iso nglirwakake pesen iki.",
"emails.verification.thanks": "Matur nuwun",
"emails.verification.signature": "Tim {{project}}",
"emails.magicSession.subject": "Masuk",
"emails.magicSession.hello": "Hai,",
"emails.magicSession.body": "Klik link iki kanggo masuk.",
"emails.magicSession.footer": "Yen sampeyan ora njaluk masuk nggunakake alamat email iki, sampeyan iso nglirwakake pesen iki.",
"emails.magicSession.thanks": "Matur nuwun",
"emails.magicSession.signature": "Tim {{project}}",
"emails.recovery.subject": "Setel ulang sandi",
"emails.recovery.hello": "Halo {{name}}",
"emails.recovery.body": "Klik link iki kanggo setel ulang sandi {{project}}.",
"emails.recovery.footer": "Yen sampeyan ora njaluk setel ulang sandi, sampeyan iso nglirwakake pesen iki.",
"emails.recovery.thanks": "Matur nuwun",
"emails.recovery.signature": "Tim {{project}}",
"emails.invitation.subject": "Undangan ke Tim %s di %s",
"emails.invitation.hello": "Halo",
"emails.invitation.body": "Email iki dikirim menyang sampeyan amarga {{owner}} pengin ngajak sampeyan dadi anggota tim {{team}} di {{project}}.",
"emails.invitation.footer": "Yen sampeyan ora tertarik, sampeyan iso nglirwakake pesen iki.",
"emails.invitation.thanks": "Matur nuwun",
"emails.invitation.signature": "Tim {{project}}",
"locale.country.unknown": "Ora dingerteni",
"countries.af": "Afghanistan",
"countries.ao": "Angola",

View file

@ -3,30 +3,30 @@
"settings.locale": "mr",
"settings.direction": "ltr",
"emails.sender": "%s टीम",
"emails.verification.subject": "",
"emails.verification.hello": "",
"emails.verification.body": "",
"emails.verification.footer": "",
"emails.verification.thanks": "",
"emails.verification.signature": "",
"emails.magicSession.subject": "",
"emails.magicSession.hello": "",
"emails.magicSession.body": "",
"emails.magicSession.footer": "",
"emails.magicSession.thanks": "",
"emails.magicSession.signature": "",
"emails.recovery.subject": "",
"emails.recovery.hello": "",
"emails.recovery.body": "",
"emails.recovery.footer": "",
"emails.recovery.thanks": "",
"emails.recovery.signature": "",
"emails.invitation.subject": "",
"emails.invitation.hello": "",
"emails.invitation.body": "",
"emails.invitation.footer": "",
"emails.invitation.thanks": "",
"emails.invitation.signature": "",
"emails.verification.subject": "खाते सत्यापन",
"emails.verification.hello": "नमस्कार {{name}}",
"emails.verification.body": "आपला ईमेल पत्ता सत्यापित करण्यासाठी या दुव्याचे अनुसरण करा.",
"emails.verification.footer": "आपण या पत्त्याची पडताळणी करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.verification.thanks": "धन्यवाद",
"emails.verification.signature": "{{project}} संघ",
"emails.magicSession.subject": "लॉगिन करा",
"emails.magicSession.hello": "नमस्कार ,",
"emails.magicSession.body": "लॉगिन करण्यासाठी या लिंकचे अनुसरण करा.",
"emails.magicSession.footer": "आपण या ईमेलचा वापर करून लॉगिन करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.magicSession.thanks": "धन्यवाद",
"emails.magicSession.signature": "{{project}} संघ",
"emails.recovery.subject": "पासवर्ड रीसेट",
"emails.recovery.hello": "नमस्कार {{name}}",
"emails.recovery.body": "आपला {{project}}चे पासवर्ड रीसेट करण्यासाठी या लिंकचे अनुसरण करा",
"emails.recovery.footer": "आपण आपला पासवर्ड रीसेट करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.recovery.thanks": "धन्यवाद",
"emails.recovery.signature": "{{project}} संघ",
"emails.invitation.subject": "%s संघ %s येथे सामील होण्यासाठी आमंत्रण",
"emails.invitation.hello": "नमस्कार",
"emails.invitation.body": "हा मेल तुम्हाला पाठवला होता कारण {{owner}} तुम्हाला {{project}} येथे {{team}} टीमचे सदस्य होण्यासाठी आमंत्रित करू इच्छित होते.",
"emails.invitation.footer": "आपल्याला स्वारस्य नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.",
"emails.invitation.thanks": "धन्यवाद",
"emails.invitation.signature": "{{project}} संघ",
"locale.country.unknown": "अज्ञात",
"countries.af": "अफगानिस्तान",
"countries.ao": "अंगोला",

View file

@ -3,30 +3,30 @@
"settings.locale": "ur",
"settings.direction": "rtl",
"emails.sender": "%s ٹیم",
"emails.verification.subject": "",
"emails.verification.hello": "",
"emails.verification.body": "",
"emails.verification.footer": "",
"emails.verification.thanks": "",
"emails.verification.signature": "",
"emails.magicSession.subject": "",
"emails.magicSession.hello": "",
"emails.magicSession.body": "",
"emails.magicSession.footer": "",
"emails.magicSession.thanks": "",
"emails.magicSession.signature": "",
"emails.recovery.subject": "",
"emails.recovery.hello": "",
"emails.recovery.body": "",
"emails.recovery.footer": "",
"emails.recovery.thanks": "",
"emails.recovery.signature": "",
"emails.invitation.subject": "",
"emails.invitation.hello": "",
"emails.invitation.body": "",
"emails.invitation.footer": "",
"emails.invitation.thanks": "",
"emails.invitation.signature": "",
"emails.verification.subject": "اکاؤنٹ کی تصدیق",
"emails.verification.hello": "خوش آمدید {{name}}",
"emails.verification.body": "براہ کرم اپنے ای میل کی تصدیق کے لیے درج ذیل لنک پر عمل کریں۔",
"emails.verification.footer": "اگر آپ نے اس پتے کی تصدیق کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.verification.thanks": "شکریہ",
"emails.verification.signature": "ٹیم۔ {{project}}",
"emails.magicSession.subject": "اگ ان کریں",
"emails.magicSession.hello": "خوش آمدید,",
"emails.magicSession.body": "لاگ ان کرنے کے لیے اس لنک پر عمل کریں۔",
"emails.magicSession.footer": "اگر آپ نے اس ای میل کا استعمال کرتے ہوئے لاگ ان کرنے کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.magicSession.thanks": "شکریہ",
"emails.magicSession.signature": "ٹیم۔ {{project}}",
"emails.recovery.subject": "پاس ورڈ ری سیٹ۔",
"emails.recovery.hello": "ہیلو {{name}}",
"emails.recovery.body": "{{project}} کا پاس ورڈ تبدیل کرنے کے لیے درج ذیل لنک پر عمل کریں",
"emails.recovery.footer": "اگر آپ نے اپنا پاس ورڈ دوبارہ ترتیب دینے کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.recovery.thanks": "شکریہ",
"emails.recovery.signature": "ٹیم۔ {{project}}",
"emails.invitation.subject": "%s پر %s ٹیم کو دعوت",
"emails.invitation.hello": "خوش آمدید",
"emails.invitation.body": "یہ پیغام آپ کو اس لیے بھیجا گیا تھا کہ {{owner}} نے آپ کو {{project}} میں {{team}} ٹیم کا رکن بننے کی دعوت بھیجی",
"emails.invitation.footer": "اگر آپ دلچسپی نہیں رکھتے تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔",
"emails.invitation.thanks": "شکریہ",
"emails.invitation.signature": "ٹیم۔ {{project}",
"locale.country.unknown": "نامعلوم",
"countries.af": "افغانستان",
"countries.ao": "انگولا",
@ -229,4 +229,4 @@
"continents.na": "شمالی امریکہ",
"continents.oc": "اوشینیا",
"continents.sa": "جنوبی امریکہ"
}
}

View file

@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '4.0.4',
'version' => '5.0.0',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@ -190,7 +190,7 @@ return [
[
'key' => 'nodejs',
'name' => 'Node.js',
'version' => '2.5.1',
'version' => '3.0.0',
'url' => 'https://github.com/appwrite/sdk-for-node',
'package' => 'https://www.npmjs.com/package/node-appwrite',
'enabled' => true,
@ -208,11 +208,11 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '0.4.1',
'version' => '1.0.0',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
'beta' => true,
'beta' => false,
'dev' => false,
'hidden' => false,
'family' => APP_PLATFORM_SERVER,

View file

@ -44,7 +44,7 @@ App::post('/v1/account')
->label('sdk.response.model', Response::MODEL_USER)
->label('abuse-limit', 10)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('request')
->inject('response')
@ -160,7 +160,7 @@ App::post('/v1/account/sessions')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('request')
->inject('response')
->inject('projectDB')
@ -1356,8 +1356,8 @@ App::patch('/v1/account/password')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('password', '', new Password(), 'New user password. Must be between 6 to 32 chars.')
->param('oldPassword', '', new Password(), 'Old user password. Must be between 6 to 32 chars.', true)
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('oldPassword', '', new Password(), 'Old user password. Must be at least 8 chars.', true)
->inject('response')
->inject('user')
->inject('projectDB')
@ -1404,7 +1404,7 @@ App::patch('/v1/account/email')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('response')
->inject('user')
->inject('projectDB')
@ -1863,8 +1863,8 @@ App::put('/v1/account/recovery')
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', new UID(), 'User account UID address.')
->param('secret', '', new Text(256), 'Valid reset token.')
->param('password', '', new Password(), 'New password. Must be between 6 to 32 chars.')
->param('passwordAgain', '', new Password(), 'New password again. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('passwordAgain', '', new Password(), 'New password again. Must be at least 8 chars.')
->inject('response')
->inject('projectDB')
->inject('audits')

View file

@ -46,9 +46,20 @@ App::get('/v1/health/db')
->action(function ($response, $utopia) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\App $utopia */
$utopia->getResource('db');
try {
$db = $utopia->getResource('db'); /* @var $db PDO */
$response->json(['status' => 'OK']);
// Run a small test to check the connection
$statement = $db->prepare("SELECT 1;");
$statement->closeCursor();
$statement->execute();
} catch (Exception $_e) {
throw new Exception('Database is not available', 500);
}
return $response->json(['status' => 'OK']);
});
App::get('/v1/health/cache')
@ -64,9 +75,14 @@ App::get('/v1/health/cache')
->action(function ($response, $utopia) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\App $utopia */
$utopia->getResource('cache');
/** @var Redis */
$redis = $utopia->getResource('cache');
$response->json(['status' => 'OK']);
if ($redis->ping(true)) {
return $response->json(['status' => 'OK']);
} else {
throw new Exception('Cache is not available', 500);
}
});
App::get('/v1/health/time')

View file

@ -12,6 +12,7 @@ use Utopia\Validator\Integer;
use Utopia\Config\Config;
use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Validator\Password;
use Appwrite\Task\Validator\Cron;
use Appwrite\Database\Database;
use Appwrite\Database\Document;
@ -578,7 +579,7 @@ App::delete('/v1/projects/:projectId')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('password', '', new UID(), 'Your user password for confirmation. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'Your user password for confirmation. Must be at least 8 chars.')
->inject('response')
->inject('user')
->inject('consoleDB')

View file

@ -247,7 +247,7 @@ App::get('/v1/storage/files/:fileId/preview')
->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true)
->param('borderRadius', 0, new Range(0, 4000), 'Preview image border radius in pixels. Pass an integer between 0 to 4000.', true)
->param('opacity', 1, new Range(0,1, Range::TYPE_FLOAT), 'Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.', true)
->param('rotation', 0, new Range(0,360), 'Preview image rotation in degrees. Pass an integer between 0 and 360.', true)
->param('rotation', 0, new Range(-360,360), 'Preview image rotation in degrees. Pass an integer between -360 and 360.', true)
->param('background', '', new HexColor(), 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->inject('request')
@ -362,7 +362,7 @@ App::get('/v1/storage/files/:fileId/preview')
}
if (!empty($rotation)) {
$image->setRotation($rotation);
$image->setRotation(($rotation + 360) % 360);
}
$output = (empty($output)) ? $type : $output;

View file

@ -33,7 +33,7 @@ App::post('/v1/users')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('projectDB')

View file

@ -234,29 +234,74 @@ App::post('/v1/mock/tests/general/upload')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->param('file', [], new File(), 'Sample file param', false)
->inject('request')
->action(function ($x, $y, $z, $file, $request) {
->inject('response')
->action(function ($x, $y, $z, $file, $request, $response) {
/** @var Utopia\Swoole\Request $request */
/** @var Utopia\Swoole\Response $response */
$file = $request->getFiles('file');
$file['tmp_name'] = (\is_array($file['tmp_name'])) ? $file['tmp_name'] : [$file['tmp_name']];
$file['name'] = (\is_array($file['name'])) ? $file['name'] : [$file['name']];
$file['size'] = (\is_array($file['size'])) ? $file['size'] : [$file['size']];
$contentRange = $request->getHeader('content-range');
if(!empty($contentRange)) {
$start = $request->getContentRangeStart();
$end = $request->getContentRangeEnd();
$size = $request->getContentRangeSize();
$id = $request->getHeader('x-appwrite-id', '');
$file['size'] = (\is_array($file['size'])) ? $file['size'] : [$file['size']];
foreach ($file['name'] as $i => $name) {
if ($name !== 'file.png') {
throw new Exception('Wrong file name', 400);
if(is_null($start) || is_null($end) || is_null($size)) {
throw new Exception('Invalid content-range header', 400);
}
}
foreach ($file['size'] as $i => $size) {
if ($size !== 38756) {
throw new Exception('Wrong file size', 400);
if($start > $end || $end > $size) {
throw new Exception('Invalid content-range header', 400);
}
}
foreach ($file['tmp_name'] as $i => $tmpName) {
if (\md5(\file_get_contents($tmpName)) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
throw new Exception('Wrong file uploaded', 400);
if($start === 0 && !empty($id)) {
throw new Exception('First chunked request cannot have id header', 400);
}
if($start !== 0 && $id !== 'newfileid') {
throw new Exception('All chunked request must have id header (except first)', 400);
}
if($end !== $size && $end-$start+1 !== 5*1024*1024) {
throw new Exception('Chunk size must be 5MB (except last chunk)', 400);
}
foreach ($file['size'] as $i => $sz) {
if ($end !== $size && $sz !== 5*1024*1024) {
throw new Exception('Wrong chunk size', 400);
}
if($sz > 5*1024*1024) {
throw new Exception('Chunk size must be 5MB or less', 400);
}
}
if($end !== $size) {
$response->json(['$id'=> 'newfileid']);
}
} else {
$file['tmp_name'] = (\is_array($file['tmp_name'])) ? $file['tmp_name'] : [$file['tmp_name']];
$file['name'] = (\is_array($file['name'])) ? $file['name'] : [$file['name']];
$file['size'] = (\is_array($file['size'])) ? $file['size'] : [$file['size']];
foreach ($file['name'] as $i => $name) {
if ($name !== 'file.png') {
throw new Exception('Wrong file name', 400);
}
}
foreach ($file['size'] as $i => $size) {
if ($size !== 38756) {
throw new Exception('Wrong file size', 400);
}
}
foreach ($file['tmp_name'] as $i => $tmpName) {
if (\md5(\file_get_contents($tmpName)) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
throw new Exception('Wrong file uploaded', 400);
}
}
}
});

View file

@ -487,7 +487,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
*
* Abuse limits are sending 32 times per minute and connection.
*/
$timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $db);
$timeLimit = new TimeLimit('url:{url},connection:{connection}', 32, 60, $db);
$timeLimit
->setNamespace('app_' . $realtime->connections[$connection]['projectId'])
->setParam('{connection}', $connection)

View file

@ -45,7 +45,7 @@ $root = ($this->getParam('root') !== 'disabled');
<input name="email" type="email" autocomplete="email" placeholder="" required data-ls-bind="{{router.params.email}}">
<label>Password</label>
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter pattern=".{6,}" title="Six or more characters">
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter pattern=".{8,}" title="Eight or more characters">
<div class="agree margin-top-large margin-bottom-large">
<div class="pull-start margin-end-small margin-bottom">

View file

@ -51,7 +51,7 @@ if(!empty($platforms)) {
<?php endforeach; ?>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" />
<meta name="theme-color" content="#24f4d4">
<meta name="theme-color" content="#f02e65">
<meta property="og:type" content="website" />
<meta property="og:title" content="<?php echo $this->escape($this->getParam('title', '')); ?>" />
<meta property="og:description" content="<?php echo $this->escape($this->getParam('description', '')); ?>" />

View file

@ -381,7 +381,7 @@ class FunctionsV1 extends Worker
}
}
if (isset($list[$container]) && !(\substr($list[$container]->getStatus(), 0, 2) === 'Up')) { // Remove conatiner if not online
if (isset($list[$container]) && !(\substr($list[$container]->getStatus(), 0, 2) === 'Up')) { // Remove container if not online
$stdout = '';
$stderr = '';
@ -403,7 +403,7 @@ class FunctionsV1 extends Worker
* Make sure no access to NFS server / storage volumes
* Access Appwrite REST from internal network for improved performance
*/
if (!isset($list[$container])) { // Create contianer if not ready
if (!isset($list[$container])) { // Create container if not ready
$stdout = '';
$stderr = '';

View file

@ -64,7 +64,7 @@
"slickdeals/statsd": "3.1.0"
},
"require-dev": {
"appwrite/sdk-generator": "0.16.0",
"appwrite/sdk-generator": "0.16.2",
"phpunit/phpunit": "9.5.6",
"swoole/ide-helper": "4.6.7",
"textalk/websocket": "1.5.2",

133
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c5e9d3dbc8964f01310bb249b654fb7a",
"content-hash": "a3aad9d7aba75e837b4c6e242c7a91a3",
"packages": [
{
"name": "adhocore/jwt",
@ -540,16 +540,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.5.0",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0"
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"shasum": ""
},
"require": {
@ -604,7 +604,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.5.0"
"source": "https://github.com/guzzle/promises/tree/1.5.1"
},
"funding": [
{
@ -620,7 +620,7 @@
"type": "tidelift"
}
],
"time": "2021-10-07T13:05:22+00:00"
"time": "2021-10-22T20:56:57+00:00"
},
{
"name": "guzzlehttp/psr7",
@ -1959,20 +1959,19 @@
},
{
"name": "utopia-php/image",
"version": "0.5.2",
"version": "0.5.3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
"reference": "049446fea7cb53db8a431455ec382e30e6d1482a"
"reference": "4a8429b62dcf56562b038d6712375f75166f0c02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/049446fea7cb53db8a431455ec382e30e6d1482a",
"reference": "049446fea7cb53db8a431455ec382e30e6d1482a",
"url": "https://api.github.com/repos/utopia-php/image/zipball/4a8429b62dcf56562b038d6712375f75166f0c02",
"reference": "4a8429b62dcf56562b038d6712375f75166f0c02",
"shasum": ""
},
"require": {
"chillerlan/php-qrcode": "4.3.1",
"ext-imagick": "*",
"php": ">=7.4"
},
@ -2006,9 +2005,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/image/issues",
"source": "https://github.com/utopia-php/image/tree/0.5.2"
"source": "https://github.com/utopia-php/image/tree/0.5.3"
},
"time": "2021-10-18T06:41:05+00:00"
"time": "2021-11-02T05:47:16+00:00"
},
{
"name": "utopia-php/locale",
@ -2670,16 +2669,16 @@
},
{
"name": "appwrite/sdk-generator",
"version": "0.16.0",
"version": "0.16.2",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "5a57afe89ded393a3eca8d9ba96b8e2c479f2601"
"reference": "e3a20c96a745a9c4aa048fd344650fcfbf41cf6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/5a57afe89ded393a3eca8d9ba96b8e2c479f2601",
"reference": "5a57afe89ded393a3eca8d9ba96b8e2c479f2601",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/e3a20c96a745a9c4aa048fd344650fcfbf41cf6f",
"reference": "e3a20c96a745a9c4aa048fd344650fcfbf41cf6f",
"shasum": ""
},
"require": {
@ -2713,9 +2712,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.16.0"
"source": "https://github.com/appwrite/sdk-generator/tree/0.16.2"
},
"time": "2021-10-21T06:49:55+00:00"
"time": "2021-11-12T11:09:38+00:00"
},
{
"name": "composer/package-versions-deprecated",
@ -2792,16 +2791,16 @@
},
{
"name": "composer/semver",
"version": "3.2.5",
"version": "3.2.6",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9"
"reference": "83e511e247de329283478496f7a1e114c9517506"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9",
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9",
"url": "https://api.github.com/repos/composer/semver/zipball/83e511e247de329283478496f7a1e114c9517506",
"reference": "83e511e247de329283478496f7a1e114c9517506",
"shasum": ""
},
"require": {
@ -2853,7 +2852,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.5"
"source": "https://github.com/composer/semver/tree/3.2.6"
},
"funding": [
{
@ -2869,7 +2868,7 @@
"type": "tidelift"
}
],
"time": "2021-05-24T12:41:47+00:00"
"time": "2021-10-25T11:34:17+00:00"
},
{
"name": "composer/xdebug-handler",
@ -3384,16 +3383,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.13.0",
"version": "v4.13.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "50953a2691a922aa1769461637869a0a2faa3f53"
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53",
"reference": "50953a2691a922aa1769461637869a0a2faa3f53",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd",
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd",
"shasum": ""
},
"require": {
@ -3434,9 +3433,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1"
},
"time": "2021-09-20T12:20:58+00:00"
"time": "2021-11-03T20:52:16+00:00"
},
{
"name": "openlss/lib-array2xml",
@ -3831,23 +3830,23 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.7",
"version": "9.2.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218"
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.12.0",
"nikic/php-parser": "^4.13.0",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@ -3896,7 +3895,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8"
},
"funding": [
{
@ -3904,7 +3903,7 @@
"type": "github"
}
],
"time": "2021-09-17T05:39:03+00:00"
"time": "2021-10-30T08:01:38+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -4252,20 +4251,20 @@
},
{
"name": "psr/container",
"version": "1.1.1",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
"php": ">=7.4.0"
},
"type": "library",
"autoload": {
@ -4294,9 +4293,9 @@
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/1.1.1"
"source": "https://github.com/php-fig/container/tree/1.1.2"
},
"time": "2021-03-05T17:36:06+00:00"
"time": "2021-11-05T16:50:12+00:00"
},
{
"name": "sebastian/cli-parser",
@ -4727,16 +4726,16 @@
},
{
"name": "sebastian/exporter",
"version": "4.0.3",
"version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65"
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65",
"reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"shasum": ""
},
"require": {
@ -4785,14 +4784,14 @@
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3"
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
},
"funding": [
{
@ -4800,7 +4799,7 @@
"type": "github"
}
],
"time": "2020-09-28T05:24:23+00:00"
"time": "2021-11-11T14:18:36+00:00"
},
{
"name": "sebastian/global-state",
@ -5151,7 +5150,6 @@
"type": "github"
}
],
"abandoned": true,
"time": "2020-09-28T06:45:17+00:00"
},
{
@ -5317,16 +5315,16 @@
},
{
"name": "symfony/console",
"version": "v5.3.7",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a"
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a",
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a",
"url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3",
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3",
"shasum": ""
},
"require": {
@ -5396,7 +5394,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.3.7"
"source": "https://github.com/symfony/console/tree/v5.3.10"
},
"funding": [
{
@ -5412,7 +5410,7 @@
"type": "tidelift"
}
],
"time": "2021-08-25T20:02:16+00:00"
"time": "2021-10-26T09:30:15+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
@ -5902,16 +5900,16 @@
},
{
"name": "symfony/string",
"version": "v5.3.7",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5"
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5",
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5",
"url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c",
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c",
"shasum": ""
},
"require": {
@ -5965,7 +5963,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.3.7"
"source": "https://github.com/symfony/string/tree/v5.3.10"
},
"funding": [
{
@ -5981,7 +5979,7 @@
"type": "tidelift"
}
],
"time": "2021-08-26T08:00:08+00:00"
"time": "2021-10-27T18:21:46+00:00"
},
{
"name": "textalk/websocket",
@ -6314,6 +6312,7 @@
"issues": "https://github.com/webmozart/path-util/issues",
"source": "https://github.com/webmozart/path-util/tree/2.3.0"
},
"abandoned": "symfony/filesystem",
"time": "2015-12-17T08:42:14+00:00"
}
],
@ -6341,5 +6340,5 @@
"platform-overrides": {
"php": "8.0"
},
"plugin-api-version": "2.0.0"
"plugin-api-version": "2.1.0"
}

View file

@ -71,9 +71,9 @@ services:
- ./psalm.xml:/usr/src/code/psalm.xml
- ./tests:/usr/src/code/tests
- ./app:/usr/src/code/app
- ./public:/usr/src/code/public
# - ./vendor:/usr/src/code/vendor
- ./docs:/usr/src/code/docs
- ./public:/usr/src/code/public
- ./src:/usr/src/code/src
- ./debug:/tmp
- ./dev:/usr/local/dev

View file

@ -1,2 +1,2 @@
Update currently logged in user account email address. After changing user address, user confirmation status is being reset and a new confirmation mail is sent. For security measures, user password is required to complete this request.
This endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.
Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.
This endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.

View file

@ -1 +1 @@
Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.
Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.

View file

@ -12,7 +12,6 @@ client
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
```
### Make your first request
@ -22,13 +21,8 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```typescript
let users = new sdk.Users(client);
let promise = users.create('email@example.com', 'password');
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
let response = await users.create('email@example.com', 'password');
console.log(response);
```
### Full Example
@ -45,13 +39,8 @@ client
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
let promise = users.create('email@example.com', 'password');
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
let response = await users.create('email@example.com', 'password');
console.log(response);
```
### Error Handling
@ -61,7 +50,7 @@ The Appwrite Deno SDK raises `AppwriteException` object with `message`, `code` a
let users = new sdk.Users(client);
try {
let res = await users.create('email@example.com', 'password');
let response = await users.create('email@example.com', 'password');
} catch(e) {
console.log(e.message);
}

View file

@ -58,14 +58,16 @@ For **Windows** add your app <u>name</u> and <u>package name</u>, Your package n
```dart
import 'package:appwrite/appwrite.dart';
Client client = Client();
void main() {
Client client = Client();
client
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
.setProject('5e8cf4f46b5e8') // Your project ID
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
client
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
.setProject('5e8cf4f46b5e8') // Your project ID
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
}
```
Before starting to send any API calls to your new Appwrite instance, make sure your Android or iOS emulators has network access to the Appwrite server hostname or IP address.
@ -91,25 +93,28 @@ Response user = await account
```dart
import 'package:appwrite/appwrite.dart';
Client client = Client();
void main() {
Client client = Client();
client
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
.setProject('5e8cf4f46b5e8') // Your project ID
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
client
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
.setProject('5e8cf4f46b5e8') // Your project ID
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
// Register User
Account account = Account(client);
// Register User
Account account = Account(client);
Response user = await account
.create(
email: 'me@appwrite.io',
password: 'password',
name: 'My Name'
);
Response user = await account
.create(
email: 'me@appwrite.io',
password: 'password',
name: 'My Name'
);
}
```
### Error Handling

View file

@ -0,0 +1,257 @@
# Creating a new functions runtime 🏃
This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
## Getting started
Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's Cloud Functions! Appwrite's goal is to support as many function runtimes as possible.
## 1. Prerequisites
For a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works:
- [ ] The Language in question must be able to run a web server that can serve JSON and text.
- [ ] The Runtime must be able to be packaged into a Docker container
Note: Both Compiled and Interpreted languages work with Appwrite's execution model but are written in slightly different ways.
It's really easy to contribute to an open-source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your local version of Appwrite, where you can make any changes without affecting Appwrite right away.
> If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime).
### 1.1 Fork the Appwrite repository
Before making any changes, you will need to fork Appwrite's repository to keep branches on the official repo clean. To do that, visit [Appwrite's Runtime repository](https://github.com/appwrite/php-runtimes) and click on the fork button.
[![Fork button](https://github.com/appwrite/appwrite/raw/master/docs/tutorials/images/fork.png)](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/images/fork.png)
This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using the `git clone` command:
```bash
$ git clone COPIED_URL
```
> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a clean and simple visual Git client.
Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `refactor` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name.
## 2. Implement new runtime
### 2.1 Preparing the files for your new runtime
The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance, if I was to write a Rust Runtime with version 1.55 the folder name would be: `rust-1.55`
Within that folder you will need to create a few basic files that all Appwrite runtimes require:
```
Dockerfile - Dockerfile that explains how the container will be built.
README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 runtime.
```
### 2.2 Differences between compiled and interpreted runtimes
Runtimes within Appwrite are created differently depending on whether they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code.
Interpreted languages have both a `build.sh` file and a `launch.sh` file.
The `build.sh` file for an interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code and then to copy it to the `/usr/code` folder which is then packaged and can be used later for running the server.
The build script is always executed during the build stage of tag deployment.
The `launch.sh` file for an interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution.
---
Compiled Languages only have a `build.sh` file.
The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` for the ubuntu or alpine images to detect and run them.
#### Note:
`/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need.
### 2.3 Writing the runtime
Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes.
The best way to go about writing a runtime is like so:
Initialize a web server that runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following:
1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and an `unauthorized` error message.
2. Decode the executor's JSON POST request. This normally looks like so:
```json
{
"path": "/usr/code",
"file": "index.js",
"env": {
"hello":"world!"
},
"payload":"An Example Payload",
"timeout": 10
}
```
For a compiled language you can disregard the `path` and `file` attribute if you like,
`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise, it doesn't matter since the connection will simply be dropped by the executor.
You must create two classes for users to use within their scripts. A `Request` Class and a `Response` class
The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function.
The Request always goes before the response in the user's function parameters.
The `Response` class must have two functions.
- A `send(string)` function which will return text to the request
- and a `json(object)` function which will return JSON to the request setting the appropriate headers
For interpreted languages use the `path` and `file` parameters to find the file and require it.
Please make sure to add appropriate checks to make sure the imported file is a function that you can execute.
5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return them cleanly to the executor with the error schema.
### 2.4 The Error Schema
All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user.
```json
{
"code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed.
"message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user.
}
```
### 2.5 Writing your Dockerfile
The Dockerfile is very important as it's the environment you are creating to run build the runtime and also run the code if you are writing an Interpreted Runtime (Compiled runtimes will use an alpine or ubuntu image)
The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are creating a runtime for.
Next in your Dockerfile at the start add the docker image you want to base it off at the top like so:
```bash
FROM Dart:2.12 # Dart is used as an example.
```
This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for.
Create a user and group for the runtime, this user will be used to both build and run the code:
```bash
RUN groupadd -g 2000 appwrite \
&& useradd -m -u 2001 -g appwrite appwrite
```
then create the folders you will use in your build step:
```bash
RUN mkdir -p /usr/local/src/
RUN mkdir -p /usr/code
RUN mkdir -p /usr/workspace
RUN mkdir -p /usr/builtCode
```
Next copy your source code and set the working directory for the image like so:
```
WORKDIR /usr/local/src
COPY . /usr/local/src
```
Next, you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so:
```
RUN chmod +x ./build.sh
RUN chmod +x ./launch.sh
```
Note: Do not chmod a `launch.sh` file if you don't have one.
If needed use the `RUN` commands to install any dependencies you require for the build stage.
Next set the permissions for the user you created so your build and run step will have access to them:
```
RUN ["chown", "-R", "appwrite:appwrite", "/usr/local/src"]
RUN ["chown", "-R", "appwrite:appwrite", "/usr/code"]
RUN ["chown", "-R", "appwrite:appwrite", "/usr/workspace"]
RUN ["chown", "-R", "appwrite:appwrite", "/usr/builtCode"]
```
Finally, you'll add a `CMD` command. For an interpreted language this should be:
```
CMD ["/usr/local/src/launch.sh"]
```
Since this will use your launch script when the runtime starts.
For a compiled language this must be:
```
CMD ["tail", "-f", "/dev/null"]
```
so the build steps can be run.
## 3. Building your Docker image and adding it to the list
With your runtime successfully created you can now move on to building your docker image and adding it to the script files used for generating all of the image files.
Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to it. The following is an example with dart version 2.12
```
echo 'Dart 2.12...'
docker build -t dart-runtime:2.12 ./runtimes/dart-2.12
```
Next, open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross-platform compiles and deploying it to Docker hub. The following is an example also with dart version 2.12:
```
echo 'Dart 2.12...'
docker buildx build --platform linux/amd64,linux/arm64 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push
```
## 4. Adding the runtime to the runtimes list
In `src/Runtimes/Runtimes` create a new entry in the `__construct()` method in the Runtimes class like so:
```
$dart = new Runtime('dart', 'Dart');
$dart->addVersion('2.12', 'dart-runtime:2.12', 'appwrite-ubuntu:20.04', [System::X86, System::ARM]);
$this->runtimes['dart'] = $dart;
```
This is an example of what you would do for a compiled language such as dart.
The first line is creating a new language entry, The first parameter is the internal name and the second one is the external one which is what the user will see in Appwrite.
The second line adds a new version to the language entry, I'll break down the parameters:
```
1: Version - The version of the runtime you are creating.
2: Build Image - The image used to build the code
3: Run Image - The image used to run the code.
For interpreted languages, this is normally the same as the Build Image, but for compiled languages, this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04"
We recommend using Alpine when possible and using Ubuntu if the runtime doesn't work on Alpine.
4: Platforms Supported - These are the architectures this runtime is available to.
```
The third line simply adds the new runtime to the main list.
## 5. Adding tests
### 5.1 Writing your test execution script
Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema:
```json
{
"normal": "Hello World!",
"env1": request.env['ENV1'], // ENV1 from the request environment variable
"payload": request.payload, // Payload from the request
}
```
### 5.2 Creating the test packaging script for your runtime
With your test execution written you can move on to writing the script used to package your test execution script into a tarball for later use by the test system. Move into `/test/resources` again and notice how we have shell scripts for all runtimes we have made tests for.
Next create a shell script yourself with your language name. As an example, the shell script name for dart would be `package-dart.sh`
Within this newly created script copy-paste this script and replace all the `LANGUAGE_NAME` parts with your language's name
```
echo 'LANGUAGE_NAME Packaging...'
rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz
tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME .
```
Then save this file. Then `cd` into the root of the `php-runtimes` project in a terminal. Run the following command replacing the `LANGUAGE_NAME` with your language's name:
```
chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh
```
This command adds execution permissions to your script and executes it.
NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once.
### 5.3 Adding your runtime to the main testing script
Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`.
Once you have found this, Add your own entry into this array like so:
```php
'LANGUAGE_NAME-VERSION' => [
'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz',
'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME
'timeout' => 15,
'runtime' => 'LANGUAGE_NAME-VERSION',
'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value.
],
```
Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version.
Once you have done this and saved it, it is finally time to move onto one of the final steps.
### 5.4 Running the tests.
Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a Docker container with the test script and start running through all the runtimes making sure to test them thoroughly.
If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo making sure to target the `refactor` branch, make sure you're ready to respond to any feedback which can arise during our code review.
## 6. Raise a pull request
First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted.
## ![face_with_head_bandage](https://github.githubassets.com/images/icons/emoji/unicode/1f915.png) Stuck ?
If you need any help with the contribution, feel free to head over to [our discord channel](https://appwrite.io/discord) and we'll be happy to help you out.

View file

@ -9,7 +9,7 @@ const gulpCleanCSS = require('gulp-clean-css');
// Config
const configApp = {
const configApp = {
mainFile: 'app.js',
src: [
'public/scripts/dependencies/litespeed.js',
@ -76,7 +76,7 @@ const configApp = {
'public/scripts/views/general/switch.js',
'public/scripts/views/general/theme.js',
'public/scripts/views/general/version.js',
'public/scripts/views/paging/back.js',
'public/scripts/views/paging/next.js',
@ -87,19 +87,44 @@ const configApp = {
'public/scripts/views/ui/phases.js',
'public/scripts/views/ui/trigger.js',
],
dest: './public/dist/scripts'
};
const configDep = {
mainFile: 'app-dep.js',
src: [
//'node_modules/appwrite/src/sdk.js',
'public/scripts/dependencies/appwrite.js',
'public/scripts/dependencies/chart.js',
'public/scripts/dependencies/markdown-it.js',
'public/scripts/dependencies/pell.js',
'public/scripts/dependencies/prism.js',
'public/scripts/dependencies/turndown.js',
'node_modules/chart.js/dist/chart.js',
'node_modules/markdown-it/dist/markdown-it.js',
'node_modules/pell/dist/pell.js',
'node_modules/turndown/dist/turndown.js',
// PrismJS Core
'node_modules/prismjs/components/prism-core.min.js',
// PrismJS Languages
'node_modules/prismjs/components/prism-markup.min.js',
'node_modules/prismjs/components/prism-css.min.js',
'node_modules/prismjs/components/prism-clike.min.js',
'node_modules/prismjs/components/prism-javascript.min.js',
'node_modules/prismjs/components/prism-bash.min.js',
'node_modules/prismjs/components/prism-csharp.min.js',
'node_modules/prismjs/components/prism-dart.min.js',
'node_modules/prismjs/components/prism-go.min.js',
'node_modules/prismjs/components/prism-graphql.min.js',
'node_modules/prismjs/components/prism-http.min.js',
'node_modules/prismjs/components/prism-java.min.js',
'node_modules/prismjs/components/prism-json.min.js',
'node_modules/prismjs/components/prism-kotlin.min.js',
'node_modules/prismjs/components/prism-markup-templating.min.js',
'node_modules/prismjs/components/prism-php.min.js',
'node_modules/prismjs/components/prism-powershell.min.js',
'node_modules/prismjs/components/prism-python.min.js',
'node_modules/prismjs/components/prism-ruby.min.js',
'node_modules/prismjs/components/prism-swift.min.js',
'node_modules/prismjs/components/prism-typescript.min.js',
'node_modules/prismjs/components/prism-yaml.min.js',
// PrismJS Plugins
'node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js',
],
dest: './public/dist/scripts'
};
@ -113,40 +138,40 @@ const config = {
dest: './public/dist/scripts'
};
function lessLTR () {
function lessLTR() {
return src('./public/styles/default-ltr.less')
.pipe(gulpLess())
.pipe(gulpCleanCSS({compatibility: 'ie8'}))
.pipe(gulpCleanCSS({ compatibility: 'ie8' }))
.pipe(dest('./public/dist/styles'));
}
function lessRTL () {
function lessRTL() {
return src('./public/styles/default-rtl.less')
.pipe(gulpLess())
.pipe(gulpCleanCSS({compatibility: 'ie8'}))
.pipe(gulpCleanCSS({ compatibility: 'ie8' }))
.pipe(dest('./public/dist/styles'));
}
function concatApp () {
function concatApp() {
return src(configApp.src)
.pipe(gulpConcat(configApp.mainFile))
.pipe(gulpJsmin())
.pipe(dest(configApp.dest));
}
function concatDep () {
function concatDep() {
return src(configDep.src)
.pipe(gulpConcat(configDep.mainFile))
.pipe(gulpJsmin())
.pipe(dest(configDep.dest));
}
function concat () {
function concat() {
return src(config.src)
.pipe(gulpConcat(config.mainFile))
.pipe(dest(config.dest));
}
exports.import = series(concatDep);
exports.less = series(lessLTR, lessRTL);
exports.build = series(concatApp, concat);
exports.import = series(concatDep);
exports.less = series(lessLTR, lessRTL);
exports.build = series(concatApp, concat);

169
package-lock.json generated
View file

@ -1,13 +1,20 @@
{
"name": "appwrite-server",
"version": "0.1.0",
"lockfileVersion": 1,
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "appwrite-server",
"version": "0.1.0",
"license": "BSD-3-Clause",
"dependencies": {
"chart.js": "^3.5.1",
"markdown-it": "^12.2.0",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"
},
"devDependencies": {
"gulp": "^4.0.2",
"gulp-clean-css": "^4.3.0",
@ -116,6 +123,11 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@ -536,6 +548,11 @@
"node": ">= 0.6.0"
}
},
"node_modules/chart.js": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
},
"node_modules/chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@ -980,6 +997,11 @@
"node": ">=0.10.0"
}
},
"node_modules/domino": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz",
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
},
"node_modules/duplexer2": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
@ -1044,6 +1066,14 @@
"once": "^1.4.0"
}
},
"node_modules/entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/errno": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
@ -2575,6 +2605,14 @@
"node": ">= 0.8"
}
},
"node_modules/linkify-it": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@ -2823,6 +2861,21 @@
"node": ">=0.10.0"
}
},
"node_modules/markdown-it": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.2.0.tgz",
"integrity": "sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/matchdep": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
@ -2865,6 +2918,11 @@
"node": ">=0.10.0"
}
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"node_modules/meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
@ -3438,6 +3496,11 @@
"node": ">=0.10.0"
}
},
"node_modules/pell": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pell/-/pell-1.0.6.tgz",
"integrity": "sha512-wuackvgjFCHmVABy7ACSmY2u53w+TlYFrVL2hN6V3rGL/iWWwVXMw2uphpZSXNnqFQTI8nMpD3UNNX8+R4BAYw=="
},
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@ -3502,6 +3565,11 @@
"node": ">= 0.8"
}
},
"node_modules/prismjs": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
"integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg=="
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -4548,6 +4616,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/turndown": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.1.1.tgz",
"integrity": "sha512-BEkXaWH7Wh7e9bd2QumhfAXk5g34+6QUmmWx+0q6ThaVOLuLUqsnkq35HQ5SBHSaxjSfSM7US5o4lhJNH7B9MA==",
"dependencies": {
"domino": "^2.1.6"
}
},
"node_modules/type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
@ -4560,6 +4636,11 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@ -5068,6 +5149,11 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@ -5397,6 +5483,11 @@
"integrity": "sha1-W5UvniDqIc0Iyn/hNaEPb+kcEJ4=",
"dev": true
},
"chart.js": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
},
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@ -5761,6 +5852,11 @@
"integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
"dev": true
},
"domino": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz",
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
},
"duplexer2": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
@ -5827,6 +5923,11 @@
"once": "^1.4.0"
}
},
"entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
},
"errno": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
@ -7076,6 +7177,14 @@
"resolve": "^1.1.7"
}
},
"linkify-it": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@ -7303,6 +7412,18 @@
"object-visit": "^1.0.0"
}
},
"markdown-it": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.2.0.tgz",
"integrity": "sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg==",
"requires": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
},
"matchdep": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
@ -7338,6 +7459,11 @@
}
}
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
@ -7800,6 +7926,11 @@
}
}
},
"pell": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pell/-/pell-1.0.6.tgz",
"integrity": "sha512-wuackvgjFCHmVABy7ACSmY2u53w+TlYFrVL2hN6V3rGL/iWWwVXMw2uphpZSXNnqFQTI8nMpD3UNNX8+R4BAYw=="
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@ -7846,6 +7977,11 @@
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
"dev": true
},
"prismjs": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
"integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg=="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -8489,6 +8625,15 @@
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
"dev": true
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@ -8517,15 +8662,6 @@
}
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
@ -8710,6 +8846,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"turndown": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.1.1.tgz",
"integrity": "sha512-BEkXaWH7Wh7e9bd2QumhfAXk5g34+6QUmmWx+0q6ThaVOLuLUqsnkq35HQ5SBHSaxjSfSM7US5o4lhJNH7B9MA==",
"requires": {
"domino": "^2.1.6"
}
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
@ -8722,6 +8866,11 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",

View file

@ -15,5 +15,12 @@
"gulp-concat": "^2.6.1",
"gulp-jsmin": "^0.1.5",
"gulp-less": "^5.0.0"
},
"dependencies": {
"chart.js": "^3.5.1",
"markdown-it": "^12.2.0",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -369,7 +369,7 @@ if(target){target=document.getElementById(target);}
button.addEventListener("click",function(){var clone=document.createElement(element.tagName);if(element.name){clone.name=element.name;}
clone.innerHTML=template;clone.className=element.className;view.render(clone);if(target){target.appendChild(clone);}else{button.parentNode.insertBefore(clone,button);}
clone.querySelector("input").focus();Array.prototype.slice.call(clone.querySelectorAll("[data-remove]")).map(function(obj){obj.addEventListener("click",function(){clone.parentNode.removeChild(clone);obj.scrollIntoView({behavior:"smooth"});});});Array.prototype.slice.call(clone.querySelectorAll("[data-up]")).map(function(obj){obj.addEventListener("click",function(){if(clone.previousElementSibling){clone.parentNode.insertBefore(clone,clone.previousElementSibling);obj.scrollIntoView({behavior:"smooth"});}});});Array.prototype.slice.call(clone.querySelectorAll("[data-down]")).map(function(obj){obj.addEventListener("click",function(){if(clone.nextElementSibling){clone.parentNode.insertBefore(clone.nextElementSibling,clone);obj.scrollIntoView({behavior:"smooth"});}});});});element.parentNode.insertBefore(button,element.nextSibling);element.parentNode.removeChild(element);if(first){button.click();}}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-add",repeat:false,controller:function(element,view,container,document){for(var i=0;i<element.children.length;i++){let button=document.createElement("button");let template=element.children[i].cloneNode(true);let as=element.getAttribute('data-ls-as');let counter=0;button.type="button";button.innerText="Add";button.classList.add("reverse");button.classList.add("margin-end-small");button.addEventListener('click',function(){container.addNamespace(as,'new-'+counter++);console.log(container.namespaces,container.get(as),as);container.set(as,null,true,true);let child=template.cloneNode(true);view.render(child);element.appendChild(child);element.style.visibility='visible';let inputs=child.querySelectorAll('input,textarea');for(let index=0;index<inputs.length;++index){if(inputs[index].type!=='hidden'){inputs[index].focus();break;}}});element.after(button);}}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-chart",controller:function(element,container,date,document){let wrapper=document.createElement("div");let child=document.createElement("canvas");let sources=element.getAttribute('data-forms-chart');let width=element.getAttribute('data-width')||500;let height=element.getAttribute('data-height')||175;let colors=(element.getAttribute('data-colors')||'blue,green,orange,red').split(',');let themes={'blue':'#29b5d9','green':'#4eb55b','orange':'#fba233','red':'#dc3232',};let range={'24h':'H:i','7d':'d F Y','30d':'d F Y','90d':'d F Y'}
element.parentNode.insertBefore(wrapper,element.nextSibling);wrapper.classList.add('content');child.width=width;child.height=height;sources=sources.split(',');wrapper.appendChild(child);let chart=null;let check=function(){let config={type:"line",data:{labels:[],datasets:[]},options:{responsive:true,title:{display:false,text:"Stats"},legend:{display:false},tooltips:{mode:"index",intersect:false,caretPadding:0},hover:{mode:"nearest",intersect:true},scales:{xAxes:[{display:false}],yAxes:[{display:false}]}}};for(let i=0;i<sources.length;i++){let label=sources[i].substring(0,sources[i].indexOf('='));let path=sources[i].substring(sources[i].indexOf('=')+1);let data=container.path(path);let value=JSON.parse(element.value);config.data.labels[i]=label;config.data.datasets[i]={};config.data.datasets[i].label=label;config.data.datasets[i].borderColor=themes[colors[i]];config.data.datasets[i].backgroundColor=themes[colors[i]]+'36';config.data.datasets[i].borderWidth=2;config.data.datasets[i].data=[0,0,0,0,0,0,0];config.data.datasets[i].fill=true;if(!data){return;}
element.parentNode.insertBefore(wrapper,element.nextSibling);wrapper.classList.add('content');child.width=width;child.height=height;sources=sources.split(',');wrapper.appendChild(child);let chart=null;let check=function(){let config={type:"line",data:{labels:[],datasets:[]},options:{responsive:true,tooltip:{mode:"index",intersect:false,caretPadding:0},hover:{mode:"nearest",intersect:true},scales:{x:{display:false},y:{display:false}},plugins:{title:{display:false,text:"Stats"},legend:{display:false},}}};for(let i=0;i<sources.length;i++){let label=sources[i].substring(0,sources[i].indexOf('='));let path=sources[i].substring(sources[i].indexOf('=')+1);let data=container.path(path);let value=JSON.parse(element.value);config.data.labels[i]=label;config.data.datasets[i]={};config.data.datasets[i].label=label;config.data.datasets[i].borderColor=themes[colors[i]];config.data.datasets[i].backgroundColor=themes[colors[i]]+'36';config.data.datasets[i].borderWidth=2;config.data.datasets[i].data=[0,0,0,0,0,0,0];config.data.datasets[i].fill=true;if(!data){return;}
let dateFormat=(value.range&&range[value.range])?range[value.range]:'d F Y';for(let x=0;x<data.length;x++){config.data.datasets[i].data[x]=data[x].value;config.data.labels[x]=date.format(dateFormat,data[x].date);}}
if(chart){chart.destroy();}
else{}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 86 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
/*https://github.com/jaredreich/pell*/!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.pell={})}(this,function(t){"use strict";var e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t},n=function(t,e,n){return t.addEventListener(e,n)},r=function(t,e){return t.appendChild(e)},i=function(t){return document.createElement(t)},o=function(t){return document.queryCommandState(t)},u=function(t){return document.queryCommandValue(t)},c=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return document.execCommand(t,!1,e)},l={bold:{icon:"<b>B</b>",title:"Bold",state:function(){return o("bold")},result:function(){return c("bold")}},italic:{icon:"<i>I</i>",title:"Italic",state:function(){return o("italic")},result:function(){return c("italic")}},underline:{icon:"<u>U</u>",title:"Underline",state:function(){return o("underline")},result:function(){return c("underline")}},strikethrough:{icon:"<strike>S</strike>",title:"Strike-through",state:function(){return o("strikeThrough")},result:function(){return c("strikeThrough")}},heading1:{icon:"<b>H<sub>1</sub></b>",title:"Heading 1",result:function(){return c("formatBlock","<h1>")}},heading2:{icon:"<b>H<sub>2</sub></b>",title:"Heading 2",result:function(){return c("formatBlock","<h2>")}},paragraph:{icon:"&#182;",title:"Paragraph",result:function(){return c("formatBlock","<p>")}},quote:{icon:"&#8220; &#8221;",title:"Quote",result:function(){return c("formatBlock","<blockquote>")}},olist:{icon:"&#35;",title:"Ordered List",result:function(){return c("insertOrderedList")}},ulist:{icon:"&#8226;",title:"Unordered List",result:function(){return c("insertUnorderedList")}},code:{icon:"&lt;/&gt;",title:"Code",result:function(){return c("formatBlock","<pre>")}},line:{icon:"&#8213;",title:"Horizontal Line",result:function(){return c("insertHorizontalRule")}},link:{icon:"&#128279;",title:"Link",result:function(){var t=window.prompt("Enter the link URL");t&&c("createLink",t)}},image:{icon:"&#128247;",title:"Image",result:function(){var t=window.prompt("Enter the image URL");t&&c("insertImage",t)}}},a={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"},s=function(t){var o=t.actions?t.actions.map(function(t){return"string"==typeof t?l[t]:l[t.name]?e({},l[t.name],t):t}):Object.keys(l).map(function(t){return l[t]}),s=e({},a,t.classes),f=t.defaultParagraphSeparator||"div",d=i("div");d.className=s.actionbar,r(t.element,d);var m=t.element.content=i("div");return m.contentEditable=!0,m.className=s.content,m.oninput=function(e){var n=e.target.firstChild;n&&3===n.nodeType?c("formatBlock","<"+f+">"):"<br>"===m.innerHTML&&(m.innerHTML=""),t.onChange(m.innerHTML)},m.onkeydown=function(t){"Tab"===t.key?t.preventDefault():"Enter"===t.key&&"blockquote"===u("formatBlock")&&setTimeout(function(){return c("formatBlock","<"+f+">")},0)},r(t.element,m),o.forEach(function(t){var e=i("button");if(e.className=s.button,e.innerHTML=t.icon,e.title=t.title,e.setAttribute("type","button"),e.onclick=function(){return t.result()&&m.focus()},t.state){var o=function(){return e.classList[t.state()?"add":"remove"](s.selected)};n(m,"keyup",o),n(m,"mouseup",o),n(e,"click",o)}r(d,e)}),t.styleWithCSS&&c("styleWithCSS"),c("defaultParagraphSeparator",f),t.element},f={exec:c,init:s};t.exec=c,t.init=s,t.default=f,Object.defineProperty(t,"__esModule",{value:!0})});

File diff suppressed because one or more lines are too long

View file

@ -1,932 +0,0 @@
var TurndownService = (function () {
'use strict';
function extend (destination) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (source.hasOwnProperty(key)) destination[key] = source[key];
}
}
return destination
}
function repeat (character, count) {
return Array(count + 1).join(character)
}
var blockElements = [
'address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas',
'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
];
function isBlock (node) {
return blockElements.indexOf(node.nodeName.toLowerCase()) !== -1
}
var voidElements = [
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
];
function isVoid (node) {
return voidElements.indexOf(node.nodeName.toLowerCase()) !== -1
}
var voidSelector = voidElements.join();
function hasVoid (node) {
return node.querySelector && node.querySelector(voidSelector)
}
var rules = {};
rules.paragraph = {
filter: 'p',
replacement: function (content) {
return '\n\n' + content + '\n\n'
}
};
rules.lineBreak = {
filter: 'br',
replacement: function (content, node, options) {
return options.br + '\n'
}
};
rules.heading = {
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
replacement: function (content, node, options) {
var hLevel = Number(node.nodeName.charAt(1));
if (options.headingStyle === 'setext' && hLevel < 3) {
var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
return (
'\n\n' + content + '\n' + underline + '\n\n'
)
} else {
return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
}
}
};
rules.blockquote = {
filter: 'blockquote',
replacement: function (content) {
content = content.replace(/^\n+|\n+$/g, '');
content = content.replace(/^/gm, '> ');
return '\n\n' + content + '\n\n'
}
};
rules.list = {
filter: ['ul', 'ol'],
replacement: function (content, node) {
var parent = node.parentNode;
if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
return '\n' + content
} else {
return '\n\n' + content + '\n\n'
}
}
};
rules.listItem = {
filter: 'li',
replacement: function (content, node, options) {
content = content
.replace(/^\n+/, '') // remove leading newlines
.replace(/\n+$/, '\n') // replace trailing newlines with just a single one
.replace(/\n/gm, '\n '); // indent
var prefix = options.bulletListMarker + ' ';
var parent = node.parentNode;
if (parent.nodeName === 'OL') {
var start = parent.getAttribute('start');
var index = Array.prototype.indexOf.call(parent.children, node);
prefix = (start ? Number(start) + index : index + 1) + '. ';
}
return (
prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
)
}
};
rules.indentedCodeBlock = {
filter: function (node, options) {
return (
options.codeBlockStyle === 'indented' &&
node.nodeName === 'PRE' &&
node.firstChild &&
node.firstChild.nodeName === 'CODE'
)
},
replacement: function (content, node, options) {
return (
'\n\n ' +
node.firstChild.textContent.replace(/\n/g, '\n ') +
'\n\n'
)
}
};
rules.fencedCodeBlock = {
filter: function (node, options) {
return (
options.codeBlockStyle === 'fenced' &&
node.nodeName === 'PRE' &&
node.firstChild &&
node.firstChild.nodeName === 'CODE'
)
},
replacement: function (content, node, options) {
var className = node.firstChild.className || '';
var language = (className.match(/language-(\S+)/) || [null, ''])[1];
return (
'\n\n' + options.fence + language + '\n' +
node.firstChild.textContent +
'\n' + options.fence + '\n\n'
)
}
};
rules.horizontalRule = {
filter: 'hr',
replacement: function (content, node, options) {
return '\n\n' + options.hr + '\n\n'
}
};
rules.inlineLink = {
filter: function (node, options) {
return (
options.linkStyle === 'inlined' &&
node.nodeName === 'A' &&
node.getAttribute('href')
)
},
replacement: function (content, node) {
var href = node.getAttribute('href');
var title = node.title ? ' "' + node.title + '"' : '';
return '[' + content + '](' + href + title + ')'
}
};
rules.referenceLink = {
filter: function (node, options) {
return (
options.linkStyle === 'referenced' &&
node.nodeName === 'A' &&
node.getAttribute('href')
)
},
replacement: function (content, node, options) {
var href = node.getAttribute('href');
var title = node.title ? ' "' + node.title + '"' : '';
var replacement;
var reference;
switch (options.linkReferenceStyle) {
case 'collapsed':
replacement = '[' + content + '][]';
reference = '[' + content + ']: ' + href + title;
break
case 'shortcut':
replacement = '[' + content + ']';
reference = '[' + content + ']: ' + href + title;
break
default:
var id = this.references.length + 1;
replacement = '[' + content + '][' + id + ']';
reference = '[' + id + ']: ' + href + title;
}
this.references.push(reference);
return replacement
},
references: [],
append: function (options) {
var references = '';
if (this.references.length) {
references = '\n\n' + this.references.join('\n') + '\n\n';
this.references = []; // Reset references
}
return references
}
};
rules.emphasis = {
filter: ['em', 'i'],
replacement: function (content, node, options) {
if (!content.trim()) return ''
return options.emDelimiter + content + options.emDelimiter
}
};
rules.strong = {
filter: ['strong', 'b'],
replacement: function (content, node, options) {
if (!content.trim()) return ''
return options.strongDelimiter + content + options.strongDelimiter
}
};
rules.code = {
filter: function (node) {
var hasSiblings = node.previousSibling || node.nextSibling;
var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
return node.nodeName === 'CODE' && !isCodeBlock
},
replacement: function (content) {
if (!content.trim()) return ''
var delimiter = '`';
var leadingSpace = '';
var trailingSpace = '';
var matches = content.match(/`+/gm);
if (matches) {
if (/^`/.test(content)) leadingSpace = ' ';
if (/`$/.test(content)) trailingSpace = ' ';
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
}
return delimiter + leadingSpace + content + trailingSpace + delimiter
}
};
rules.image = {
filter: 'img',
replacement: function (content, node) {
var alt = node.alt || '';
var src = node.getAttribute('src') || '';
var title = node.title || '';
var titlePart = title ? ' "' + title + '"' : '';
return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
}
};
/**
* Manages a collection of rules used to convert HTML to Markdown
*/
function Rules (options) {
this.options = options;
this._keep = [];
this._remove = [];
this.blankRule = {
replacement: options.blankReplacement
};
this.keepReplacement = options.keepReplacement;
this.defaultRule = {
replacement: options.defaultReplacement
};
this.array = [];
for (var key in options.rules) this.array.push(options.rules[key]);
}
Rules.prototype = {
add: function (key, rule) {
this.array.unshift(rule);
},
keep: function (filter) {
this._keep.unshift({
filter: filter,
replacement: this.keepReplacement
});
},
remove: function (filter) {
this._remove.unshift({
filter: filter,
replacement: function () {
return ''
}
});
},
forNode: function (node) {
if (node.isBlank) return this.blankRule
var rule;
if ((rule = findRule(this.array, node, this.options))) return rule
if ((rule = findRule(this._keep, node, this.options))) return rule
if ((rule = findRule(this._remove, node, this.options))) return rule
return this.defaultRule
},
forEach: function (fn) {
for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
}
};
function findRule (rules, node, options) {
for (var i = 0; i < rules.length; i++) {
var rule = rules[i];
if (filterValue(rule, node, options)) return rule
}
return void 0
}
function filterValue (rule, node, options) {
var filter = rule.filter;
if (typeof filter === 'string') {
if (filter === node.nodeName.toLowerCase()) return true
} else if (Array.isArray(filter)) {
if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
} else if (typeof filter === 'function') {
if (filter.call(rule, node, options)) return true
} else {
throw new TypeError('`filter` needs to be a string, array, or function')
}
}
/**
* The collapseWhitespace function is adapted from collapse-whitespace
* by Luc Thevenard.
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* collapseWhitespace(options) removes extraneous whitespace from an the given element.
*
* @param {Object} options
*/
function collapseWhitespace (options) {
var element = options.element;
var isBlock = options.isBlock;
var isVoid = options.isVoid;
var isPre = options.isPre || function (node) {
return node.nodeName === 'PRE'
};
if (!element.firstChild || isPre(element)) return
var prevText = null;
var prevVoid = false;
var prev = null;
var node = next(prev, element, isPre);
while (node !== element) {
if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
var text = node.data.replace(/[ \r\n\t]+/g, ' ');
if ((!prevText || / $/.test(prevText.data)) &&
!prevVoid && text[0] === ' ') {
text = text.substr(1);
}
// `text` might be empty at this point.
if (!text) {
node = remove(node);
continue
}
node.data = text;
prevText = node;
} else if (node.nodeType === 1) { // Node.ELEMENT_NODE
if (isBlock(node) || node.nodeName === 'BR') {
if (prevText) {
prevText.data = prevText.data.replace(/ $/, '');
}
prevText = null;
prevVoid = false;
} else if (isVoid(node)) {
// Avoid trimming space around non-block, non-BR void elements.
prevText = null;
prevVoid = true;
}
} else {
node = remove(node);
continue
}
var nextNode = next(prev, node, isPre);
prev = node;
node = nextNode;
}
if (prevText) {
prevText.data = prevText.data.replace(/ $/, '');
if (!prevText.data) {
remove(prevText);
}
}
}
/**
* remove(node) removes the given node from the DOM and returns the
* next node in the sequence.
*
* @param {Node} node
* @return {Node} node
*/
function remove (node) {
var next = node.nextSibling || node.parentNode;
node.parentNode.removeChild(node);
return next
}
/**
* next(prev, current, isPre) returns the next node in the sequence, given the
* current and previous nodes.
*
* @param {Node} prev
* @param {Node} current
* @param {Function} isPre
* @return {Node}
*/
function next (prev, current, isPre) {
if ((prev && prev.parentNode === current) || isPre(current)) {
return current.nextSibling || current.parentNode
}
return current.firstChild || current.nextSibling || current.parentNode
}
/*
* Set up window for Node.js
*/
var root = (typeof window !== 'undefined' ? window : {});
/*
* Parsing HTML strings
*/
function canParseHTMLNatively () {
var Parser = root.DOMParser;
var canParse = false;
// Adapted from https://gist.github.com/1129031
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if (new Parser().parseFromString('', 'text/html')) {
canParse = true;
}
} catch (e) {}
return canParse
}
function createHTMLParser () {
var Parser = function () {};
{
if (shouldUseActiveX()) {
Parser.prototype.parseFromString = function (string) {
var doc = new window.ActiveXObject('htmlfile');
doc.designMode = 'on'; // disable on-page scripts
doc.open();
doc.write(string);
doc.close();
return doc
};
} else {
Parser.prototype.parseFromString = function (string) {
var doc = document.implementation.createHTMLDocument('');
doc.open();
doc.write(string);
doc.close();
return doc
};
}
}
return Parser
}
function shouldUseActiveX () {
var useActiveX = false;
try {
document.implementation.createHTMLDocument('').open();
} catch (e) {
if (window.ActiveXObject) useActiveX = true;
}
return useActiveX
}
var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
function RootNode (input) {
var root;
if (typeof input === 'string') {
var doc = htmlParser().parseFromString(
// DOM parsers arrange elements in the <head> and <body>.
// Wrapping in a custom element ensures elements are reliably arranged in
// a single element.
'<x-turndown id="turndown-root">' + input + '</x-turndown>',
'text/html'
);
root = doc.getElementById('turndown-root');
} else {
root = input.cloneNode(true);
}
collapseWhitespace({
element: root,
isBlock: isBlock,
isVoid: isVoid
});
return root
}
var _htmlParser;
function htmlParser () {
_htmlParser = _htmlParser || new HTMLParser();
return _htmlParser
}
function Node (node) {
node.isBlock = isBlock(node);
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
node.isBlank = isBlank(node);
node.flankingWhitespace = flankingWhitespace(node);
return node
}
function isBlank (node) {
return (
['A', 'TH', 'TD'].indexOf(node.nodeName) === -1 &&
/^\s*$/i.test(node.textContent) &&
!isVoid(node) &&
!hasVoid(node)
)
}
function flankingWhitespace (node) {
var leading = '';
var trailing = '';
if (!node.isBlock) {
var hasLeading = /^[ \r\n\t]/.test(node.textContent);
var hasTrailing = /[ \r\n\t]$/.test(node.textContent);
if (hasLeading && !isFlankedByWhitespace('left', node)) {
leading = ' ';
}
if (hasTrailing && !isFlankedByWhitespace('right', node)) {
trailing = ' ';
}
}
return { leading: leading, trailing: trailing }
}
function isFlankedByWhitespace (side, node) {
var sibling;
var regExp;
var isFlanked;
if (side === 'left') {
sibling = node.previousSibling;
regExp = / $/;
} else {
sibling = node.nextSibling;
regExp = /^ /;
}
if (sibling) {
if (sibling.nodeType === 3) {
isFlanked = regExp.test(sibling.nodeValue);
} else if (sibling.nodeType === 1 && !isBlock(sibling)) {
isFlanked = regExp.test(sibling.textContent);
}
}
return isFlanked
}
var reduce = Array.prototype.reduce;
var leadingNewLinesRegExp = /^\n*/;
var trailingNewLinesRegExp = /\n*$/;
function TurndownService (options) {
if (!(this instanceof TurndownService)) return new TurndownService(options)
var defaults = {
rules: rules,
headingStyle: 'setext',
hr: '* * *',
bulletListMarker: '*',
codeBlockStyle: 'indented',
fence: '```',
emDelimiter: '_',
strongDelimiter: '**',
linkStyle: 'inlined',
linkReferenceStyle: 'full',
br: ' ',
blankReplacement: function (content, node) {
return node.isBlock ? '\n\n' : ''
},
keepReplacement: function (content, node) {
return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
},
defaultReplacement: function (content, node) {
return node.isBlock ? '\n\n' + content + '\n\n' : content
}
};
this.options = extend({}, defaults, options);
this.rules = new Rules(this.options);
}
TurndownService.prototype = {
/**
* The entry point for converting a string or DOM node to Markdown
* @public
* @param {String|HTMLElement} input The string or DOM node to convert
* @returns A Markdown representation of the input
* @type String
*/
turndown: function (input) {
if (!canConvert(input)) {
throw new TypeError(
input + ' is not a string, or an element/document/fragment node.'
)
}
if (input === '') return ''
var output = process.call(this, new RootNode(input));
return postProcess.call(this, output)
},
/**
* Add one or more plugins
* @public
* @param {Function|Array} plugin The plugin or array of plugins to add
* @returns The Turndown instance for chaining
* @type Object
*/
use: function (plugin) {
if (Array.isArray(plugin)) {
for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
} else if (typeof plugin === 'function') {
plugin(this);
} else {
throw new TypeError('plugin must be a Function or an Array of Functions')
}
return this
},
/**
* Adds a rule
* @public
* @param {String} key The unique key of the rule
* @param {Object} rule The rule
* @returns The Turndown instance for chaining
* @type Object
*/
addRule: function (key, rule) {
this.rules.add(key, rule);
return this
},
/**
* Keep a node (as HTML) that matches the filter
* @public
* @param {String|Array|Function} filter The unique key of the rule
* @returns The Turndown instance for chaining
* @type Object
*/
keep: function (filter) {
this.rules.keep(filter);
return this
},
/**
* Remove a node that matches the filter
* @public
* @param {String|Array|Function} filter The unique key of the rule
* @returns The Turndown instance for chaining
* @type Object
*/
remove: function (filter) {
this.rules.remove(filter);
return this
},
/**
* Escapes Markdown syntax
* @public
* @param {String} string The string to escape
* @returns A string with Markdown syntax escaped
* @type String
*/
escape: function (string) {
return (
string
// Escape backslash escapes!
.replace(/\\(\S)/g, '\\\\$1')
// Escape headings
.replace(/^(#{1,6} )/gm, '\\$1')
// Escape hr
.replace(/^([-*_] *){3,}$/gm, function (match, character) {
return match.split(character).join('\\' + character)
})
// Escape ol bullet points
.replace(/^(\W* {0,3})(\d+)\. /gm, '$1$2\\. ')
// Escape ul bullet points
.replace(/^([^\\\w]*)[*+-] /gm, function (match) {
return match.replace(/([*+-])/g, '\\$1')
})
// Escape blockquote indents
.replace(/^(\W* {0,3})> /gm, '$1\\> ')
// Escape em/strong *
.replace(/\*+(?![*\s\W]).+?\*+/g, function (match) {
return match.replace(/\*/g, '\\*')
})
// Escape em/strong _
.replace(/_+(?![_\s\W]).+?_+/g, function (match) {
return match.replace(/_/g, '\\_')
})
// Escape code _
.replace(/`+(?![`\s\W]).+?`+/g, function (match) {
return match.replace(/`/g, '\\`')
})
// Escape link brackets
.replace(/[\[\]]/g, '\\$&') // eslint-disable-line no-useless-escape
)
}
};
/**
* Reduces a DOM node down to its Markdown string equivalent
* @private
* @param {HTMLElement} parentNode The node to convert
* @returns A Markdown representation of the node
* @type String
*/
function process (parentNode) {
var self = this;
return reduce.call(parentNode.childNodes, function (output, node) {
node = new Node(node);
var replacement = '';
if (node.nodeType === 3) {
replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
} else if (node.nodeType === 1) {
replacement = replacementForNode.call(self, node);
}
return join(output, replacement)
}, '')
}
/**
* Appends strings as each rule requires and trims the output
* @private
* @param {String} output The conversion output
* @returns A trimmed version of the ouput
* @type String
*/
function postProcess (output) {
var self = this;
this.rules.forEach(function (rule) {
if (typeof rule.append === 'function') {
output = join(output, rule.append(self.options));
}
});
return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
}
/**
* Converts an element node to its Markdown equivalent
* @private
* @param {HTMLElement} node The node to convert
* @returns A Markdown representation of the node
* @type String
*/
function replacementForNode (node) {
var rule = this.rules.forNode(node);
var content = process.call(this, node);
var whitespace = node.flankingWhitespace;
if (whitespace.leading || whitespace.trailing) content = content.trim();
return (
whitespace.leading +
rule.replacement(content, node, this.options) +
whitespace.trailing
)
}
/**
* Determines the new lines between the current output and the replacement
* @private
* @param {String} output The current conversion output
* @param {String} replacement The string to append to the output
* @returns The whitespace to separate the current output and the replacement
* @type String
*/
function separatingNewlines (output, replacement) {
var newlines = [
output.match(trailingNewLinesRegExp)[0],
replacement.match(leadingNewLinesRegExp)[0]
].sort();
var maxNewlines = newlines[newlines.length - 1];
return maxNewlines.length < 2 ? maxNewlines : '\n\n'
}
function join (string1, string2) {
var separator = separatingNewlines(string1, string2);
// Remove trailing/leading newlines and replace with separator
string1 = string1.replace(trailingNewLinesRegExp, '');
string2 = string2.replace(leadingNewLinesRegExp, '');
return string1 + separator + string2
}
/**
* Determines whether an input can be converted
* @private
* @param {String|HTMLElement} input Describe this parameter
* @returns Describe what it returns
* @type String|Object|Array|Boolean|Number
*/
function canConvert (input) {
return (
input != null && (
typeof input === 'string' ||
(input.nodeType && (
input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
))
)
)
}
return TurndownService;
}());

View file

@ -1,22 +1,22 @@
(function(window) {
(function (window) {
"use strict";
window.ls.container.get("view").add({
selector: "data-forms-chart",
controller: function(element, container, date, document) {
controller: function (element, container, date, document) {
let wrapper = document.createElement("div");
let child = document.createElement("canvas");
let sources = element.getAttribute('data-forms-chart');
let width = element.getAttribute('data-width') || 500;
let height = element.getAttribute('data-height') || 175;
let colors = (element.getAttribute('data-colors') || 'blue,green,orange,red').split(',');
let themes = {'blue': '#29b5d9', 'green': '#4eb55b', 'orange': '#fba233', 'red': '#dc3232',};
let range = {'24h': 'H:i', '7d': 'd F Y', '30d': 'd F Y', '90d': 'd F Y'}
let themes = { 'blue': '#29b5d9', 'green': '#4eb55b', 'orange': '#fba233', 'red': '#dc3232', };
let range = { '24h': 'H:i', '7d': 'd F Y', '30d': 'd F Y', '90d': 'd F Y' }
element.parentNode.insertBefore(wrapper, element.nextSibling);
wrapper.classList.add('content');
child.width = width;
child.height = height;
@ -26,7 +26,7 @@
let chart = null;
let check = function() {
let check = function () {
let config = {
type: "line",
@ -36,14 +36,7 @@
},
options: {
responsive: true,
title: {
display: false,
text: "Stats"
},
legend: {
display: false
},
tooltips: {
tooltip: {
mode: "index",
intersect: false,
caretPadding: 0
@ -53,16 +46,21 @@
intersect: true
},
scales: {
xAxes: [
{
display: false
}
],
yAxes: [
{
display: false
}
]
x: {
display: false
},
y: {
display: false
}
},
plugins: {
title: {
display: false,
text: "Stats"
},
legend: {
display: false
},
}
}
};
@ -82,25 +80,25 @@
config.data.datasets[i].data = [0, 0, 0, 0, 0, 0, 0];
config.data.datasets[i].fill = true;
if(!data) {
if (!data) {
return;
}
let dateFormat = (value.range && range[value.range]) ? range[value.range] : 'd F Y';
for (let x = 0; x < data.length; x++) {
config.data.datasets[i].data[x] = data[x].value;
config.data.labels[x] = date.format(dateFormat, data[x].date);
}
}
if(chart) {
if (chart) {
chart.destroy();
}
else {
}
chart = new Chart(child.getContext("2d"), config);
wrapper.dataset["canvas"] = true;
}
@ -110,4 +108,4 @@
element.addEventListener('change', check);
}
});
})(window);
})(window);

View file

@ -19,6 +19,7 @@ img[src=""] {
@import "icons";
@import "polyfills";
@import "forms";
@import "ide";
@import "scopes/console";
@import "scopes/home";
@import "comps/alerts";
@ -32,7 +33,6 @@ img[src=""] {
@import "comps/modal";
@import "comps/scroll";
@import "comps/tabs";
@import "dependencies/prism";
html {
padding: 0;

View file

@ -1,358 +0,0 @@
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript+ruby+markup-templating+php&plugins=line-numbers */
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
.ide {
background-color: var(--config-prism-background);
overflow: hidden;
position: relative;
z-index: 1;
box-shadow: 0 2px 4px 0 rgba(50,50,93,.3);
border-radius: 10px;
margin-bottom: 30px;
&:extend(.force-left);
&:extend(.force-ltr);
* {
font-family: 'Source Code Pro', monospace;
}
&[data-lang]::after {
content: attr(data-lang-label);
display: inline-block;
background: #ffffff;
color: #000000;
position: absolute;
top: 15px;
padding: 5px 10px;
border-radius: 15px;
font-size: 10px;
right: 10px; // should be right for both ltr and rtl
opacity: 0.95;
}
&[data-lang="bash"]::after {
background: var(--config-language-bash);
color: var(--config-language-bash-contrast);
}
&[data-lang="javascript"]::after {
background: var(--config-language-javascript);
color: var(--config-language-javascript-contrast);
}
&[data-lang="web"]::after {
background: var(--config-language-web);
color: var(--config-language-web-contrast);
}
&[data-lang="html"]::after {
background: var(--config-language-html);
color: var(--config-language-html-contrast);
}
&[data-lang="php"]::after {
background: var(--config-language-php);
color: var(--config-language-php-contrast);
}
&[data-lang="nodejs"]::after {
background: var(--config-language-nodejs);
color: var(--config-language-nodejs-contrast);
}
&[data-lang="ruby"]::after {
background: var(--config-language-ruby);
color: var(--config-language-ruby-contrast);
}
&[data-lang="python"]::after {
background: var(--config-language-python);
color: var(--config-language-python-contrast);
}
&[data-lang="go"]::after {
background: var(--config-language-go);
color: var(--config-language-go-contrast);
}
&[data-lang="dart"]::after {
background: var(--config-language-dart);
color: var(--config-language-dart-contrast);
}
&[data-lang="flutter"]::after {
background: var(--config-language-flutter);
color: var(--config-language-flutter-contrast);
}
&[data-lang="android"]::after {
background: var(--config-language-android);
color: var(--config-language-android-contrast);
}
&[data-lang="kotlin"]::after {
background: var(--config-language-kotlin);
color: var(--config-language-kotlin-contrast);
}
&[data-lang="java"]::after {
background: var(--config-language-java);
color: var(--config-language-java-contrast);
}
&[data-lang="yaml"]::after {
background: var(--config-language-yaml);
color: var(--config-language-yaml-contrast);
}
.tag {
color: inherit!important;
background: transparent!important;
padding: inherit!important;
font-size: inherit!important;
line-height: 14px;
}
.copy {
cursor: pointer;
content: attr(data-lang);
display: inline-block;
background: #ffffff;
color: #000000;
position: absolute;
transform: translateX(-50%);
bottom: -20px;
padding: 5px 10px;
border-radius: 15px;
font-size: 10px;
font-style: normal;
.func-start(50%);
opacity: 0;
transition: bottom .3s, opacity .3s;
line-height: normal;
font-family: 'Poppins', sans-serif;
&::before {
.func-padding-end(5px);
}
}
&:hover {
.copy {
transition: bottom .3s, opacity .3s;
opacity: 0.90;
bottom: 16px;
}
}
pre {
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
color: #e6ebf1;
font-weight: 400;
line-height: 20px;
font-size: 13px;
margin: 0;
padding: 20px;
padding-left: 60px;
}
&.light {
box-shadow: 0 2px 4px 0 rgba(50,50,93,.1);
background-color: #ffffff;
pre {
color: #414770;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #91a2b0;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #149570;
}
.token.punctuation {
color: #414770;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #414770;
}
.line-numbers .line-numbers-rows {
background: #f2feef;
}
.line-numbers-rows > span:before {
color: #5dc79e;
}
.token.keyword {
color: #6772e4;
font-weight: 500;
}
}
}
code[class*="language-"],
pre[class*="language-"] {
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
}
/* Code blocks */
pre[class*="language-"] {
overflow: auto;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #6b7c93;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #f79a59;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #3ecf8e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #45b2e8;
}
.token.keyword {
color: #7795f8;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
//font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
pre[class*="language-"].line-numbers {
position: relative;
padding-left: 60px;
counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
background: var(--config-prism-numbers);
position: absolute;
pointer-events: none;
top: -20px;
bottom: -21px;
padding: 20px 0;
font-size: 100%;
left: -60px;
width: 40px; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
.func-padding-end(5px);
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #636365;
display: block;
padding-right: 0.8em;
text-align: right;
}

349
public/styles/ide.less Normal file
View file

@ -0,0 +1,349 @@
.ide {
background-color: var(--config-prism-background);
overflow: hidden;
position: relative;
z-index: 1;
box-shadow: 0 2px 4px 0 rgba(50, 50, 93, 0.3);
border-radius: 10px;
margin-bottom: 30px;
&:extend(.force-left);
&:extend(.force-ltr);
* {
font-family: "Source Code Pro", monospace;
}
&[data-lang]::after {
content: attr(data-lang-label);
display: inline-block;
background: #ffffff;
color: #000000;
position: absolute;
top: 15px;
padding: 5px 10px;
border-radius: 15px;
font-size: 10px;
right: 10px; // should be right for both ltr and rtl
opacity: 0.95;
}
&[data-lang="bash"]::after {
background: var(--config-language-bash);
color: var(--config-language-bash-contrast);
}
&[data-lang="javascript"]::after {
background: var(--config-language-javascript);
color: var(--config-language-javascript-contrast);
}
&[data-lang="web"]::after {
background: var(--config-language-web);
color: var(--config-language-web-contrast);
}
&[data-lang="html"]::after {
background: var(--config-language-html);
color: var(--config-language-html-contrast);
}
&[data-lang="php"]::after {
background: var(--config-language-php);
color: var(--config-language-php-contrast);
}
&[data-lang="nodejs"]::after {
background: var(--config-language-nodejs);
color: var(--config-language-nodejs-contrast);
}
&[data-lang="ruby"]::after {
background: var(--config-language-ruby);
color: var(--config-language-ruby-contrast);
}
&[data-lang="python"]::after {
background: var(--config-language-python);
color: var(--config-language-python-contrast);
}
&[data-lang="go"]::after {
background: var(--config-language-go);
color: var(--config-language-go-contrast);
}
&[data-lang="dart"]::after {
background: var(--config-language-dart);
color: var(--config-language-dart-contrast);
}
&[data-lang="flutter"]::after {
background: var(--config-language-flutter);
color: var(--config-language-flutter-contrast);
}
&[data-lang="android"]::after {
background: var(--config-language-android);
color: var(--config-language-android-contrast);
}
&[data-lang="kotlin"]::after {
background: var(--config-language-kotlin);
color: var(--config-language-kotlin-contrast);
}
&[data-lang="java"]::after {
background: var(--config-language-java);
color: var(--config-language-java-contrast);
}
&[data-lang="yaml"]::after {
background: var(--config-language-yaml);
color: var(--config-language-yaml-contrast);
}
.tag {
color: inherit !important;
background: transparent !important;
padding: inherit !important;
font-size: inherit !important;
line-height: 14px;
}
.copy {
cursor: pointer;
content: attr(data-lang);
display: inline-block;
background: #ffffff;
color: #000000;
position: absolute;
transform: translateX(-50%);
bottom: -20px;
padding: 5px 10px;
border-radius: 15px;
font-size: 10px;
font-style: normal;
.func-start(50%);
opacity: 0;
transition: bottom 0.3s, opacity 0.3s;
line-height: normal;
font-family: "Poppins", sans-serif;
&::before {
.func-padding-end(5px);
}
}
&:hover {
.copy {
transition: bottom 0.3s, opacity 0.3s;
opacity: 0.9;
bottom: 16px;
}
}
pre {
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
color: #e6ebf1;
font-weight: 400;
line-height: 20px;
font-size: 13px;
margin: 0;
padding: 20px;
padding-left: 60px;
}
&.light {
box-shadow: 0 2px 4px 0 rgba(50, 50, 93, 0.1);
background-color: #ffffff;
pre {
color: #414770;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #91a2b0;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #149570;
}
.token.punctuation {
color: #414770;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #414770;
}
.line-numbers .line-numbers-rows {
background: #f2feef;
}
.line-numbers-rows > span:before {
color: #5dc79e;
}
.token.keyword {
color: #6772e4;
font-weight: 500;
}
}
}
code[class*="language-"],
pre[class*="language-"] {
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
}
/* Code blocks */
pre[class*="language-"] {
overflow: auto;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #6b7c93;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #f79a59;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #3ecf8e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #45b2e8;
}
.token.keyword {
color: #7795f8;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
//font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
pre[class*="language-"].line-numbers {
position: relative;
padding-left: 60px;
counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
background: var(--config-prism-numbers);
position: absolute;
pointer-events: none;
top: -20px;
bottom: -21px;
padding: 20px 0;
font-size: 100%;
left: -60px;
width: 40px; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
.func-padding-end(5px);
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #636365;
display: block;
padding-right: 0.8em;
text-align: right;
}

View file

@ -5,6 +5,7 @@
--config-width-large: 700px;
--config-width-medium: 550px;
--config-width-small: 320px;
--config-color-primary: #f02e65;
--config-color-link: #1e849e;
--config-color-background: #eceff1;
--config-color-background-dark: #dfe2e4;
@ -92,6 +93,7 @@
--config-console-nav-switch-arrow: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='%23868686' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
.theme-dark {
--config-color-primary: #f02e65;
--config-color-background: #061F2F;
--config-color-background-dark: #262d50;
--config-color-background-fade: #1c223a;

View file

@ -20,21 +20,23 @@ class Password extends Validator
*/
public function getDescription()
{
return 'Password must be between 6 and 32 chars and contain ...';
return 'Password must be at least 8 characters';
}
/**
* Is valid.
*
* Validation username
*
* @param mixed $value
*
* @return bool
*/
public function isValid($value)
{
if (\strlen($value) < 6 || \strlen($value) > 32) {
if (!\is_string($value)) {
return false;
}
if (\strlen($value) < 8) {
return false;
}

View file

@ -49,7 +49,7 @@ class PDO extends PDONative
return $this->pdo->setAttribute($attribute, $value);
}
public function prepare($statement, $driver_options = NULL)
public function prepare($statement, $driver_options = null)
{
return new PDOStatement($this, $this->pdo->prepare($statement, []));
}
@ -71,4 +71,4 @@ class PDO extends PDONative
return $this->pdo;
}
}
}

View file

@ -100,10 +100,10 @@ class PDOStatement extends PDOStatementNative
/**
* Fetch All
*
*
* @param int $fetch_style
* @param mixed $fetch_args
*
*
* @return array|false
*/
public function fetchAll(int $fetch_style = PDO::FETCH_BOTH, mixed ...$fetch_args)
@ -112,4 +112,4 @@ class PDOStatement extends PDOStatementNative
return $result;
}
}
}

View file

@ -4,7 +4,7 @@ namespace Appwrite\OpenSSL;
class OpenSSL
{
const CIPHER_AES_128_GCM = 'aes-128-gcm';
public const CIPHER_AES_128_GCM = 'aes-128-gcm';
/**
* @param $data

View file

@ -22,6 +22,7 @@ use Appwrite\Utopia\Response\Model\ErrorDev;
use Appwrite\Utopia\Response\Model\Execution;
use Appwrite\Utopia\Response\Model\File;
use Appwrite\Utopia\Response\Model\Func;
use Appwrite\Utopia\Response\Model\FuncPermissions;
use Appwrite\Utopia\Response\Model\JWT;
use Appwrite\Utopia\Response\Model\Key;
use Appwrite\Utopia\Response\Model\Language;
@ -106,6 +107,7 @@ class Response extends SwooleResponse
const MODEL_TAG_LIST = 'tagList';
const MODEL_EXECUTION = 'execution';
const MODEL_EXECUTION_LIST = 'executionList';
const MODEL_FUNC_PERMISSIONS = 'funcPermissions';
// Project
const MODEL_PROJECT = 'project';
@ -186,6 +188,7 @@ class Response extends SwooleResponse
->setModel(new Team())
->setModel(new Membership())
->setModel(new Func())
->setModel(new FuncPermissions())
->setModel(new Tag())
->setModel(new Execution())
->setModel(new Project())

View file

@ -17,7 +17,7 @@ class Func extends Model
'example' => '5e5ea5c16897e',
])
->addRule('$permissions', [
'type' => Response::MODEL_PERMISSIONS,
'type' => Response::MODEL_FUNC_PERMISSIONS,
'description' => 'Function permissions.',
'default' => new \stdClass,
'example' => new \stdClass,

View file

@ -0,0 +1,42 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class FuncPermissions extends Model
{
public function __construct()
{
$this
->addRule('execute', [
'type' => self::TYPE_STRING,
'description' => 'Execution permissions.',
'default' => [],
'example' => 'user:5e5ea5c16897e',
'array' => true,
])
;
}
/**
* Get Name
*
* @return string
*/
public function getName():string
{
return 'FuncPermissions';
}
/**
* Get Collection
*
* @return string
*/
public function getType():string
{
return Response::MODEL_FUNC_PERMISSIONS;
}
}

View file

@ -144,6 +144,31 @@ trait StorageBase
$this->assertEquals('image/png', $file6['headers']['content-type']);
$this->assertNotEmpty($file6['body']);
// Test for negative angle values in fileGetPreview
$file7 = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'] . '/preview', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'width' => 300,
'height' => 100,
'borderRadius' => '50',
'opacity' => '0.5',
'output' => 'png',
'rotation' => '-315',
]);
$this->assertEquals(200, $file7['headers']['status-code']);
$this->assertEquals('image/png', $file7['headers']['content-type']);
$this->assertNotEmpty($file7['body']);
$image = new \Imagick();
$image->readImageBlob($file7['body']);
$original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png');
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
$this->assertEquals('PNG', $image->getImageFormat());
/**
* Test for FAILURE
*/

View file

@ -26,5 +26,5 @@ echo $_ENV['APPWRITE_FUNCTION_RUNTIME_VERSION']."\n";
// echo $result['$id'];
echo $_ENV['APPWRITE_FUNCTION_EVENT']."\n";
echo $_ENV['APPWRITE_FUNCTION_EVENT_DATA']."\n";
// Test unknwon UTF-8 chars
// Test unknown UTF-8 chars
echo "\xEA\xE4\n";

View file

@ -31,9 +31,8 @@ class PasswordTest extends TestCase
$this->assertEquals($this->object->isValid('123'), false);
$this->assertEquals($this->object->isValid('1234'), false);
$this->assertEquals($this->object->isValid('12345'), false);
$this->assertEquals($this->object->isValid('123456'), true);
$this->assertEquals($this->object->isValid('1234567'), true);
$this->assertEquals($this->object->isValid('123456'), false);
$this->assertEquals($this->object->isValid('1234567'), false);
$this->assertEquals($this->object->isValid('WUnOZcn0piQMN8Mh31xw4KQPF0gcNGVA'), true);
$this->assertEquals($this->object->isValid('WUnOZcn0piQMN8Mh31xw4KQPF0gcNGVAx'), false);
}
}

View file

@ -22,13 +22,13 @@ class CollectionsTest extends TestCase
foreach ($this->collections as $key => $collection) {
if (array_key_exists('rules', $collection)) {
foreach ($collection['rules'] as $check) {
$occurences = 0;
$occurrences = 0;
foreach ($collection['rules'] as $rule) {
if ($rule['key'] == $check['key']) {
$occurences++;
$occurrences++;
}
}
$this->assertEquals(1, $occurences);
$this->assertEquals(1, $occurrences);
}
}
}