Merge branch 'master' of github.com:appwrite/appwrite into feat-expire-key
Conflicts: app/controllers/general.php
This commit is contained in:
commit
d39e6a842c
20
.gitpod.Dockerfile
vendored
20
.gitpod.Dockerfile
vendored
|
@ -1,13 +1,13 @@
|
|||
FROM gitpod/workspace-full
|
||||
|
||||
# Disable current PHP installation
|
||||
RUN sudo a2dismod php7.4
|
||||
RUN sudo a2dismod mpm_prefork
|
||||
|
||||
# Install apache2 (PHP install requires to do this first)
|
||||
RUN sudo apt --yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install apache2
|
||||
|
||||
# Update to PHP 8.0 with unattended installation
|
||||
RUN sudo apt --yes install software-properties-common && sudo add-apt-repository ppa:ondrej/php -y
|
||||
RUN sudo apt update
|
||||
RUN sudo apt --yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install php8.0
|
||||
RUN sudo add-apt-repository ppa:ondrej/php -y
|
||||
# Disable current PHP installation
|
||||
RUN sudo a2dismod php7.4 mpm_prefork
|
||||
|
||||
# Install apache2 (PHP install requires to do this first) and php8.0
|
||||
RUN sudo install-packages \
|
||||
-o Dpkg::Options::="--force-confdef" \
|
||||
-o Dpkg::Options::="--force-confold" \
|
||||
apache2 php8.0
|
||||
|
||||
|
|
16
.gitpod.yml
16
.gitpod.yml
|
@ -2,9 +2,19 @@ image:
|
|||
file: .gitpod.Dockerfile
|
||||
|
||||
tasks:
|
||||
- init: docker-compose pull &&
|
||||
docker-compose build &&
|
||||
docker run --rm --interactive --tty --volume $PWD:/app composer update --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist
|
||||
- name: Run Appwrite Docker Stack
|
||||
init: |
|
||||
docker-compose pull
|
||||
docker-compose build
|
||||
command: |
|
||||
docker run --rm --interactive --tty \
|
||||
--volume $PWD:/app \
|
||||
composer update \
|
||||
--ignore-platform-reqs \
|
||||
--optimize-autoloader \
|
||||
--no-plugins \
|
||||
--no-scripts \
|
||||
--prefer-dist
|
||||
|
||||
ports:
|
||||
- port: 8080
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
require_once __DIR__.'/init.php';
|
||||
require_once __DIR__.'/controllers/general.php';
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__ . '/controllers/general.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\CLI;
|
||||
|
@ -28,4 +29,4 @@ $cli
|
|||
Console::log(App::getEnv('_APP_VERSION', 'UNKNOWN'));
|
||||
});
|
||||
|
||||
$cli->run();
|
||||
$cli->run();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php
|
||||
|
||||
// Auth methods
|
||||
|
||||
|
@ -45,4 +45,4 @@ return [
|
|||
'docs' => '',
|
||||
'enabled' => false,
|
||||
],
|
||||
];
|
||||
];
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'aa' => __DIR__.'/browsers/avant.png',
|
||||
'an' => __DIR__.'/browsers/android-webview-beta.png',
|
||||
'ch' => __DIR__.'/browsers/chrome.png',
|
||||
'ci' => __DIR__.'/browsers/chrome.png', //Chrome Mobile iOS
|
||||
'cm' => __DIR__.'/browsers/chrome.png', //Chrome Mobile
|
||||
'cr' => __DIR__.'/browsers/chromium.png',
|
||||
'ff' => __DIR__.'/browsers/firefox.png',
|
||||
'sf' => __DIR__.'/browsers/safari.png',
|
||||
'mf' => __DIR__.'/browsers/safari.png',
|
||||
'ps' => __DIR__.'/browsers/edge.png',
|
||||
'oi' => __DIR__.'/browsers/edge.png',
|
||||
'om' => __DIR__.'/browsers/opera-mini.png',
|
||||
'op' => __DIR__.'/browsers/opera.png',
|
||||
'on' => __DIR__.'/browsers/opera.png',
|
||||
'aa' => __DIR__ . '/browsers/avant.png',
|
||||
'an' => __DIR__ . '/browsers/android-webview-beta.png',
|
||||
'ch' => __DIR__ . '/browsers/chrome.png',
|
||||
'ci' => __DIR__ . '/browsers/chrome.png', //Chrome Mobile iOS
|
||||
'cm' => __DIR__ . '/browsers/chrome.png', //Chrome Mobile
|
||||
'cr' => __DIR__ . '/browsers/chromium.png',
|
||||
'ff' => __DIR__ . '/browsers/firefox.png',
|
||||
'sf' => __DIR__ . '/browsers/safari.png',
|
||||
'mf' => __DIR__ . '/browsers/safari.png',
|
||||
'ps' => __DIR__ . '/browsers/edge.png',
|
||||
'oi' => __DIR__ . '/browsers/edge.png',
|
||||
'om' => __DIR__ . '/browsers/opera-mini.png',
|
||||
'op' => __DIR__ . '/browsers/opera.png',
|
||||
'on' => __DIR__ . '/browsers/opera.png',
|
||||
|
||||
/*
|
||||
'36' => '360 Phone Browser',
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'amex' => __DIR__.'/credit-cards/amex.png',
|
||||
'argencard' => __DIR__.'/credit-cards/argencard.png',
|
||||
'cabal' => __DIR__.'/credit-cards/cabal.png',
|
||||
'censosud' => __DIR__.'/credit-cards/consosud.png',
|
||||
'diners' => __DIR__.'/credit-cards/diners.png',
|
||||
'discover' => __DIR__.'/credit-cards/discover.png',
|
||||
'elo' => __DIR__.'/credit-cards/elo.png',
|
||||
'hipercard' => __DIR__.'/credit-cards/hipercard.png',
|
||||
'jcb' => __DIR__.'/credit-cards/jcb.png',
|
||||
'mastercard' => __DIR__.'/credit-cards/mastercard.png',
|
||||
'naranja' => __DIR__.'/credit-cards/naranja.png',
|
||||
'targeta-shopping' => __DIR__.'/credit-cards/tarjeta-shopping.png',
|
||||
'union-china-pay' => __DIR__.'/credit-cards/union-china-pay.png',
|
||||
'visa' => __DIR__.'/credit-cards/visa.png',
|
||||
'mir' => __DIR__.'/credit-cards/mir.png',
|
||||
'maestro' => __DIR__.'/credit-cards/maestro.png',
|
||||
'amex' => __DIR__ . '/credit-cards/amex.png',
|
||||
'argencard' => __DIR__ . '/credit-cards/argencard.png',
|
||||
'cabal' => __DIR__ . '/credit-cards/cabal.png',
|
||||
'censosud' => __DIR__ . '/credit-cards/consosud.png',
|
||||
'diners' => __DIR__ . '/credit-cards/diners.png',
|
||||
'discover' => __DIR__ . '/credit-cards/discover.png',
|
||||
'elo' => __DIR__ . '/credit-cards/elo.png',
|
||||
'hipercard' => __DIR__ . '/credit-cards/hipercard.png',
|
||||
'jcb' => __DIR__ . '/credit-cards/jcb.png',
|
||||
'mastercard' => __DIR__ . '/credit-cards/mastercard.png',
|
||||
'naranja' => __DIR__ . '/credit-cards/naranja.png',
|
||||
'targeta-shopping' => __DIR__ . '/credit-cards/tarjeta-shopping.png',
|
||||
'union-china-pay' => __DIR__ . '/credit-cards/union-china-pay.png',
|
||||
'visa' => __DIR__ . '/credit-cards/visa.png',
|
||||
'mir' => __DIR__ . '/credit-cards/mir.png',
|
||||
'maestro' => __DIR__ . '/credit-cards/maestro.png',
|
||||
];
|
||||
|
|
|
@ -1,198 +1,198 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'af' => __DIR__.'/flags/af.png',
|
||||
'ao' => __DIR__.'/flags/ao.png',
|
||||
'al' => __DIR__.'/flags/al.png',
|
||||
'ad' => __DIR__.'/flags/ad.png',
|
||||
'ae' => __DIR__.'/flags/ae.png',
|
||||
'ar' => __DIR__.'/flags/ar.png',
|
||||
'am' => __DIR__.'/flags/am.png',
|
||||
'ag' => __DIR__.'/flags/ag.png',
|
||||
'au' => __DIR__.'/flags/au.png',
|
||||
'at' => __DIR__.'/flags/at.png',
|
||||
'az' => __DIR__.'/flags/az.png',
|
||||
'bi' => __DIR__.'/flags/bi.png',
|
||||
'be' => __DIR__.'/flags/be.png',
|
||||
'bj' => __DIR__.'/flags/bj.png',
|
||||
'bf' => __DIR__.'/flags/bf.png',
|
||||
'bd' => __DIR__.'/flags/bd.png',
|
||||
'bg' => __DIR__.'/flags/bg.png',
|
||||
'bh' => __DIR__.'/flags/bh.png',
|
||||
'bs' => __DIR__.'/flags/bs.png',
|
||||
'ba' => __DIR__.'/flags/ba.png',
|
||||
'by' => __DIR__.'/flags/by.png',
|
||||
'bz' => __DIR__.'/flags/bz.png',
|
||||
'bo' => __DIR__.'/flags/bo.png',
|
||||
'br' => __DIR__.'/flags/br.png',
|
||||
'bb' => __DIR__.'/flags/bb.png',
|
||||
'bn' => __DIR__.'/flags/bn.png',
|
||||
'bt' => __DIR__.'/flags/bt.png',
|
||||
'bw' => __DIR__.'/flags/bw.png',
|
||||
'cf' => __DIR__.'/flags/cf.png',
|
||||
'ca' => __DIR__.'/flags/ca.png',
|
||||
'ch' => __DIR__.'/flags/ch.png',
|
||||
'cl' => __DIR__.'/flags/cl.png',
|
||||
'cn' => __DIR__.'/flags/cn.png',
|
||||
'ci' => __DIR__.'/flags/ci.png',
|
||||
'cm' => __DIR__.'/flags/cm.png',
|
||||
'cd' => __DIR__.'/flags/cd.png',
|
||||
'cg' => __DIR__.'/flags/cg.png',
|
||||
'co' => __DIR__.'/flags/co.png',
|
||||
'km' => __DIR__.'/flags/km.png',
|
||||
'cv' => __DIR__.'/flags/cv.png',
|
||||
'cr' => __DIR__.'/flags/cr.png',
|
||||
'cu' => __DIR__.'/flags/cu.png',
|
||||
'cy' => __DIR__.'/flags/cy.png',
|
||||
'cz' => __DIR__.'/flags/cz.png',
|
||||
'de' => __DIR__.'/flags/de.png',
|
||||
'dj' => __DIR__.'/flags/dj.png',
|
||||
'dm' => __DIR__.'/flags/dm.png',
|
||||
'dk' => __DIR__.'/flags/dk.png',
|
||||
'do' => __DIR__.'/flags/do.png',
|
||||
'dz' => __DIR__.'/flags/dz.png',
|
||||
'ec' => __DIR__.'/flags/ec.png',
|
||||
'eg' => __DIR__.'/flags/eg.png',
|
||||
'er' => __DIR__.'/flags/er.png',
|
||||
'es' => __DIR__.'/flags/es.png',
|
||||
'ee' => __DIR__.'/flags/ee.png',
|
||||
'et' => __DIR__.'/flags/et.png',
|
||||
'fi' => __DIR__.'/flags/fi.png',
|
||||
'fj' => __DIR__.'/flags/fj.png',
|
||||
'fr' => __DIR__.'/flags/fr.png',
|
||||
'fm' => __DIR__.'/flags/fm.png',
|
||||
'ga' => __DIR__.'/flags/ga.png',
|
||||
'gb' => __DIR__.'/flags/gb.png',
|
||||
'ge' => __DIR__.'/flags/ge.png',
|
||||
'gh' => __DIR__.'/flags/gh.png',
|
||||
'gn' => __DIR__.'/flags/gn.png',
|
||||
'gm' => __DIR__.'/flags/gm.png',
|
||||
'gw' => __DIR__.'/flags/gw.png',
|
||||
'gq' => __DIR__.'/flags/gq.png',
|
||||
'gr' => __DIR__.'/flags/gr.png',
|
||||
'gd' => __DIR__.'/flags/gd.png',
|
||||
'gt' => __DIR__.'/flags/gt.png',
|
||||
'gy' => __DIR__.'/flags/gy.png',
|
||||
'hn' => __DIR__.'/flags/hn.png',
|
||||
'hr' => __DIR__.'/flags/hr.png',
|
||||
'ht' => __DIR__.'/flags/ht.png',
|
||||
'hu' => __DIR__.'/flags/hu.png',
|
||||
'id' => __DIR__.'/flags/id.png',
|
||||
'in' => __DIR__.'/flags/in.png',
|
||||
'ie' => __DIR__.'/flags/ie.png',
|
||||
'ir' => __DIR__.'/flags/ir.png',
|
||||
'iq' => __DIR__.'/flags/iq.png',
|
||||
'is' => __DIR__.'/flags/is.png',
|
||||
'il' => __DIR__.'/flags/il.png',
|
||||
'it' => __DIR__.'/flags/it.png',
|
||||
'jm' => __DIR__.'/flags/jm.png',
|
||||
'jo' => __DIR__.'/flags/jo.png',
|
||||
'jp' => __DIR__.'/flags/jp.png',
|
||||
'kz' => __DIR__.'/flags/kz.png',
|
||||
'ke' => __DIR__.'/flags/ke.png',
|
||||
'kg' => __DIR__.'/flags/kg.png',
|
||||
'kh' => __DIR__.'/flags/kh.png',
|
||||
'ki' => __DIR__.'/flags/ki.png',
|
||||
'kn' => __DIR__.'/flags/kn.png',
|
||||
'kr' => __DIR__.'/flags/kr.png',
|
||||
'kw' => __DIR__.'/flags/kw.png',
|
||||
'la' => __DIR__.'/flags/la.png',
|
||||
'lb' => __DIR__.'/flags/lb.png',
|
||||
'lr' => __DIR__.'/flags/lr.png',
|
||||
'ly' => __DIR__.'/flags/ly.png',
|
||||
'lc' => __DIR__.'/flags/lc.png',
|
||||
'li' => __DIR__.'/flags/li.png',
|
||||
'lk' => __DIR__.'/flags/lk.png',
|
||||
'ls' => __DIR__.'/flags/ls.png',
|
||||
'lt' => __DIR__.'/flags/ls.png',
|
||||
'lu' => __DIR__.'/flags/lu.png',
|
||||
'lv' => __DIR__.'/flags/lv.png',
|
||||
'ma' => __DIR__.'/flags/ma.png',
|
||||
'mc' => __DIR__.'/flags/mc.png',
|
||||
'md' => __DIR__.'/flags/md.png',
|
||||
'mg' => __DIR__.'/flags/mg.png',
|
||||
'mv' => __DIR__.'/flags/mv.png',
|
||||
'mx' => __DIR__.'/flags/mx.png',
|
||||
'mh' => __DIR__.'/flags/mh.png',
|
||||
'mk' => __DIR__.'/flags/mk.png',
|
||||
'ml' => __DIR__.'/flags/ml.png',
|
||||
'mt' => __DIR__.'/flags/mt.png',
|
||||
'mm' => __DIR__.'/flags/mm.png',
|
||||
'me' => __DIR__.'/flags/me.png',
|
||||
'mn' => __DIR__.'/flags/mn.png',
|
||||
'mz' => __DIR__.'/flags/mz.png',
|
||||
'mr' => __DIR__.'/flags/mr.png',
|
||||
'mu' => __DIR__.'/flags/mu.png',
|
||||
'mw' => __DIR__.'/flags/mw.png',
|
||||
'my' => __DIR__.'/flags/my.png',
|
||||
'na' => __DIR__.'/flags/na.png',
|
||||
'ne' => __DIR__.'/flags/ne.png',
|
||||
'ng' => __DIR__.'/flags/ng.png',
|
||||
'ni' => __DIR__.'/flags/ni.png',
|
||||
'nl' => __DIR__.'/flags/nl.png',
|
||||
'no' => __DIR__.'/flags/no.png',
|
||||
'np' => __DIR__.'/flags/np.png',
|
||||
'nr' => __DIR__.'/flags/nr.png',
|
||||
'nz' => __DIR__.'/flags/nz.png',
|
||||
'om' => __DIR__.'/flags/om.png',
|
||||
'pk' => __DIR__.'/flags/pk.png',
|
||||
'pa' => __DIR__.'/flags/pa.png',
|
||||
'pe' => __DIR__.'/flags/pe.png',
|
||||
'ph' => __DIR__.'/flags/ph.png',
|
||||
'pw' => __DIR__.'/flags/pw.png',
|
||||
'pg' => __DIR__.'/flags/pg.png',
|
||||
'pl' => __DIR__.'/flags/pl.png',
|
||||
'kp' => __DIR__.'/flags/kp.png',
|
||||
'pt' => __DIR__.'/flags/pt.png',
|
||||
'py' => __DIR__.'/flags/py.png',
|
||||
'qa' => __DIR__.'/flags/qa.png',
|
||||
'ro' => __DIR__.'/flags/ro.png',
|
||||
'ru' => __DIR__.'/flags/ru.png',
|
||||
'rw' => __DIR__.'/flags/rw.png',
|
||||
'sa' => __DIR__.'/flags/sa.png',
|
||||
'sd' => __DIR__.'/flags/sd.png',
|
||||
'sn' => __DIR__.'/flags/sn.png',
|
||||
'sg' => __DIR__.'/flags/sg.png',
|
||||
'sb' => __DIR__.'/flags/sb.png',
|
||||
'sl' => __DIR__.'/flags/sl.png',
|
||||
'sv' => __DIR__.'/flags/sv.png',
|
||||
'sm' => __DIR__.'/flags/sm.png',
|
||||
'so' => __DIR__.'/flags/so.png',
|
||||
'rs' => __DIR__.'/flags/rs.png',
|
||||
'ss' => __DIR__.'/flags/ss.png',
|
||||
'st' => __DIR__.'/flags/st.png',
|
||||
'sr' => __DIR__.'/flags/sr.png',
|
||||
'sk' => __DIR__.'/flags/sk.png',
|
||||
'si' => __DIR__.'/flags/si.png',
|
||||
'se' => __DIR__.'/flags/se.png',
|
||||
'sz' => __DIR__.'/flags/sz.png',
|
||||
'sc' => __DIR__.'/flags/sc.png',
|
||||
'sy' => __DIR__.'/flags/sy.png',
|
||||
'td' => __DIR__.'/flags/td.png',
|
||||
'tg' => __DIR__.'/flags/tg.png',
|
||||
'th' => __DIR__.'/flags/th.png',
|
||||
'tj' => __DIR__.'/flags/tj.png',
|
||||
'tm' => __DIR__.'/flags/tm.png',
|
||||
'tl' => __DIR__.'/flags/tl.png',
|
||||
'to' => __DIR__.'/flags/to.png',
|
||||
'tt' => __DIR__.'/flags/tt.png',
|
||||
'tn' => __DIR__.'/flags/tn.png',
|
||||
'tr' => __DIR__.'/flags/tr.png',
|
||||
'tv' => __DIR__.'/flags/tv.png',
|
||||
'tz' => __DIR__.'/flags/tz.png',
|
||||
'ug' => __DIR__.'/flags/ug.png',
|
||||
'ua' => __DIR__.'/flags/ua.png',
|
||||
'uy' => __DIR__.'/flags/uy.png',
|
||||
'us' => __DIR__.'/flags/us.png',
|
||||
'uz' => __DIR__.'/flags/uz.png',
|
||||
'va' => __DIR__.'/flags/va.png',
|
||||
'vc' => __DIR__.'/flags/vc.png',
|
||||
've' => __DIR__.'/flags/ve.png',
|
||||
'vn' => __DIR__.'/flags/vn.png',
|
||||
'vu' => __DIR__.'/flags/vu.png',
|
||||
'ws' => __DIR__.'/flags/ws.png',
|
||||
'ye' => __DIR__.'/flags/ye.png',
|
||||
'za' => __DIR__.'/flags/za.png',
|
||||
'zm' => __DIR__.'/flags/zm.png',
|
||||
'zw' => __DIR__.'/flags/zw.png',
|
||||
'af' => __DIR__ . '/flags/af.png',
|
||||
'ao' => __DIR__ . '/flags/ao.png',
|
||||
'al' => __DIR__ . '/flags/al.png',
|
||||
'ad' => __DIR__ . '/flags/ad.png',
|
||||
'ae' => __DIR__ . '/flags/ae.png',
|
||||
'ar' => __DIR__ . '/flags/ar.png',
|
||||
'am' => __DIR__ . '/flags/am.png',
|
||||
'ag' => __DIR__ . '/flags/ag.png',
|
||||
'au' => __DIR__ . '/flags/au.png',
|
||||
'at' => __DIR__ . '/flags/at.png',
|
||||
'az' => __DIR__ . '/flags/az.png',
|
||||
'bi' => __DIR__ . '/flags/bi.png',
|
||||
'be' => __DIR__ . '/flags/be.png',
|
||||
'bj' => __DIR__ . '/flags/bj.png',
|
||||
'bf' => __DIR__ . '/flags/bf.png',
|
||||
'bd' => __DIR__ . '/flags/bd.png',
|
||||
'bg' => __DIR__ . '/flags/bg.png',
|
||||
'bh' => __DIR__ . '/flags/bh.png',
|
||||
'bs' => __DIR__ . '/flags/bs.png',
|
||||
'ba' => __DIR__ . '/flags/ba.png',
|
||||
'by' => __DIR__ . '/flags/by.png',
|
||||
'bz' => __DIR__ . '/flags/bz.png',
|
||||
'bo' => __DIR__ . '/flags/bo.png',
|
||||
'br' => __DIR__ . '/flags/br.png',
|
||||
'bb' => __DIR__ . '/flags/bb.png',
|
||||
'bn' => __DIR__ . '/flags/bn.png',
|
||||
'bt' => __DIR__ . '/flags/bt.png',
|
||||
'bw' => __DIR__ . '/flags/bw.png',
|
||||
'cf' => __DIR__ . '/flags/cf.png',
|
||||
'ca' => __DIR__ . '/flags/ca.png',
|
||||
'ch' => __DIR__ . '/flags/ch.png',
|
||||
'cl' => __DIR__ . '/flags/cl.png',
|
||||
'cn' => __DIR__ . '/flags/cn.png',
|
||||
'ci' => __DIR__ . '/flags/ci.png',
|
||||
'cm' => __DIR__ . '/flags/cm.png',
|
||||
'cd' => __DIR__ . '/flags/cd.png',
|
||||
'cg' => __DIR__ . '/flags/cg.png',
|
||||
'co' => __DIR__ . '/flags/co.png',
|
||||
'km' => __DIR__ . '/flags/km.png',
|
||||
'cv' => __DIR__ . '/flags/cv.png',
|
||||
'cr' => __DIR__ . '/flags/cr.png',
|
||||
'cu' => __DIR__ . '/flags/cu.png',
|
||||
'cy' => __DIR__ . '/flags/cy.png',
|
||||
'cz' => __DIR__ . '/flags/cz.png',
|
||||
'de' => __DIR__ . '/flags/de.png',
|
||||
'dj' => __DIR__ . '/flags/dj.png',
|
||||
'dm' => __DIR__ . '/flags/dm.png',
|
||||
'dk' => __DIR__ . '/flags/dk.png',
|
||||
'do' => __DIR__ . '/flags/do.png',
|
||||
'dz' => __DIR__ . '/flags/dz.png',
|
||||
'ec' => __DIR__ . '/flags/ec.png',
|
||||
'eg' => __DIR__ . '/flags/eg.png',
|
||||
'er' => __DIR__ . '/flags/er.png',
|
||||
'es' => __DIR__ . '/flags/es.png',
|
||||
'ee' => __DIR__ . '/flags/ee.png',
|
||||
'et' => __DIR__ . '/flags/et.png',
|
||||
'fi' => __DIR__ . '/flags/fi.png',
|
||||
'fj' => __DIR__ . '/flags/fj.png',
|
||||
'fr' => __DIR__ . '/flags/fr.png',
|
||||
'fm' => __DIR__ . '/flags/fm.png',
|
||||
'ga' => __DIR__ . '/flags/ga.png',
|
||||
'gb' => __DIR__ . '/flags/gb.png',
|
||||
'ge' => __DIR__ . '/flags/ge.png',
|
||||
'gh' => __DIR__ . '/flags/gh.png',
|
||||
'gn' => __DIR__ . '/flags/gn.png',
|
||||
'gm' => __DIR__ . '/flags/gm.png',
|
||||
'gw' => __DIR__ . '/flags/gw.png',
|
||||
'gq' => __DIR__ . '/flags/gq.png',
|
||||
'gr' => __DIR__ . '/flags/gr.png',
|
||||
'gd' => __DIR__ . '/flags/gd.png',
|
||||
'gt' => __DIR__ . '/flags/gt.png',
|
||||
'gy' => __DIR__ . '/flags/gy.png',
|
||||
'hn' => __DIR__ . '/flags/hn.png',
|
||||
'hr' => __DIR__ . '/flags/hr.png',
|
||||
'ht' => __DIR__ . '/flags/ht.png',
|
||||
'hu' => __DIR__ . '/flags/hu.png',
|
||||
'id' => __DIR__ . '/flags/id.png',
|
||||
'in' => __DIR__ . '/flags/in.png',
|
||||
'ie' => __DIR__ . '/flags/ie.png',
|
||||
'ir' => __DIR__ . '/flags/ir.png',
|
||||
'iq' => __DIR__ . '/flags/iq.png',
|
||||
'is' => __DIR__ . '/flags/is.png',
|
||||
'il' => __DIR__ . '/flags/il.png',
|
||||
'it' => __DIR__ . '/flags/it.png',
|
||||
'jm' => __DIR__ . '/flags/jm.png',
|
||||
'jo' => __DIR__ . '/flags/jo.png',
|
||||
'jp' => __DIR__ . '/flags/jp.png',
|
||||
'kz' => __DIR__ . '/flags/kz.png',
|
||||
'ke' => __DIR__ . '/flags/ke.png',
|
||||
'kg' => __DIR__ . '/flags/kg.png',
|
||||
'kh' => __DIR__ . '/flags/kh.png',
|
||||
'ki' => __DIR__ . '/flags/ki.png',
|
||||
'kn' => __DIR__ . '/flags/kn.png',
|
||||
'kr' => __DIR__ . '/flags/kr.png',
|
||||
'kw' => __DIR__ . '/flags/kw.png',
|
||||
'la' => __DIR__ . '/flags/la.png',
|
||||
'lb' => __DIR__ . '/flags/lb.png',
|
||||
'lr' => __DIR__ . '/flags/lr.png',
|
||||
'ly' => __DIR__ . '/flags/ly.png',
|
||||
'lc' => __DIR__ . '/flags/lc.png',
|
||||
'li' => __DIR__ . '/flags/li.png',
|
||||
'lk' => __DIR__ . '/flags/lk.png',
|
||||
'ls' => __DIR__ . '/flags/ls.png',
|
||||
'lt' => __DIR__ . '/flags/ls.png',
|
||||
'lu' => __DIR__ . '/flags/lu.png',
|
||||
'lv' => __DIR__ . '/flags/lv.png',
|
||||
'ma' => __DIR__ . '/flags/ma.png',
|
||||
'mc' => __DIR__ . '/flags/mc.png',
|
||||
'md' => __DIR__ . '/flags/md.png',
|
||||
'mg' => __DIR__ . '/flags/mg.png',
|
||||
'mv' => __DIR__ . '/flags/mv.png',
|
||||
'mx' => __DIR__ . '/flags/mx.png',
|
||||
'mh' => __DIR__ . '/flags/mh.png',
|
||||
'mk' => __DIR__ . '/flags/mk.png',
|
||||
'ml' => __DIR__ . '/flags/ml.png',
|
||||
'mt' => __DIR__ . '/flags/mt.png',
|
||||
'mm' => __DIR__ . '/flags/mm.png',
|
||||
'me' => __DIR__ . '/flags/me.png',
|
||||
'mn' => __DIR__ . '/flags/mn.png',
|
||||
'mz' => __DIR__ . '/flags/mz.png',
|
||||
'mr' => __DIR__ . '/flags/mr.png',
|
||||
'mu' => __DIR__ . '/flags/mu.png',
|
||||
'mw' => __DIR__ . '/flags/mw.png',
|
||||
'my' => __DIR__ . '/flags/my.png',
|
||||
'na' => __DIR__ . '/flags/na.png',
|
||||
'ne' => __DIR__ . '/flags/ne.png',
|
||||
'ng' => __DIR__ . '/flags/ng.png',
|
||||
'ni' => __DIR__ . '/flags/ni.png',
|
||||
'nl' => __DIR__ . '/flags/nl.png',
|
||||
'no' => __DIR__ . '/flags/no.png',
|
||||
'np' => __DIR__ . '/flags/np.png',
|
||||
'nr' => __DIR__ . '/flags/nr.png',
|
||||
'nz' => __DIR__ . '/flags/nz.png',
|
||||
'om' => __DIR__ . '/flags/om.png',
|
||||
'pk' => __DIR__ . '/flags/pk.png',
|
||||
'pa' => __DIR__ . '/flags/pa.png',
|
||||
'pe' => __DIR__ . '/flags/pe.png',
|
||||
'ph' => __DIR__ . '/flags/ph.png',
|
||||
'pw' => __DIR__ . '/flags/pw.png',
|
||||
'pg' => __DIR__ . '/flags/pg.png',
|
||||
'pl' => __DIR__ . '/flags/pl.png',
|
||||
'kp' => __DIR__ . '/flags/kp.png',
|
||||
'pt' => __DIR__ . '/flags/pt.png',
|
||||
'py' => __DIR__ . '/flags/py.png',
|
||||
'qa' => __DIR__ . '/flags/qa.png',
|
||||
'ro' => __DIR__ . '/flags/ro.png',
|
||||
'ru' => __DIR__ . '/flags/ru.png',
|
||||
'rw' => __DIR__ . '/flags/rw.png',
|
||||
'sa' => __DIR__ . '/flags/sa.png',
|
||||
'sd' => __DIR__ . '/flags/sd.png',
|
||||
'sn' => __DIR__ . '/flags/sn.png',
|
||||
'sg' => __DIR__ . '/flags/sg.png',
|
||||
'sb' => __DIR__ . '/flags/sb.png',
|
||||
'sl' => __DIR__ . '/flags/sl.png',
|
||||
'sv' => __DIR__ . '/flags/sv.png',
|
||||
'sm' => __DIR__ . '/flags/sm.png',
|
||||
'so' => __DIR__ . '/flags/so.png',
|
||||
'rs' => __DIR__ . '/flags/rs.png',
|
||||
'ss' => __DIR__ . '/flags/ss.png',
|
||||
'st' => __DIR__ . '/flags/st.png',
|
||||
'sr' => __DIR__ . '/flags/sr.png',
|
||||
'sk' => __DIR__ . '/flags/sk.png',
|
||||
'si' => __DIR__ . '/flags/si.png',
|
||||
'se' => __DIR__ . '/flags/se.png',
|
||||
'sz' => __DIR__ . '/flags/sz.png',
|
||||
'sc' => __DIR__ . '/flags/sc.png',
|
||||
'sy' => __DIR__ . '/flags/sy.png',
|
||||
'td' => __DIR__ . '/flags/td.png',
|
||||
'tg' => __DIR__ . '/flags/tg.png',
|
||||
'th' => __DIR__ . '/flags/th.png',
|
||||
'tj' => __DIR__ . '/flags/tj.png',
|
||||
'tm' => __DIR__ . '/flags/tm.png',
|
||||
'tl' => __DIR__ . '/flags/tl.png',
|
||||
'to' => __DIR__ . '/flags/to.png',
|
||||
'tt' => __DIR__ . '/flags/tt.png',
|
||||
'tn' => __DIR__ . '/flags/tn.png',
|
||||
'tr' => __DIR__ . '/flags/tr.png',
|
||||
'tv' => __DIR__ . '/flags/tv.png',
|
||||
'tz' => __DIR__ . '/flags/tz.png',
|
||||
'ug' => __DIR__ . '/flags/ug.png',
|
||||
'ua' => __DIR__ . '/flags/ua.png',
|
||||
'uy' => __DIR__ . '/flags/uy.png',
|
||||
'us' => __DIR__ . '/flags/us.png',
|
||||
'uz' => __DIR__ . '/flags/uz.png',
|
||||
'va' => __DIR__ . '/flags/va.png',
|
||||
'vc' => __DIR__ . '/flags/vc.png',
|
||||
've' => __DIR__ . '/flags/ve.png',
|
||||
'vn' => __DIR__ . '/flags/vn.png',
|
||||
'vu' => __DIR__ . '/flags/vu.png',
|
||||
'ws' => __DIR__ . '/flags/ws.png',
|
||||
'ye' => __DIR__ . '/flags/ye.png',
|
||||
'za' => __DIR__ . '/flags/za.png',
|
||||
'zm' => __DIR__ . '/flags/zm.png',
|
||||
'zw' => __DIR__ . '/flags/zw.png',
|
||||
];
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'AND' => __DIR__.'/os/android.png',
|
||||
'ATV' => __DIR__.'/os/apple-tv.png',
|
||||
'COS' => __DIR__.'/os/chrome-os.png',
|
||||
'AND' => __DIR__ . '/os/android.png',
|
||||
'ATV' => __DIR__ . '/os/apple-tv.png',
|
||||
'COS' => __DIR__ . '/os/chrome-os.png',
|
||||
|
||||
/*
|
||||
'AIX' => 'AIX',
|
||||
|
|
|
@ -232,7 +232,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => new stdClass,
|
||||
'default' => new stdClass(),
|
||||
'array' => false,
|
||||
'filters' => ['json', 'range', 'enum'],
|
||||
],
|
||||
|
@ -2066,7 +2066,7 @@ $collections = [
|
|||
],
|
||||
[
|
||||
'$id' => 'status',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 256,
|
||||
'signed' => true,
|
||||
|
@ -2110,7 +2110,7 @@ $collections = [
|
|||
],
|
||||
[
|
||||
'$id' => 'sourceType',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 2048,
|
||||
'signed' => true,
|
||||
|
@ -2121,7 +2121,7 @@ $collections = [
|
|||
],
|
||||
[
|
||||
'$id' => 'source',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 2048,
|
||||
'signed' => true,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* List of server wide error codes and their respective messages.
|
||||
* List of server wide error codes and their respective messages.
|
||||
*/
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
|
@ -11,17 +11,17 @@ return [
|
|||
Exception::GENERAL_UNKNOWN => [
|
||||
'name' => Exception::GENERAL_UNKNOWN,
|
||||
'description' => 'An unknown error has occured. Please check the logs for more information.',
|
||||
'code' => 500,
|
||||
'code' => 500,
|
||||
],
|
||||
Exception::GENERAL_MOCK => [
|
||||
'name' => Exception::GENERAL_MOCK,
|
||||
'description' => 'General errors thrown by the mock controller used for testing.',
|
||||
'code' => 400,
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::GENERAL_ACCESS_FORBIDDEN => [
|
||||
'name' => Exception::GENERAL_ACCESS_FORBIDDEN,
|
||||
'description' => 'Access to this API is forbidden.',
|
||||
'code' => 401,
|
||||
'code' => 401,
|
||||
],
|
||||
Exception::GENERAL_UNKNOWN_ORIGIN => [
|
||||
'name' => Exception::GENERAL_UNKNOWN_ORIGIN,
|
||||
|
@ -81,7 +81,7 @@ return [
|
|||
Exception::GENERAL_PROTOCOL_UNSUPPORTED => [
|
||||
'name' => Exception::GENERAL_PROTOCOL_UNSUPPORTED,
|
||||
'description' => 'The request cannot be fulfilled with the current protocol. Please check the value of the _APP_OPTIONS_FORCE_HTTPS environment variable.',
|
||||
'code' => 500,
|
||||
'code' => 500,
|
||||
],
|
||||
|
||||
/** User Errors */
|
||||
|
@ -497,4 +497,4 @@ return [
|
|||
'description' => 'Domain verification for the requested domain has failed.',
|
||||
'code' => 401,
|
||||
]
|
||||
];
|
||||
];
|
||||
|
|
|
@ -51,7 +51,7 @@ return [
|
|||
'or', // Oriya
|
||||
'tl', // Filipino
|
||||
'pl', // Polish
|
||||
'pt-br', // Portuguese - Brazil
|
||||
'pt-br', // Portuguese - Brazil
|
||||
'pt-pt', // Portuguese - Portugal
|
||||
'pa', // Punjabi
|
||||
'ro', // Romanian
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
"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.hello": "നമസ്കാരം",
|
||||
"emails.invitation.body": "നിങ്ങളെ {{project}} -ലെ {{team}} ടീമിലെ അംഗമാകുവാന് ക്ഷണിക്കാൻ {{owner}} ആഗ്രഹിക്കുതിനാലാണ് ഈ മെയിൽ നിങ്ങൾക്ക് അയക്കുന്നത്.",
|
||||
"emails.invitation.body": "നിങ്ങളെ {{project}} -ലെ {{team}} ടീമിലെ അംഗമാകുവാന് ക്ഷണിക്കാൻ {{owner}} ആഗ്രഹിക്കുന്നതിനാലാണ് ഈ മെയിൽ നിങ്ങൾക്ക് അയക്കുന്നത്.",
|
||||
"emails.invitation.footer": "നിങ്ങൾക്ക് താൽപ്പര്യമില്ലെങ്കിൽ, ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.",
|
||||
"emails.invitation.thanks": "നന്ദി",
|
||||
"emails.invitation.signature": "{{project}} ടീം",
|
||||
|
@ -229,4 +229,4 @@
|
|||
"continents.na": "വടക്കേ അമേരിക്ക",
|
||||
"continents.oc": "ഓഷ്യാനിയ",
|
||||
"continents.sa": "തെക്കേ അമേരിക്ക"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
|
||||
/**
|
||||
* List of Appwrite Cloud Functions supported runtimes
|
||||
*/
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
|
||||
$runtimes = new Runtimes('v1');
|
||||
|
||||
$allowList = empty(App::getEnv('_APP_FUNCTIONS_RUNTIMES')) ? [] : \explode(',', App::getEnv('_APP_FUNCTIONS_RUNTIMES'));
|
||||
|
||||
$runtimes = $runtimes->getAll(true, $allowList);
|
||||
|
||||
return $runtimes;
|
||||
return $runtimes;
|
||||
|
|
|
@ -70,4 +70,5 @@ return [ // List of publicly visible scopes
|
|||
'health.read' => [
|
||||
'description' => 'Access to read your project\'s health status',
|
||||
],
|
||||
];;
|
||||
];
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ return [
|
|||
'avatars' => [
|
||||
'key' => 'avatars',
|
||||
'name' => 'Avatars',
|
||||
'subtitle'=> 'The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.',
|
||||
'subtitle' => 'The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.',
|
||||
'description' => '/docs/services/avatars.md',
|
||||
'controller' => 'api/avatars.php',
|
||||
'sdk' => true,
|
||||
|
|
|
@ -5,4 +5,4 @@ return [ // Accepted inputs files
|
|||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
];
|
||||
];
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<?php
|
||||
|
||||
return [ // Based on this list @see http://stackoverflow.com/a/4212908/2299554
|
||||
'default' => __DIR__.'/logos/none.png',
|
||||
'default_image' => __DIR__.'/logos/image.png',
|
||||
|
||||
'default' => __DIR__ . '/logos/none.png',
|
||||
'default_image' => __DIR__ . '/logos/image.png',
|
||||
|
||||
// Video Files
|
||||
'video/mp4' => __DIR__.'/logos/video.png',
|
||||
'video/x-flv' => __DIR__.'/logos/video.png',
|
||||
'application/x-mpegURL' => __DIR__.'/logos/video.png',
|
||||
'video/MP2T' => __DIR__.'/logos/video.png',
|
||||
'video/3gpp' => __DIR__.'/logos/video.png',
|
||||
'video/quicktime' => __DIR__.'/logos/video.png',
|
||||
'video/x-msvideo' => __DIR__.'/logos/video.png',
|
||||
'video/x-ms-wmv' => __DIR__.'/logos/video.png',
|
||||
'video/mp4' => __DIR__ . '/logos/video.png',
|
||||
'video/x-flv' => __DIR__ . '/logos/video.png',
|
||||
'application/x-mpegURL' => __DIR__ . '/logos/video.png',
|
||||
'video/MP2T' => __DIR__ . '/logos/video.png',
|
||||
'video/3gpp' => __DIR__ . '/logos/video.png',
|
||||
'video/quicktime' => __DIR__ . '/logos/video.png',
|
||||
'video/x-msvideo' => __DIR__ . '/logos/video.png',
|
||||
'video/x-ms-wmv' => __DIR__ . '/logos/video.png',
|
||||
|
||||
// // Microsoft Word
|
||||
// 'application/msword' => __DIR__.'/logos/word.png',
|
||||
|
@ -41,4 +41,4 @@ return [ // Based on this list @see http://stackoverflow.com/a/4212908/2299554
|
|||
|
||||
// Adobe PDF
|
||||
// 'application/pdf' => __DIR__.'/logos/pdf.png',
|
||||
];
|
||||
];
|
||||
|
|
|
@ -30,7 +30,7 @@ return [
|
|||
'audio/ogg', // Ogg Vorbis RFC 5334
|
||||
'audio/vorbis', // Vorbis RFC 5215
|
||||
'audio/vnd.wav', // wav RFC 2361
|
||||
|
||||
|
||||
// Microsoft Word
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
|
@ -61,4 +61,4 @@ return [
|
|||
|
||||
// Adobe PDF
|
||||
'application/pdf',
|
||||
];
|
||||
];
|
||||
|
|
|
@ -6,4 +6,4 @@ return [ // Accepted outputs files
|
|||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'webp' => 'image/webp',
|
||||
];
|
||||
];
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Utopia\Config\Config;
|
||||
|
||||
return [
|
||||
[
|
||||
'category' => 'General',
|
||||
|
|
|
@ -4,22 +4,30 @@ use Ahc\Jwt\JWT;
|
|||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Host;
|
||||
use Appwrite\Network\Validator\URL;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Stats\Stats;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\URL\URL as URLParser;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Appwrite\Event\Audit;
|
||||
use Utopia\Audit\Audit as EventAudit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
|
@ -55,14 +63,7 @@ App::post('/v1/account')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$email = \strtolower($email);
|
||||
if ('console' === $project->getId()) {
|
||||
|
@ -117,7 +118,7 @@ App::post('/v1/account')
|
|||
Authorization::setRole('role:' . Auth::USER_ROLE_MEMBER);
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
|
@ -153,22 +154,13 @@ App::post('/v1/account/sessions')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($email, $password, $request, $response, $dbForProject, $locale, $geodb, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $email, string $password, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$email = \strtolower($email);
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
$profile = $dbForProject->findOne('users', [
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]);
|
||||
|
||||
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
|
||||
throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); // Wrong password or username
|
||||
|
@ -193,20 +185,22 @@ App::post('/v1/account/sessions')
|
|||
'userAgent' => $request->getUserAgent('UNKNOWN'),
|
||||
'ip' => $request->getIP(),
|
||||
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
|
||||
], $detector->getOS(), $detector->getClient(), $detector->getDevice()
|
||||
],
|
||||
$detector->getOS(),
|
||||
$detector->getClient(),
|
||||
$detector->getDevice()
|
||||
));
|
||||
|
||||
Authorization::setRole('user:' . $profile->getId());
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:' . $profile->getId()])
|
||||
->setAttribute('$write', ['user:' . $profile->getId()])
|
||||
);
|
||||
->setAttribute('$write', ['user:' . $profile->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$profile->getId())
|
||||
->setResource('user/' . $profile->getId())
|
||||
->setUser($profile)
|
||||
;
|
||||
|
||||
|
@ -222,7 +216,7 @@ App::post('/v1/account/sessions')
|
|||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
;
|
||||
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
|
||||
$session
|
||||
->setAttribute('current', true)
|
||||
|
@ -257,22 +251,19 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
|||
->label('sdk.methodType', 'webAuth')
|
||||
->label('abuse-limit', 50)
|
||||
->label('abuse-key', 'ip:{ip}')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), function($node) {return (!$node['mock']);}))).'.')
|
||||
->param('success', '', function ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('failure', '', function ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), fn($node) => (!$node['mock'])))) . '.')
|
||||
->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('scopes', [], new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each 128 characters long.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->action(function ($provider, $success, $failure, $scopes, $request, $response, $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$callback = $protocol.'://'.$request->getHostname().'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId();
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}';
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
|
||||
if (!empty($appSecret) && isset($appSecret['version'])) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']);
|
||||
|
@ -283,17 +274,17 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
|||
throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::PROJECT_PROVIDER_DISABLED);
|
||||
}
|
||||
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider);
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
|
||||
|
||||
if (!\class_exists($className)) {
|
||||
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if(empty($success)) {
|
||||
if (empty($success)) {
|
||||
$success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess;
|
||||
}
|
||||
|
||||
if(empty($failure)) {
|
||||
if (empty($failure)) {
|
||||
$failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure;
|
||||
}
|
||||
|
||||
|
@ -317,9 +308,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function ($projectId, $provider, $code, $state, $request, $response) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
@ -344,9 +333,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function ($projectId, $provider, $code, $state, $request, $response) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
@ -379,23 +366,14 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($provider, $code, $state, $request, $response, $project, $user, $dbForProject, $geodb, $audits, $events, $usage) use ($oauthDefaultSuccess) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Audit $audits, Event $events, Stats $usage) use ($oauthDefaultSuccess) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
|
||||
$validateURL = new URL();
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}';
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
|
||||
if (!empty($appSecret) && isset($appSecret['version'])) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']);
|
||||
|
@ -431,7 +409,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$state['failure'] = null;
|
||||
|
||||
$accessToken = $oauth2->getAccessToken($code);
|
||||
$refreshToken =$oauth2->getRefreshToken($code);
|
||||
$refreshToken = $oauth2->getRefreshToken($code);
|
||||
$accessTokenExpiry = $oauth2->getAccessTokenExpiry($code);
|
||||
|
||||
if (empty($accessToken)) {
|
||||
|
@ -457,7 +435,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
|
||||
if ($current) { // Delete current session of new one.
|
||||
$currentDocument = $dbForProject->getDocument('sessions', $current);
|
||||
if(!$currentDocument->isEmpty()) {
|
||||
if (!$currentDocument->isEmpty()) {
|
||||
$dbForProject->deleteDocument('sessions', $currentDocument->getId());
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
}
|
||||
|
@ -478,8 +456,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$isVerified = $oauth2->isEmailVerified($accessToken);
|
||||
|
||||
$user = $dbForProject->findOne('users', [
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]);
|
||||
|
||||
if ($user === false || $user->isEmpty()) { // Last option -> create the user, generate random password
|
||||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
@ -561,20 +538,19 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.create', 1)
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('provider', 'oauth2-'.$provider)
|
||||
->setParam('provider', 'oauth2-' . $provider)
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -625,7 +601,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
@ -634,17 +610,9 @@ App::post('/v1/account/sessions/magic-url')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('mails')
|
||||
->action(function ($userId, $email, $url, $request, $response, $project, $dbForProject, $locale, $audits, $events, $mails) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Mail $mails */
|
||||
->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails) {
|
||||
|
||||
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
|
@ -700,17 +668,16 @@ App::post('/v1/account/sessions/magic-url')
|
|||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole('user:'.$user->getId());
|
||||
Authorization::setRole('user:' . $user->getId());
|
||||
|
||||
$token = $dbForProject->createDocument('tokens', $token
|
||||
->setAttribute('$read', ['user:'.$user->getId()])
|
||||
->setAttribute('$write', ['user:'.$user->getId()])
|
||||
);
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
if(empty($url)) {
|
||||
$url = $request->getProtocol().'://'.$request->getHostname().'/auth/magic-url';
|
||||
if (empty($url)) {
|
||||
$url = $request->getProtocol() . '://' . $request->getHostname() . '/auth/magic-url';
|
||||
}
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
|
@ -736,7 +703,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
$token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $loginSecret : '');
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
|
@ -769,16 +736,7 @@ App::put('/v1/account/sessions/magic-url')
|
|||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($userId, $secret, $request, $response, $dbForProject, $locale, $geodb, $audits, $events) {
|
||||
/** @var string $userId */
|
||||
/** @var string $secret */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Event $events) {
|
||||
|
||||
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
|
@ -816,8 +774,7 @@ App::put('/v1/account/sessions/magic-url')
|
|||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
|
@ -838,7 +795,7 @@ App::put('/v1/account/sessions/magic-url')
|
|||
throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$audits->setResource('user/'.$user->getId());
|
||||
$audits->setResource('user/' . $user->getId());
|
||||
|
||||
$events
|
||||
->setParam('userId', $user->getId())
|
||||
|
@ -852,12 +809,12 @@ App::put('/v1/account/sessions/magic-url')
|
|||
$protocol = $request->getProtocol();
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
;
|
||||
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
|
||||
$session
|
||||
->setAttribute('current', true)
|
||||
|
@ -892,17 +849,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($request, $response, $locale, $user, $project, $dbForProject, $geodb, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Stats\Stats $events */
|
||||
->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
|
@ -970,12 +917,11 @@ App::post('/v1/account/sessions/anonymous')
|
|||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$audits->setResource('user/'.$user->getId());
|
||||
$audits->setResource('user/' . $user->getId());
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.create', 1)
|
||||
|
@ -997,7 +943,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
;
|
||||
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
|
||||
$session
|
||||
->setAttribute('current', true)
|
||||
|
@ -1024,10 +970,7 @@ App::post('/v1/account/jwt')
|
|||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->action(function ($response, $user, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (Response $response, Document $user, Database $dbForProject) {
|
||||
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
@ -1070,10 +1013,7 @@ App::get('/v1/account')
|
|||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (Response $response, Document $user, Stats $usage) {
|
||||
|
||||
$usage->setParam('users.read', 1);
|
||||
|
||||
|
@ -1094,10 +1034,7 @@ App::get('/v1/account/prefs')
|
|||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (Response $response, Document $user, Stats $usage) {
|
||||
|
||||
$prefs = $user->getAttribute('prefs', new \stdClass());
|
||||
|
||||
|
@ -1121,17 +1058,13 @@ App::get('/v1/account/sessions')
|
|||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $locale, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (Response $response, Document $user, Locale $locale, Stats $usage) {
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = Auth::sessionVerify($sessions, Auth::$secret);
|
||||
|
||||
foreach ($sessions as $key => $session) {/** @var Document $session */
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
|
||||
$session->setAttribute('countryName', $countryName);
|
||||
$session->setAttribute('current', ($current == $session->getId()) ? true : false);
|
||||
|
@ -1166,16 +1099,9 @@ App::get('/v1/account/logs')
|
|||
->inject('geodb')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($limit, $offset, $response, $user, $locale, $geodb, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (int $limit, int $offset, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$audit = new EventAudit($dbForProject);
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getId(), $limit, $offset);
|
||||
|
||||
|
@ -1197,13 +1123,12 @@ App::get('/v1/account/logs')
|
|||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$usage->setParam('users.read', 1);
|
||||
|
@ -1231,12 +1156,7 @@ App::get('/v1/account/sessions/:sessionId')
|
|||
->inject('locale')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($sessionId, $response, $user, $locale, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (?string $sessionId, Response $response, Document $user, Locale $locale, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$sessionId = ($sessionId === 'current')
|
||||
|
@ -1245,7 +1165,7 @@ App::get('/v1/account/sessions/:sessionId')
|
|||
|
||||
foreach ($sessions as $session) {/** @var Document $session */
|
||||
if ($sessionId == $session->getId()) {
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
|
||||
$session
|
||||
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret)))
|
||||
|
@ -1280,21 +1200,14 @@ App::patch('/v1/account/name')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($name, $response, $user, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Stats\Stats $events */
|
||||
->action(function (string $name, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email')]))
|
||||
);
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email')])));
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
|
@ -1324,13 +1237,7 @@ App::patch('/v1/account/password')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($password, $oldPassword, $response, $user, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Stats\Stats $events */
|
||||
->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
// Check old password only if its an existing user.
|
||||
if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password
|
||||
|
@ -1346,7 +1253,7 @@ App::patch('/v1/account/password')
|
|||
);
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
|
@ -1376,13 +1283,7 @@ App::patch('/v1/account/email')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($email, $password, $response, $user, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Stats\Stats $events */
|
||||
->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting
|
||||
|
||||
|
@ -1405,14 +1306,13 @@ App::patch('/v1/account/email')
|
|||
->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', ''))
|
||||
->setAttribute('email', $email)
|
||||
->setAttribute('emailVerification', false) // After this user needs to confirm mail again
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')]))
|
||||
);
|
||||
} catch(Duplicate $th) {
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
->setUser($user)
|
||||
;
|
||||
|
||||
|
@ -1441,17 +1341,11 @@ App::patch('/v1/account/prefs')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($prefs, $response, $user, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
|
||||
|
||||
$audits->setResource('user/'.$user->getId());
|
||||
$audits->setResource('user/' . $user->getId());
|
||||
$usage->setParam('users.update', 1);
|
||||
$events->setParam('userId', $user->getId());
|
||||
|
||||
|
@ -1477,14 +1371,7 @@ App::patch('/v1/account/status')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($request, $response, $user, $dbForProject, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
|
||||
|
||||
|
@ -1526,15 +1413,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($sessionId, $request, $response, $user, $dbForProject, $locale, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$sessionId = ($sessionId === 'current')
|
||||
|
@ -1556,7 +1435,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||
$session
|
||||
->setAttribute('current', true)
|
||||
->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||
->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
|
@ -1570,7 +1449,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$events
|
||||
|
@ -1613,17 +1492,7 @@ App::patch('/v1/account/sessions/:sessionId')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($sessionId, $request, $response, $user, $dbForProject, $project, $locale, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var boolean $force */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Audit $audits, Event $events, Stats $usage) {
|
||||
|
||||
$sessionId = ($sessionId === 'current')
|
||||
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
|
||||
|
@ -1633,7 +1502,6 @@ App::patch('/v1/account/sessions/:sessionId')
|
|||
|
||||
foreach ($sessions as $key => $session) {/** @var Document $session */
|
||||
if ($sessionId == $session->getId()) {
|
||||
|
||||
// Comment below would skip re-generation if token is still valid
|
||||
// We decided to not include this because developer can get expiration date from the session
|
||||
// I kept code in comment because it might become relevant in the future
|
||||
|
@ -1646,10 +1514,10 @@ App::patch('/v1/account/sessions/:sessionId')
|
|||
$provider = $session->getAttribute('provider');
|
||||
$refreshToken = $session->getAttribute('providerRefreshToken');
|
||||
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}';
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider);
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
|
||||
|
||||
if (!\class_exists($className)) {
|
||||
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
|
@ -1709,15 +1577,7 @@ App::delete('/v1/account/sessions')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($request, $response, $user, $dbForProject, $locale, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
@ -1733,7 +1593,7 @@ App::delete('/v1/account/sessions')
|
|||
|
||||
$session
|
||||
->setAttribute('current', false)
|
||||
->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||
->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||
;
|
||||
|
||||
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) {
|
||||
|
@ -1780,7 +1640,7 @@ App::post('/v1/account/recovery')
|
|||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', ['url:{url},email:{param-email}', 'ip:{ip}'])
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', function ($clients) {return new Host($clients);}, 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
|
||||
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -1790,18 +1650,9 @@ App::post('/v1/account/recovery')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($email, $url, $request, $response, $dbForProject, $project, $locale, $mails, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Mail $mails */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $email, string $url, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Audit $audits, Event $events, Stats $usage) {
|
||||
|
||||
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
|
@ -1839,9 +1690,8 @@ App::post('/v1/account/recovery')
|
|||
Authorization::setRole('user:' . $profile->getId());
|
||||
|
||||
$recovery = $dbForProject->createDocument('tokens', $recovery
|
||||
->setAttribute('$read', ['user:'.$profile->getId()])
|
||||
->setAttribute('$write', ['user:'.$profile->getId()])
|
||||
);
|
||||
->setAttribute('$read', ['user:' . $profile->getId()])
|
||||
->setAttribute('$write', ['user:' . $profile->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
|
||||
|
@ -1901,12 +1751,7 @@ App::put('/v1/account/recovery')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $secret, string $password, string $passwordAgain, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
if ($password !== $passwordAgain) {
|
||||
throw new Exception('Passwords must match', 400, Exception::USER_PASSWORD_MISMATCH);
|
||||
|
@ -1930,8 +1775,7 @@ App::put('/v1/account/recovery')
|
|||
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile
|
||||
->setAttribute('password', Auth::passwordHash($password))
|
||||
->setAttribute('passwordUpdate', \time())
|
||||
->setAttribute('emailVerification', true)
|
||||
);
|
||||
->setAttribute('emailVerification', true));
|
||||
|
||||
$recoveryDocument = $dbForProject->getDocument('tokens', $recovery);
|
||||
|
||||
|
@ -1968,7 +1812,7 @@ App::post('/v1/account/verification')
|
|||
->label('sdk.response.model', Response::MODEL_TOKEN)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
@ -1979,19 +1823,9 @@ App::post('/v1/account/verification')
|
|||
->inject('events')
|
||||
->inject('mails')
|
||||
->inject('usage')
|
||||
->action(function ($url, $request, $response, $project, $user, $dbForProject, $locale, $audits, $events, $mails, $usage) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Mail $mails */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails, Stats $usage) {
|
||||
|
||||
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
|
@ -2016,9 +1850,8 @@ App::post('/v1/account/verification')
|
|||
Authorization::setRole('user:' . $user->getId());
|
||||
|
||||
$verification = $dbForProject->createDocument('tokens', $verification
|
||||
->setAttribute('$read', ['user:'.$user->getId()])
|
||||
->setAttribute('$write', ['user:'.$user->getId()])
|
||||
);
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
|
@ -2076,13 +1909,7 @@ App::put('/v1/account/verification')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $secret, $response, $user, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ App::get('/v1/avatars/image')
|
|||
->setContentType('image/png')
|
||||
->addHeader('Expires', $date)
|
||||
->addHeader('X-Appwrite-Cache', 'miss')
|
||||
->send($data);;
|
||||
->send($data);
|
||||
|
||||
unset($image);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
@ -25,6 +26,7 @@ use Utopia\Database\Exception\Authorization as AuthorizationException;
|
|||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Exception\Limit as LimitException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Locale\Locale;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\IP;
|
||||
|
@ -38,17 +40,11 @@ use Appwrite\Event\Audit as EventAudit;
|
|||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Stats\Stats;
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* Create attribute of varying type
|
||||
*
|
||||
* @param string $collectionId
|
||||
* @param Utopia\Database\Document $attribute
|
||||
* @param Appwrite\Utopia\Response $response
|
||||
* @param Utopia\Database\Database $dbForProject
|
||||
* @param Appwrite\Event\Database $database
|
||||
* @param Appwrite\Event\Audit $audits
|
||||
* @param Appwrite\Stats\Stats $usage
|
||||
*
|
||||
* @return Document Newly created attribute document
|
||||
*/
|
||||
|
@ -58,11 +54,11 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
|
|||
$type = $attribute->getAttribute('type', '');
|
||||
$size = $attribute->getAttribute('size', 0);
|
||||
$required = $attribute->getAttribute('required', true);
|
||||
$signed = $attribute->getAttribute('signed', true); // integers are signed by default
|
||||
$signed = $attribute->getAttribute('signed', true); // integers are signed by default
|
||||
$array = $attribute->getAttribute('array', false);
|
||||
$format = $attribute->getAttribute('format', '');
|
||||
$formatOptions = $attribute->getAttribute('formatOptions', []);
|
||||
$filters = $attribute->getAttribute('filters', []); // filters are hidden from the endpoint
|
||||
$filters = $attribute->getAttribute('filters', []); // filters are hidden from the endpoint
|
||||
$default = $attribute->getAttribute('default');
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
@ -88,7 +84,7 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
|
|||
|
||||
try {
|
||||
$attribute = new Document([
|
||||
'$id' => $collectionId.'_'.$key,
|
||||
'$id' => $collectionId . '_' . $key,
|
||||
'key' => $key,
|
||||
'collectionId' => $collectionId,
|
||||
'type' => $type,
|
||||
|
@ -105,11 +101,9 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
|
|||
|
||||
$dbForProject->checkAttribute($collection, $attribute);
|
||||
$attribute = $dbForProject->createDocument('attributes', $attribute);
|
||||
}
|
||||
catch (DuplicateException $exception) {
|
||||
} catch (DuplicateException $exception) {
|
||||
throw new Exception('Attribute already exists', 409, Exception::ATTRIBUTE_ALREADY_EXISTS);
|
||||
}
|
||||
catch (LimitException $exception) {
|
||||
} catch (LimitException $exception) {
|
||||
throw new Exception('Attribute limit exceeded', 400, Exception::ATTRIBUTE_LIMIT_EXCEEDED);
|
||||
}
|
||||
|
||||
|
@ -131,14 +125,14 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collectionId)
|
||||
->setResource('collection/' . $collectionId)
|
||||
->setPayload($attribute->getArrayCopy())
|
||||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
|
||||
return $attribute;
|
||||
};
|
||||
}
|
||||
|
||||
App::post('/v1/database/collections')
|
||||
->desc('Create Collection')
|
||||
|
@ -162,12 +156,7 @@ App::post('/v1/database/collections')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $name, $permission, $read, $write, $response, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $name, ?string $permission, ?array $read, ?array $write, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$collectionId = $collectionId == 'unique()' ? $dbForProject->getId() : $collectionId;
|
||||
|
||||
|
@ -193,7 +182,7 @@ App::post('/v1/database/collections')
|
|||
}
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collectionId)
|
||||
->setResource('collection/' . $collectionId)
|
||||
->setPayload($collection->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -224,9 +213,7 @@ App::get('/v1/database/collections')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $search, int $limit, int $offset, string $cursor, string $cursorDirection, string $orderType, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
if (!empty($cursor)) {
|
||||
$cursorCollection = $dbForProject->getDocument('collections', $cursor);
|
||||
|
@ -265,9 +252,7 @@ App::get('/v1/database/collections/:collectionId')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $collectionId, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -293,11 +278,7 @@ App::get('/v1/database/usage')
|
|||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($range, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
|
@ -335,7 +316,7 @@ App::get('/v1/database/usage')
|
|||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$limit = $periods[$range]['limit'];
|
||||
$period = $periods[$range]['period'];
|
||||
|
@ -357,7 +338,7 @@ App::get('/v1/database/usage')
|
|||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
@ -404,10 +385,7 @@ App::get('/v1/database/:collectionId/usage')
|
|||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($range, $collectionId, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
->action(function (string $range, string $collectionId, Response $response, Database $dbForProject) {
|
||||
|
||||
$collectionDocument = $dbForProject->getDocument('collections', $collectionId);
|
||||
$collection = $dbForProject->getCollection('collection_' . $collectionDocument->getInternalId());
|
||||
|
@ -417,7 +395,7 @@ App::get('/v1/database/:collectionId/usage')
|
|||
}
|
||||
|
||||
$usage = [];
|
||||
if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$periods = [
|
||||
'24h' => [
|
||||
'period' => '30m',
|
||||
|
@ -447,7 +425,7 @@ App::get('/v1/database/:collectionId/usage')
|
|||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$limit = $periods[$range]['limit'];
|
||||
$period = $periods[$range]['period'];
|
||||
|
@ -469,7 +447,7 @@ App::get('/v1/database/:collectionId/usage')
|
|||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
@ -514,12 +492,7 @@ App::get('/v1/database/collections/:collectionId/logs')
|
|||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function ($collectionId, $limit, $offset, $response, $dbForProject, $locale, $geodb) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
->action(function (string $collectionId, int $limit, int $offset, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$collectionDocument = $dbForProject->getDocument('collections', $collectionId);
|
||||
$collection = $dbForProject->getCollection('collection_' . $collectionDocument->getInternalId());
|
||||
|
@ -529,7 +502,7 @@ App::get('/v1/database/collections/:collectionId/logs')
|
|||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'collection/'.$collectionId;
|
||||
$resource = 'collection/' . $collectionId;
|
||||
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||
|
||||
$output = [];
|
||||
|
@ -569,8 +542,8 @@ App::get('/v1/database/collections/:collectionId/logs')
|
|||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
|
@ -606,12 +579,7 @@ App::put('/v1/database/collections/:collectionId')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $name, $permission, $read, $write, $enabled, $response, $dbForProject, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -631,18 +599,15 @@ App::put('/v1/database/collections/:collectionId')
|
|||
->setAttribute('permission', $permission)
|
||||
->setAttribute('dateUpdated', time())
|
||||
->setAttribute('enabled', $enabled)
|
||||
->setAttribute('search', implode(' ', [$collectionId, $name]))
|
||||
);
|
||||
}
|
||||
catch (AuthorizationException $exception) {
|
||||
->setAttribute('search', implode(' ', [$collectionId, $name])));
|
||||
} catch (AuthorizationException $exception) {
|
||||
throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
catch (StructureException $exception) {
|
||||
throw new Exception('Bad structure. '.$exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception('Bad structure. ' . $exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collectionId)
|
||||
->setResource('collection/' . $collectionId)
|
||||
->setPayload($collection->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -670,13 +635,7 @@ App::delete('/v1/database/collections/:collectionId')
|
|||
->inject('audits')
|
||||
->inject('deletes')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $response, $dbForProject, $events, $audits, $deletes, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $collectionId, Response $response, Database $dbForProject, Event $events, EventAudit $audits, Delete $deletes, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -701,7 +660,7 @@ App::delete('/v1/database/collections/:collectionId')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collectionId)
|
||||
->setResource('collection/' . $collectionId)
|
||||
->setPayload($collection->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -734,13 +693,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $size, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
// Ensure attribute default is within required size
|
||||
$validator = new Text($size);
|
||||
|
@ -783,12 +736,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $audits, Stats $usage, Event $events) {
|
||||
|
||||
$attribute = createAttribute($collectionId, new Document([
|
||||
'key' => $key,
|
||||
|
@ -827,13 +775,7 @@ App::post('/v1/database/collections/:collectionId/attributes/enum')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $elements, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
// use length of longest string as attribute size
|
||||
$size = 0;
|
||||
|
@ -841,7 +783,6 @@ App::post('/v1/database/collections/:collectionId/attributes/enum')
|
|||
$length = \strlen($element);
|
||||
if ($length === 0) {
|
||||
throw new Exception('Each enum element must not be empty', 400, Exception::ATTRIBUTE_VALUE_INVALID);
|
||||
|
||||
}
|
||||
$size = ($length > $size) ? $length : $size;
|
||||
}
|
||||
|
@ -887,12 +828,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$attribute = createAttribute($collectionId, new Document([
|
||||
'key' => $key,
|
||||
|
@ -930,12 +866,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$attribute = createAttribute($collectionId, new Document([
|
||||
'key' => $key,
|
||||
|
@ -975,13 +906,7 @@ App::post('/v1/database/collections/:collectionId/attributes/integer')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
// Ensure attribute default is within range
|
||||
$min = (is_null($min)) ? PHP_INT_MIN : \intval($min);
|
||||
|
@ -1048,13 +973,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage) {
|
||||
|
||||
// Ensure attribute default is within range
|
||||
$min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min);
|
||||
|
@ -1122,13 +1041,7 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject*/
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$attribute = createAttribute($collectionId, new Document([
|
||||
'key' => $key,
|
||||
|
@ -1157,9 +1070,7 @@ App::get('/v1/database/collections/:collectionId/attributes')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $collectionId, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1201,9 +1112,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:key')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $key, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $collectionId, string $key, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1211,7 +1120,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:key')
|
|||
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$attribute = $dbForProject->getDocument('attributes', $collectionId.'_'.$key);
|
||||
$attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key);
|
||||
|
||||
if ($attribute->isEmpty()) {
|
||||
throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND);
|
||||
|
@ -1221,11 +1130,11 @@ App::get('/v1/database/collections/:collectionId/attributes/:key')
|
|||
$type = $attribute->getAttribute('type');
|
||||
$format = $attribute->getAttribute('format');
|
||||
|
||||
$model = match($type) {
|
||||
$model = match ($type) {
|
||||
Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN,
|
||||
Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER,
|
||||
Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT,
|
||||
Database::VAR_STRING => match($format) {
|
||||
Database::VAR_STRING => match ($format) {
|
||||
APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL,
|
||||
APP_DATABASE_ATTRIBUTE_ENUM => Response::MODEL_ATTRIBUTE_ENUM,
|
||||
APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP,
|
||||
|
@ -1259,13 +1168,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
|
|||
->inject('events')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $key, $response, $dbForProject, $database, $events, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, EventAudit $audits, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1273,7 +1176,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
|
|||
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$attribute = $dbForProject->getDocument('attributes', $collectionId.'_'.$key);
|
||||
$attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key);
|
||||
|
||||
if ($attribute->isEmpty()) {
|
||||
throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND);
|
||||
|
@ -1299,11 +1202,11 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
|
|||
$type = $attribute->getAttribute('type');
|
||||
$format = $attribute->getAttribute('format');
|
||||
|
||||
$model = match($type) {
|
||||
$model = match ($type) {
|
||||
Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN,
|
||||
Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER,
|
||||
Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT,
|
||||
Database::VAR_STRING => match($format) {
|
||||
Database::VAR_STRING => match ($format) {
|
||||
APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL,
|
||||
APP_DATABASE_ATTRIBUTE_ENUM => Response::MODEL_ATTRIBUTE_ENUM,
|
||||
APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP,
|
||||
|
@ -1321,7 +1224,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collectionId)
|
||||
->setResource('collection/' . $collectionId)
|
||||
->setPayload($attribute->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -1351,13 +1254,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
|
|||
->inject('audits')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($collectionId, $key, $type, $attributes, $orders, $response, $dbForProject, $database, $audits, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1395,7 +1292,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
|
|||
|
||||
// ensure attribute is available
|
||||
if ($attributeStatus !== 'available') {
|
||||
throw new Exception ('Attribute not available: ' . $oldAttributes[$attributeIndex]['key'], 400, Exception::ATTRIBUTE_NOT_AVAILABLE);
|
||||
throw new Exception('Attribute not available: ' . $oldAttributes[$attributeIndex]['key'], 400, Exception::ATTRIBUTE_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
// set attribute size as index length only for strings
|
||||
|
@ -1404,7 +1301,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
|
|||
|
||||
try {
|
||||
$index = $dbForProject->createDocument('indexes', new Document([
|
||||
'$id' => $collectionId.'_'.$key,
|
||||
'$id' => $collectionId . '_' . $key,
|
||||
'key' => $key,
|
||||
'status' => 'processing', // processing, available, failed, deleting, stuck
|
||||
'collectionId' => $collectionId,
|
||||
|
@ -1434,7 +1331,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collection->getId())
|
||||
->setResource('collection/' . $collection->getId())
|
||||
->setPayload($index->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -1457,9 +1354,7 @@ App::get('/v1/database/collections/:collectionId/indexes')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $collectionId, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1493,9 +1388,7 @@ App::get('/v1/database/collections/:collectionId/indexes/:key')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $key, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $collectionId, string $key, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1540,13 +1433,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
|
|||
->inject('events')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->action(function ($collectionId, $key, $response, $dbForProject, $database, $events, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, EventAudit $audits, Stats $usage) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1554,7 +1441,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
|
|||
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$index = $dbForProject->getDocument('indexes', $collectionId.'_'.$key);
|
||||
$index = $dbForProject->getDocument('indexes', $collectionId . '_' . $key);
|
||||
|
||||
if (empty($index->getId())) {
|
||||
throw new Exception('Index not found', 404, Exception::INDEX_NOT_FOUND);
|
||||
|
@ -1583,7 +1470,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('collection/'.$collection->getId())
|
||||
->setResource('collection/' . $collection->getId())
|
||||
->setPayload($index->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -1614,14 +1501,7 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
->inject('usage')
|
||||
->inject('events')
|
||||
->inject('mode')
|
||||
->action(function ($documentId, $collectionId, $data, $read, $write, $response, $dbForProject, $user, $audits, $usage, $events, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var string $mode */
|
||||
->action(function (string $documentId, string $collectionId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, EventAudit $audits, Stats $usage, Event $events, string $mode) {
|
||||
|
||||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
|
||||
|
@ -1635,7 +1515,7 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
|
||||
/**
|
||||
* Skip Authorization to get the collection. Needed in case of empty permissions for document level permissions.
|
||||
*
|
||||
*
|
||||
* @var Document $collection
|
||||
*/
|
||||
$collection = Authorization::skip(fn() => $dbForProject->getDocument('collections', $collectionId));
|
||||
|
@ -1656,8 +1536,8 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
|
||||
$data['$collection'] = $collection->getId(); // Adding this param to make API easier for developers
|
||||
$data['$id'] = $documentId == 'unique()' ? $dbForProject->getId() : $documentId;
|
||||
$data['$read'] = (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? []; // By default set read permissions for user
|
||||
$data['$write'] = (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? []; // By default set write permissions for user
|
||||
$data['$read'] = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user
|
||||
$data['$write'] = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? []; // By default set write permissions for user
|
||||
|
||||
// Users can only add their roles to documents, API keys and Admin users can add any
|
||||
$roles = Authorization::getRoles();
|
||||
|
@ -1665,13 +1545,13 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
foreach ($data['$read'] as $read) {
|
||||
if (!Authorization::isRole($read)) {
|
||||
// TODO: Isn't this a 401: Unauthorized Error ?
|
||||
throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED);
|
||||
// TODO: Isn't this a 401: Unauthorized Error ?
|
||||
throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
foreach ($data['$write'] as $write) {
|
||||
if (!Authorization::isRole($write)) {
|
||||
throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED);
|
||||
throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1684,11 +1564,9 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
$document = $dbForProject->createDocument('collection_' . $collection->getInternalId(), new Document($data));
|
||||
}
|
||||
$document->setAttribute('$collection', $collectionId);
|
||||
}
|
||||
catch (StructureException $exception) {
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
catch (DuplicateException $exception) {
|
||||
} catch (DuplicateException $exception) {
|
||||
throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1582,7 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('document/'.$document->getId())
|
||||
->setResource('document/' . $document->getId())
|
||||
->setPayload($document->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -1724,7 +1602,7 @@ App::get('/v1/database/collections/:collectionId/documents')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST)
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).')
|
||||
->param('queries', [], new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/database#querying-documents). Maximum of 100 queries are allowed, each 128 characters long.', true)
|
||||
->param('queries', [], new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/database#querying-documents). Maximum of 100 queries are allowed, each 128 characters long.', true)
|
||||
->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. By default will return maximum 25 results. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' results allowed per request.', true)
|
||||
->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
|
||||
->param('cursor', '', new UID(), 'ID of the document used as the starting point for the query, excluding the document itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
|
||||
|
@ -1735,11 +1613,7 @@ App::get('/v1/database/collections/:collectionId/documents')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($collectionId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderAttributes, $orderTypes, $response, $dbForProject, $usage, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var string $mode */
|
||||
->action(function (string $collectionId, array $queries, int $limit, int $offset, string $cursor, string $cursorDirection, array $orderAttributes, array $orderTypes, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
|
||||
/**
|
||||
* Skip Authorization to get the collection. Needed in case of empty permissions for document level permissions.
|
||||
|
@ -1772,13 +1646,13 @@ App::get('/v1/database/collections/:collectionId/documents')
|
|||
return $query;
|
||||
}, $queries);
|
||||
|
||||
if(!empty($orderAttributes)) {
|
||||
if (!empty($orderAttributes)) {
|
||||
$validator = new OrderAttributes($collection->getAttribute('attributes', []), $collection->getAttribute('indexes', []), true);
|
||||
if (!$validator->isValid($orderAttributes)) {
|
||||
throw new Exception($validator->getDescription(), 400, Exception::GENERAL_QUERY_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!empty($queries)) {
|
||||
$validator = new QueriesValidator(new QueryValidator($collection->getAttribute('attributes', [])), $collection->getAttribute('indexes', []), true);
|
||||
if (!$validator->isValid($queries)) {
|
||||
|
@ -1839,10 +1713,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($collectionId, $documentId, $response, $dbForProject, $usage, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var string $mode */
|
||||
->action(function (string $collectionId, string $documentId, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
|
||||
/**
|
||||
* Skip Authorization to get the collection. Needed in case of empty permissions for document level permissions.
|
||||
|
@ -1906,12 +1777,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
|
|||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function ($collectionId, $documentId, $limit, $offset, $response, $dbForProject, $locale, $geodb) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
->action(function (string $collectionId, string $documentId, int $limit, int $offset, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$collection = $dbForProject->getDocument('collections', $collectionId);
|
||||
|
||||
|
@ -1926,7 +1792,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
|
|||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'document/'.$document->getId();
|
||||
$resource = 'document/' . $document->getId();
|
||||
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||
|
||||
$output = [];
|
||||
|
@ -1966,8 +1832,8 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
|
|||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
|
@ -2002,13 +1868,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
->inject('usage')
|
||||
->inject('events')
|
||||
->inject('mode')
|
||||
->action(function ($collectionId, $documentId, $data, $read, $write, $response, $dbForProject, $audits, $usage, $events, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var string $mode */
|
||||
->action(function (string $collectionId, string $documentId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events, string $mode) {
|
||||
|
||||
/**
|
||||
* Skip Authorization to get the collection. Needed in case of empty permissions for document level permissions.
|
||||
|
@ -2059,14 +1919,14 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
$roles = Authorization::getRoles();
|
||||
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
if(!is_null($read)) {
|
||||
if (!is_null($read)) {
|
||||
foreach ($data['$read'] as $read) {
|
||||
if (!Authorization::isRole($read)) {
|
||||
throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED);
|
||||
throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!is_null($write)) {
|
||||
if (!is_null($write)) {
|
||||
foreach ($data['$write'] as $write) {
|
||||
if (!Authorization::isRole($write)) {
|
||||
throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
|
@ -2086,14 +1946,11 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
* Reset $collection attribute to remove prefix.
|
||||
*/
|
||||
$document->setAttribute('$collection', $collectionId);
|
||||
}
|
||||
catch (AuthorizationException $exception) {
|
||||
} catch (AuthorizationException $exception) {
|
||||
throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
catch (DuplicateException $exception) {
|
||||
} catch (DuplicateException $exception) {
|
||||
throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS);
|
||||
}
|
||||
catch (StructureException $exception) {
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
|
||||
|
@ -2109,7 +1966,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('document/'.$document->getId())
|
||||
->setResource('document/' . $document->getId())
|
||||
->setPayload($document->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -2136,14 +1993,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
->inject('deletes')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($collectionId, $documentId, $response, $dbForProject, $events, $audits, $deletes, $usage, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var string $mode */
|
||||
->action(function (string $collectionId, string $documentId, Response $response, Database $dbForProject, Event $events, EventAudit $audits, Delete $deletes, Stats $usage, string $mode) {
|
||||
|
||||
/**
|
||||
* Skip Authorization to get the collection. Needed in case of empty permissions for document level permissions.
|
||||
|
@ -2206,7 +2056,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
;
|
||||
|
||||
$audits
|
||||
->setResource('document/'.$document->getId())
|
||||
->setResource('document/' . $document->getId())
|
||||
->setPayload($document->getArrayCopy())
|
||||
;
|
||||
|
||||
|
|
|
@ -3,16 +3,21 @@
|
|||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Validator\Event as ValidatorEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Appwrite\Stats\Stats;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Swoole\Request;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Database;
|
||||
|
@ -55,10 +60,7 @@ App::post('/v1/functions')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $name, $execute, $runtime, $vars, $events, $schedule, $timeout, $response, $dbForProject, $eventsInstance) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $eventsInstance */
|
||||
->action(function (string $functionId, string $name, array $execute, string $runtime, array $vars, array $events, string $schedule, int $timeout, Response $response, Database $dbForProject, Event $eventsInstance) {
|
||||
|
||||
$functionId = ($functionId == 'unique()') ? $dbForProject->getId() : $functionId;
|
||||
$function = $dbForProject->createDocument('functions', new Document([
|
||||
|
@ -104,9 +106,7 @@ App::get('/v1/functions')
|
|||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $search, int $limit, int $offset, string $cursor, string $cursorDirection, string $orderType, Response $response, Database $dbForProject) {
|
||||
|
||||
if (!empty($cursor)) {
|
||||
$cursorFunction = $dbForProject->getDocument('functions', $cursor);
|
||||
|
@ -140,8 +140,7 @@ App::get('/v1/functions/runtimes')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_RUNTIME_LIST)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$runtimes = Config::getParam('runtimes');
|
||||
|
||||
|
@ -170,10 +169,7 @@ App::get('/v1/functions/:functionId')
|
|||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
|
@ -197,11 +193,7 @@ App::get('/v1/functions/:functionId/usage')
|
|||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d']), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $range, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
->action(function (string $functionId, string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -309,12 +301,7 @@ App::put('/v1/functions/:functionId')
|
|||
->inject('project')
|
||||
->inject('user')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $name, $execute, $vars, $events, $schedule, $timeout, $response, $dbForProject, $project, $user, $eventsInstance) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Event\Event $eventsInstance */
|
||||
->action(function (string $functionId, string $name, array $execute, array $vars, array $events, string $schedule, int $timeout, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -373,11 +360,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $deploymentId, $response, $dbForProject, $project, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
@ -440,11 +423,7 @@ App::delete('/v1/functions/:functionId')
|
|||
->inject('dbForProject')
|
||||
->inject('deletes')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $response, $dbForProject, $deletes, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -491,15 +470,7 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
->inject('project')
|
||||
->inject('deviceFunctions')
|
||||
->inject('deviceLocal')
|
||||
->action(function ($functionId, $entrypoint, $file, $activate, $request, $response, $dbForProject, $usage, $events, $project, $deviceFunctions, $deviceLocal) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Storage\Device $deviceFunctions */
|
||||
/** @var Utopia\Storage\Device $deviceLocal */
|
||||
->action(function (string $functionId, string $entrypoint, array $file, bool $activate, Request $request, Response $response, Database $dbForProject, Stats $usage, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -679,9 +650,7 @@ App::get('/v1/functions/:functionId/deployments')
|
|||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $functionId, string $search, int $limit, int $offset, string $cursor, string $cursorDirection, string $orderType, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -737,9 +706,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
->param('deploymentId', '', new UID(), 'Deployment ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $deploymentId, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
@ -779,13 +746,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
->inject('deletes')
|
||||
->inject('events')
|
||||
->inject('deviceFunctions')
|
||||
->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $deletes, $events, $deviceFunctions) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Utopia\Storage\Device $deviceFunctions */
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Stats $usage, Delete $deletes, Event $events, Device $deviceFunctions) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
|
@ -849,12 +810,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
->inject('dbForProject')
|
||||
->inject('user')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $data, $async, $response, $project, $dbForProject, $user, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
|
@ -916,7 +872,6 @@ App::post('/v1/functions/:functionId/executions')
|
|||
|
||||
$jwt = ''; // initialize
|
||||
if (!$user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = new Document();
|
||||
|
||||
|
@ -1031,9 +986,7 @@ App::get('/v1/functions/:functionId/executions')
|
|||
->param('cursorDirection', Database::CURSOR_AFTER, new WhiteList([Database::CURSOR_AFTER, Database::CURSOR_BEFORE]), 'Direction of the cursor.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $limit, $offset, $search, $cursor, $cursorDirection, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $functionId, int $limit, int $offset, string $search, string $cursor, string $cursorDirection, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
|
@ -1081,9 +1034,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
|||
->param('executionId', '', new UID(), 'Execution ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($functionId, $executionId, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
|
@ -1122,11 +1073,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
|||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function ($functionId, $deploymentId, $buildId, $response, $dbForProject, $project, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\App;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* 1. Map all objects, object-params, object-fields
|
||||
|
@ -13,6 +10,9 @@ use Utopia\App;
|
|||
* 6. Write tests!
|
||||
*/
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\App;
|
||||
|
||||
App::post('/v1/graphql')
|
||||
->desc('GraphQL Endpoint')
|
||||
->groups(['api', 'graphql'])
|
||||
|
|
|
@ -9,7 +9,7 @@ use Utopia\Database\Document;
|
|||
use Utopia\Registry\Registry;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::get('/v1/health')
|
||||
->desc('Get HTTP')
|
||||
|
@ -68,9 +68,9 @@ App::get('/v1/health/db')
|
|||
|
||||
// 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, Exception::GENERAL_SERVER_ERROR);
|
||||
|
@ -141,7 +141,7 @@ App::get('/v1/health/time')
|
|||
\socket_connect($sock, $host, 123);
|
||||
|
||||
/* Send request */
|
||||
$msg = "\010".\str_repeat("\0", 47);
|
||||
$msg = "\010" . \str_repeat("\0", 47);
|
||||
|
||||
\socket_send($sock, $msg, \strlen($msg), 0);
|
||||
|
||||
|
@ -256,20 +256,22 @@ App::get('/v1/health/storage/local')
|
|||
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
foreach ([
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
] as $key => $volume) {
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
if (!\is_readable($device->getRoot())) {
|
||||
throw new Exception('Device '.$key.' dir is not readable', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
throw new Exception('Device ' . $key . ' dir is not readable', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (!\is_writable($device->getRoot())) {
|
||||
throw new Exception('Device '.$key.' dir is not writable', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
throw new Exception('Device ' . $key . ' dir is not writable', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,13 +306,15 @@ App::get('/v1/health/anti-virus')
|
|||
$output['status'] = 'disabled';
|
||||
$output['version'] = '';
|
||||
} else {
|
||||
$antivirus = new Network(App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310));
|
||||
$antivirus = new Network(
|
||||
App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
try {
|
||||
$output['version'] = @$antivirus->version();
|
||||
$output['status'] = (@$antivirus->ping()) ? 'pass' : 'fail';
|
||||
} catch( \Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
throw new Exception('Antivirus is not available', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +342,7 @@ App::get('/v1/health/stats') // Currently only used internally
|
|||
$response
|
||||
->json([
|
||||
'storage' => [
|
||||
'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot().'/')),
|
||||
'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot() . '/')),
|
||||
'partitionTotal' => Storage::human($deviceFiles->getPartitionTotalSpace()),
|
||||
'partitionFree' => Storage::human($deviceFiles->getPartitionFreeSpace()),
|
||||
],
|
||||
|
|
|
@ -78,7 +78,7 @@ App::post('/v1/projects')
|
|||
}
|
||||
|
||||
$projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId;
|
||||
if($projectId === 'console') {
|
||||
if ($projectId === 'console') {
|
||||
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
|
||||
}
|
||||
$project = $dbForConsole->createDocument('projects', new Document([
|
||||
|
@ -107,7 +107,7 @@ App::post('/v1/projects')
|
|||
'search' => implode(' ', [$projectId, $name]),
|
||||
]));
|
||||
/** @var array $collections */
|
||||
$collections = Config::getParam('collections', []);
|
||||
$collections = Config::getParam('collections', []);
|
||||
|
||||
$dbForProject->setNamespace("_{$project->getId()}");
|
||||
$dbForProject->create('appwrite');
|
||||
|
@ -119,7 +119,7 @@ App::post('/v1/projects')
|
|||
$adapter->setup();
|
||||
|
||||
foreach ($collections as $key => $collection) {
|
||||
if(($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
$attributes = [];
|
||||
|
@ -282,7 +282,7 @@ App::get('/v1/projects/:projectId/usage')
|
|||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$limit = $periods[$range]['limit'];
|
||||
$period = $periods[$range]['period'];
|
||||
|
@ -304,7 +304,7 @@ App::get('/v1/projects/:projectId/usage')
|
|||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
@ -375,8 +375,7 @@ App::patch('/v1/projects/:projectId')
|
|||
->setAttribute('legalCity', $legalCity)
|
||||
->setAttribute('legalAddress', $legalAddress)
|
||||
->setAttribute('legalTaxId', $legalTaxId)
|
||||
->setAttribute('search', implode(' ', [$projectId, $name]))
|
||||
);
|
||||
->setAttribute('search', implode(' ', [$projectId, $name])));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
@ -392,7 +391,7 @@ App::patch('/v1/projects/:projectId/service')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), function ($element) {return $element['optional'];})), true), 'Service name.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
|
@ -471,8 +470,7 @@ App::patch('/v1/projects/:projectId/auth/limit')
|
|||
$auths['limit'] = $limit;
|
||||
|
||||
$dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('auths', $auths)
|
||||
);
|
||||
->setAttribute('auths', $auths));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
@ -752,7 +750,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
|||
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
|
||||
]);
|
||||
|
||||
if($webhook === false || $webhook->isEmpty()) {
|
||||
if ($webhook === false || $webhook->isEmpty()) {
|
||||
throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -946,7 +944,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
|||
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
|
||||
]);
|
||||
|
||||
if($key === false || $key->isEmpty()) {
|
||||
if ($key === false || $key->isEmpty()) {
|
||||
throw new Exception('Key not found', 404, Exception::KEY_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ use Utopia\Validator\Integer;
|
|||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\Swoole\Request;
|
||||
|
||||
App::post('/v1/storage/buckets')
|
||||
->desc('Create bucket')
|
||||
|
@ -262,8 +262,7 @@ App::put('/v1/storage/buckets/:bucketId')
|
|||
->setAttribute('enabled', (bool) filter_var($enabled, FILTER_VALIDATE_BOOLEAN))
|
||||
->setAttribute('encryption', (bool) filter_var($encryption, FILTER_VALIDATE_BOOLEAN))
|
||||
->setAttribute('permission', $permission)
|
||||
->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))
|
||||
);
|
||||
->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN)));
|
||||
|
||||
$audits
|
||||
->setResource('storage/buckets/' . $bucket->getId())
|
||||
|
@ -360,8 +359,10 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->action(function (string $bucketId, string $fileId, array $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -462,7 +463,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize??=$deviceLocal->getFileSize($fileTmpName);
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
|
||||
|
||||
|
@ -492,8 +493,10 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
$write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? [];
|
||||
if ($chunksUploaded === $chunks) {
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled' && $bucket->getAttribute('antivirus', true) && $fileSize <= APP_LIMIT_ANTIVIRUS && App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) === Storage::DEVICE_LOCAL) {
|
||||
$antivirus = new Network(App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310));
|
||||
$antivirus = new Network(
|
||||
App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
if (!$antivirus->fileScan($path)) {
|
||||
$deviceFiles->delete($path);
|
||||
|
@ -587,7 +590,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
} else {
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
|
@ -604,7 +606,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->setParam('storage.files.create', 1)
|
||||
->setParam('bucketId', $bucketId)
|
||||
;
|
||||
|
||||
} else {
|
||||
try {
|
||||
if ($file->isEmpty()) {
|
||||
|
@ -689,8 +690,10 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -765,8 +768,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -837,8 +842,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -879,7 +886,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
$mime = $file->getAttribute('mimeType');
|
||||
|
||||
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
|
||||
if(!\in_array($mime, $inputs)) {
|
||||
if (!\in_array($mime, $inputs)) {
|
||||
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
|
||||
} else {
|
||||
// it was an image but the file size exceeded the limit
|
||||
|
@ -904,7 +911,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId() . DIRECTORY_SEPARATOR . $bucketId . DIRECTORY_SEPARATOR . $fileId)); // Limit file number or size
|
||||
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3/* 3 months */);
|
||||
|
||||
if(empty($output)) {
|
||||
if (empty($output)) {
|
||||
// when file extension is not provided and the mime type is not one of our supported outputs
|
||||
// we fallback to `jpg` output format
|
||||
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
|
||||
|
@ -1003,8 +1010,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -1140,8 +1149,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -1311,8 +1322,10 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
}
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -1386,8 +1399,10 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)
|
||||
) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -1527,10 +1542,10 @@ App::get('/v1/storage/usage')
|
|||
}
|
||||
|
||||
// backfill metrics with empty values for graphs
|
||||
$backfill = $limit-\count($requestDocs);
|
||||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
@ -1636,10 +1651,10 @@ App::get('/v1/storage/:bucketId/usage')
|
|||
}
|
||||
|
||||
// backfill metrics with empty values for graphs
|
||||
$backfill = $limit-\count($requestDocs);
|
||||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
|
|
@ -59,8 +59,8 @@ App::post('/v1/teams')
|
|||
$teamId = $teamId == 'unique()' ? $dbForProject->getId() : $teamId;
|
||||
$team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([
|
||||
'$id' => $teamId ,
|
||||
'$read' => ['team:'.$teamId],
|
||||
'$write' => ['team:'.$teamId .'/owner'],
|
||||
'$read' => ['team:' . $teamId],
|
||||
'$write' => ['team:' . $teamId . '/owner'],
|
||||
'name' => $name,
|
||||
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
|
||||
'dateCreated' => \time(),
|
||||
|
@ -71,8 +71,8 @@ App::post('/v1/teams')
|
|||
$membershipId = $dbForProject->getId();
|
||||
$membership = new Document([
|
||||
'$id' => $membershipId,
|
||||
'$read' => ['user:'.$user->getId(), 'team:'.$team->getId()],
|
||||
'$write' => ['user:'.$user->getId(), 'team:'.$team->getId().'/owner'],
|
||||
'$read' => ['user:' . $user->getId(), 'team:' . $team->getId()],
|
||||
'$write' => ['user:' . $user->getId(), 'team:' . $team->getId() . '/owner'],
|
||||
'userId' => $user->getId(),
|
||||
'teamId' => $team->getId(),
|
||||
'roles' => $roles,
|
||||
|
@ -95,7 +95,7 @@ App::post('/v1/teams')
|
|||
|
||||
$audits
|
||||
->setParam('event', 'teams.create')
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
->setParam('resource', 'team/' . $teamId)
|
||||
->setParam('data', $team->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -198,10 +198,9 @@ App::put('/v1/teams/:teamId')
|
|||
throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND);
|
||||
}
|
||||
|
||||
$team = $dbForProject->updateDocument('teams', $team->getId(),$team
|
||||
$team = $dbForProject->updateDocument('teams', $team->getId(), $team
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('search', implode(' ', [$teamId, $name]))
|
||||
);
|
||||
->setAttribute('search', implode(' ', [$teamId, $name])));
|
||||
|
||||
$events->setParam('teamId', $team->getId());
|
||||
$audits->setResource('team/' . $team->getId());
|
||||
|
@ -260,7 +259,7 @@ App::delete('/v1/teams/:teamId')
|
|||
|
||||
$audits
|
||||
->setParam('event', 'teams.delete')
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
->setParam('resource', 'team/' . $teamId)
|
||||
->setParam('data', $team->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -284,7 +283,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('email', '', new Email(), 'Email of the new team member.')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
@ -296,7 +295,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->inject('events')
|
||||
->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, EventAudit $audits, Mail $mails, Event $events) {
|
||||
|
||||
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
|
@ -314,13 +313,12 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$invitee = $dbForProject->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
|
||||
|
||||
if (empty($invitee)) { // Create new user if no user with same email found
|
||||
|
||||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0 && $project->getId() !== 'console') { // check users limit, console invites are allways allowed.
|
||||
$total = $dbForProject->count('users', [], APP_LIMIT_USERS);
|
||||
|
||||
if($total >= $limit) {
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
}
|
||||
}
|
||||
|
@ -329,16 +327,16 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$userId = $dbForProject->getId();
|
||||
$invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
'$read' => ['user:'.$userId, 'role:all'],
|
||||
'$write' => ['user:'.$userId],
|
||||
'$read' => ['user:' . $userId, 'role:all'],
|
||||
'$write' => ['user:' . $userId],
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
'status' => true,
|
||||
'password' => Auth::passwordHash(Auth::passwordGenerator()),
|
||||
/**
|
||||
* Set the password update time to 0 for users created using
|
||||
* team invite and OAuth to allow password updates without an
|
||||
* old password
|
||||
/**
|
||||
* Set the password update time to 0 for users created using
|
||||
* team invite and OAuth to allow password updates without an
|
||||
* old password
|
||||
*/
|
||||
'passwordUpdate' => 0,
|
||||
'registration' => \time(),
|
||||
|
@ -355,7 +353,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
}
|
||||
}
|
||||
|
||||
$isOwner = Authorization::isRole('team:'.$team->getId().'/owner');;
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception('User is not allowed to send invitations for this team', 401, Exception::USER_UNAUTHORIZED);
|
||||
|
@ -367,7 +365,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$membership = new Document([
|
||||
'$id' => $membershipId,
|
||||
'$read' => ['role:all'],
|
||||
'$write' => ['user:'.$invitee->getId(), 'team:'.$team->getId().'/owner'],
|
||||
'$write' => ['user:' . $invitee->getId(), 'team:' . $team->getId() . '/owner'],
|
||||
'userId' => $invitee->getId(),
|
||||
'teamId' => $team->getId(),
|
||||
'roles' => $roles,
|
||||
|
@ -414,7 +412,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
}
|
||||
|
||||
$audits
|
||||
->setResource('team/'.$teamId)
|
||||
->setResource('team/' . $teamId)
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -423,11 +421,13 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($membership
|
||||
$response->dynamic(
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
, Response::MODEL_MEMBERSHIP);
|
||||
->setAttribute('userEmail', $user->getAttribute('email')),
|
||||
Response::MODEL_MEMBERSHIP
|
||||
);
|
||||
});
|
||||
|
||||
App::get('/v1/teams/:teamId/memberships')
|
||||
|
@ -490,7 +490,7 @@ App::get('/v1/teams/:teamId/memberships')
|
|||
|
||||
$memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId')));
|
||||
|
||||
$memberships = array_map(function($membership) use ($dbForProject, $team) {
|
||||
$memberships = array_map(function ($membership) use ($dbForProject, $team) {
|
||||
$user = $dbForProject->getDocument('users', $membership->getAttribute('userId'));
|
||||
|
||||
$membership
|
||||
|
@ -533,7 +533,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
|||
|
||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||
|
||||
if($membership->isEmpty() || empty($membership->getAttribute('userId'))) {
|
||||
if ($membership->isEmpty() || empty($membership->getAttribute('userId'))) {
|
||||
throw new Exception('Membership not found', 404, Exception::MEMBERSHIP_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -545,7 +545,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
|||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
;
|
||||
|
||||
$response->dynamic($membership, Response::MODEL_MEMBERSHIP );
|
||||
$response->dynamic($membership, Response::MODEL_MEMBERSHIP);
|
||||
});
|
||||
|
||||
App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
@ -588,7 +588,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
|||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');;
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception('User is not allowed to modify roles', 401, Exception::USER_UNAUTHORIZED);
|
||||
|
@ -667,7 +667,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
}
|
||||
|
||||
if ($userId !== $membership->getAttribute('userId')) {
|
||||
throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401, Exception::TEAM_INVITE_MISMATCH);
|
||||
throw new Exception('Invite does not belong to current user (' . $user->getAttribute('email') . ')', 401, Exception::TEAM_INVITE_MISMATCH);
|
||||
}
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
|
@ -675,7 +675,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
}
|
||||
|
||||
if ($membership->getAttribute('userId') !== $user->getId()) {
|
||||
throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401, Exception::TEAM_INVITE_MISMATCH);
|
||||
throw new Exception('Invite does not belong to current user (' . $user->getAttribute('email') . ')', 401, Exception::TEAM_INVITE_MISMATCH);
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('confirm') === true) {
|
||||
|
@ -693,7 +693,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
|
||||
// Log user in
|
||||
|
||||
Authorization::setRole('user:'.$user->getId());
|
||||
Authorization::setRole('user:' . $user->getId());
|
||||
|
||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||
$record = $geodb->get($request->getIP());
|
||||
|
@ -712,13 +712,12 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
], $detector->getOS(), $detector->getClient(), $detector->getDevice()));
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:'.$user->getId()])
|
||||
->setAttribute('$write', ['user:'.$user->getId()])
|
||||
);
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
Authorization::setRole('user:'.$userId);
|
||||
Authorization::setRole('user:' . $userId);
|
||||
|
||||
$membership = $dbForProject->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
|
@ -726,7 +725,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
|
||||
$audits->setResource('team/'.$teamId);
|
||||
$audits->setResource('team/' . $teamId);
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
|
@ -740,15 +739,17 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
}
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
|
||||
$response->dynamic($membership
|
||||
$response->dynamic(
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
, Response::MODEL_MEMBERSHIP);
|
||||
->setAttribute('userEmail', $user->getAttribute('email')),
|
||||
Response::MODEL_MEMBERSHIP
|
||||
);
|
||||
});
|
||||
|
||||
App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
@ -807,7 +808,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
|||
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
}
|
||||
|
||||
$audits->setResource('team/'.$teamId);
|
||||
$audits->setResource('team/' . $teamId);
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
|
@ -850,7 +851,7 @@ App::get('/v1/teams/:teamId/logs')
|
|||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'team/'.$team->getId();
|
||||
$resource = 'team/' . $team->getId();
|
||||
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||
|
||||
$output = [];
|
||||
|
@ -890,8 +891,8 @@ App::get('/v1/teams/:teamId/logs')
|
|||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
|
|
|
@ -3,12 +3,17 @@
|
|||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Audit as EventAudit;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Stats\Stats;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Locale\Locale;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
|
@ -21,6 +26,7 @@ use Utopia\Validator\WhiteList;
|
|||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Boolean;
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
App::post('/v1/users')
|
||||
->desc('Create User')
|
||||
|
@ -42,11 +48,7 @@ App::post('/v1/users')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $email, $password, $name, $response, $dbForProject, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Stats $usage, Event $events) {
|
||||
|
||||
$email = \strtolower($email);
|
||||
|
||||
|
@ -55,7 +57,7 @@ App::post('/v1/users')
|
|||
$user = $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
'$read' => ['role:all'],
|
||||
'$write' => ['user:'.$userId],
|
||||
'$write' => ['user:' . $userId],
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
'status' => true,
|
||||
|
@ -106,10 +108,7 @@ App::get('/v1/users')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $search, int $limit, int $offset, string $cursor, string $cursorDirection, string $orderType, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
if (!empty($cursor)) {
|
||||
$cursorUser = $dbForProject->getDocument('users', $cursor);
|
||||
|
@ -150,10 +149,7 @@ App::get('/v1/users/:userId')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -182,10 +178,7 @@ App::get('/v1/users/:userId/prefs')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForProject, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -217,11 +210,7 @@ App::get('/v1/users/:userId/sessions')
|
|||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForProject, $locale, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -231,10 +220,10 @@ App::get('/v1/users/:userId/sessions')
|
|||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
||||
foreach ($sessions as $key => $session) {
|
||||
foreach ($sessions as $key => $session) {
|
||||
/** @var Document $session */
|
||||
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$session->setAttribute('countryName', $countryName);
|
||||
$session->setAttribute('current', false);
|
||||
|
||||
|
@ -264,10 +253,7 @@ App::get('/v1/users/:userId/memberships')
|
|||
->param('userId', '', new UID(), 'User ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($userId, $response, $dbForProject) {
|
||||
/** @var string $userId */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -275,7 +261,7 @@ App::get('/v1/users/:userId/memberships')
|
|||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$memberships = array_map(function($membership) use ($dbForProject, $user) {
|
||||
$memberships = array_map(function ($membership) use ($dbForProject, $user) {
|
||||
$team = $dbForProject->getDocument('teams', $membership->getAttribute('teamId'));
|
||||
|
||||
$membership
|
||||
|
@ -311,13 +297,7 @@ App::get('/v1/users/:userId/logs')
|
|||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $limit, $offset, $response, $dbForProject, $locale, $geodb, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, int $limit, int $offset, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -362,8 +342,8 @@ App::get('/v1/users/:userId/logs')
|
|||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
|
@ -398,11 +378,7 @@ App::patch('/v1/users/:userId/status')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $status, $response, $dbForProject, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Stats $usage, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -441,11 +417,7 @@ App::patch('/v1/users/:userId/verification')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $emailVerification, $response, $dbForProject, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Stats $usage, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -484,11 +456,7 @@ App::patch('/v1/users/:userId/name')
|
|||
->inject('dbForProject')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($userId, $name, $response, $dbForProject, $audits, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $name, Response $response, Database $dbForProject, EventAudit $audits, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -504,7 +472,7 @@ App::patch('/v1/users/:userId/name')
|
|||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -532,11 +500,7 @@ App::patch('/v1/users/:userId/password')
|
|||
->inject('dbForProject')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($userId, $password, $response, $dbForProject, $audits, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $password, Response $response, Database $dbForProject, EventAudit $audits, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -551,7 +515,7 @@ App::patch('/v1/users/:userId/password')
|
|||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -579,11 +543,7 @@ App::patch('/v1/users/:userId/email')
|
|||
->inject('dbForProject')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($userId, $email, $response, $dbForProject, $audits, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, string $email, Response $response, Database $dbForProject, EventAudit $audits, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -605,13 +565,13 @@ App::patch('/v1/users/:userId/email')
|
|||
|
||||
try {
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
} catch(Duplicate $th) {
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
|
||||
$audits
|
||||
->setResource('user/'.$user->getId())
|
||||
->setResource('user/' . $user->getId())
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -639,11 +599,7 @@ App::patch('/v1/users/:userId/prefs')
|
|||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('events')
|
||||
->action(function ($userId, $prefs, $response, $dbForProject, $usage, $events) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Stats $usage, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -681,11 +637,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $sessionId, $response, $dbForProject, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -695,7 +647,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
|
||||
$session = $dbForProject->getDocument('sessions', $sessionId);
|
||||
|
||||
if($session->isEmpty()) {
|
||||
if ($session->isEmpty()) {
|
||||
throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -732,11 +684,7 @@ App::delete('/v1/users/:userId/sessions')
|
|||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForProject, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -777,18 +725,13 @@ App::delete('/v1/users/:userId')
|
|||
->label('sdk.description', '/docs/references/users/delete.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('userId', '', function () {return new UID();}, 'User ID.')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForProject, $events, $deletes, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes, Stats $usage) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
|
@ -829,13 +772,11 @@ App::get('/v1/users/usage')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_USERS)
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn($value) => "oauth-".$value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true)
|
||||
->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn($value) => "oauth-" . $value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('register')
|
||||
->action(function ($range, $provider, $response, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
->action(function (string $range, string $provider, Response $response, Database $dbForProject) {
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
|
@ -871,7 +812,7 @@ App::get('/v1/users/usage')
|
|||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$limit = $periods[$range]['limit'];
|
||||
$period = $periods[$range]['period'];
|
||||
|
@ -880,7 +821,7 @@ App::get('/v1/users/usage')
|
|||
new Query('period', Query::TYPE_EQUAL, [$period]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $limit, 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
|
@ -892,9 +833,8 @@ App::get('/v1/users/usage')
|
|||
// backfill metrics with empty values for graphs
|
||||
$backfill = $limit - \count($requestDocs);
|
||||
while ($backfill > 0) {
|
||||
|
||||
$last = $limit - $backfill - 1; // array index of last added metric
|
||||
$diff = match($period) { // convert period to seconds for unix timestamp math
|
||||
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
||||
'30m' => 1800,
|
||||
'1d' => 86400,
|
||||
};
|
||||
|
@ -905,7 +845,7 @@ App::get('/v1/users/usage')
|
|||
$backfill--;
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$usage = new Document([
|
||||
|
@ -919,8 +859,7 @@ App::get('/v1/users/usage')
|
|||
'sessionsProviderCreate' => $stats["users.sessions.$provider.create"],
|
||||
'sessionsDelete' => $stats["users.sessions.delete"]
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_USERS);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\View;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Auth\Auth;
|
||||
|
@ -18,6 +20,7 @@ use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
|||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||
use Appwrite\Utopia\Response\Filters\V13 as ResponseV13;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
@ -31,34 +34,24 @@ Config::setParam('domainVerification', false);
|
|||
Config::setParam('cookieDomain', 'localhost');
|
||||
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
||||
|
||||
App::init(function ($utopia, $request, $response, $console, $project, $dbForConsole, $user, $locale, $clients) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var array $clients */
|
||||
App::init(function (App $utopia, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $clients) {
|
||||
|
||||
/*
|
||||
* Request format
|
||||
*/
|
||||
|
||||
$route = $utopia->match($request);
|
||||
Request::setRoute($route);
|
||||
|
||||
$requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
if ($requestFormat) {
|
||||
switch($requestFormat) {
|
||||
case version_compare ($requestFormat , '0.12.0', '<') :
|
||||
switch ($requestFormat) {
|
||||
case version_compare($requestFormat, '0.12.0', '<'):
|
||||
Request::setFilter(new RequestV12());
|
||||
break;
|
||||
case version_compare ($requestFormat , '0.13.0', '<') :
|
||||
case version_compare($requestFormat, '0.13.0', '<'):
|
||||
Request::setFilter(new RequestV13());
|
||||
break;
|
||||
case version_compare ($requestFormat , '0.14.0', '<') :
|
||||
case version_compare($requestFormat, '0.14.0', '<'):
|
||||
Request::setFilter(new RequestV14());
|
||||
break;
|
||||
default:
|
||||
|
@ -76,21 +69,21 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||
$domains[$domain->get()] = false;
|
||||
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
} elseif(str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||
} else {
|
||||
Authorization::disable();
|
||||
|
||||
$envDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
$mainDomain = null;
|
||||
if(!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
$mainDomain = $envDomain;
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [], 0, ['_id'], ['ASC']);
|
||||
$mainDomain = $domainDocument ? $domainDocument->getAttribute('domain') : $domain->get();
|
||||
}
|
||||
|
||||
if($mainDomain !== $domain->get()) {
|
||||
if ($mainDomain !== $domain->get()) {
|
||||
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [
|
||||
|
@ -128,11 +121,11 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND);
|
||||
throw new AppwriteException('Project not found', 404, AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
throw new Exception('Missing or unknown project ID', 400, Exception::PROJECT_UNKNOWN);
|
||||
throw new AppwriteException('Missing or unknown project ID', 400, AppwriteException::PROJECT_UNKNOWN);
|
||||
}
|
||||
|
||||
$referrer = $request->getReferer();
|
||||
|
@ -150,37 +143,38 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
|
||||
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
||||
? $refDomain
|
||||
: (!empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(!empty($port) ? ':'.$port : '');
|
||||
: (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||
|
||||
$selfDomain = new Domain($request->getHostname());
|
||||
$endDomain = new Domain((string)$origin);
|
||||
|
||||
Config::setParam('domainVerification',
|
||||
Config::setParam(
|
||||
'domainVerification',
|
||||
($selfDomain->getRegisterable() === $endDomain->getRegisterable()) &&
|
||||
$endDomain->getRegisterable() !== '');
|
||||
$endDomain->getRegisterable() !== ''
|
||||
);
|
||||
|
||||
Config::setParam('cookieDomain', (
|
||||
$request->getHostname() === 'localhost' ||
|
||||
$request->getHostname() === 'localhost:'.$request->getPort() ||
|
||||
$request->getHostname() === 'localhost:' . $request->getPort() ||
|
||||
(\filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false)
|
||||
)
|
||||
? null
|
||||
: '.'.$request->getHostname()
|
||||
);
|
||||
: '.' . $request->getHostname());
|
||||
|
||||
/*
|
||||
/*
|
||||
* Response format
|
||||
*/
|
||||
$responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
if ($responseFormat) {
|
||||
switch($responseFormat) {
|
||||
case version_compare ($responseFormat , '0.11.2', '<=') :
|
||||
switch ($responseFormat) {
|
||||
case version_compare($responseFormat, '0.11.2', '<='):
|
||||
Response::setFilter(new ResponseV11());
|
||||
break;
|
||||
case version_compare ($responseFormat , '0.12.4', '<='):
|
||||
case version_compare($responseFormat, '0.12.4', '<='):
|
||||
Response::setFilter(new ResponseV12());
|
||||
break;
|
||||
case version_compare ($responseFormat , '0.13.4', '<='):
|
||||
case version_compare($responseFormat, '0.13.4', '<='):
|
||||
Response::setFilter(new ResponseV13());
|
||||
break;
|
||||
default:
|
||||
|
@ -198,14 +192,14 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
*/
|
||||
if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
|
||||
if ($request->getProtocol() !== 'https') {
|
||||
if($request->getMethod() !== Request::METHOD_GET) {
|
||||
throw new Exception('Method unsupported over HTTP.', 500, Exception::GENERAL_PROTOCOL_UNSUPPORTED);
|
||||
if ($request->getMethod() !== Request::METHOD_GET) {
|
||||
throw new AppwriteException('Method unsupported over HTTP.', 500, AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
||||
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
|
||||
}
|
||||
|
||||
$response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days
|
||||
$response->addHeader('Strict-Transport-Security', 'max-age=' . (60 * 60 * 24 * 126)); // 126 days
|
||||
}
|
||||
|
||||
$response
|
||||
|
@ -226,11 +220,13 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
$origin = $request->getOrigin($request->getReferer(''));
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
|
||||
if (!$originValidator->isValid($origin)
|
||||
if (
|
||||
!$originValidator->isValid($origin)
|
||||
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
||||
&& $route->getLabel('origin', false) !== '*'
|
||||
&& empty($request->getHeader('x-appwrite-key', ''))) {
|
||||
throw new Exception($originValidator->getDescription(), 403, Exception::GENERAL_UNKNOWN_ORIGIN);
|
||||
&& empty($request->getHeader('x-appwrite-key', ''))
|
||||
) {
|
||||
throw new AppwriteException($originValidator->getDescription(), 403, AppwriteException::GENERAL_UNKNOWN_ORIGIN);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -271,12 +267,11 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
* Try app auth when we have project key and no user
|
||||
* Mock user to app and grant API key scopes in addition to default app scopes
|
||||
*/
|
||||
|
||||
if ($key && $user->isEmpty()) {
|
||||
$user = new Document([
|
||||
'$id' => '',
|
||||
'status' => true,
|
||||
'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(),
|
||||
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
|
||||
'password' => '',
|
||||
'name' => $project->getAttribute('name', 'Untitled'),
|
||||
]);
|
||||
|
@ -287,50 +282,50 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
$expire = $key->getAttribute('expire', 0);
|
||||
|
||||
if($expire !== 0 && $expire < \time()){
|
||||
throw new Exception('Project key expired', 401, Exception:: PROJECT_KEY_EXPIRED);
|
||||
throw new AppwriteException('Project key expired', 401, Exception:: PROJECT_KEY_EXPIRED);
|
||||
}
|
||||
|
||||
Authorization::setRole('role:'.Auth::USER_ROLE_APP);
|
||||
Authorization::setRole('role:' . Auth::USER_ROLE_APP);
|
||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
||||
}
|
||||
}
|
||||
|
||||
Authorization::setRole('role:'.$role);
|
||||
Authorization::setRole('role:' . $role);
|
||||
|
||||
foreach (Auth::getRoles($user) as $authRole) {
|
||||
Authorization::setRole($authRole);
|
||||
}
|
||||
|
||||
$service = $route->getLabel('sdk.namespace','');
|
||||
if(!empty($service)) {
|
||||
if(array_key_exists($service, $project->getAttribute('services',[]))
|
||||
&& !$project->getAttribute('services',[])[$service]
|
||||
&& !Auth::isPrivilegedUser(Authorization::getRoles())) {
|
||||
throw new Exception('Service is disabled', 503, Exception::GENERAL_SERVICE_DISABLED);
|
||||
$service = $route->getLabel('sdk.namespace', '');
|
||||
if (!empty($service)) {
|
||||
if (
|
||||
array_key_exists($service, $project->getAttribute('services', []))
|
||||
&& !$project->getAttribute('services', [])[$service]
|
||||
&& !Auth::isPrivilegedUser(Authorization::getRoles())
|
||||
) {
|
||||
throw new AppwriteException('Service is disabled', 503, AppwriteException::GENERAL_SERVICE_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array($scope, $scopes)) {
|
||||
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
||||
throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND);
|
||||
throw new AppwriteException('Project not found', 404, AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401, Exception::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
throw new AppwriteException($user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')', 401, AppwriteException::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
}
|
||||
|
||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||
throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED);
|
||||
throw new AppwriteException('Invalid credentials. User is blocked', 401, AppwriteException::USER_BLOCKED);
|
||||
}
|
||||
|
||||
if ($user->getAttribute('reset')) {
|
||||
throw new Exception('Password reset is required', 412, Exception::USER_PASSWORD_RESET_REQUIRED);
|
||||
throw new AppwriteException('Password reset is required', 412, AppwriteException::USER_PASSWORD_RESET_REQUIRED);
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']);
|
||||
|
||||
App::options(function ($request, $response) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
App::options(function (Request $request, Response $response) {
|
||||
|
||||
$origin = $request->getOrigin();
|
||||
|
||||
|
@ -344,15 +339,7 @@ App::options(function ($request, $response) {
|
|||
->noContent();
|
||||
}, ['request', 'response']);
|
||||
|
||||
App::error(function ($error, $utopia, $request, $response, $layout, $project, $logger, $loggerBreadcrumbs) {
|
||||
/** @var Exception $error */
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Logger\Logger $logger */
|
||||
/** @var Utopia\Logger\Log\Breadcrumb[] $loggerBreadcrumbs */
|
||||
App::error(function (Throwable $error, App $utopia, Request $request, Response $response, View $layout, Document $project, ?Logger $logger, array $loggerBreadcrumbs) {
|
||||
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$route = $utopia->match($request);
|
||||
|
@ -362,18 +349,18 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
throw $error;
|
||||
}
|
||||
|
||||
if($logger) {
|
||||
if($error->getCode() >= 500 || $error->getCode() === 0) {
|
||||
if ($logger) {
|
||||
if ($error->getCode() >= 500 || $error->getCode() === 0) {
|
||||
try {
|
||||
/** @var Utopia\Database\Document $user */
|
||||
$user = $utopia->getResource('user');
|
||||
} catch(\Throwable $th) {
|
||||
} catch (\Throwable $th) {
|
||||
// All good, user is optional information for logger
|
||||
}
|
||||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if(isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
|
@ -384,7 +371,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
$log->setMessage($error->getMessage());
|
||||
|
||||
$log->addTag('method', $route->getMethod());
|
||||
$log->addTag('url', $route->getPath());
|
||||
$log->addTag('url', $route->getPath());
|
||||
$log->addTag('verboseType', get_class($error));
|
||||
$log->addTag('code', $error->getCode());
|
||||
$log->addTag('projectId', $project->getId());
|
||||
|
@ -403,12 +390,12 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
foreach($loggerBreadcrumbs as $loggerBreadcrumb) {
|
||||
foreach ($loggerBreadcrumbs as $loggerBreadcrumb) {
|
||||
$log->addBreadcrumb($loggerBreadcrumb);
|
||||
}
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Log pushed with status code: '.$responseCode);
|
||||
Console::info('Log pushed with status code: ' . $responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,35 +406,35 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
$trace = $error->getTrace();
|
||||
|
||||
if (php_sapi_name() === 'cli') {
|
||||
Console::error('[Error] Timestamp: '.date('c', time()));
|
||||
Console::error('[Error] Timestamp: ' . date('c', time()));
|
||||
|
||||
if($route) {
|
||||
Console::error('[Error] Method: '.$route->getMethod());
|
||||
Console::error('[Error] URL: '.$route->getPath());
|
||||
if ($route) {
|
||||
Console::error('[Error] Method: ' . $route->getMethod());
|
||||
Console::error('[Error] URL: ' . $route->getPath());
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$message);
|
||||
Console::error('[Error] File: '.$file);
|
||||
Console::error('[Error] Line: '.$line);
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $message);
|
||||
Console::error('[Error] File: ' . $file);
|
||||
Console::error('[Error] Line: ' . $line);
|
||||
}
|
||||
|
||||
/** Handle Utopia Errors */
|
||||
if ($error instanceof Utopia\Exception) {
|
||||
$error = new Exception($message, $code, Exception::GENERAL_UNKNOWN, $error);
|
||||
switch($code) {
|
||||
$error = new AppwriteException($message, $code, AppwriteException::GENERAL_UNKNOWN, $error);
|
||||
switch ($code) {
|
||||
case 400:
|
||||
$error->setType(Exception::GENERAL_ARGUMENT_INVALID);
|
||||
$error->setType(AppwriteException::GENERAL_ARGUMENT_INVALID);
|
||||
break;
|
||||
case 404:
|
||||
$error->setType(Exception::GENERAL_ROUTE_NOT_FOUND);
|
||||
$error->setType(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrap all exceptions inside Appwrite\Extend\Exception */
|
||||
if (!($error instanceof Exception)) {
|
||||
$error = new Exception($message, $code, Exception::GENERAL_UNKNOWN, $error);
|
||||
if (!($error instanceof AppwriteException)) {
|
||||
$error = new AppwriteException($message, $code, AppwriteException::GENERAL_UNKNOWN, $error);
|
||||
}
|
||||
|
||||
switch ($code) { // Don't show 500 errors!
|
||||
|
@ -509,7 +496,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', $project->getAttribute('name').' - Error')
|
||||
->setParam('title', $project->getAttribute('name') . ' - Error')
|
||||
->setParam('description', 'No Description')
|
||||
->setParam('body', $comp)
|
||||
->setParam('version', $version)
|
||||
|
@ -519,8 +506,10 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
|
|||
$response->html($layout->render());
|
||||
}
|
||||
|
||||
$response->dynamic(new Document($output),
|
||||
$utopia->isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR);
|
||||
$response->dynamic(
|
||||
new Document($output),
|
||||
$utopia->isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR
|
||||
);
|
||||
}, ['error', 'utopia', 'request', 'response', 'layout', 'project', 'logger', 'loggerBreadcrumbs']);
|
||||
|
||||
App::get('/manifest.json')
|
||||
|
@ -528,8 +517,7 @@ App::get('/manifest.json')
|
|||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->json([
|
||||
'name' => APP_NAME,
|
||||
|
@ -555,8 +543,8 @@ App::get('/robots.txt')
|
|||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
$template = new View(__DIR__.'/../views/general/robots.phtml');
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/robots.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
|
@ -565,8 +553,8 @@ App::get('/humans.txt')
|
|||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
$template = new View(__DIR__.'/../views/general/humans.phtml');
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/humans.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
|
@ -576,7 +564,7 @@ App::get('/.well-known/acme-challenge')
|
|||
->label('docs', false)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function ($request, $response) {
|
||||
->action(function (Request $request, Response $response) {
|
||||
$uriChunks = \explode('/', $request->getURI());
|
||||
$token = $uriChunks[\count($uriChunks) - 1];
|
||||
|
||||
|
@ -589,32 +577,32 @@ App::get('/.well-known/acme-challenge')
|
|||
]);
|
||||
|
||||
if (!$validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||
throw new Exception('Invalid challenge token.', 400);
|
||||
throw new AppwriteException('Invalid challenge token.', 400);
|
||||
}
|
||||
|
||||
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
||||
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$token);
|
||||
$absolute = \realpath($base . '/.well-known/acme-challenge/' . $token);
|
||||
|
||||
if (!$base) {
|
||||
throw new Exception('Storage error', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
throw new AppwriteException('Storage error', 500, AppwriteException::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (!$absolute) {
|
||||
throw new Exception('Unknown path', 404);
|
||||
throw new AppwriteException('Unknown path', 404);
|
||||
}
|
||||
|
||||
if (!\substr($absolute, 0, \strlen($base)) === $base) {
|
||||
throw new Exception('Invalid path', 401);
|
||||
throw new AppwriteException('Invalid path', 401);
|
||||
}
|
||||
|
||||
if (!\file_exists($absolute)) {
|
||||
throw new Exception('Unknown path', 404);
|
||||
throw new AppwriteException('Unknown path', 404);
|
||||
}
|
||||
|
||||
$content = @\file_get_contents($absolute);
|
||||
|
||||
if (!$content) {
|
||||
throw new Exception('Failed to get contents', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
throw new AppwriteException('Failed to get contents', 500, AppwriteException::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$response->text($content);
|
||||
|
|
|
@ -5,6 +5,7 @@ global $utopia, $request, $response;
|
|||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Appwrite\Network\Validator\Host;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Validator\ArrayList;
|
||||
|
@ -206,13 +207,12 @@ App::get('/v1/mock/tests/general/download')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setContentType('text/plain')
|
||||
->addHeader('Content-Disposition', 'attachment; filename="test.txt"')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
->send("Download test passed.")
|
||||
;
|
||||
|
@ -237,54 +237,52 @@ App::post('/v1/mock/tests/general/upload')
|
|||
->param('file', [], new File(), 'Sample file param', false)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function ($x, $y, $z, $file, $request, $response) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Utopia\Swoole\Response $response */
|
||||
|
||||
->action(function (string $x, int $y, array $z, array $file, Request $request, Response $response) {
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
|
||||
$contentRange = $request->getHeader('content-range');
|
||||
|
||||
$chunkSize = 5*1024*1024; // 5MB
|
||||
$chunkSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
if(!empty($contentRange)) {
|
||||
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'][0] : $file['size'];
|
||||
|
||||
if(is_null($start) || is_null($end) || is_null($size)) {
|
||||
if (is_null($start) || is_null($end) || is_null($size)) {
|
||||
throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($start > $end || $end > $size) {
|
||||
if ($start > $end || $end > $size) {
|
||||
throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($start === 0 && !empty($id)) {
|
||||
if ($start === 0 && !empty($id)) {
|
||||
throw new Exception('First chunked request cannot have id header', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($start !== 0 && $id !== 'newfileid') {
|
||||
if ($start !== 0 && $id !== 'newfileid') {
|
||||
throw new Exception('All chunked request must have id header (except first)', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($end !== $size && $end-$start+1 !== $chunkSize) {
|
||||
if ($end !== $size && $end - $start + 1 !== $chunkSize) {
|
||||
throw new Exception('Chunk size must be 5MB (except last chunk)', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if ($end !== $size && $file['size'] !== $chunkSize) {
|
||||
throw new Exception('Wrong chunk size', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($file['size'] > $chunkSize) {
|
||||
|
||||
if ($file['size'] > $chunkSize) {
|
||||
throw new Exception('Chunk size must be 5MB or less', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
if($end !== $size) {
|
||||
if ($end !== $size) {
|
||||
$response->json([
|
||||
'$id'=> 'newfileid',
|
||||
'$id' => 'newfileid',
|
||||
'chunksTotal' => $file['size'] / $chunkSize,
|
||||
'chunksUploaded' => $start / $chunkSize
|
||||
]);
|
||||
|
@ -293,11 +291,11 @@ App::post('/v1/mock/tests/general/upload')
|
|||
$file['tmp_name'] = (\is_array($file['tmp_name'])) ? $file['tmp_name'][0] : $file['tmp_name'];
|
||||
$file['name'] = (\is_array($file['name'])) ? $file['name'][0] : $file['name'];
|
||||
$file['size'] = (\is_array($file['size'])) ? $file['size'][0] : $file['size'];
|
||||
|
||||
|
||||
if ($file['name'] !== 'file.png') {
|
||||
throw new Exception('Wrong file name', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
|
||||
if ($file['size'] !== 38756) {
|
||||
throw new Exception('Wrong file size', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
@ -321,8 +319,7 @@ App::get('/v1/mock/tests/general/redirect')
|
|||
->label('sdk.response.model', Response::MODEL_MOCK)
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->redirect('/v1/mock/tests/general/redirect/done');
|
||||
});
|
||||
|
@ -356,9 +353,7 @@ App::get('/v1/mock/tests/general/set-cookie')
|
|||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->action(function ($response, $request) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
->action(function (Response $response, Request $request) {
|
||||
|
||||
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true);
|
||||
});
|
||||
|
@ -376,8 +371,7 @@ App::get('/v1/mock/tests/general/get-cookie')
|
|||
->label('sdk.response.model', Response::MODEL_MOCK)
|
||||
->label('sdk.mock', true)
|
||||
->inject('request')
|
||||
->action(function ($request) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
->action(function (Request $request) {
|
||||
|
||||
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
|
||||
throw new Exception('Missing cookie value', 400, Exception::GENERAL_MOCK);
|
||||
|
@ -396,8 +390,7 @@ App::get('/v1/mock/tests/general/empty')
|
|||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
@ -447,8 +440,7 @@ App::get('/v1/mock/tests/general/502-error')
|
|||
->label('sdk.response.model', Response::MODEL_ANY)
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(502)
|
||||
|
@ -467,10 +459,9 @@ App::get('/v1/mock/tests/general/oauth2')
|
|||
->param('scope', '', new Text(100), 'OAuth2 scope list.')
|
||||
->param('state', '', new Text(1024), 'OAuth2 state.')
|
||||
->inject('response')
|
||||
->action(function ($client_id, $redirectURI, $scope, $state, $response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) {
|
||||
|
||||
$response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
$response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2/token')
|
||||
|
@ -486,8 +477,7 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
|||
->param('code', '', new Text(100), 'OAuth2 state.', true)
|
||||
->param('refresh_token', '', new Text(100), 'OAuth2 refresh token.', true)
|
||||
->inject('response')
|
||||
->action(function ($client_id, $client_secret, $grantType, $redirectURI, $code, $refreshToken, $response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) {
|
||||
|
||||
if ($client_id != '1') {
|
||||
throw new Exception('Invalid client ID', 400, Exception::GENERAL_MOCK);
|
||||
|
@ -503,13 +493,13 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
|||
'expires_in' => 14400
|
||||
];
|
||||
|
||||
if($grantType === 'authorization_code') {
|
||||
if ($grantType === 'authorization_code') {
|
||||
if ($code !== 'abcdef') {
|
||||
throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
||||
$response->json($responseJson);
|
||||
} else if($grantType === 'refresh_token') {
|
||||
} elseif ($grantType === 'refresh_token') {
|
||||
if ($refreshToken !== 'tuvwxyz') {
|
||||
throw new Exception('Invalid refresh token', 400, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
@ -527,8 +517,7 @@ App::get('/v1/mock/tests/general/oauth2/user')
|
|||
->label('docs', false)
|
||||
->param('token', '', new Text(100), 'OAuth2 Access Token.')
|
||||
->inject('response')
|
||||
->action(function ($token, $response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (string $token, Response $response) {
|
||||
|
||||
if ($token != '123456') {
|
||||
throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK);
|
||||
|
@ -547,8 +536,7 @@ App::get('/v1/mock/tests/general/oauth2/success')
|
|||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->json([
|
||||
'result' => 'success',
|
||||
|
@ -561,8 +549,7 @@ App::get('/v1/mock/tests/general/oauth2/failure')
|
|||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_BAD_REQUEST)
|
||||
|
@ -571,16 +558,13 @@ App::get('/v1/mock/tests/general/oauth2/failure')
|
|||
]);
|
||||
});
|
||||
|
||||
App::shutdown(function($utopia, $response, $request) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
App::shutdown(function (App $utopia, Response $response, Request $request) {
|
||||
|
||||
$result = [];
|
||||
$route = $utopia->match($request);
|
||||
$path = APP_STORAGE_CACHE.'/tests.json';
|
||||
$path = APP_STORAGE_CACHE . '/tests.json';
|
||||
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
|
||||
|
||||
|
||||
if (!\is_array($tests)) {
|
||||
throw new Exception('Failed to read results', 500, Exception::GENERAL_MOCK);
|
||||
}
|
||||
|
@ -594,4 +578,4 @@ App::shutdown(function($utopia, $response, $request) {
|
|||
}
|
||||
|
||||
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK);
|
||||
}, ['utopia', 'response', 'request'], 'mock');
|
||||
}, ['utopia', 'response', 'request'], 'mock');
|
||||
|
|
|
@ -1,30 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Stats\Stats;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\App;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Registry\Registry;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $events, $audits, $mails, $usage, $deletes, $database, $dbForProject, $mode) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Mail $mails */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $database */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
App::init(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Mail $mails, Stats $usage, Delete $deletes, Event $database, Database $dbForProject, string $mode) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
|
@ -46,7 +40,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath());
|
||||
->setParam('{url}', $request->getHostname() . $route->getPath());
|
||||
$timeLimitArray[] = $timeLimit;
|
||||
}
|
||||
|
||||
|
@ -58,8 +52,8 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
|
||||
foreach ($timeLimitArray as $timeLimit) {
|
||||
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
|
||||
if(!empty($value)) {
|
||||
$timeLimit->setParam('{param-'.$key.'}', (\is_array($value)) ? \json_encode($value) : $value);
|
||||
if (!empty($value)) {
|
||||
$timeLimit->setParam('{param-' . $key . '}', (\is_array($value)) ? \json_encode($value) : $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,10 +68,11 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
;
|
||||
}
|
||||
|
||||
if ((App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled' // Route is rate-limited
|
||||
&& $abuse->check()) // Abuse is not disabled
|
||||
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
|
||||
{
|
||||
if (
|
||||
(App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled' // Route is rate-limited
|
||||
&& $abuse->check()) // Abuse is not disabled
|
||||
&& (!$isAppUser && !$isPrivilegedUser)
|
||||
) { // User is not an admin or API key
|
||||
throw new Exception('Too many requests', 429, Exception::GENERAL_RATE_LIMIT_EXCEEDED);
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +103,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
$usage
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('httpRequest', 1)
|
||||
->setParam('httpUrl', $request->getHostname().$request->getURI())
|
||||
->setParam('httpUrl', $request->getHostname() . $request->getURI())
|
||||
->setParam('httpMethod', $request->getMethod())
|
||||
->setParam('httpPath', $route->getPath())
|
||||
->setParam('networkRequestSize', 0)
|
||||
|
@ -120,48 +115,45 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
$database->setProject($project);
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'events', 'audits', 'mails', 'usage', 'deletes', 'database', 'dbForProject', 'mode'], 'api');
|
||||
|
||||
App::init(function ($utopia, $request, $project) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
App::init(function (App $utopia, Request $request, Document $project) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
|
||||
if($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
|
||||
if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
|
||||
return;
|
||||
}
|
||||
|
||||
$auths = $project->getAttribute('auths', []);
|
||||
switch ($route->getLabel('auth.type', '')) {
|
||||
case 'emailPassword':
|
||||
if(($auths['emailPassword'] ?? true) === false) {
|
||||
if (($auths['emailPassword'] ?? true) === false) {
|
||||
throw new Exception('Email / Password authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'magic-url':
|
||||
if($project->getAttribute('usersAuthMagicURL', true) === false) {
|
||||
if ($project->getAttribute('usersAuthMagicURL', true) === false) {
|
||||
throw new Exception('Magic URL authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'anonymous':
|
||||
if(($auths['anonymous'] ?? true) === false) {
|
||||
if (($auths['anonymous'] ?? true) === false) {
|
||||
throw new Exception('Anonymous authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'invites':
|
||||
if(($auths['invites'] ?? true) === false) {
|
||||
if (($auths['invites'] ?? true) === false) {
|
||||
throw new Exception('Invites authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'jwt':
|
||||
if(($auths['JWT'] ?? true) === false) {
|
||||
if (($auths['JWT'] ?? true) === false) {
|
||||
throw new Exception('JWT authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
}
|
||||
break;
|
||||
|
@ -170,21 +162,9 @@ App::init(function ($utopia, $request, $project) {
|
|||
throw new Exception('Unsupported authentication route', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
|
||||
break;
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'project'], 'auth');
|
||||
|
||||
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $database, $mode, $dbForProject) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Delete $deletes */
|
||||
/** @var Appwrite\Event\Database $database */
|
||||
/** @var bool $mode */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
App::shutdown(function (App $utopia, Request $request, Response $response, Document $project, Event $events, Audit $audits, Stats $usage, Delete $deletes, Event $database, string $mode, Database $dbForProject) {
|
||||
|
||||
if (!empty($events->getEvent())) {
|
||||
if (empty($events->getPayload())) {
|
||||
|
@ -233,7 +213,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
channels: $target['channels'],
|
||||
roles: $target['roles'],
|
||||
options: [
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'userId' => $events->getParam('userId')
|
||||
]
|
||||
);
|
||||
|
@ -256,15 +236,15 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
}
|
||||
|
||||
$route = $utopia->match($request);
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||
if (
|
||||
App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||
&& $project->getId()
|
||||
&& $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin
|
||||
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
|
||||
|
||||
&& !empty($route->getLabel('sdk.namespace', null))
|
||||
) { // Don't calculate console usage on admin mode
|
||||
$usage
|
||||
->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage'))
|
||||
->setParam('networkResponseSize', $response->getSize())
|
||||
->submit();
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode', 'dbForProject'], 'api');
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode', 'dbForProject'], 'api');
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\View;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $layout) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
App::init(function (App $utopia, Request $request, Response $response, View $layout) {
|
||||
|
||||
/* AJAX check */
|
||||
if (!empty($request->getQuery('version', ''))) {
|
||||
|
@ -48,10 +47,10 @@ App::init(function ($utopia, $request, $response, $layout) {
|
|||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$route->label('error', __DIR__.'/../../views/general/error.phtml');
|
||||
$route->label('error', __DIR__ . '/../../views/general/error.phtml');
|
||||
|
||||
$scope = $route->getLabel('scope', '');
|
||||
|
||||
|
||||
$layout
|
||||
->setParam('version', App::getEnv('_APP_VERSION', 'UNKNOWN'))
|
||||
->setParam('isDev', App::isDevelopment())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\View;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
|
@ -8,8 +9,7 @@ use Utopia\Domains\Domain;
|
|||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::init(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
App::init(function (View $layout) {
|
||||
|
||||
$layout
|
||||
->setParam('description', 'Appwrite Console allows you to easily manage, monitor, and control your entire backend API and tools.')
|
||||
|
@ -17,12 +17,10 @@ App::init(function ($layout) {
|
|||
;
|
||||
}, ['layout'], 'console');
|
||||
|
||||
App::shutdown(function ($response, $layout) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
App::shutdown(function (Response $response, View $layout) {
|
||||
|
||||
$header = new View(__DIR__.'/../../views/console/comps/header.phtml');
|
||||
$footer = new View(__DIR__.'/../../views/console/comps/footer.phtml');
|
||||
$header = new View(__DIR__ . '/../../views/console/comps/header.phtml');
|
||||
$footer = new View(__DIR__ . '/../../views/console/comps/footer.phtml');
|
||||
|
||||
$footer
|
||||
->setParam('home', App::getEnv('_APP_HOME', ''))
|
||||
|
@ -43,17 +41,16 @@ App::get('/error/:code')
|
|||
->label('scope', 'home')
|
||||
->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false)
|
||||
->inject('layout')
|
||||
->action(function ($code, $layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (int $code, View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/error.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/error.phtml');
|
||||
|
||||
$page
|
||||
->setParam('code', $code)
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Error')
|
||||
->setParam('title', APP_NAME . ' - Error')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -62,17 +59,16 @@ App::get('/console')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/index.phtml');
|
||||
|
||||
$page
|
||||
->setParam('home', App::getEnv('_APP_HOME', ''))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Console')
|
||||
->setParam('title', APP_NAME . ' - Console')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -81,19 +77,18 @@ App::get('/console/account')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/account/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/account/index.phtml');
|
||||
|
||||
$cc = new View(__DIR__.'/../../views/console/forms/credit-card.phtml');
|
||||
$cc = new View(__DIR__ . '/../../views/console/forms/credit-card.phtml');
|
||||
|
||||
$page
|
||||
->setParam('cc', $cc)
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Account - '.APP_NAME)
|
||||
->setParam('title', 'Account - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -102,13 +97,12 @@ App::get('/console/notifications')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/v1/console/notifications/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/v1/console/notifications/index.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Notifications')
|
||||
->setParam('title', APP_NAME . ' - Notifications')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -117,14 +111,13 @@ App::get('/console/home')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/home/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/home/index.phtml');
|
||||
$page
|
||||
->setParam('usageStatsEnabled',App::getEnv('_APP_USAGE_STATS','enabled') == 'enabled');
|
||||
->setParam('usageStatsEnabled', App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled');
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Console')
|
||||
->setParam('title', APP_NAME . ' - Console')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -133,22 +126,20 @@ App::get('/console/settings')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/settings/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/settings/index.phtml');
|
||||
|
||||
$page
|
||||
->setParam('services', array_filter(Config::getParam('services'), function($element) {return $element['optional'];}))
|
||||
$page->setParam('services', array_filter(Config::getParam('services'), fn($element) => $element['optional']))
|
||||
->setParam('customDomainsEnabled', ($target->isKnown() && !$target->isTest()))
|
||||
->setParam('customDomainsTarget', $target->get())
|
||||
->setParam('smtpEnabled', (!empty(App::getEnv('_APP_SMTP_HOST'))))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Settings')
|
||||
->setParam('title', APP_NAME . ' - Settings')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -157,15 +148,14 @@ App::get('/console/webhooks')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/webhooks/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/webhooks/index.phtml');
|
||||
|
||||
$page->setParam('events', Config::getParam('events', []));
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Webhooks')
|
||||
->setParam('title', APP_NAME . ' - Webhooks')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -175,10 +165,9 @@ App::get('/console/webhooks/webhook')
|
|||
->label('scope', 'console')
|
||||
->param('id', '', new UID(), 'Webhook unique ID.')
|
||||
->inject('layout')
|
||||
->action(function ($id, $layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (string $id, View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/webhooks/webhook.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/webhooks/webhook.phtml');
|
||||
|
||||
$page
|
||||
->setParam('events', Config::getParam('events', []))
|
||||
|
@ -186,7 +175,7 @@ App::get('/console/webhooks/webhook')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Webhooks')
|
||||
->setParam('title', APP_NAME . ' - Webhooks')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -195,10 +184,9 @@ App::get('/console/webhooks/webhook/new')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/webhooks/webhook.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/webhooks/webhook.phtml');
|
||||
|
||||
$page
|
||||
->setParam('events', Config::getParam('events', []))
|
||||
|
@ -206,7 +194,7 @@ App::get('/console/webhooks/webhook/new')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Webhooks')
|
||||
->setParam('title', APP_NAME . ' - Webhooks')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -215,16 +203,15 @@ App::get('/console/keys')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$scopes = array_keys(Config::getParam('scopes'));
|
||||
$page = new View(__DIR__.'/../../views/console/keys/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/keys/index.phtml');
|
||||
|
||||
$page->setParam('scopes', $scopes);
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - API Keys')
|
||||
->setParam('title', APP_NAME . ' - API Keys')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -233,13 +220,12 @@ App::get('/console/database')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/database/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/database/index.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Database')
|
||||
->setParam('title', APP_NAME . ' - Database')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -250,11 +236,9 @@ App::get('/console/database/collection')
|
|||
->param('id', '', new UID(), 'Collection unique ID.')
|
||||
->inject('response')
|
||||
->inject('layout')
|
||||
->action(function ($id, $response, $layout) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (string $id, Response $response, View $layout) {
|
||||
|
||||
$logs = new View(__DIR__.'/../../views/console/comps/logs.phtml');
|
||||
$logs = new View(__DIR__ . '/../../views/console/comps/logs.phtml');
|
||||
|
||||
$logs
|
||||
->setParam('interval', App::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 0))
|
||||
|
@ -264,12 +248,12 @@ App::get('/console/database/collection')
|
|||
])
|
||||
;
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/database/collection.phtml');
|
||||
|
||||
$page = new View(__DIR__ . '/../../views/console/database/collection.phtml');
|
||||
|
||||
$page->setParam('logs', $logs);
|
||||
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Database Collection')
|
||||
->setParam('title', APP_NAME . ' - Database Collection')
|
||||
->setParam('body', $page)
|
||||
;
|
||||
|
||||
|
@ -286,10 +270,9 @@ App::get('/console/database/document')
|
|||
->label('scope', 'console')
|
||||
->param('collection', '', new UID(), 'Collection unique ID.')
|
||||
->inject('layout')
|
||||
->action(function ($collection, $layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (string $collection, View $layout) {
|
||||
|
||||
$logs = new View(__DIR__.'/../../views/console/comps/logs.phtml');
|
||||
$logs = new View(__DIR__ . '/../../views/console/comps/logs.phtml');
|
||||
|
||||
$logs
|
||||
->setParam('interval', App::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 0))
|
||||
|
@ -300,7 +283,7 @@ App::get('/console/database/document')
|
|||
])
|
||||
;
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/database/document.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/database/document.phtml');
|
||||
|
||||
$page
|
||||
->setParam('new', false)
|
||||
|
@ -309,7 +292,7 @@ App::get('/console/database/document')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Database Document')
|
||||
->setParam('title', APP_NAME . ' - Database Document')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -319,10 +302,9 @@ App::get('/console/database/document/new')
|
|||
->label('scope', 'console')
|
||||
->param('collection', '', new UID(), 'Collection unique ID.')
|
||||
->inject('layout')
|
||||
->action(function ($collection, $layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (string $collection, View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/database/document.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/database/document.phtml');
|
||||
|
||||
$page
|
||||
->setParam('new', true)
|
||||
|
@ -331,7 +313,7 @@ App::get('/console/database/document/new')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Database Document')
|
||||
->setParam('title', APP_NAME . ' - Database Document')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -340,10 +322,10 @@ App::get('/console/storage')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
$page = new View(__DIR__.'/../../views/console/storage/index.phtml');
|
||||
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__ . '/../../views/console/storage/index.phtml');
|
||||
|
||||
$page
|
||||
->setParam('home', App::getEnv('_APP_HOME', 0))
|
||||
->setParam('fileLimit', App::getEnv('_APP_STORAGE_LIMIT', 0))
|
||||
|
@ -351,7 +333,7 @@ App::get('/console/storage')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Storage')
|
||||
->setParam('title', APP_NAME . ' - Storage')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -362,19 +344,17 @@ App::get('/console/storage/bucket')
|
|||
->param('id', '', new UID(), 'Bucket unique ID.')
|
||||
->inject('response')
|
||||
->inject('layout')
|
||||
->action(function ($id, $response, $layout) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\View $layout */
|
||||
->action(function (string $id, Response $response, View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/storage/bucket.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/storage/bucket.phtml');
|
||||
$page
|
||||
->setParam('home', App::getEnv('_APP_HOME', 0))
|
||||
->setParam('fileLimit', App::getEnv('_APP_STORAGE_LIMIT', 0))
|
||||
->setParam('fileLimitHuman', Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0)))
|
||||
;
|
||||
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Storage Buckets')
|
||||
->setParam('title', APP_NAME . ' - Storage Buckets')
|
||||
->setParam('body', $page)
|
||||
;
|
||||
|
||||
|
@ -390,10 +370,9 @@ App::get('/console/users')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/users/index.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/users/index.phtml');
|
||||
|
||||
$page
|
||||
->setParam('auth', Config::getParam('auth'))
|
||||
|
@ -402,7 +381,7 @@ App::get('/console/users')
|
|||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Users')
|
||||
->setParam('title', APP_NAME . ' - Users')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -411,13 +390,12 @@ App::get('/console/users/user')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/users/user.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/users/user.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - User')
|
||||
->setParam('title', APP_NAME . ' - User')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -426,13 +404,12 @@ App::get('/console/users/teams/team')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/users/team.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/console/users/team.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Team')
|
||||
->setParam('title', APP_NAME . ' - Team')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -442,15 +419,15 @@ App::get('/console/functions')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
$page = new View(__DIR__.'/../../views/console/functions/index.phtml');
|
||||
->action(function (View $layout) {
|
||||
$page = new View(__DIR__ . '/../../views/console/functions/index.phtml');
|
||||
|
||||
$page
|
||||
->setParam('runtimes', Config::getParam('runtimes'))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Functions')
|
||||
->setParam('title', APP_NAME . ' - Functions')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -460,19 +437,19 @@ App::get('/console/functions/function')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
$page = new View(__DIR__.'/../../views/console/functions/function.phtml');
|
||||
->action(function (View $layout) {
|
||||
$page = new View(__DIR__ . '/../../views/console/functions/function.phtml');
|
||||
|
||||
$page
|
||||
->setParam('events', Config::getParam('events', []))
|
||||
->setParam('fileLimit', App::getEnv('_APP_STORAGE_LIMIT', 0))
|
||||
->setParam('fileLimitHuman', Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0)))
|
||||
->setParam('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900))
|
||||
->setParam('usageStatsEnabled',App::getEnv('_APP_USAGE_STATS','enabled') == 'enabled');
|
||||
->setParam('usageStatsEnabled', App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled');
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Function')
|
||||
->setParam('title', APP_NAME . ' - Function')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -484,8 +461,8 @@ App::get('/console/version')
|
|||
->inject('response')
|
||||
->action(function ($response) {
|
||||
try {
|
||||
$version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true);
|
||||
|
||||
$version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost') . '/v1/health/version'), true);
|
||||
|
||||
if ($version && isset($version['version'])) {
|
||||
return $response->json(['version' => $version['version']]);
|
||||
} else {
|
||||
|
@ -494,4 +471,4 @@ App::get('/console/version')
|
|||
} catch (\Throwable $th) {
|
||||
throw new Exception('Failed to check for a newer version', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Utopia\View;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
App::init(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
App::init(function (View $layout) {
|
||||
|
||||
$header = new View(__DIR__.'/../../views/home/comps/header.phtml');
|
||||
$footer = new View(__DIR__.'/../../views/home/comps/footer.phtml');
|
||||
$header = new View(__DIR__ . '/../../views/home/comps/header.phtml');
|
||||
$footer = new View(__DIR__ . '/../../views/home/comps/footer.phtml');
|
||||
|
||||
$footer
|
||||
->setParam('version', App::getEnv('_APP_VERSION', 'UNKNOWN'))
|
||||
|
@ -24,9 +26,7 @@ App::init(function ($layout) {
|
|||
;
|
||||
}, ['layout'], 'home');
|
||||
|
||||
App::shutdown(function ($response, $layout) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
App::shutdown(function (Response $response, View $layout) {
|
||||
|
||||
$response->html($layout->render());
|
||||
}, ['response', 'layout'], 'home');
|
||||
|
@ -38,10 +38,7 @@ App::get('/')
|
|||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->inject('project')
|
||||
->action(function ($response, $dbForConsole, $project) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
->action(function (Response $response, Database $dbForConsole, Document $project) {
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
|
@ -52,10 +49,10 @@ App::get('/')
|
|||
if ('console' === $project->getId() || $project->isEmpty()) {
|
||||
$whitelistRoot = App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled');
|
||||
|
||||
if($whitelistRoot !== 'disabled') {
|
||||
if ($whitelistRoot !== 'disabled') {
|
||||
$count = $dbForConsole->count('users', [], 1);
|
||||
|
||||
if($count !== 0) {
|
||||
if ($count !== 0) {
|
||||
return $response->redirect('/auth/signin');
|
||||
}
|
||||
}
|
||||
|
@ -69,17 +66,16 @@ App::get('/auth/signin')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/signin.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/signin.phtml');
|
||||
|
||||
$page
|
||||
->setParam('root', App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled'))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Sign In - '.APP_NAME)
|
||||
->setParam('title', 'Sign In - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -88,16 +84,16 @@ App::get('/auth/signup')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
$page = new View(__DIR__.'/../../views/home/auth/signup.phtml');
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/signup.phtml');
|
||||
|
||||
$page
|
||||
->setParam('root', App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled'))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Sign Up - '.APP_NAME)
|
||||
->setParam('title', 'Sign Up - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -106,17 +102,16 @@ App::get('/auth/recovery')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/recovery.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/recovery.phtml');
|
||||
|
||||
$page
|
||||
->setParam('smtpEnabled', (!empty(App::getEnv('_APP_SMTP_HOST'))))
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Password Recovery - '.APP_NAME)
|
||||
->setParam('title', 'Password Recovery - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -125,13 +120,12 @@ App::get('/auth/confirm')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/confirm.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/confirm.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Account Confirmation - '.APP_NAME)
|
||||
->setParam('title', 'Account Confirmation - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -140,13 +134,12 @@ App::get('/auth/join')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/join.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/join.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Invitation - '.APP_NAME)
|
||||
->setParam('title', 'Invitation - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -155,13 +148,12 @@ App::get('/auth/recovery/reset')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/recovery/reset.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/recovery/reset.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Password Reset - '.APP_NAME)
|
||||
->setParam('title', 'Password Reset - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -170,10 +162,9 @@ App::get('/auth/oauth2/success')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/oauth2.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/oauth2.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME)
|
||||
|
@ -188,10 +179,9 @@ App::get('/auth/magic-url')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/magicURL.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/magicURL.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME)
|
||||
|
@ -206,10 +196,9 @@ App::get('/auth/oauth2/failure')
|
|||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/oauth2.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/home/auth/oauth2.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME)
|
||||
|
@ -225,17 +214,16 @@ App::get('/error/:code')
|
|||
->label('scope', 'home')
|
||||
->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false)
|
||||
->inject('layout')
|
||||
->action(function ($code, $layout) {
|
||||
/** @var Appwrite\Utopia\View $layout */
|
||||
->action(function (int $code, View $layout) {
|
||||
|
||||
$page = new View(__DIR__.'/../../views/error.phtml');
|
||||
$page = new View(__DIR__ . '/../../views/error.phtml');
|
||||
|
||||
$page
|
||||
->setParam('code', $code)
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', 'Error'.' - '.APP_NAME)
|
||||
->setParam('title', 'Error' . ' - ' . APP_NAME)
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
|
@ -244,8 +232,7 @@ App::get('/versions')
|
|||
->groups(['web', 'home'])
|
||||
->label('scope', 'public')
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
->action(function (Response $response) {
|
||||
|
||||
$platforms = Config::getParam('platforms');
|
||||
|
||||
|
@ -253,15 +240,15 @@ App::get('/versions')
|
|||
'server' => APP_VERSION_STABLE,
|
||||
];
|
||||
|
||||
foreach($platforms as $platform) {
|
||||
foreach ($platforms as $platform) {
|
||||
$languages = $platform['languages'] ?? [];
|
||||
|
||||
foreach ($languages as $key => $language) {
|
||||
if(isset($language['dev']) && $language['dev']) {
|
||||
if (isset($language['dev']) && $language['dev']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isset($language['enabled']) && !$language['enabled']) {
|
||||
if (isset($language['enabled']) && !$language['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
|
@ -38,7 +39,7 @@ Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
|||
const MAINTENANCE_INTERVAL = 3600; // 3600 seconds = 1 hour
|
||||
|
||||
/**
|
||||
* Create a Swoole table to store runtime information
|
||||
* Create a Swoole table to store runtime information
|
||||
*/
|
||||
$activeRuntimes = new Swoole\Table(1024);
|
||||
$activeRuntimes->column('id', Swoole\Table::TYPE_STRING, 256);
|
||||
|
@ -67,8 +68,8 @@ $providerName = App::getEnv('_APP_LOGGING_PROVIDER', '');
|
|||
$providerConfig = App::getEnv('_APP_LOGGING_CONFIG', '');
|
||||
$logger = null;
|
||||
|
||||
if(!empty($providerName) && !empty($providerConfig) && Logger::hasProvider($providerName)) {
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName);
|
||||
if (!empty($providerName) && !empty($providerConfig) && Logger::hasProvider($providerName)) {
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
|
||||
$adapter = new $classname($providerConfig);
|
||||
$logger = new Logger($adapter);
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ function logError(Throwable $error, string $action, Utopia\Route $route = null)
|
|||
|
||||
if ($route) {
|
||||
$log->addTag('method', $route->getMethod());
|
||||
$log->addTag('url', $route->getPath());
|
||||
$log->addTag('url', $route->getPath());
|
||||
}
|
||||
|
||||
$log->addTag('code', $error->getCode());
|
||||
|
@ -113,11 +114,13 @@ function logError(Throwable $error, string $action, Utopia\Route $route = null)
|
|||
Console::error('[Error] Message: ' . $error->getMessage());
|
||||
Console::error('[Error] File: ' . $error->getFile());
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
};
|
||||
}
|
||||
|
||||
function getStorageDevice($root): Device {
|
||||
function getStorageDevice($root): Device
|
||||
{
|
||||
switch (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)) {
|
||||
case Storage::DEVICE_LOCAL:default:
|
||||
case Storage::DEVICE_LOCAL:
|
||||
default:
|
||||
return new Local($root);
|
||||
case Storage::DEVICE_S3:
|
||||
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
|
||||
|
@ -187,9 +190,9 @@ App::post('/v1/runtimes')
|
|||
|
||||
try {
|
||||
Console::info('Building container : ' . $runtimeId);
|
||||
|
||||
/**
|
||||
* Temporary file paths in the executor
|
||||
|
||||
/**
|
||||
* Temporary file paths in the executor
|
||||
*/
|
||||
$tmpSource = "/tmp/$runtimeId/src/code.tar.gz";
|
||||
$tmpBuild = "/tmp/$runtimeId/builds/code.tar.gz";
|
||||
|
@ -200,7 +203,7 @@ App::post('/v1/runtimes')
|
|||
$sourceDevice = getStorageDevice("/");
|
||||
$localDevice = new Local();
|
||||
$buffer = $sourceDevice->read($source);
|
||||
if(!$localDevice->write($tmpSource, $buffer)) {
|
||||
if (!$localDevice->write($tmpSource, $buffer)) {
|
||||
throw new Exception('Failed to copy source code to temporary directory', 500);
|
||||
};
|
||||
|
||||
|
@ -226,7 +229,7 @@ App::post('/v1/runtimes')
|
|||
->setCpus((int) App::getEnv('_APP_FUNCTIONS_CPUS', 0))
|
||||
->setMemory((int) App::getEnv('_APP_FUNCTIONS_MEMORY', 0))
|
||||
->setSwap((int) App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', 0));
|
||||
|
||||
|
||||
/** Keep the container alive if we have commands to be executed */
|
||||
$entrypoint = !empty($commands) ? [
|
||||
'tail',
|
||||
|
@ -248,8 +251,8 @@ App::post('/v1/runtimes')
|
|||
],
|
||||
workdir: $workdir,
|
||||
volumes: [
|
||||
\dirname($tmpSource). ':/tmp:rw',
|
||||
\dirname($tmpBuild). ':/usr/code:rw'
|
||||
\dirname($tmpSource) . ':/tmp:rw',
|
||||
\dirname($tmpBuild) . ':/usr/code:rw'
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -259,7 +262,7 @@ App::post('/v1/runtimes')
|
|||
|
||||
$orchestration->networkConnect($runtimeId, App::getEnv('OPEN_RUNTIMES_NETWORK', 'appwrite_runtimes'));
|
||||
|
||||
/**
|
||||
/**
|
||||
* Execute any commands if they were provided
|
||||
*/
|
||||
if (!empty($commands)) {
|
||||
|
@ -289,7 +292,7 @@ App::post('/v1/runtimes')
|
|||
$outputPath = $destinationDevice->getPath(\uniqid() . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
|
||||
$buffer = $localDevice->read($tmpBuild);
|
||||
if(!$destinationDevice->write($outputPath, $buffer, $localDevice->getFileMimeType($tmpBuild))) {
|
||||
if (!$destinationDevice->write($outputPath, $buffer, $localDevice->getFileMimeType($tmpBuild))) {
|
||||
throw new Exception('Failed to move built code to storage', 500);
|
||||
};
|
||||
|
||||
|
@ -322,13 +325,12 @@ App::post('/v1/runtimes')
|
|||
}
|
||||
|
||||
Console::success('Build Stage completed in ' . ($endTime - $startTime) . ' seconds');
|
||||
|
||||
} catch (Throwable $th) {
|
||||
Console::error('Build failed: ' . $th->getMessage() . $stdout);
|
||||
throw new Exception($th->getMessage() . $stdout, 500);
|
||||
} finally {
|
||||
// Container cleanup
|
||||
if($remove) {
|
||||
if ($remove) {
|
||||
if (!empty($containerId)) {
|
||||
// If container properly created
|
||||
$orchestration->remove($containerId, true);
|
||||
|
@ -361,7 +363,7 @@ App::get('/v1/runtimes')
|
|||
->action(function ($activeRuntimes, Response $response) {
|
||||
$runtimes = [];
|
||||
|
||||
foreach($activeRuntimes as $runtime) {
|
||||
foreach ($activeRuntimes as $runtime) {
|
||||
$runtimes[] = $runtime;
|
||||
}
|
||||
|
||||
|
@ -377,7 +379,7 @@ App::get('/v1/runtimes/:runtimeId')
|
|||
->inject('response')
|
||||
->action(function ($runtimeId, $activeRuntimes, Response $response) {
|
||||
|
||||
if(!$activeRuntimes->exists($runtimeId)) {
|
||||
if (!$activeRuntimes->exists($runtimeId)) {
|
||||
throw new Exception('Runtime not found', 404);
|
||||
}
|
||||
|
||||
|
@ -396,7 +398,7 @@ App::delete('/v1/runtimes/:runtimeId')
|
|||
->inject('response')
|
||||
->action(function (string $runtimeId, $orchestrationPool, $activeRuntimes, Response $response) {
|
||||
|
||||
if(!$activeRuntimes->exists($runtimeId)) {
|
||||
if (!$activeRuntimes->exists($runtimeId)) {
|
||||
throw new Exception('Runtime not found', 404);
|
||||
}
|
||||
|
||||
|
@ -473,33 +475,33 @@ App::post('/v1/execution')
|
|||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
|
||||
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . \strlen($body),
|
||||
'x-internal-challenge: ' . $secret,
|
||||
'host: null'
|
||||
]);
|
||||
|
||||
|
||||
$executorResponse = \curl_exec($ch);
|
||||
|
||||
|
||||
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
|
||||
$error = \curl_error($ch);
|
||||
|
||||
|
||||
$errNo = \curl_errno($ch);
|
||||
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
switch (true) {
|
||||
/** No Error. */
|
||||
case $errNo === 0:
|
||||
case $errNo === 0:
|
||||
break;
|
||||
/** Runtime not ready for requests yet. 111 is the swoole error code for Connection Refused - see https://openswoole.com/docs/swoole-error-code */
|
||||
case $errNo === 111:
|
||||
throw new Exception('An internal curl error has occurred within the executor! Error Msg: ' . $error, 406);
|
||||
/** Any other CURL error */
|
||||
default:
|
||||
default:
|
||||
throw new Exception('An internal curl error has occurred within the executor! Error Msg: ' . $error, 500);
|
||||
}
|
||||
|
||||
|
@ -551,7 +553,7 @@ App::setResource('activeRuntimes', fn() => $activeRuntimes);
|
|||
App::error(function ($utopia, $error, $request, $response) {
|
||||
$route = $utopia->match($request);
|
||||
logError($error, "httpError", $route);
|
||||
|
||||
|
||||
switch ($error->getCode()) {
|
||||
case 400: // Error allowed publicly
|
||||
case 401: // Error allowed publicly
|
||||
|
@ -570,7 +572,7 @@ App::error(function ($utopia, $error, $request, $response) {
|
|||
default:
|
||||
$code = 500; // All other errors get the generic 500 server error status code
|
||||
}
|
||||
|
||||
|
||||
$output = [
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
|
@ -591,13 +593,13 @@ App::error(function ($utopia, $error, $request, $response) {
|
|||
|
||||
App::init(function ($request, $response) {
|
||||
$secretKey = $request->getHeader('x-appwrite-executor-key', '');
|
||||
if (empty($secretKey)) {
|
||||
throw new Exception('Missing executor key', 401);
|
||||
}
|
||||
|
||||
if ($secretKey !== App::getEnv('_APP_EXECUTOR_SECRET', '')) {
|
||||
if (empty($secretKey)) {
|
||||
throw new Exception('Missing executor key', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if ($secretKey !== App::getEnv('_APP_EXECUTOR_SECRET', '')) {
|
||||
throw new Exception('Missing executor key', 401);
|
||||
}
|
||||
}, ['request', 'response']);
|
||||
|
||||
|
||||
|
@ -605,7 +607,7 @@ $http->on('start', function ($http) {
|
|||
global $orchestrationPool;
|
||||
global $activeRuntimes;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Warmup: make sure images are ready to run fast 🚀
|
||||
*/
|
||||
$runtimes = new Runtimes('v1');
|
||||
|
@ -696,11 +698,10 @@ $http->on('start', function ($http) {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
$http->on('beforeShutdown', function() {
|
||||
$http->on('beforeShutdown', function () {
|
||||
global $orchestrationPool;
|
||||
Console::info('Cleaning up containers before shutdown...');
|
||||
|
||||
|
@ -709,7 +710,7 @@ $http->on('beforeShutdown', function() {
|
|||
$orchestrationPool->put($orchestration);
|
||||
|
||||
foreach ($functionsToRemove as $container) {
|
||||
go(function () use ($orchestrationPool, $container) {
|
||||
go(function () use ($orchestrationPool, $container) {
|
||||
try {
|
||||
$orchestration = $orchestrationPool->get();
|
||||
$orchestration->remove($container->getId(), true);
|
||||
|
@ -735,7 +736,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
logError($th, "serverError");
|
||||
$swooleResponse->setStatusCode(500);
|
||||
$output = [
|
||||
'message' => 'Error: '. $th->getMessage(),
|
||||
'message' => 'Error: ' . $th->getMessage(),
|
||||
'code' => 500,
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
|
|
70
app/http.php
70
app/http.php
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Process;
|
||||
|
@ -38,15 +38,15 @@ $http
|
|||
])
|
||||
;
|
||||
|
||||
$http->on('WorkerStart', function($server, $workerId) {
|
||||
Console::success('Worker '.++$workerId.' started successfully');
|
||||
$http->on('WorkerStart', function ($server, $workerId) {
|
||||
Console::success('Worker ' . ++$workerId . ' started successfully');
|
||||
});
|
||||
|
||||
$http->on('BeforeReload', function($server, $workerId) {
|
||||
$http->on('BeforeReload', function ($server, $workerId) {
|
||||
Console::success('Starting reload...');
|
||||
});
|
||||
|
||||
$http->on('AfterReload', function($server, $workerId) {
|
||||
$http->on('AfterReload', function ($server, $workerId) {
|
||||
Console::success('Reload completed...');
|
||||
});
|
||||
|
||||
|
@ -57,7 +57,7 @@ include __DIR__ . '/controllers/general.php';
|
|||
$http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$app = new App('UTC');
|
||||
|
||||
go(function() use ($register, $app) {
|
||||
go(function () use ($register, $app) {
|
||||
// wait for database to be ready
|
||||
$attempts = 0;
|
||||
$max = 10;
|
||||
|
@ -69,10 +69,10 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
break; // leave the do-while if successful
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed to connect to database: '. $e->getMessage());
|
||||
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
Console::success('[Setup] - Server database init started...');
|
||||
$collections = Config::getParam('collections', []); /** @var array $collections */
|
||||
|
||||
if(!$dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'))) {
|
||||
if (!$dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'))) {
|
||||
$redis->flushAll();
|
||||
|
||||
Console::success('[Setup] - Creating database: appwrite...');
|
||||
|
@ -101,7 +101,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
}
|
||||
|
||||
if($dbForConsole->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
if ($dbForConsole->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForConsole);
|
||||
$audit->setup();
|
||||
}
|
||||
|
@ -112,10 +112,10 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
}
|
||||
|
||||
foreach ($collections as $key => $collection) {
|
||||
if(($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
if(!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
if (!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
|
||||
|
@ -150,7 +150,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
if($dbForConsole->getDocument('buckets', 'default')->isEmpty()) {
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty()) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => 'default',
|
||||
|
@ -170,16 +170,16 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
]));
|
||||
|
||||
$bucket = $dbForConsole->getDocument('buckets', 'default');
|
||||
|
||||
|
||||
Console::success('[Setup] - Creating files collection for default bucket...');
|
||||
$files = $collections['files'] ?? [];
|
||||
if(empty($files)) {
|
||||
if (empty($files)) {
|
||||
throw new Exception('Files collection is not configured.');
|
||||
}
|
||||
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
|
||||
|
||||
foreach ($files['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => $attribute['$id'],
|
||||
|
@ -193,7 +193,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
foreach ($files['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => $index['$id'],
|
||||
|
@ -203,14 +203,14 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
'orders' => $index['orders'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
}
|
||||
|
||||
Console::success('[Setup] - Server database init completed...');
|
||||
});
|
||||
|
||||
Console::success('Server started successfully (max payload is '.number_format($payloadSize).' bytes)');
|
||||
Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)');
|
||||
|
||||
Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}");
|
||||
|
||||
|
@ -225,13 +225,13 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$request = new Request($swooleRequest);
|
||||
$response = new Response($swooleResponse);
|
||||
|
||||
if(Files::isFileLoaded($request->getURI())) {
|
||||
if (Files::isFileLoaded($request->getURI())) {
|
||||
$time = (60 * 60 * 24 * 365 * 2); // 45 days cache
|
||||
|
||||
$response
|
||||
->setContentType(Files::getFileMimeType($request->getURI()))
|
||||
->addHeader('Cache-Control', 'public, max-age='.$time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache
|
||||
->addHeader('Cache-Control', 'public, max-age=' . $time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache
|
||||
->send(Files::getFileContents($request->getURI()))
|
||||
;
|
||||
|
||||
|
@ -255,11 +255,11 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$logger = $app->getResource("logger");
|
||||
if($logger) {
|
||||
if ($logger) {
|
||||
try {
|
||||
/** @var Utopia\Database\Document $user */
|
||||
$user = $app->getResource('user');
|
||||
} catch(\Throwable $_th) {
|
||||
} catch (\Throwable $_th) {
|
||||
// All good, user is optional information for logger
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if(isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$log->setMessage($th->getMessage());
|
||||
|
||||
$log->addTag('method', $route->getMethod());
|
||||
$log->addTag('url', $route->getPath());
|
||||
$log->addTag('url', $route->getPath());
|
||||
$log->addTag('verboseType', get_class($th));
|
||||
$log->addTag('code', $th->getCode());
|
||||
// $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant
|
||||
|
@ -298,18 +298,18 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
foreach($loggerBreadcrumbs as $loggerBreadcrumb) {
|
||||
foreach ($loggerBreadcrumbs as $loggerBreadcrumb) {
|
||||
$log->addBreadcrumb($loggerBreadcrumb);
|
||||
}
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Log pushed with status code: '.$responseCode);
|
||||
Console::info('Log pushed with status code: ' . $responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: '.get_class($th));
|
||||
Console::error('[Error] Message: '.$th->getMessage());
|
||||
Console::error('[Error] File: '.$th->getFile());
|
||||
Console::error('[Error] Line: '.$th->getLine());
|
||||
Console::error('[Error] Type: ' . get_class($th));
|
||||
Console::error('[Error] Message: ' . $th->getMessage());
|
||||
Console::error('[Error] File: ' . $th->getFile());
|
||||
Console::error('[Error] Line: ' . $th->getLine());
|
||||
|
||||
/**
|
||||
* Reset Database connection if PDOException was thrown.
|
||||
|
@ -321,7 +321,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$swooleResponse->setStatusCode(500);
|
||||
|
||||
$output = ((App::isDevelopment())) ? [
|
||||
'message' => 'Error: '. $th->getMessage(),
|
||||
'message' => 'Error: ' . $th->getMessage(),
|
||||
'code' => 500,
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
|
@ -345,4 +345,4 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
}
|
||||
});
|
||||
|
||||
$http->start();
|
||||
$http->start();
|
||||
|
|
441
app/init.php
441
app/init.php
|
@ -2,16 +2,17 @@
|
|||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
*
|
||||
* Initializes both Appwrite API entry point, queue workers, and CLI tasks.
|
||||
* Set configuration, framework resources & app constants
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
if (\file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
}
|
||||
|
||||
ini_set('memory_limit','512M');
|
||||
ini_set('memory_limit', '512M');
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('default_socket_timeout', -1);
|
||||
|
@ -67,7 +68,7 @@ const APP_NAME = 'Appwrite';
|
|||
const APP_DOMAIN = 'appwrite.io';
|
||||
const APP_EMAIL_TEAM = 'team@localhost.test'; // Default email address
|
||||
const APP_EMAIL_SECURITY = ''; // Default security email address
|
||||
const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s';
|
||||
const APP_USERAGENT = APP_NAME . '-Server v%s. Please report abuse at %s';
|
||||
const APP_MODE_DEFAULT = 'default';
|
||||
const APP_MODE_ADMIN = 'admin';
|
||||
const APP_PAGING_LIMIT = 12;
|
||||
|
@ -102,7 +103,7 @@ const APP_SOCIAL_GITHUB = 'https://github.com/appwrite';
|
|||
const APP_SOCIAL_DISCORD = 'https://appwrite.io/discord';
|
||||
const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244';
|
||||
const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
|
||||
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
|
||||
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
|
||||
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1';
|
||||
// Database Reconnect
|
||||
const DATABASE_RECONNECT_SLEEP = 2;
|
||||
|
@ -122,7 +123,7 @@ const DELETE_TYPE_PROJECTS = 'projects';
|
|||
const DELETE_TYPE_FUNCTIONS = 'functions';
|
||||
const DELETE_TYPE_DEPLOYMENTS = 'deployments';
|
||||
const DELETE_TYPE_USERS = 'users';
|
||||
const DELETE_TYPE_TEAMS= 'teams';
|
||||
const DELETE_TYPE_TEAMS = 'teams';
|
||||
const DELETE_TYPE_EXECUTIONS = 'executions';
|
||||
const DELETE_TYPE_AUDIT = 'audit';
|
||||
const DELETE_TYPE_ABUSE = 'abuse';
|
||||
|
@ -142,7 +143,7 @@ const APP_AUTH_TYPE_JWT = 'JWT';
|
|||
const APP_AUTH_TYPE_KEY = 'Key';
|
||||
const APP_AUTH_TYPE_ADMIN = 'Admin';
|
||||
// Response related
|
||||
const MAX_OUTPUT_CHUNK_SIZE = 2*1024*1024; // 2MB
|
||||
const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB
|
||||
|
||||
$register = new Registry();
|
||||
|
||||
|
@ -151,48 +152,49 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
|
|||
/*
|
||||
* ENV vars
|
||||
*/
|
||||
Config::load('events', __DIR__.'/config/events.php');
|
||||
Config::load('auth', __DIR__.'/config/auth.php');
|
||||
Config::load('errors', __DIR__.'/config/errors.php');
|
||||
Config::load('providers', __DIR__.'/config/providers.php');
|
||||
Config::load('platforms', __DIR__.'/config/platforms.php');
|
||||
Config::load('collections', __DIR__.'/config/collections.php');
|
||||
Config::load('runtimes', __DIR__.'/config/runtimes.php');
|
||||
Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__.'/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__.'/config/variables.php'); // List of env variables
|
||||
Config::load('avatar-browsers', __DIR__.'/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__.'/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__.'/config/avatars/flags.php');
|
||||
Config::load('locale-codes', __DIR__.'/config/locale/codes.php');
|
||||
Config::load('locale-currencies', __DIR__.'/config/locale/currencies.php');
|
||||
Config::load('locale-eu', __DIR__.'/config/locale/eu.php');
|
||||
Config::load('locale-languages', __DIR__.'/config/locale/languages.php');
|
||||
Config::load('locale-phones', __DIR__.'/config/locale/phones.php');
|
||||
Config::load('locale-countries', __DIR__.'/config/locale/countries.php');
|
||||
Config::load('locale-continents', __DIR__.'/config/locale/continents.php');
|
||||
Config::load('storage-logos', __DIR__.'/config/storage/logos.php');
|
||||
Config::load('storage-mimes', __DIR__.'/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__.'/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__.'/config/storage/outputs.php');
|
||||
Config::load('events', __DIR__ . '/config/events.php');
|
||||
Config::load('auth', __DIR__ . '/config/auth.php');
|
||||
Config::load('errors', __DIR__ . '/config/errors.php');
|
||||
Config::load('providers', __DIR__ . '/config/providers.php');
|
||||
Config::load('platforms', __DIR__ . '/config/platforms.php');
|
||||
Config::load('collections', __DIR__ . '/config/collections.php');
|
||||
Config::load('runtimes', __DIR__ . '/config/runtimes.php');
|
||||
Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__ . '/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables
|
||||
Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php');
|
||||
Config::load('locale-codes', __DIR__ . '/config/locale/codes.php');
|
||||
Config::load('locale-currencies', __DIR__ . '/config/locale/currencies.php');
|
||||
Config::load('locale-eu', __DIR__ . '/config/locale/eu.php');
|
||||
Config::load('locale-languages', __DIR__ . '/config/locale/languages.php');
|
||||
Config::load('locale-phones', __DIR__ . '/config/locale/phones.php');
|
||||
Config::load('locale-countries', __DIR__ . '/config/locale/countries.php');
|
||||
Config::load('locale-continents', __DIR__ . '/config/locale/continents.php');
|
||||
Config::load('storage-logos', __DIR__ . '/config/storage/logos.php');
|
||||
Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
|
||||
|
||||
$user = App::getEnv('_APP_REDIS_USER','');
|
||||
$pass = App::getEnv('_APP_REDIS_PASS','');
|
||||
if(!empty($user) || !empty($pass)) {
|
||||
Resque::setBackend('redis://'.$user.':'.$pass.'@'.App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', ''));
|
||||
$user = App::getEnv('_APP_REDIS_USER', '');
|
||||
$pass = App::getEnv('_APP_REDIS_PASS', '');
|
||||
if (!empty($user) || !empty($pass)) {
|
||||
Resque::setBackend('redis://' . $user . ':' . $pass . '@' . App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
|
||||
} else {
|
||||
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', ''));
|
||||
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* New DB Filters
|
||||
*/
|
||||
Database::addFilter('casting',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'casting',
|
||||
function ($value) {
|
||||
return json_encode(['value' => $value], JSON_PRESERVE_ZERO_FRACTION);
|
||||
},
|
||||
function($value) {
|
||||
function ($value) {
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -200,14 +202,15 @@ Database::addFilter('casting',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('enum',
|
||||
function($value, Document $attribute) {
|
||||
Database::addFilter(
|
||||
'enum',
|
||||
function ($value, Document $attribute) {
|
||||
if ($attribute->isSet('elements')) {
|
||||
$attribute->removeAttribute('elements');
|
||||
}
|
||||
return $value;
|
||||
},
|
||||
function($value, Document $attribute) {
|
||||
function ($value, Document $attribute) {
|
||||
$formatOptions = json_decode($attribute->getAttribute('formatOptions', '[]'), true);
|
||||
if (isset($formatOptions['elements'])) {
|
||||
$attribute->setAttribute('elements', $formatOptions['elements']);
|
||||
|
@ -216,8 +219,9 @@ Database::addFilter('enum',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('range',
|
||||
function($value, Document $attribute) {
|
||||
Database::addFilter(
|
||||
'range',
|
||||
function ($value, Document $attribute) {
|
||||
if ($attribute->isSet('min')) {
|
||||
$attribute->removeAttribute('min');
|
||||
}
|
||||
|
@ -226,7 +230,7 @@ Database::addFilter('range',
|
|||
}
|
||||
return $value;
|
||||
},
|
||||
function($value, Document $attribute) {
|
||||
function ($value, Document $attribute) {
|
||||
$formatOptions = json_decode($attribute->getAttribute('formatOptions', '[]'), true);
|
||||
if (isset($formatOptions['min']) || isset($formatOptions['max'])) {
|
||||
$attribute
|
||||
|
@ -238,11 +242,12 @@ Database::addFilter('range',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryAttributes',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryAttributes',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('attributes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -250,11 +255,12 @@ Database::addFilter('subQueryAttributes',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryIndexes',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryIndexes',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('indexes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -262,11 +268,12 @@ Database::addFilter('subQueryIndexes',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryPlatforms',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryPlatforms',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('platforms', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -274,11 +281,12 @@ Database::addFilter('subQueryPlatforms',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryDomains',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryDomains',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('domains', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -286,11 +294,12 @@ Database::addFilter('subQueryDomains',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryKeys',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryKeys',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('keys', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -298,11 +307,12 @@ Database::addFilter('subQueryKeys',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryWebhooks',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryWebhooks',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('webhooks', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -310,11 +320,12 @@ Database::addFilter('subQueryWebhooks',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQuerySessions',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQuerySessions',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
$sessions = Authorization::skip(fn () => $database->find('sessions', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $database->getIndexLimit(), 0, []));
|
||||
|
@ -323,23 +334,25 @@ Database::addFilter('subQuerySessions',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryTokens',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'subQueryTokens',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
->find('tokens', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $database->getIndexLimit(), 0, []));
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryMemberships',
|
||||
function($value) {
|
||||
|
||||
Database::addFilter(
|
||||
'subQueryMemberships',
|
||||
function ($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
function ($value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
->find('memberships', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
|
@ -347,8 +360,9 @@ Database::addFilter('subQueryMemberships',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('encrypt',
|
||||
function($value) {
|
||||
Database::addFilter(
|
||||
'encrypt',
|
||||
function ($value) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$tag = null;
|
||||
|
@ -360,12 +374,12 @@ Database::addFilter('encrypt',
|
|||
'version' => '1',
|
||||
]);
|
||||
},
|
||||
function($value) {
|
||||
if(is_null($value)) {
|
||||
function ($value) {
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
$value = json_decode($value, true);
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']);
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $value['version']);
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
|
@ -374,30 +388,30 @@ Database::addFilter('encrypt',
|
|||
/**
|
||||
* DB Formats
|
||||
*/
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function() {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function () {
|
||||
return new Email();
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function($attribute) {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) {
|
||||
$elements = $attribute['formatOptions']['elements'];
|
||||
return new WhiteList($elements, true);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_IP, function() {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_IP, function () {
|
||||
return new IP();
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function() {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () {
|
||||
return new URL();
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function($attribute) {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
return new Range($min, $max, Range::TYPE_INTEGER);
|
||||
}, Database::VAR_INTEGER);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function($attribute) {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
return new Range($min, $max, Range::TYPE_FLOAT);
|
||||
|
@ -406,30 +420,33 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function($attribute) {
|
|||
/*
|
||||
* Registry
|
||||
*/
|
||||
$register->set('logger', function () { // Register error logger
|
||||
$register->set('logger', function () {
|
||||
// Register error logger
|
||||
$providerName = App::getEnv('_APP_LOGGING_PROVIDER', '');
|
||||
$providerConfig = App::getEnv('_APP_LOGGING_CONFIG', '');
|
||||
|
||||
if(empty($providerName) || empty($providerConfig)) {
|
||||
if (empty($providerName) || empty($providerConfig)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!Logger::hasProvider($providerName)) {
|
||||
if (!Logger::hasProvider($providerName)) {
|
||||
throw new Exception("Logging provider not supported. Logging disabled.", 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName);
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
|
||||
$adapter = new $classname($providerConfig);
|
||||
return new Logger($adapter);
|
||||
});
|
||||
$register->set('dbPool', function () { // Register DB connection
|
||||
$register->set('dbPool', function () {
|
||||
// Register DB connection
|
||||
$dbHost = App::getEnv('_APP_DB_HOST', '');
|
||||
$dbPort = App::getEnv('_APP_DB_PORT', '');
|
||||
$dbUser = App::getEnv('_APP_DB_USER', '');
|
||||
$dbPass = App::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
$pool = new PDOPool((new PDOConfig())
|
||||
$pool = new PDOPool(
|
||||
(new PDOConfig())
|
||||
->withHost($dbHost)
|
||||
->withPort($dbPort)
|
||||
->withDbName($dbScheme)
|
||||
|
@ -438,8 +455,9 @@ $register->set('dbPool', function () { // Register DB connection
|
|||
->withPassword($dbPass)
|
||||
->withOptions([
|
||||
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
|
||||
])
|
||||
, 64);
|
||||
]),
|
||||
64
|
||||
);
|
||||
|
||||
return $pool;
|
||||
});
|
||||
|
@ -451,19 +469,22 @@ $register->set('redisPool', function () {
|
|||
$redisAuth = '';
|
||||
|
||||
if ($redisUser && $redisPass) {
|
||||
$redisAuth = $redisUser.':'.$redisPass;
|
||||
$redisAuth = $redisUser . ':' . $redisPass;
|
||||
}
|
||||
|
||||
$pool = new RedisPool((new RedisConfig)
|
||||
$pool = new RedisPool(
|
||||
(new RedisConfig())
|
||||
->withHost($redisHost)
|
||||
->withPort($redisPort)
|
||||
->withAuth($redisAuth)
|
||||
->withDbIndex(0)
|
||||
, 64);
|
||||
->withDbIndex(0),
|
||||
64
|
||||
);
|
||||
|
||||
return $pool;
|
||||
});
|
||||
$register->set('influxdb', function () { // Register DB connection
|
||||
$register->set('influxdb', function () {
|
||||
// Register DB connection
|
||||
$host = App::getEnv('_APP_INFLUXDB_HOST', '');
|
||||
$port = App::getEnv('_APP_INFLUXDB_PORT', '');
|
||||
|
||||
|
@ -476,7 +497,8 @@ $register->set('influxdb', function () { // Register DB connection
|
|||
|
||||
return $client;
|
||||
});
|
||||
$register->set('statsd', function () { // Register DB connection
|
||||
$register->set('statsd', function () {
|
||||
// Register DB connection
|
||||
$host = App::getEnv('_APP_STATSD_HOST', 'telegraf');
|
||||
$port = App::getEnv('_APP_STATSD_PORT', 8125);
|
||||
|
||||
|
@ -503,7 +525,7 @@ $register->set('smtp', function () {
|
|||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
$from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server'));
|
||||
$from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
|
||||
$email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
||||
$mail->setFrom($email, $from);
|
||||
|
@ -514,9 +536,10 @@ $register->set('smtp', function () {
|
|||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__.'/db/DBIP/dbip-country-lite-2022-03.mmdb');
|
||||
return new Reader(__DIR__ . '/db/DBIP/dbip-country-lite-2022-03.mmdb');
|
||||
});
|
||||
$register->set('db', function () { // This is usually for our workers or CLI commands scope
|
||||
$register->set('db', function () {
|
||||
// This is usually for our workers or CLI commands scope
|
||||
$dbHost = App::getEnv('_APP_DB_HOST', '');
|
||||
$dbPort = App::getEnv('_APP_DB_PORT', '');
|
||||
$dbUser = App::getEnv('_APP_DB_USER', '');
|
||||
|
@ -533,7 +556,8 @@ $register->set('db', function () { // This is usually for our workers or CLI com
|
|||
|
||||
return $pdo;
|
||||
});
|
||||
$register->set('cache', function () { // This is usually for our workers or CLI commands scope
|
||||
$register->set('cache', function () {
|
||||
// This is usually for our workers or CLI commands scope
|
||||
$redis = new Redis();
|
||||
$redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
|
||||
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
|
||||
|
@ -545,59 +569,59 @@ $register->set('cache', function () { // This is usually for our workers or CLI
|
|||
* Localization
|
||||
*/
|
||||
Locale::$exceptions = false;
|
||||
Locale::setLanguageFromJSON('af', __DIR__.'/config/locale/translations/af.json');
|
||||
Locale::setLanguageFromJSON('ar', __DIR__.'/config/locale/translations/ar.json');
|
||||
Locale::setLanguageFromJSON('as', __DIR__.'/config/locale/translations/as.json');
|
||||
Locale::setLanguageFromJSON('az', __DIR__.'/config/locale/translations/az.json');
|
||||
Locale::setLanguageFromJSON('be', __DIR__.'/config/locale/translations/be.json');
|
||||
Locale::setLanguageFromJSON('bg', __DIR__.'/config/locale/translations/bg.json');
|
||||
Locale::setLanguageFromJSON('bh', __DIR__.'/config/locale/translations/bh.json');
|
||||
Locale::setLanguageFromJSON('bn', __DIR__.'/config/locale/translations/bn.json');
|
||||
Locale::setLanguageFromJSON('bs', __DIR__.'/config/locale/translations/bs.json');
|
||||
Locale::setLanguageFromJSON('ca', __DIR__.'/config/locale/translations/ca.json');
|
||||
Locale::setLanguageFromJSON('cs', __DIR__.'/config/locale/translations/cs.json');
|
||||
Locale::setLanguageFromJSON('da', __DIR__.'/config/locale/translations/da.json');
|
||||
Locale::setLanguageFromJSON('de', __DIR__.'/config/locale/translations/de.json');
|
||||
Locale::setLanguageFromJSON('el', __DIR__.'/config/locale/translations/el.json');
|
||||
Locale::setLanguageFromJSON('en', __DIR__.'/config/locale/translations/en.json');
|
||||
Locale::setLanguageFromJSON('eo', __DIR__.'/config/locale/translations/eo.json');
|
||||
Locale::setLanguageFromJSON('es', __DIR__.'/config/locale/translations/es.json');
|
||||
Locale::setLanguageFromJSON('fa', __DIR__.'/config/locale/translations/fa.json');
|
||||
Locale::setLanguageFromJSON('fi', __DIR__.'/config/locale/translations/fi.json');
|
||||
Locale::setLanguageFromJSON('fo', __DIR__.'/config/locale/translations/fo.json');
|
||||
Locale::setLanguageFromJSON('fr', __DIR__.'/config/locale/translations/fr.json');
|
||||
Locale::setLanguageFromJSON('ga', __DIR__.'/config/locale/translations/ga.json');
|
||||
Locale::setLanguageFromJSON('gu', __DIR__.'/config/locale/translations/gu.json');
|
||||
Locale::setLanguageFromJSON('he', __DIR__.'/config/locale/translations/he.json');
|
||||
Locale::setLanguageFromJSON('hi', __DIR__.'/config/locale/translations/hi.json');
|
||||
Locale::setLanguageFromJSON('hr', __DIR__.'/config/locale/translations/hr.json');
|
||||
Locale::setLanguageFromJSON('hu', __DIR__.'/config/locale/translations/hu.json');
|
||||
Locale::setLanguageFromJSON('hy', __DIR__.'/config/locale/translations/hy.json');
|
||||
Locale::setLanguageFromJSON('id', __DIR__.'/config/locale/translations/id.json');
|
||||
Locale::setLanguageFromJSON('is', __DIR__.'/config/locale/translations/is.json');
|
||||
Locale::setLanguageFromJSON('it', __DIR__.'/config/locale/translations/it.json');
|
||||
Locale::setLanguageFromJSON('ja', __DIR__.'/config/locale/translations/ja.json');
|
||||
Locale::setLanguageFromJSON('jv', __DIR__.'/config/locale/translations/jv.json');
|
||||
Locale::setLanguageFromJSON('kn', __DIR__.'/config/locale/translations/kn.json');
|
||||
Locale::setLanguageFromJSON('km', __DIR__.'/config/locale/translations/km.json');
|
||||
Locale::setLanguageFromJSON('ko', __DIR__.'/config/locale/translations/ko.json');
|
||||
Locale::setLanguageFromJSON('la', __DIR__.'/config/locale/translations/la.json');
|
||||
Locale::setLanguageFromJSON('lb', __DIR__.'/config/locale/translations/lb.json');
|
||||
Locale::setLanguageFromJSON('lt', __DIR__.'/config/locale/translations/lt.json');
|
||||
Locale::setLanguageFromJSON('lv', __DIR__.'/config/locale/translations/lv.json');
|
||||
Locale::setLanguageFromJSON('ml', __DIR__.'/config/locale/translations/ml.json');
|
||||
Locale::setLanguageFromJSON('mr', __DIR__.'/config/locale/translations/mr.json');
|
||||
Locale::setLanguageFromJSON('ms', __DIR__.'/config/locale/translations/ms.json');
|
||||
Locale::setLanguageFromJSON('nb', __DIR__.'/config/locale/translations/nb.json');
|
||||
Locale::setLanguageFromJSON('ne', __DIR__.'/config/locale/translations/ne.json');
|
||||
Locale::setLanguageFromJSON('nl', __DIR__.'/config/locale/translations/nl.json');
|
||||
Locale::setLanguageFromJSON('nn', __DIR__.'/config/locale/translations/nn.json');
|
||||
Locale::setLanguageFromJSON('or', __DIR__.'/config/locale/translations/or.json');
|
||||
Locale::setLanguageFromJSON('pa', __DIR__.'/config/locale/translations/pa.json');
|
||||
Locale::setLanguageFromJSON('pl', __DIR__.'/config/locale/translations/pl.json');
|
||||
Locale::setLanguageFromJSON('pt-br', __DIR__.'/config/locale/translations/pt-br.json');
|
||||
Locale::setLanguageFromJSON('pt-pt', __DIR__.'/config/locale/translations/pt-pt.json');
|
||||
Locale::setLanguageFromJSON('ro', __DIR__.'/config/locale/translations/ro.json');
|
||||
Locale::setLanguageFromJSON('af', __DIR__ . '/config/locale/translations/af.json');
|
||||
Locale::setLanguageFromJSON('ar', __DIR__ . '/config/locale/translations/ar.json');
|
||||
Locale::setLanguageFromJSON('as', __DIR__ . '/config/locale/translations/as.json');
|
||||
Locale::setLanguageFromJSON('az', __DIR__ . '/config/locale/translations/az.json');
|
||||
Locale::setLanguageFromJSON('be', __DIR__ . '/config/locale/translations/be.json');
|
||||
Locale::setLanguageFromJSON('bg', __DIR__ . '/config/locale/translations/bg.json');
|
||||
Locale::setLanguageFromJSON('bh', __DIR__ . '/config/locale/translations/bh.json');
|
||||
Locale::setLanguageFromJSON('bn', __DIR__ . '/config/locale/translations/bn.json');
|
||||
Locale::setLanguageFromJSON('bs', __DIR__ . '/config/locale/translations/bs.json');
|
||||
Locale::setLanguageFromJSON('ca', __DIR__ . '/config/locale/translations/ca.json');
|
||||
Locale::setLanguageFromJSON('cs', __DIR__ . '/config/locale/translations/cs.json');
|
||||
Locale::setLanguageFromJSON('da', __DIR__ . '/config/locale/translations/da.json');
|
||||
Locale::setLanguageFromJSON('de', __DIR__ . '/config/locale/translations/de.json');
|
||||
Locale::setLanguageFromJSON('el', __DIR__ . '/config/locale/translations/el.json');
|
||||
Locale::setLanguageFromJSON('en', __DIR__ . '/config/locale/translations/en.json');
|
||||
Locale::setLanguageFromJSON('eo', __DIR__ . '/config/locale/translations/eo.json');
|
||||
Locale::setLanguageFromJSON('es', __DIR__ . '/config/locale/translations/es.json');
|
||||
Locale::setLanguageFromJSON('fa', __DIR__ . '/config/locale/translations/fa.json');
|
||||
Locale::setLanguageFromJSON('fi', __DIR__ . '/config/locale/translations/fi.json');
|
||||
Locale::setLanguageFromJSON('fo', __DIR__ . '/config/locale/translations/fo.json');
|
||||
Locale::setLanguageFromJSON('fr', __DIR__ . '/config/locale/translations/fr.json');
|
||||
Locale::setLanguageFromJSON('ga', __DIR__ . '/config/locale/translations/ga.json');
|
||||
Locale::setLanguageFromJSON('gu', __DIR__ . '/config/locale/translations/gu.json');
|
||||
Locale::setLanguageFromJSON('he', __DIR__ . '/config/locale/translations/he.json');
|
||||
Locale::setLanguageFromJSON('hi', __DIR__ . '/config/locale/translations/hi.json');
|
||||
Locale::setLanguageFromJSON('hr', __DIR__ . '/config/locale/translations/hr.json');
|
||||
Locale::setLanguageFromJSON('hu', __DIR__ . '/config/locale/translations/hu.json');
|
||||
Locale::setLanguageFromJSON('hy', __DIR__ . '/config/locale/translations/hy.json');
|
||||
Locale::setLanguageFromJSON('id', __DIR__ . '/config/locale/translations/id.json');
|
||||
Locale::setLanguageFromJSON('is', __DIR__ . '/config/locale/translations/is.json');
|
||||
Locale::setLanguageFromJSON('it', __DIR__ . '/config/locale/translations/it.json');
|
||||
Locale::setLanguageFromJSON('ja', __DIR__ . '/config/locale/translations/ja.json');
|
||||
Locale::setLanguageFromJSON('jv', __DIR__ . '/config/locale/translations/jv.json');
|
||||
Locale::setLanguageFromJSON('kn', __DIR__ . '/config/locale/translations/kn.json');
|
||||
Locale::setLanguageFromJSON('km', __DIR__ . '/config/locale/translations/km.json');
|
||||
Locale::setLanguageFromJSON('ko', __DIR__ . '/config/locale/translations/ko.json');
|
||||
Locale::setLanguageFromJSON('la', __DIR__ . '/config/locale/translations/la.json');
|
||||
Locale::setLanguageFromJSON('lb', __DIR__ . '/config/locale/translations/lb.json');
|
||||
Locale::setLanguageFromJSON('lt', __DIR__ . '/config/locale/translations/lt.json');
|
||||
Locale::setLanguageFromJSON('lv', __DIR__ . '/config/locale/translations/lv.json');
|
||||
Locale::setLanguageFromJSON('ml', __DIR__ . '/config/locale/translations/ml.json');
|
||||
Locale::setLanguageFromJSON('mr', __DIR__ . '/config/locale/translations/mr.json');
|
||||
Locale::setLanguageFromJSON('ms', __DIR__ . '/config/locale/translations/ms.json');
|
||||
Locale::setLanguageFromJSON('nb', __DIR__ . '/config/locale/translations/nb.json');
|
||||
Locale::setLanguageFromJSON('ne', __DIR__ . '/config/locale/translations/ne.json');
|
||||
Locale::setLanguageFromJSON('nl', __DIR__ . '/config/locale/translations/nl.json');
|
||||
Locale::setLanguageFromJSON('nn', __DIR__ . '/config/locale/translations/nn.json');
|
||||
Locale::setLanguageFromJSON('or', __DIR__ . '/config/locale/translations/or.json');
|
||||
Locale::setLanguageFromJSON('pa', __DIR__ . '/config/locale/translations/pa.json');
|
||||
Locale::setLanguageFromJSON('pl', __DIR__ . '/config/locale/translations/pl.json');
|
||||
Locale::setLanguageFromJSON('pt-br', __DIR__ . '/config/locale/translations/pt-br.json');
|
||||
Locale::setLanguageFromJSON('pt-pt', __DIR__ . '/config/locale/translations/pt-pt.json');
|
||||
Locale::setLanguageFromJSON('ro', __DIR__ . '/config/locale/translations/ro.json');
|
||||
Locale::setLanguageFromJSON('ru', __DIR__ . '/config/locale/translations/ru.json');
|
||||
Locale::setLanguageFromJSON('sa', __DIR__ . '/config/locale/translations/sa.json');
|
||||
Locale::setLanguageFromJSON('sd', __DIR__ . '/config/locale/translations/sd.json');
|
||||
|
@ -608,39 +632,41 @@ Locale::setLanguageFromJSON('sn', __DIR__ . '/config/locale/translations/sn.json
|
|||
Locale::setLanguageFromJSON('sq', __DIR__ . '/config/locale/translations/sq.json');
|
||||
Locale::setLanguageFromJSON('sv', __DIR__ . '/config/locale/translations/sv.json');
|
||||
Locale::setLanguageFromJSON('ta', __DIR__ . '/config/locale/translations/ta.json');
|
||||
Locale::setLanguageFromJSON('te', __DIR__.'/config/locale/translations/te.json');
|
||||
Locale::setLanguageFromJSON('th', __DIR__.'/config/locale/translations/th.json');
|
||||
Locale::setLanguageFromJSON('tl', __DIR__.'/config/locale/translations/tl.json');
|
||||
Locale::setLanguageFromJSON('tr', __DIR__.'/config/locale/translations/tr.json');
|
||||
Locale::setLanguageFromJSON('uk', __DIR__.'/config/locale/translations/uk.json');
|
||||
Locale::setLanguageFromJSON('ur', __DIR__.'/config/locale/translations/ur.json');
|
||||
Locale::setLanguageFromJSON('vi', __DIR__.'/config/locale/translations/vi.json');
|
||||
Locale::setLanguageFromJSON('zh-cn', __DIR__.'/config/locale/translations/zh-cn.json');
|
||||
Locale::setLanguageFromJSON('zh-tw', __DIR__.'/config/locale/translations/zh-tw.json');
|
||||
Locale::setLanguageFromJSON('te', __DIR__ . '/config/locale/translations/te.json');
|
||||
Locale::setLanguageFromJSON('th', __DIR__ . '/config/locale/translations/th.json');
|
||||
Locale::setLanguageFromJSON('tl', __DIR__ . '/config/locale/translations/tl.json');
|
||||
Locale::setLanguageFromJSON('tr', __DIR__ . '/config/locale/translations/tr.json');
|
||||
Locale::setLanguageFromJSON('uk', __DIR__ . '/config/locale/translations/uk.json');
|
||||
Locale::setLanguageFromJSON('ur', __DIR__ . '/config/locale/translations/ur.json');
|
||||
Locale::setLanguageFromJSON('vi', __DIR__ . '/config/locale/translations/vi.json');
|
||||
Locale::setLanguageFromJSON('zh-cn', __DIR__ . '/config/locale/translations/zh-cn.json');
|
||||
Locale::setLanguageFromJSON('zh-tw', __DIR__ . '/config/locale/translations/zh-tw.json');
|
||||
|
||||
\stream_context_set_default([ // Set global user agent and http settings
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'user_agent' => \sprintf(APP_USERAGENT,
|
||||
'user_agent' => \sprintf(
|
||||
APP_USERAGENT,
|
||||
App::getEnv('_APP_VERSION', 'UNKNOWN'),
|
||||
App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)),
|
||||
App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)
|
||||
),
|
||||
'timeout' => 2,
|
||||
],
|
||||
]);
|
||||
|
||||
// Runtime Execution
|
||||
App::setResource('logger', function($register) {
|
||||
App::setResource('logger', function ($register) {
|
||||
return $register->get('logger');
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('loggerBreadcrumbs', function() {
|
||||
App::setResource('loggerBreadcrumbs', function () {
|
||||
return [];
|
||||
});
|
||||
|
||||
App::setResource('register', fn() => $register);
|
||||
|
||||
App::setResource('layout', function($locale) {
|
||||
$layout = new View(__DIR__.'/views/layouts/default.phtml');
|
||||
App::setResource('layout', function ($locale) {
|
||||
$layout = new View(__DIR__ . '/views/layouts/default.phtml');
|
||||
$layout->setParam('locale', $locale);
|
||||
|
||||
return $layout;
|
||||
|
@ -654,7 +680,7 @@ App::setResource('audits', fn() => new Audit());
|
|||
App::setResource('mails', fn() => new Mail());
|
||||
App::setResource('deletes', fn() => new Delete());
|
||||
App::setResource('database', fn() => new EventDatabase());
|
||||
App::setResource('usage', function($register) {
|
||||
App::setResource('usage', function ($register) {
|
||||
return new Stats($register->get('statsd'));
|
||||
}, ['register']);
|
||||
|
||||
|
@ -694,7 +720,7 @@ App::setResource('clients', function ($request, $console, $project) {
|
|||
return $clients;
|
||||
}, ['request', 'console', 'project']);
|
||||
|
||||
App::setResource('user', function($mode, $project, $console, $request, $response, $dbForProject, $dbForConsole) {
|
||||
App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
@ -704,21 +730,28 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
|
||||
Authorization::setDefaultStatus(true);
|
||||
|
||||
Auth::setCookieName('a_session_'.$project->getId());
|
||||
Auth::setCookieName('a_session_' . $project->getId());
|
||||
|
||||
if (APP_MODE_ADMIN === $mode) {
|
||||
Auth::setCookieName('a_session_'.$console->getId());
|
||||
Auth::setCookieName('a_session_' . $console->getId());
|
||||
}
|
||||
|
||||
$session = Auth::decodeSession(
|
||||
$request->getCookie(Auth::$cookieName, // Get sessions
|
||||
$request->getCookie(Auth::$cookieName.'_legacy', '')));// Get fallback session from old clients (no SameSite support)
|
||||
$request->getCookie(
|
||||
Auth::$cookieName, // Get sessions
|
||||
$request->getCookie(Auth::$cookieName . '_legacy', '')
|
||||
)
|
||||
);// Get fallback session from old clients (no SameSite support)
|
||||
|
||||
// Get fallback session from clients who block 3rd-party cookies
|
||||
if($response) $response->addHeader('X-Debug-Fallback', 'false');
|
||||
if ($response) {
|
||||
$response->addHeader('X-Debug-Fallback', 'false');
|
||||
}
|
||||
|
||||
if(empty($session['id']) && empty($session['secret'])) {
|
||||
if($response) $response->addHeader('X-Debug-Fallback', 'true');
|
||||
if (empty($session['id']) && empty($session['secret'])) {
|
||||
if ($response) {
|
||||
$response->addHeader('X-Debug-Fallback', 'true');
|
||||
}
|
||||
$fallback = $request->getHeader('x-fallback-cookies', '');
|
||||
$fallback = \json_decode($fallback, true);
|
||||
$session = Auth::decodeSession(((isset($fallback[Auth::$cookieName])) ? $fallback[Auth::$cookieName] : ''));
|
||||
|
@ -730,17 +763,17 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
if (APP_MODE_ADMIN !== $mode) {
|
||||
if ($project->isEmpty()) {
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$user = $dbForProject->getDocument('users', Auth::$unique);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$user = $dbForConsole->getDocument('users', Auth::$unique);
|
||||
}
|
||||
|
||||
if ($user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)) { // Validate user has valid login token
|
||||
if (
|
||||
$user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)
|
||||
) { // Validate user has valid login token
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
|
||||
|
@ -760,13 +793,13 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
try {
|
||||
$payload = $jwt->decode($authJWT);
|
||||
} catch (JWTException $error) {
|
||||
throw new Exception('Failed to verify JWT. '.$error->getMessage(), 401, Exception::USER_JWT_INVALID);
|
||||
throw new Exception('Failed to verify JWT. ' . $error->getMessage(), 401, Exception::USER_JWT_INVALID);
|
||||
}
|
||||
|
||||
$jwtUserId = $payload['userId'] ?? '';
|
||||
$jwtSessionId = $payload['sessionId'] ?? '';
|
||||
|
||||
if($jwtUserId && $jwtSessionId) {
|
||||
if ($jwtUserId && $jwtSessionId) {
|
||||
$user = $dbForProject->getDocument('users', $jwtUserId);
|
||||
}
|
||||
|
||||
|
@ -778,14 +811,14 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
return $user;
|
||||
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForConsole']);
|
||||
|
||||
App::setResource('project', function($dbForConsole, $request, $console) {
|
||||
App::setResource('project', function ($dbForConsole, $request, $console) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
|
||||
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', 'console'));
|
||||
|
||||
if($projectId === 'console') {
|
||||
if ($projectId === 'console') {
|
||||
return $console;
|
||||
}
|
||||
|
||||
|
@ -794,7 +827,7 @@ App::setResource('project', function($dbForConsole, $request, $console) {
|
|||
return $project;
|
||||
}, ['dbForConsole', 'request', 'console']);
|
||||
|
||||
App::setResource('console', function() {
|
||||
App::setResource('console', function () {
|
||||
return new Document([
|
||||
'$id' => 'console',
|
||||
'name' => 'Appwrite',
|
||||
|
@ -826,7 +859,7 @@ App::setResource('console', function() {
|
|||
]);
|
||||
}, []);
|
||||
|
||||
App::setResource('dbForProject', function($db, $cache, $project) {
|
||||
App::setResource('dbForProject', function ($db, $cache, $project) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
|
@ -836,7 +869,7 @@ App::setResource('dbForProject', function($db, $cache, $project) {
|
|||
return $database;
|
||||
}, ['db', 'cache', 'project']);
|
||||
|
||||
App::setResource('dbForConsole', function($db, $cache) {
|
||||
App::setResource('dbForConsole', function ($db, $cache) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
|
@ -847,25 +880,27 @@ App::setResource('dbForConsole', function($db, $cache) {
|
|||
}, ['db', 'cache']);
|
||||
|
||||
|
||||
App::setResource('deviceLocal', function() {
|
||||
App::setResource('deviceLocal', function () {
|
||||
return new Local();
|
||||
});
|
||||
|
||||
App::setResource('deviceFiles', function($project) {
|
||||
App::setResource('deviceFiles', function ($project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceFunctions', function($project) {
|
||||
App::setResource('deviceFunctions', function ($project) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceBuilds', function($project) {
|
||||
App::setResource('deviceBuilds', function ($project) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
function getDevice($root): Device {
|
||||
function getDevice($root): Device
|
||||
{
|
||||
switch (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)) {
|
||||
case Storage::DEVICE_LOCAL:default:
|
||||
case Storage::DEVICE_LOCAL:
|
||||
default:
|
||||
return new Local($root);
|
||||
case Storage::DEVICE_S3:
|
||||
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
|
||||
|
@ -905,7 +940,7 @@ function getDevice($root): Device {
|
|||
}
|
||||
}
|
||||
|
||||
App::setResource('mode', function($request) {
|
||||
App::setResource('mode', function ($request) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
|
||||
/**
|
||||
|
@ -916,7 +951,7 @@ App::setResource('mode', function($request) {
|
|||
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));
|
||||
}, ['request']);
|
||||
|
||||
App::setResource('geodb', function($register) {
|
||||
App::setResource('geodb', function ($register) {
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
return $register->get('geodb');
|
||||
}, ['register']);
|
||||
|
|
|
@ -2,27 +2,28 @@
|
|||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
*
|
||||
* Inializes both Appwrite API entry point, queue workers, and CLI tasks.
|
||||
* Set configuration, framework resources, app constants
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
}
|
||||
|
||||
use Utopia\Preloader\Preloader;
|
||||
|
||||
include __DIR__.'/controllers/general.php';
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
|
||||
$preloader = new Preloader();
|
||||
|
||||
foreach ([
|
||||
foreach (
|
||||
[
|
||||
realpath(__DIR__ . '/../vendor/composer'),
|
||||
realpath(__DIR__ . '/../vendor/amphp'),
|
||||
realpath(__DIR__ . '/../vendor/felixfbecker'),
|
||||
|
@ -34,8 +35,9 @@ foreach ([
|
|||
realpath(__DIR__ . '/../vendor/symfony'),
|
||||
realpath(__DIR__ . '/../vendor/mongodb'),
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
|
||||
] as $key => $value) {
|
||||
if($value !== false) {
|
||||
] as $key => $value
|
||||
) {
|
||||
if ($value !== false) {
|
||||
$preloader->ignore($value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ function getDatabase(Registry &$register, string $namespace)
|
|||
$register->get('redisPool')->put($redis);
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument, $logError) {
|
||||
sleep(5); // wait for the initial database schema to be ready
|
||||
|
@ -197,7 +197,6 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
|||
* Sending current connections to project channels on the console project every 5 seconds.
|
||||
*/
|
||||
if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
|
||||
|
||||
[$database, $returnDatabase] = getDatabase($register, '_console');
|
||||
|
||||
$payload = [];
|
||||
|
|
|
@ -19,46 +19,41 @@ $cli
|
|||
/ \ ) __/ ) __/\ /\ / ) / )( )( ) _) _ )(( O )
|
||||
\_/\_/(__) (__) (_/\_)(__\_)(__) (__) (____)(_)(__)\__/ ");
|
||||
|
||||
Console::log("\n".'👩⚕️ Running '.APP_NAME.' Doctor for version '.App::getEnv('_APP_VERSION', 'UNKNOWN').' ...'."\n");
|
||||
Console::log("\n" . '👩⚕️ Running ' . APP_NAME . ' Doctor for version ' . App::getEnv('_APP_VERSION', 'UNKNOWN') . ' ...' . "\n");
|
||||
|
||||
Console::log('Checking for production best practices...');
|
||||
|
||||
$domain = new Domain(App::getEnv('_APP_DOMAIN'));
|
||||
|
||||
if(!$domain->isKnown() || $domain->isTest()) {
|
||||
Console::log('🔴 Hostname has no public suffix ('.$domain->get().')');
|
||||
}
|
||||
else {
|
||||
Console::log('🟢 Hostname has a public suffix ('.$domain->get().')');
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
Console::log('🔴 Hostname has no public suffix (' . $domain->get() . ')');
|
||||
} else {
|
||||
Console::log('🟢 Hostname has a public suffix (' . $domain->get() . ')');
|
||||
}
|
||||
|
||||
$domain = new Domain(App::getEnv('_APP_DOMAIN_TARGET'));
|
||||
|
||||
if(!$domain->isKnown() || $domain->isTest()) {
|
||||
Console::log('🔴 CNAME target has no public suffix ('.$domain->get().')');
|
||||
}
|
||||
else {
|
||||
Console::log('🟢 CNAME target has a public suffix ('.$domain->get().')');
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
Console::log('🔴 CNAME target has no public suffix (' . $domain->get() . ')');
|
||||
} else {
|
||||
Console::log('🟢 CNAME target has a public suffix (' . $domain->get() . ')');
|
||||
}
|
||||
|
||||
if(App::getEnv('_APP_OPENSSL_KEY_V1') === 'your-secret-key' || empty(App::getEnv('_APP_OPENSSL_KEY_V1'))) {
|
||||
if (App::getEnv('_APP_OPENSSL_KEY_V1') === 'your-secret-key' || empty(App::getEnv('_APP_OPENSSL_KEY_V1'))) {
|
||||
Console::log('🔴 Not using a unique secret key for encryption');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::log('🟢 Using a unique secret key for encryption');
|
||||
}
|
||||
|
||||
if(App::getEnv('_APP_ENV', 'development') !== 'production') {
|
||||
if (App::getEnv('_APP_ENV', 'development') !== 'production') {
|
||||
Console::log('🔴 App environment is set for development');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::log('🟢 App environment is set for production');
|
||||
}
|
||||
|
||||
if('enabled' !== App::getEnv('_APP_OPTIONS_ABUSE', 'disabled')) {
|
||||
if ('enabled' !== App::getEnv('_APP_OPTIONS_ABUSE', 'disabled')) {
|
||||
Console::log('🔴 Abuse protection is disabled');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::log('🟢 Abuse protection is enabled');
|
||||
}
|
||||
|
||||
|
@ -66,20 +61,19 @@ $cli
|
|||
$authWhitelistEmails = App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null);
|
||||
$authWhitelistIPs = App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null);
|
||||
|
||||
if(empty($authWhitelistRoot)
|
||||
if (
|
||||
empty($authWhitelistRoot)
|
||||
&& empty($authWhitelistEmails)
|
||||
&& empty($authWhitelistIPs)
|
||||
) {
|
||||
Console::log('🔴 Console access limits are disabled');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::log('🟢 Console access limits are enabled');
|
||||
}
|
||||
|
||||
if('enabled' !== App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled')) {
|
||||
if ('enabled' !== App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled')) {
|
||||
Console::log('🔴 HTTPS force option is disabled');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::log('🟢 HTTPS force option is enabled');
|
||||
}
|
||||
|
||||
|
@ -87,7 +81,7 @@ $cli
|
|||
$providerName = App::getEnv('_APP_LOGGING_PROVIDER', '');
|
||||
$providerConfig = App::getEnv('_APP_LOGGING_CONFIG', '');
|
||||
|
||||
if(empty($providerName) || empty($providerConfig) || !Logger::hasProvider($providerName)) {
|
||||
if (empty($providerName) || empty($providerConfig) || !Logger::hasProvider($providerName)) {
|
||||
Console::log('🔴 Logging adapter is disabled');
|
||||
} else {
|
||||
Console::log('🟢 Logging adapter is enabled (' . $providerName . ')');
|
||||
|
@ -96,7 +90,7 @@ $cli
|
|||
\sleep(0.2);
|
||||
|
||||
try {
|
||||
Console::log("\n".'Checking connectivity...');
|
||||
Console::log("\n" . 'Checking connectivity...');
|
||||
} catch (\Throwable $th) {
|
||||
//throw $th;
|
||||
}
|
||||
|
@ -122,15 +116,16 @@ $cli
|
|||
Console::error('Cache............disconnected 👎');
|
||||
}
|
||||
|
||||
if(App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled
|
||||
try {
|
||||
$antivirus = new Network(App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310));
|
||||
$antivirus = new Network(
|
||||
App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
if((@$antivirus->ping())) {
|
||||
if ((@$antivirus->ping())) {
|
||||
Console::success('Antivirus...........connected 👍');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::error('Antivirus........disconnected 👎');
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
|
@ -155,7 +150,7 @@ $cli
|
|||
$host = App::getEnv('_APP_STATSD_HOST', 'telegraf');
|
||||
$port = App::getEnv('_APP_STATSD_PORT', 8125);
|
||||
|
||||
if($fp = @\fsockopen('udp://'.$host, $port, $errCode, $errStr, 2)){
|
||||
if ($fp = @\fsockopen('udp://' . $host, $port, $errCode, $errStr, 2)) {
|
||||
Console::success('StatsD..............connected 👍');
|
||||
\fclose($fp);
|
||||
} else {
|
||||
|
@ -165,7 +160,7 @@ $cli
|
|||
$host = App::getEnv('_APP_INFLUXDB_HOST', '');
|
||||
$port = App::getEnv('_APP_INFLUXDB_PORT', '');
|
||||
|
||||
if($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)){
|
||||
if ($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)) {
|
||||
Console::success('InfluxDB............connected 👍');
|
||||
\fclose($fp);
|
||||
} else {
|
||||
|
@ -177,26 +172,26 @@ $cli
|
|||
Console::log('');
|
||||
Console::log('Checking volumes...');
|
||||
|
||||
foreach ([
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
] as $key => $volume) {
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
if (\is_readable($device->getRoot())) {
|
||||
Console::success('🟢 '.$key.' Volume is readable');
|
||||
}
|
||||
else {
|
||||
Console::error('🔴 '.$key.' Volume is unreadable');
|
||||
Console::success('🟢 ' . $key . ' Volume is readable');
|
||||
} else {
|
||||
Console::error('🔴 ' . $key . ' Volume is unreadable');
|
||||
}
|
||||
|
||||
if (\is_writable($device->getRoot())) {
|
||||
Console::success('🟢 '.$key.' Volume is writeable');
|
||||
}
|
||||
else {
|
||||
Console::error('🔴 '.$key.' Volume is unwriteable');
|
||||
Console::success('🟢 ' . $key . ' Volume is writeable');
|
||||
} else {
|
||||
Console::error('🔴 ' . $key . ' Volume is unwriteable');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,44 +200,44 @@ $cli
|
|||
Console::log('');
|
||||
Console::log('Checking disk space usage...');
|
||||
|
||||
foreach ([
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
] as $key => $volume) {
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
$percentage = (($device->getPartitionTotalSpace() - $device->getPartitionFreeSpace())
|
||||
/ $device->getPartitionTotalSpace()) * 100;
|
||||
|
||||
$message = $key.' Volume has '.Storage::human($device->getPartitionFreeSpace()) . ' free space ('.\round($percentage, 2).'% used)';
|
||||
$message = $key . ' Volume has ' . Storage::human($device->getPartitionFreeSpace()) . ' free space (' . \round($percentage, 2) . '% used)';
|
||||
|
||||
if ($percentage < 80) {
|
||||
Console::success('🟢 ' . $message);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Console::error('🔴 ' . $message);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if(App::isProduction()) {
|
||||
if (App::isProduction()) {
|
||||
Console::log('');
|
||||
$version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true);
|
||||
$version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost') . '/v1/health/version'), true);
|
||||
|
||||
if ($version && isset($version['version'])) {
|
||||
if(\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) {
|
||||
Console::info('You are running the latest version of '.APP_NAME.'! 🥳');
|
||||
}
|
||||
else {
|
||||
Console::info('A new version ('.$version['version'].') is available! 🥳'."\n");
|
||||
if (\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) {
|
||||
Console::info('You are running the latest version of ' . APP_NAME . '! 🥳');
|
||||
} else {
|
||||
Console::info('A new version (' . $version['version'] . ') is available! 🥳' . "\n");
|
||||
}
|
||||
} else {
|
||||
Console::error('Failed to check for a newer version'."\n");
|
||||
Console::error('Failed to check for a newer version' . "\n");
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Failed to check for a newer version'."\n");
|
||||
Console::error('Failed to check for a newer version' . "\n");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ $cli
|
|||
->param('httpsPort', '', new Text(4), 'Server HTTPS port', true)
|
||||
->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true)
|
||||
->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true)
|
||||
->param('interactive','Y', new Text(1), 'Run an interactive session', true)
|
||||
->param('interactive', 'Y', new Text(1), 'Run an interactive session', true)
|
||||
->action(function ($httpPort, $httpsPort, $organization, $image, $interactive) {
|
||||
/**
|
||||
* 1. Start - DONE
|
||||
|
@ -31,7 +31,7 @@ $cli
|
|||
* 2.4 Ask for all required vars not given as CLI args and if in interactive mode
|
||||
* Otherwise, just use default vars. - DONE
|
||||
* 3. Ask user to backup important volumes, env vars, and SQL tables
|
||||
* In th future we can try and automate this for smaller/medium size setups
|
||||
* In th future we can try and automate this for smaller/medium size setups
|
||||
* 4. Drop new docker-compose.yml setup (located inside the container, no network dependencies with appwrite.io) - DONE
|
||||
* 5. Run docker-compose up -d - DONE
|
||||
* 6. Run data migration
|
||||
|
@ -48,8 +48,8 @@ $cli
|
|||
*/
|
||||
$analytics = new GoogleAnalytics('UA-26264668-9', uniqid('server.', true));
|
||||
|
||||
foreach($config as $category) {
|
||||
foreach($category['variables'] ?? [] as $var) {
|
||||
foreach ($config as $category) {
|
||||
foreach ($category['variables'] ?? [] as $var) {
|
||||
$vars[] = $var;
|
||||
}
|
||||
}
|
||||
|
@ -59,17 +59,17 @@ $cli
|
|||
// Create directory with write permissions
|
||||
if (null !== $path && !\file_exists(\dirname($path))) {
|
||||
if (!@\mkdir(\dirname($path), 0755, true)) {
|
||||
Console::error('Can\'t create directory '.\dirname($path));
|
||||
Console::error('Can\'t create directory ' . \dirname($path));
|
||||
Console::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$data = @file_get_contents($path.'/docker-compose.yml');
|
||||
$data = @file_get_contents($path . '/docker-compose.yml');
|
||||
|
||||
if($data !== false) {
|
||||
if ($data !== false) {
|
||||
$time = \time();
|
||||
Console::info('Compose file found, creating backup: docker-compose.yml.'.$time.'.backup');
|
||||
file_put_contents($path.'/docker-compose.yml.'.$time.'.backup',$data);
|
||||
Console::info('Compose file found, creating backup: docker-compose.yml.' . $time . '.backup');
|
||||
file_put_contents($path . '/docker-compose.yml.' . $time . '.backup', $data);
|
||||
$compose = new Compose($data);
|
||||
$appwrite = $compose->getService('appwrite');
|
||||
$oldVersion = ($appwrite) ? $appwrite->getImageVersion() : null;
|
||||
|
@ -83,35 +83,39 @@ $cli
|
|||
Console::warning('Traefik not found. Falling back to default ports.');
|
||||
}
|
||||
|
||||
if($oldVersion) {
|
||||
foreach($compose->getServices() as $service) { // Fetch all env vars from previous compose file
|
||||
if(!$service) {
|
||||
if ($oldVersion) {
|
||||
foreach ($compose->getServices() as $service) { // Fetch all env vars from previous compose file
|
||||
if (!$service) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$env = $service->getEnvironment()->list();
|
||||
|
||||
foreach ($env as $key => $value) {
|
||||
if (is_null($value)) continue;
|
||||
foreach($vars as &$var) {
|
||||
if($var['name'] === $key) {
|
||||
if (is_null($value)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($vars as &$var) {
|
||||
if ($var['name'] === $key) {
|
||||
$var['default'] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = @file_get_contents($path.'/.env');
|
||||
$data = @file_get_contents($path . '/.env');
|
||||
|
||||
if($data !== false) { // Fetch all env vars from previous .env file
|
||||
Console::info('Env file found, creating backup: .env.'.$time.'.backup');
|
||||
file_put_contents($path.'/.env.'.$time.'.backup',$data);
|
||||
if ($data !== false) { // Fetch all env vars from previous .env file
|
||||
Console::info('Env file found, creating backup: .env.' . $time . '.backup');
|
||||
file_put_contents($path . '/.env.' . $time . '.backup', $data);
|
||||
$env = new Env($data);
|
||||
|
||||
foreach ($env->list() as $key => $value) {
|
||||
if (is_null($value)) continue;
|
||||
foreach($vars as &$var) {
|
||||
if($var['name'] === $key) {
|
||||
if (is_null($value)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($vars as &$var) {
|
||||
if ($var['name'] === $key) {
|
||||
$var['default'] = $value;
|
||||
}
|
||||
}
|
||||
|
@ -119,60 +123,60 @@ $cli
|
|||
}
|
||||
|
||||
foreach ($ports as $key => $value) {
|
||||
if($value === $defaultHTTPPort) {
|
||||
if ($value === $defaultHTTPPort) {
|
||||
$defaultHTTPPort = $key;
|
||||
}
|
||||
|
||||
if($value === $defaultHTTPSPort) {
|
||||
if ($value === $defaultHTTPSPort) {
|
||||
$defaultHTTPSPort = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($httpPort)) {
|
||||
$httpPort = Console::confirm('Choose your server HTTP port: (default: '.$defaultHTTPPort.')');
|
||||
if (empty($httpPort)) {
|
||||
$httpPort = Console::confirm('Choose your server HTTP port: (default: ' . $defaultHTTPPort . ')');
|
||||
$httpPort = ($httpPort) ? $httpPort : $defaultHTTPPort;
|
||||
}
|
||||
|
||||
if(empty($httpsPort)) {
|
||||
$httpsPort = Console::confirm('Choose your server HTTPS port: (default: '.$defaultHTTPSPort.')');
|
||||
if (empty($httpsPort)) {
|
||||
$httpsPort = Console::confirm('Choose your server HTTPS port: (default: ' . $defaultHTTPSPort . ')');
|
||||
$httpsPort = ($httpsPort) ? $httpsPort : $defaultHTTPSPort;
|
||||
}
|
||||
|
||||
$input = [];
|
||||
|
||||
foreach($vars as $key => $var) {
|
||||
if(!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) {
|
||||
if($data && $var['default'] !== null) {
|
||||
foreach ($vars as $key => $var) {
|
||||
if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) {
|
||||
if ($data && $var['default'] !== null) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if($var['filter'] === 'token') {
|
||||
if ($var['filter'] === 'token') {
|
||||
$input[$var['name']] = Auth::tokenGenerator();
|
||||
continue;
|
||||
}
|
||||
|
||||
if($var['filter'] === 'password') {
|
||||
if ($var['filter'] === 'password') {
|
||||
$input[$var['name']] = Auth::passwordGenerator();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!$var['required'] || !Console::isInteractive() || $interactive !== 'Y') {
|
||||
if (!$var['required'] || !Console::isInteractive() || $interactive !== 'Y') {
|
||||
$input[$var['name']] = $var['default'];
|
||||
continue;
|
||||
}
|
||||
|
||||
$input[$var['name']] = Console::confirm($var['question'].' (default: \''.$var['default'].'\')');
|
||||
$input[$var['name']] = Console::confirm($var['question'] . ' (default: \'' . $var['default'] . '\')');
|
||||
|
||||
if(empty($input[$var['name']])) {
|
||||
if (empty($input[$var['name']])) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
}
|
||||
}
|
||||
|
||||
$templateForCompose = new View(__DIR__.'/../views/install/compose.phtml');
|
||||
$templateForEnv = new View(__DIR__.'/../views/install/env.phtml');
|
||||
$templateForCompose = new View(__DIR__ . '/../views/install/compose.phtml');
|
||||
$templateForEnv = new View(__DIR__ . '/../views/install/env.phtml');
|
||||
|
||||
$templateForCompose
|
||||
->setParam('httpPort', $httpPort)
|
||||
|
@ -186,16 +190,16 @@ $cli
|
|||
->setParam('vars', $input)
|
||||
;
|
||||
|
||||
if(!file_put_contents($path.'/docker-compose.yml', $templateForCompose->render(false))) {
|
||||
if (!file_put_contents($path . '/docker-compose.yml', $templateForCompose->render(false))) {
|
||||
$message = 'Failed to save Docker Compose file';
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message);
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message);
|
||||
Console::error($message);
|
||||
Console::exit(1);
|
||||
}
|
||||
|
||||
if(!file_put_contents($path.'/.env', $templateForEnv->render(false))) {
|
||||
if (!file_put_contents($path . '/.env', $templateForEnv->render(false))) {
|
||||
$message = 'Failed to save environment variables file';
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message);
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message);
|
||||
Console::error($message);
|
||||
Console::exit(1);
|
||||
}
|
||||
|
@ -205,8 +209,8 @@ $cli
|
|||
$stderr = '';
|
||||
|
||||
foreach ($input as $key => $value) {
|
||||
if($value) {
|
||||
$env .= $key.'='.\escapeshellarg($value).' ';
|
||||
if ($value) {
|
||||
$env .= $key . '=' . \escapeshellarg($value) . ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,13 +220,13 @@ $cli
|
|||
|
||||
if ($exit !== 0) {
|
||||
$message = 'Failed to install Appwrite dockers';
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message);
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message);
|
||||
Console::error($message);
|
||||
Console::error($stderr);
|
||||
Console::exit($exit);
|
||||
} else {
|
||||
$message = 'Appwrite installed successfully';
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message);
|
||||
$analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message);
|
||||
Console::success($message);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ $cli
|
|||
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
|
||||
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
|
||||
|
||||
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', 'latest'])) {
|
||||
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', 'latest'])) {
|
||||
throw new Exception('Unknown version given');
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ $cli
|
|||
$response = new Response(new HttpResponse());
|
||||
$mocks = ($mode === 'mocks');
|
||||
|
||||
App::setResource('request', fn () => new Request);
|
||||
App::setResource('request', fn () => new Request());
|
||||
App::setResource('response', fn () => $response);
|
||||
App::setResource('db', fn () => $db);
|
||||
App::setResource('cache', fn () => $redis);
|
||||
|
@ -125,7 +125,6 @@ $cli
|
|||
|
||||
foreach (['swagger2', 'open-api3'] as $format) {
|
||||
foreach ($platforms as $platform) {
|
||||
|
||||
$routes = [];
|
||||
$models = [];
|
||||
$services = [];
|
||||
|
|
|
@ -36,7 +36,7 @@ use Utopia\Database\Validator\Authorization;
|
|||
* database.collections.{collectionId}.documents.delete
|
||||
*
|
||||
* Storage
|
||||
*
|
||||
*
|
||||
* storage.buckets.create
|
||||
* storage.buckets.read
|
||||
* storage.buckets.update
|
||||
|
@ -285,7 +285,7 @@ $cli
|
|||
try {
|
||||
$attempts++;
|
||||
$database = $client->selectDB('telegraf');
|
||||
if(in_array('telegraf', $client->listDatabases())) {
|
||||
if (in_array('telegraf', $client->listDatabases())) {
|
||||
break; // leave the do-while if successful
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
|
@ -386,7 +386,7 @@ $cli
|
|||
*/
|
||||
$now = date('d-m-Y H:i:s', time());
|
||||
Console::info("[{$now}] Aggregating database counters.");
|
||||
|
||||
|
||||
$latestProject = null;
|
||||
do { // Loop over all the projects
|
||||
$attempts = 0;
|
||||
|
@ -424,7 +424,6 @@ $cli
|
|||
$id = \md5($time . '_30m_storage.deployments.total'); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
try {
|
||||
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
|
@ -460,7 +459,7 @@ $cli
|
|||
$document->setAttribute('value', $deploymentsTotal)
|
||||
);
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
Console::warning("Failed to save data for project {$projectId} and metric storage.deployments.total: {$e->getMessage()}");
|
||||
Console::warning($e->getTraceAsString());
|
||||
}
|
||||
|
@ -614,7 +613,7 @@ $cli
|
|||
|
||||
// check if sum calculation is required
|
||||
$total = $subOptions['total'] ?? [];
|
||||
if(empty($total)) {
|
||||
if (empty($total)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -639,8 +638,11 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $total));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $total)
|
||||
);
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
|
@ -656,10 +658,12 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $total));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $total)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} while (!empty($parents));
|
||||
|
@ -734,8 +738,11 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $count)
|
||||
);
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
|
@ -751,12 +758,15 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $count)
|
||||
);
|
||||
}
|
||||
|
||||
// aggregate storage.total = storage.files.total + storage.deployments.total
|
||||
if($metricPrefix === 'storage' && $subCollection === 'files') {
|
||||
if ($metricPrefix === 'storage' && $subCollection === 'files') {
|
||||
$metric = 'storage.total';
|
||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
|
@ -771,8 +781,11 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count + $deploymentsTotal));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $count + $deploymentsTotal)
|
||||
);
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
|
@ -788,8 +801,11 @@ $cli
|
|||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count + $deploymentsTotal));
|
||||
$dbForProject->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $count + $deploymentsTotal)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -807,4 +823,4 @@ $cli
|
|||
|
||||
Console::info("[{$now}] Aggregation took {$loopTook} seconds");
|
||||
}, $interval);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,13 +13,13 @@ $cli
|
|||
$config = Config::getParam('variables', []);
|
||||
$vars = [];
|
||||
|
||||
foreach($config as $category) {
|
||||
foreach($category['variables'] ?? [] as $var) {
|
||||
foreach ($config as $category) {
|
||||
foreach ($category['variables'] ?? [] as $var) {
|
||||
$vars[] = $var;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($vars as $key => $value) {
|
||||
Console::log('- '.$value['name'].'='.App::getEnv($value['name'], ''));
|
||||
Console::log('- ' . $value['name'] . '=' . App::getEnv($value['name'], ''));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -174,7 +174,7 @@ class BuildsV1 extends Worker
|
|||
$build->setAttribute('status', $response['status']);
|
||||
$build->setAttribute('outputPath', $response['outputPath']);
|
||||
$build->setAttribute('stderr', $response['stderr']);
|
||||
$build->setAttribute('stdout', $response['stdout']);
|
||||
$build->setAttribute('stdout', $response['response']);
|
||||
|
||||
Console::success("Build id: $buildId created");
|
||||
|
||||
|
@ -200,7 +200,7 @@ class BuildsV1 extends Worker
|
|||
} finally {
|
||||
$build = $dbForProject->updateDocument('builds', $buildId, $build);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Send realtime Event
|
||||
*/
|
||||
$target = Realtime::fromPayload(
|
||||
|
|
|
@ -18,10 +18,9 @@ Console::success(APP_NAME . ' certificates worker v1 has started');
|
|||
|
||||
class CertificatesV1 extends Worker
|
||||
{
|
||||
|
||||
/**
|
||||
* Database connection shared across all methods of this file
|
||||
*
|
||||
*
|
||||
* @var Database
|
||||
*/
|
||||
private Database $dbForConsole;
|
||||
|
@ -52,20 +51,20 @@ class CertificatesV1 extends Worker
|
|||
* 10. Create/Update our Storage with new Traefik config with new certificate paths
|
||||
* 11. Read certificate file and update 'renewDate' on certificate document
|
||||
* 12. Update 'issueDate' and 'attempts' on certificate
|
||||
*
|
||||
*
|
||||
* If at any point unexpected error occurs, program stops without applying changes to document, and error is thrown into worker
|
||||
*
|
||||
*
|
||||
* If code stops with expected error:
|
||||
* 1. 'log' attribute on document is updated with error message
|
||||
* 2. 'attempts' amount is increased
|
||||
* 3. Console log is shown
|
||||
* 4. Email is sent to security email
|
||||
*
|
||||
*
|
||||
* Unless unexpected error occurs, at the end, we:
|
||||
* 1. Update 'updated' attribute on document
|
||||
* 2. Save document to database
|
||||
* 3. Update all domains documents with current certificate ID
|
||||
*
|
||||
*
|
||||
* Note: Renewals are checked and scheduled from maintenence worker
|
||||
*/
|
||||
|
||||
|
@ -148,7 +147,7 @@ class CertificatesV1 extends Worker
|
|||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function saveCertificateDocument(string $domain, Document $certificate): void
|
||||
|
|
|
@ -7,10 +7,10 @@ use Utopia\CLI\Console;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
Console::title('Database V1 Worker');
|
||||
Console::success(APP_NAME.' database worker v1 has started'."\n");
|
||||
Console::success(APP_NAME . ' database worker v1 has started' . "\n");
|
||||
|
||||
class DatabaseV1 extends Worker
|
||||
{
|
||||
|
@ -27,11 +27,11 @@ class DatabaseV1 extends Worker
|
|||
$collection = new Document($this->args['collection'] ?? []);
|
||||
$document = new Document($this->args['document'] ?? []);
|
||||
|
||||
if($collection->isEmpty()) {
|
||||
if ($collection->isEmpty()) {
|
||||
throw new Exception('Missing collection');
|
||||
}
|
||||
|
||||
if($document->isEmpty()) {
|
||||
if ($document->isEmpty()) {
|
||||
throw new Exception('Missing document');
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,9 @@ class DatabaseV1 extends Worker
|
|||
break;
|
||||
|
||||
default:
|
||||
Console::error('No database operation for type: '.$type);
|
||||
Console::error('No database operation for type: ' . $type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Authorization::reset();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ class DatabaseV1 extends Worker
|
|||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if(!$dbForProject->createAttribute('collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
if (!$dbForProject->createAttribute('collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
throw new Exception('Failed to create Attribute');
|
||||
}
|
||||
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
|
||||
|
@ -151,7 +151,7 @@ class DatabaseV1 extends Worker
|
|||
// - failed: attribute was never created
|
||||
// - stuck: attribute was available but cannot be removed
|
||||
try {
|
||||
if($status !== 'failed' && !$dbForProject->deleteAttribute('collection_' . $collection->getInternalId(), $key)) {
|
||||
if ($status !== 'failed' && !$dbForProject->deleteAttribute('collection_' . $collection->getInternalId(), $key)) {
|
||||
throw new Exception('Failed to delete Attribute');
|
||||
}
|
||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||
|
@ -194,7 +194,7 @@ class DatabaseV1 extends Worker
|
|||
|
||||
if ($found !== false) {
|
||||
// If found, remove entry from attributes, lengths, and orders
|
||||
// array_values wraps array_diff to reindex array keys
|
||||
// array_values wraps array_diff to reindex array keys
|
||||
// when found attribute is removed from array
|
||||
$attributes = \array_values(\array_diff($attributes, [$attributes[$found]]));
|
||||
$lengths = \array_values(\array_diff($lengths, [$lengths[$found]]));
|
||||
|
@ -212,7 +212,8 @@ class DatabaseV1 extends Worker
|
|||
// Check if an index exists with the same attributes and orders
|
||||
$exists = false;
|
||||
foreach ($indexes as $existing) {
|
||||
if ($existing->getAttribute('key') !== $index->getAttribute('key') // Ignore itself
|
||||
if (
|
||||
$existing->getAttribute('key') !== $index->getAttribute('key') // Ignore itself
|
||||
&& $existing->getAttribute('attributes') === $index->getAttribute('attributes')
|
||||
&& $existing->getAttribute('orders') === $index->getAttribute('orders')
|
||||
) {
|
||||
|
@ -221,7 +222,7 @@ class DatabaseV1 extends Worker
|
|||
}
|
||||
}
|
||||
|
||||
if ($exists) { // Delete the duplicate if created, else update in db
|
||||
if ($exists) { // Delete the duplicate if created, else update in db
|
||||
$this->deleteIndex($collection, $index, $projectId);
|
||||
} else {
|
||||
$dbForProject->updateDocument('indexes', $index->getId(), $index);
|
||||
|
@ -257,7 +258,7 @@ class DatabaseV1 extends Worker
|
|||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if(!$dbForProject->createIndex('collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
if (!$dbForProject->createIndex('collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
throw new Exception('Failed to create Index');
|
||||
}
|
||||
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available'));
|
||||
|
@ -307,7 +308,7 @@ class DatabaseV1 extends Worker
|
|||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if($status !== 'failed' && !$dbForProject->deleteIndex('collection_' . $collection->getInternalId(), $key)) {
|
||||
if ($status !== 'failed' && !$dbForProject->deleteIndex('collection_' . $collection->getInternalId(), $key)) {
|
||||
throw new Exception('Failed to delete index');
|
||||
}
|
||||
$dbForProject->deleteDocument('indexes', $index->getId());
|
||||
|
|
|
@ -358,7 +358,7 @@ class DeletesV1 extends Worker
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Delete Executions
|
||||
*/
|
||||
Console::info("Deleting executions for function " . $functionId);
|
||||
|
@ -523,7 +523,7 @@ class DeletesV1 extends Worker
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Document $document certificates document
|
||||
* @param Document $document certificates document
|
||||
*/
|
||||
protected function deleteCertificates(Document $document): void
|
||||
{
|
||||
|
@ -574,8 +574,8 @@ class DeletesV1 extends Worker
|
|||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
|
||||
|
||||
$device = $this->getDevice(APP_STORAGE_UPLOADS.'/app-'.$projectId);
|
||||
|
||||
$device = $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId);
|
||||
|
||||
$device->deletePath($document->getId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ Console::success(APP_NAME . ' mails worker v1 has started' . "\n");
|
|||
|
||||
class MailsV1 extends Worker
|
||||
{
|
||||
public function getName(): string {
|
||||
public function getName(): string
|
||||
{
|
||||
return "mails";
|
||||
}
|
||||
|
||||
|
@ -131,9 +132,9 @@ class MailsV1 extends Worker
|
|||
|
||||
/**
|
||||
* Returns a prefix from a mail type
|
||||
*
|
||||
*
|
||||
* @param $type
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrefix(string $type): string
|
||||
|
@ -156,10 +157,10 @@ class MailsV1 extends Worker
|
|||
|
||||
/**
|
||||
* Returns true if all the required terms in a locale exist. False otherwise
|
||||
*
|
||||
*
|
||||
* @param $locale
|
||||
* @param $prefix
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function doesLocaleExist(Locale $locale, string $prefix): bool
|
||||
|
|
|
@ -62,7 +62,8 @@
|
|||
"phpmailer/phpmailer": "6.6.0",
|
||||
"chillerlan/php-qrcode": "4.3.3",
|
||||
"adhocore/jwt": "1.1.2",
|
||||
"slickdeals/statsd": "3.1.0"
|
||||
"slickdeals/statsd": "3.1.0",
|
||||
"squizlabs/php_codesniffer": "^3.6"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
|
|
60
composer.lock
generated
60
composer.lock
generated
|
@ -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": "6764d068d2f6aa5e9eb8befd84c0c2c9",
|
||||
"content-hash": "33d139681a16da8436756e9b5a27f745",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -1581,6 +1581,62 @@
|
|||
},
|
||||
"time": "2021-06-04T20:33:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a",
|
||||
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpcs",
|
||||
"bin/phpcbf"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Greg Sherwood",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
|
||||
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
|
||||
},
|
||||
"time": "2021-12-12T21:44:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.0.1",
|
||||
|
@ -6576,5 +6632,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Once you add the dependencies, its extremely easy to get started with the SDK; A
|
|||
import 'package:dart_appwrite/dart_appwrite.dart';
|
||||
|
||||
void main() async {
|
||||
Client client = Client();
|
||||
Client client = Client()
|
||||
.setEndpoint('http://[HOSTNAME_OR_IP]/v1') // Make sure your endpoint is accessible
|
||||
.setProject('5ff3379a01d25') // Your project ID
|
||||
.setKey('cd868c7af8bdc893b4...93b7535db89')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="true"
|
||||
stopOnFailure="false"
|
||||
>
|
||||
<extensions>
|
||||
<extension class="Appwrite\Tests\TestHook" />
|
||||
|
@ -35,4 +35,4 @@
|
|||
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
</phpunit>
|
||||
|
|
|
@ -163,7 +163,7 @@ class Auth
|
|||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function passwordGenerator(int $length = 20):string
|
||||
public static function passwordGenerator(int $length = 20): string
|
||||
{
|
||||
return \bin2hex(\random_bytes($length));
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ class Auth
|
|||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function tokenGenerator(int $length = 128):string
|
||||
public static function tokenGenerator(int $length = 128): string
|
||||
{
|
||||
return \bin2hex(\random_bytes($length));
|
||||
}
|
||||
|
@ -196,12 +196,14 @@ class Auth
|
|||
public static function tokenVerify(array $tokens, int $type, string $secret)
|
||||
{
|
||||
foreach ($tokens as $token) { /** @var Document $token */
|
||||
if ($token->isSet('type') &&
|
||||
if (
|
||||
$token->isSet('type') &&
|
||||
$token->isSet('secret') &&
|
||||
$token->isSet('expire') &&
|
||||
$token->getAttribute('type') == $type &&
|
||||
$token->getAttribute('secret') === self::hash($secret) &&
|
||||
$token->getAttribute('expire') >= \time()) {
|
||||
$token->getAttribute('expire') >= \time()
|
||||
) {
|
||||
return (string)$token->getId();
|
||||
}
|
||||
}
|
||||
|
@ -220,11 +222,13 @@ class Auth
|
|||
public static function sessionVerify(array $sessions, string $secret)
|
||||
{
|
||||
foreach ($sessions as $session) { /** @var Document $session */
|
||||
if ($session->isSet('secret') &&
|
||||
if (
|
||||
$session->isSet('secret') &&
|
||||
$session->isSet('expire') &&
|
||||
$session->isSet('provider') &&
|
||||
$session->getAttribute('secret') === self::hash($secret) &&
|
||||
$session->getAttribute('expire') >= \time()) {
|
||||
$session->getAttribute('expire') >= \time()
|
||||
) {
|
||||
return (string)$session->getId();
|
||||
}
|
||||
}
|
||||
|
@ -242,9 +246,9 @@ class Auth
|
|||
public static function isPrivilegedUser(array $roles): bool
|
||||
{
|
||||
if (
|
||||
in_array('role:'.self::USER_ROLE_OWNER, $roles) ||
|
||||
in_array('role:'.self::USER_ROLE_DEVELOPER, $roles) ||
|
||||
in_array('role:'.self::USER_ROLE_ADMIN, $roles)
|
||||
in_array('role:' . self::USER_ROLE_OWNER, $roles) ||
|
||||
in_array('role:' . self::USER_ROLE_DEVELOPER, $roles) ||
|
||||
in_array('role:' . self::USER_ROLE_ADMIN, $roles)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@ -261,7 +265,7 @@ class Auth
|
|||
*/
|
||||
public static function isAppUser(array $roles): bool
|
||||
{
|
||||
if (in_array('role:'.self::USER_ROLE_APP, $roles)) {
|
||||
if (in_array('role:' . self::USER_ROLE_APP, $roles)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -280,10 +284,10 @@ class Auth
|
|||
|
||||
if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) {
|
||||
if ($user->getId()) {
|
||||
$roles[] = 'user:'.$user->getId();
|
||||
$roles[] = 'role:'.Auth::USER_ROLE_MEMBER;
|
||||
$roles[] = 'user:' . $user->getId();
|
||||
$roles[] = 'role:' . Auth::USER_ROLE_MEMBER;
|
||||
} else {
|
||||
return ['role:'.Auth::USER_ROLE_GUEST];
|
||||
return ['role:' . Auth::USER_ROLE_GUEST];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,9 +82,9 @@ abstract class OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isEmailVerified(string $accessToken): bool;
|
||||
|
@ -189,7 +189,7 @@ abstract class OAuth2
|
|||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
}
|
||||
|
||||
$headers[] = 'Content-length: '.\strlen($payload);
|
||||
$headers[] = 'Content-length: ' . \strlen($payload);
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
// Send the request & save response to $response
|
||||
|
|
|
@ -140,11 +140,11 @@ class Amazon extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Amazon sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -137,11 +137,11 @@ class Apple extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://developer.apple.com/forums/thread/121411
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -132,11 +132,11 @@ class Auth0 extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://auth0.com/docs/api/authentication?javascript#user-profile
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
@ -180,7 +180,7 @@ class Auth0 extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Client Secret from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getClientSecret(): string
|
||||
|
@ -192,7 +192,7 @@ class Auth0 extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Auth0 Domain from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuth0Domain(): string
|
||||
|
@ -204,7 +204,7 @@ class Auth0 extends OAuth2
|
|||
|
||||
/**
|
||||
* Decode the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
|
|
|
@ -124,9 +124,9 @@ class Bitbucket extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -9,7 +9,6 @@ use Appwrite\Auth\OAuth2;
|
|||
|
||||
class Bitly extends OAuth2
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -149,11 +148,11 @@ class Bitly extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://dev.bitly.com/api-reference#getUser
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -141,11 +141,11 @@ class Box extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Box sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -18,7 +18,7 @@ class Discord extends OAuth2
|
|||
* @var array
|
||||
*/
|
||||
protected array $user = [];
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
@ -45,7 +45,7 @@ class Discord extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . '/oauth2/authorize?'.
|
||||
$url = $this->endpoint . '/oauth2/authorize?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
|
@ -64,7 +64,7 @@ class Discord extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth2/token',
|
||||
|
@ -88,7 +88,7 @@ class Discord extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -102,7 +102,7 @@ class Discord extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -135,11 +135,11 @@ class Discord extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://discord.com/developers/docs/resources/user
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
@ -176,7 +176,7 @@ class Discord extends OAuth2
|
|||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/users/@me',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
|
|
@ -125,11 +125,11 @@ class Dropbox extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -122,11 +122,11 @@ class Facebook extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Facebook sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -128,11 +128,11 @@ class Github extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -125,11 +125,11 @@ class Gitlab extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -131,11 +131,11 @@ class Google extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -137,11 +137,11 @@ class Linkedin extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Linkedin sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -131,11 +131,11 @@ class Microsoft extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Microsoft sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
@ -175,7 +175,7 @@ class Microsoft extends OAuth2
|
|||
|
||||
/**
|
||||
* Decode the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
|
@ -190,7 +190,7 @@ class Microsoft extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Client Secret from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getClientSecret(): string
|
||||
|
@ -202,7 +202,7 @@ class Microsoft extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTenantID(): string
|
||||
|
|
|
@ -124,9 +124,9 @@ class Mock extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -128,11 +128,11 @@ class Notion extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Notion sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -132,11 +132,11 @@ class Okta extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://developer.okta.com/docs/reference/api/oidc/#userinfo
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
@ -180,7 +180,7 @@ class Okta extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Client Secret from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getClientSecret(): string
|
||||
|
@ -192,7 +192,7 @@ class Okta extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Okta Domain from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getOktaDomain(): string
|
||||
|
@ -204,7 +204,7 @@ class Okta extends OAuth2
|
|||
|
||||
/**
|
||||
* Extracts the Okta Authorization Server ID from the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthorizationServerId(): string
|
||||
|
@ -216,7 +216,7 @@ class Okta extends OAuth2
|
|||
|
||||
/**
|
||||
* Decode the JSON stored in appSecret
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
|
|
|
@ -158,11 +158,11 @@ class Paypal extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -142,11 +142,11 @@ class Salesforce extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -121,13 +121,13 @@ class Slack extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Slack sign up process
|
||||
*
|
||||
*
|
||||
* @link https://slack.com/help/articles/207262907-Change-your-email-address
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
@ -151,7 +151,7 @@ class Slack extends OAuth2
|
|||
|
||||
/**
|
||||
* @link https://api.slack.com/methods/users.identity
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
|
|
|
@ -9,7 +9,6 @@ use Appwrite\Auth\OAuth2;
|
|||
|
||||
class Spotify extends OAuth2
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -135,13 +134,13 @@ class Spotify extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* Spotify does not assure that the email is verified
|
||||
*
|
||||
*
|
||||
* Spotify does not assure that the email is verified
|
||||
*
|
||||
* @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -138,11 +138,11 @@ class Stripe extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Stripe sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -42,7 +42,7 @@ class Tradeshift extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array$scopes = [
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'offline',
|
||||
];
|
||||
|
@ -145,11 +145,11 @@ class Tradeshift extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Tradeshift sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -9,7 +9,6 @@ use Appwrite\Auth\OAuth2;
|
|||
|
||||
class Twitch extends OAuth2
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -134,13 +133,13 @@ class Twitch extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified
|
||||
*
|
||||
*
|
||||
* @link https://dev.twitch.tv/docs/api/reference#get-users
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -129,11 +129,11 @@ class WordPress extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://developer.wordpress.com/docs/api/1.1/get/me/
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -9,7 +9,6 @@ use Appwrite\Auth\OAuth2;
|
|||
|
||||
class Yahoo extends OAuth2
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -155,11 +154,11 @@ class Yahoo extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Yahoo sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -124,11 +124,11 @@ class Yammer extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Yammer sign up process
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -138,9 +138,9 @@ class Yandex extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -30,7 +30,7 @@ class Zoom extends OAuth2
|
|||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'user_profile'
|
||||
'user_info:read'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -130,11 +130,11 @@ class Zoom extends OAuth2
|
|||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
*
|
||||
* @link https://marketplace.zoom.us/docs/api-reference/zoom-api/methods/#operation/user
|
||||
*
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
|
|
|
@ -34,7 +34,7 @@ class Password extends Validator
|
|||
{
|
||||
if (!\is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (\strlen($value) < 8) {
|
||||
return false;
|
||||
|
|
|
@ -21,7 +21,7 @@ class Compose
|
|||
|
||||
$this->compose['services'] = (isset($this->compose['services']) && is_array($this->compose['services']))
|
||||
? $this->compose['services'] : [];
|
||||
|
||||
|
||||
foreach ($this->compose['services'] as $key => &$service) {
|
||||
$service = new Service($service);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class Service
|
|||
public function __construct(array $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
|
||||
|
||||
$ports = (isset($this->service['ports']) && is_array($this->service['ports'])) ? $this->service['ports'] : [];
|
||||
$this->service['ports'] = [];
|
||||
|
||||
|
@ -54,7 +54,7 @@ class Service
|
|||
public function getImageVersion(): string
|
||||
{
|
||||
$image = $this->getImage();
|
||||
return substr($image, ((int)strpos($image, ':'))+1);
|
||||
return substr($image, ((int)strpos($image, ':')) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,7 +70,7 @@ class Env
|
|||
$output = '';
|
||||
|
||||
foreach ($this->vars as $key => $value) {
|
||||
$output .= $key.'='.$value."\n";
|
||||
$output .= $key . '=' . $value . "\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
|
|
@ -127,4 +127,4 @@ class Audit extends Event
|
|||
'events' => Event::generateEvents($this->getEvent(), $this->getParams())
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class Build extends Event
|
|||
/**
|
||||
* Returns set resource document for the build event.
|
||||
*
|
||||
* @return null|Document
|
||||
* @return null|Document
|
||||
*/
|
||||
public function getResource(): ?Document
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@ class Database extends Event
|
|||
|
||||
/**
|
||||
* Returns the set type for the database event.
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
|
@ -100,4 +100,4 @@ class Database extends Event
|
|||
'events' => Event::generateEvents($this->getEvent(), $this->getParams())
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class Delete extends Event
|
|||
/**
|
||||
* Returns the set type for the delete event.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
|
|
|
@ -392,7 +392,9 @@ class Event
|
|||
$events[] = \str_replace($paramKeys, '*', $eventPattern);
|
||||
foreach ($paramKeys as $key) {
|
||||
foreach ($paramKeys as $current) {
|
||||
if ($current === $key) continue;
|
||||
if ($current === $key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filtered = \array_filter($paramKeys, fn(string $k) => $k === $current);
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern));
|
||||
|
|
|
@ -36,7 +36,7 @@ class Func extends Event
|
|||
/**
|
||||
* Returns set function document for the function event.
|
||||
*
|
||||
* @return null|Document
|
||||
* @return null|Document
|
||||
*/
|
||||
public function getFunction(): ?Document
|
||||
{
|
||||
|
|
|
@ -6,10 +6,10 @@ class Exception extends \Exception
|
|||
{
|
||||
/**
|
||||
* Error Codes
|
||||
*
|
||||
* Naming the error types based on the following convention
|
||||
*
|
||||
* Naming the error types based on the following convention
|
||||
* <ENTITY>_<ERROR_TYPE>
|
||||
*
|
||||
*
|
||||
* Appwrite has the follwing entities:
|
||||
* - General
|
||||
* - Users
|
||||
|
@ -73,7 +73,7 @@ class Exception extends \Exception
|
|||
const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found';
|
||||
const TEAM_INVALID_SECRET = 'team_invalid_secret';
|
||||
const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch';
|
||||
const TEAM_INVITE_MISMATCH = 'team_invite_mismatch';
|
||||
const TEAM_INVITE_MISMATCH = 'team_invite_mismatch';
|
||||
|
||||
/** Membership */
|
||||
const MEMBERSHIP_NOT_FOUND = 'membership_not_found';
|
||||
|
@ -116,7 +116,7 @@ class Exception extends \Exception
|
|||
const COLLECTION_NOT_FOUND = 'collection_not_found';
|
||||
const COLLECTION_ALREADY_EXISTS = 'collection_already_exists';
|
||||
const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded';
|
||||
|
||||
|
||||
/** Documents */
|
||||
const DOCUMENT_NOT_FOUND = 'document_not_found';
|
||||
const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure';
|
||||
|
@ -175,9 +175,9 @@ class Exception extends \Exception
|
|||
|
||||
/**
|
||||
* Get the type of the exception.
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
|
@ -185,14 +185,13 @@ class Exception extends \Exception
|
|||
|
||||
/**
|
||||
* Set the type of the exception.
|
||||
*
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setType(string $type): void
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,8 +99,8 @@ class PDO extends PDONative
|
|||
{
|
||||
$this->pdo = new PDONative($this->dsn, $this->username, $this->passwd, $this->options);
|
||||
|
||||
echo '[PDO] MySQL connection restarted'.PHP_EOL;
|
||||
|
||||
echo '[PDO] MySQL connection restarted' . PHP_EOL;
|
||||
|
||||
// Connection settings
|
||||
$this->pdo->setAttribute(PDONative::ATTR_DEFAULT_FETCH_MODE, PDONative::FETCH_ASSOC); // Return arrays
|
||||
$this->pdo->setAttribute(PDONative::ATTR_ERRMODE, PDONative::ERRMODE_EXCEPTION); // Handle all errors with exceptions
|
||||
|
|
|
@ -76,7 +76,7 @@ class PDOStatement extends PDOStatementNative
|
|||
foreach ($this->values as $key => $set) {
|
||||
$this->PDOStatement->bindValue($key, $set['value'], $set['data_type']);
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->params as $key => $set) {
|
||||
$this->PDOStatement->bindParam($key, $set['variable'], $set['data_type'], $set['length'], $set['driver_options']);
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ class PDOStatement extends PDOStatementNative
|
|||
public function fetchAll(int $fetch_style = PDO::FETCH_BOTH, mixed ...$fetch_args)
|
||||
{
|
||||
$result = $this->PDOStatement->fetchAll();
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue