1
0
Fork 0
mirror of synced 2024-05-20 12:42:39 +12:00

format files in app, src, tests

This commit is contained in:
Everly Precia Suresh 2022-05-23 14:54:50 +00:00
parent 902e74a943
commit 19300ccdd7
237 changed files with 2502 additions and 2364 deletions

View file

@ -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();

View file

@ -1,4 +1,4 @@
<?php
<?php
// Auth methods
@ -45,4 +45,4 @@ return [
'docs' => '',
'enabled' => false,
],
];
];

View file

@ -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',

View file

@ -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',
];

View file

@ -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',
];

View file

@ -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',

View file

@ -232,7 +232,7 @@ $collections = [
'size' => 16384,
'signed' => true,
'required' => false,
'default' => new stdClass,
'default' => new stdClass(),
'array' => false,
'filters' => ['json', 'range', 'enum'],
],
@ -2055,7 +2055,7 @@ $collections = [
],
[
'$id' => 'status',
'type' => Database::VAR_STRING,
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
@ -2099,7 +2099,7 @@ $collections = [
],
[
'$id' => 'sourceType',
'type' => Database::VAR_STRING,
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
@ -2110,7 +2110,7 @@ $collections = [
],
[
'$id' => 'source',
'type' => Database::VAR_STRING,
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,

View file

@ -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,
]
];
];

View file

@ -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

View file

@ -6,10 +6,11 @@ use Appwrite\Runtimes\Runtimes;
/**
* List of Appwrite Cloud Functions supported 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;

View file

@ -70,4 +70,5 @@ return [ // List of publicly visible scopes
'health.read' => [
'description' => 'Access to read your project\'s health status',
],
];;
];
;

View file

@ -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,

View file

@ -5,4 +5,4 @@ return [ // Accepted inputs files
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
];
];

View file

@ -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',
];
];

View file

@ -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',
];
];

View file

@ -6,4 +6,4 @@ return [ // Accepted outputs files
'gif' => 'image/gif',
'png' => 'image/png',
'webp' => 'image/webp',
];
];

View file

@ -1,6 +1,7 @@
<?php
use Utopia\Config\Config;
return [
[
'category' => 'General',

View file

@ -117,7 +117,7 @@ App::post('/v1/account')
Authorization::setRole('role:' . Auth::USER_ROLE_MEMBER);
$audits
->setResource('user/'.$user->getId())
->setResource('user/' . $user->getId())
->setUser($user)
;
@ -167,8 +167,7 @@ App::post('/v1/account/sessions')
$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 +192,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 +223,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,9 +258,15 @@ 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'), 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('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')
@ -270,9 +277,9 @@ App::get('/v1/account/sessions/oauth2/:provider')
/** @var Utopia\Database\Document $project */
$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 +290,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;
}
@ -394,8 +401,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$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 +438,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 +464,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 +485,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 +567,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 +630,9 @@ 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', '', 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'])
->inject('request')
->inject('response')
->inject('project')
@ -644,7 +651,7 @@ App::post('/v1/account/sessions/magic-url')
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\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 +707,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 +742,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)
;
@ -816,8 +822,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 +843,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 +857,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)
@ -970,12 +975,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 +1001,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)
@ -1131,7 +1135,7 @@ App::get('/v1/account/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);
@ -1197,13 +1201,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);
@ -1245,7 +1248,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)))
@ -1290,11 +1293,10 @@ App::patch('/v1/account/name')
$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)
;
@ -1346,7 +1348,7 @@ App::patch('/v1/account/password')
);
$audits
->setResource('user/'.$user->getId())
->setResource('user/' . $user->getId())
->setUser($user)
;
@ -1405,14 +1407,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)
;
@ -1451,7 +1452,7 @@ App::patch('/v1/account/prefs')
$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());
@ -1556,7 +1557,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 +1571,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
@ -1633,7 +1634,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 +1646,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);
@ -1733,7 +1733,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 +1780,9 @@ 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', '', 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'])
->inject('request')
->inject('response')
->inject('dbForProject')
@ -1801,7 +1803,7 @@ App::post('/v1/account/recovery')
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\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 +1841,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());
@ -1930,8 +1931,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 +1968,9 @@ 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', '', 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
->inject('request')
->inject('response')
->inject('project')
@ -1991,7 +1993,7 @@ App::post('/v1/account/verification')
/** @var Appwrite\Event\Mail $mails */
/** @var Appwrite\Stats\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 +2018,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());

View file

@ -193,7 +193,8 @@ App::get('/v1/avatars/image')
->setContentType('image/png')
->addHeader('Expires', $date)
->addHeader('X-Appwrite-Cache', 'miss')
->send($data);;
->send($data);
;
unset($image);
});

View file

@ -58,11 +58,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 +88,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 +105,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,7 +129,7 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
;
$audits
->setResource('collection/'.$collectionId)
->setResource('collection/' . $collectionId)
->setPayload($attribute->getArrayCopy())
;
@ -193,7 +191,7 @@ App::post('/v1/database/collections')
}
$audits
->setResource('collection/'.$collectionId)
->setResource('collection/' . $collectionId)
->setPayload($collection->getArrayCopy())
;
@ -335,7 +333,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 +355,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,
};
@ -417,7 +415,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 +445,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 +467,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,
};
@ -529,7 +527,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 +567,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');
@ -631,18 +629,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())
;
@ -701,7 +696,7 @@ App::delete('/v1/database/collections/:collectionId')
;
$audits
->setResource('collection/'.$collectionId)
->setResource('collection/' . $collectionId)
->setPayload($collection->getArrayCopy())
;
@ -841,7 +836,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;
}
@ -1211,7 +1205,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 +1215,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,
@ -1273,7 +1267,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 +1293,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 +1315,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
;
$audits
->setResource('collection/'.$collectionId)
->setResource('collection/' . $collectionId)
->setPayload($attribute->getArrayCopy())
;
@ -1395,7 +1389,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 +1398,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 +1428,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
;
$audits
->setResource('collection/'.$collection->getId())
->setResource('collection/' . $collection->getId())
->setPayload($index->getArrayCopy())
;
@ -1554,7 +1548,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 +1577,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
;
$audits
->setResource('collection/'.$collection->getId())
->setResource('collection/' . $collection->getId())
->setPayload($index->getArrayCopy())
;
@ -1635,7 +1629,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 +1650,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 +1659,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 +1678,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 +1696,7 @@ App::post('/v1/database/collections/:collectionId/documents')
;
$audits
->setResource('document/'.$document->getId())
->setResource('document/' . $document->getId())
->setPayload($document->getArrayCopy())
;
@ -1724,7 +1716,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)
@ -1772,13 +1764,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)) {
@ -1926,7 +1918,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 +1958,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');
@ -2059,14 +2051,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 +2078,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 +2098,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
;
$audits
->setResource('document/'.$document->getId())
->setResource('document/' . $document->getId())
->setPayload($document->getArrayCopy())
;
@ -2206,7 +2195,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
;
$audits
->setResource('document/'.$document->getId())
->setResource('document/' . $document->getId())
->setPayload($document->getArrayCopy())
;

View file

@ -916,7 +916,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();

View file

@ -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()),
],

View file

@ -77,7 +77,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([
@ -106,7 +106,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');
@ -118,7 +118,7 @@ App::post('/v1/projects')
$adapter->setup();
foreach ($collections as $key => $collection) {
if(($collection['$collection'] ?? '') !== Database::METADATA) {
if (($collection['$collection'] ?? '') !== Database::METADATA) {
continue;
}
$attributes = [];
@ -281,7 +281,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'];
@ -303,7 +303,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,
};
@ -374,8 +374,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);
});
@ -391,7 +390,9 @@ 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'), function ($element) {
return $element['optional'];
})), true), 'Service name.')
->param('status', null, new Boolean(), 'Service status.')
->inject('response')
->inject('dbForConsole')
@ -470,8 +471,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);
});
@ -751,7 +751,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);
}
@ -941,7 +941,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);
}

View file

@ -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,
};

View file

@ -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,9 @@ 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', '', 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('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
->inject('response')
->inject('project')
@ -296,7 +297,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 +315,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 +329,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 +355,8 @@ 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 +368,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 +415,7 @@ App::post('/v1/teams/:teamId/memberships')
}
$audits
->setResource('team/'.$teamId)
->setResource('team/' . $teamId)
;
$events
@ -423,11 +424,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 +493,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 +536,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 +548,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 +591,8 @@ 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 +671,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 +679,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 +697,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 +716,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 +729,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 +743,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 +812,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 +855,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 +895,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');

View file

@ -55,7 +55,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,
@ -153,7 +153,7 @@ App::get('/v1/users/:userId')
->action(function ($userId, $response, $dbForProject, $usage) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
/** @var Appwrite\Stats\Stats $usage */
$user = $dbForProject->getDocument('users', $userId);
@ -231,10 +231,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);
@ -275,7 +275,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
@ -362,8 +362,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');
@ -504,7 +504,7 @@ App::patch('/v1/users/:userId/name')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$audits
->setResource('user/'.$user->getId())
->setResource('user/' . $user->getId())
;
$events
@ -551,7 +551,7 @@ App::patch('/v1/users/:userId/password')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$audits
->setResource('user/'.$user->getId())
->setResource('user/' . $user->getId())
;
$events
@ -605,13 +605,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
@ -695,7 +695,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);
}
@ -777,7 +777,9 @@ 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', '', function () {
return new UID();
}, 'User ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
@ -829,7 +831,7 @@ 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')
@ -871,7 +873,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 +882,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 +894,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 +906,7 @@ App::get('/v1/users/usage')
$backfill--;
}
$stats[$metric] = array_reverse($stats[$metric]);
}
}
});
$usage = new Document([
@ -919,8 +920,7 @@ App::get('/v1/users/usage')
'sessionsProviderCreate' => $stats["users.sessions.$provider.create"],
'sessionsDelete' => $stats["users.sessions.delete"]
]);
}
$response->dynamic($usage, Response::MODEL_USAGE_USERS);
});
});

View file

@ -1,6 +1,6 @@
<?php
require_once __DIR__.'/../init.php';
require_once __DIR__ . '/../init.php';
use Utopia\App;
use Utopia\Logger\Log;
@ -50,14 +50,14 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$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:
@ -75,21 +75,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', [
@ -149,37 +149,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:
@ -197,14 +198,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) {
if ($request->getMethod() !== Request::METHOD_GET) {
throw new Exception('Method unsupported over HTTP.', 500, Exception::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
@ -225,10 +226,12 @@ 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', ''))) {
&& empty($request->getHeader('x-appwrite-key', ''))
) {
throw new Exception($originValidator->getDescription(), 403, Exception::GENERAL_UNKNOWN_ORIGIN);
}
@ -274,7 +277,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$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'),
]);
@ -282,22 +285,24 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$role = Auth::USER_ROLE_APP;
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
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())) {
$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);
}
}
@ -307,7 +312,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
throw new Exception('Project not found', 404, Exception::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 Exception($user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')', 401, Exception::GENERAL_UNAUTHORIZED_SCOPE);
}
if (false === $user->getAttribute('status')) { // Account is blocked
@ -317,7 +322,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
if ($user->getAttribute('reset')) {
throw new Exception('Password reset is required', 412, Exception::USER_PASSWORD_RESET_REQUIRED);
}
}, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']);
App::options(function ($request, $response) {
@ -354,18 +358,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()));
}
@ -376,7 +380,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());
@ -395,12 +399,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);
}
}
@ -411,23 +415,23 @@ 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) {
switch ($code) {
case 400:
$error->setType(Exception::GENERAL_ARGUMENT_INVALID);
break;
@ -501,7 +505,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)
@ -511,8 +515,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')
@ -548,7 +554,7 @@ App::get('/robots.txt')
->label('docs', false)
->inject('response')
->action(function ($response) {
$template = new View(__DIR__.'/../views/general/robots.phtml');
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
});
@ -558,7 +564,7 @@ App::get('/humans.txt')
->label('docs', false)
->inject('response')
->action(function ($response) {
$template = new View(__DIR__.'/../views/general/humans.phtml');
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
});
@ -585,7 +591,7 @@ App::get('/.well-known/acme-challenge')
}
$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);

View file

@ -208,11 +208,11 @@ App::get('/v1/mock/tests/general/download')
->inject('response')
->action(function ($response) {
/** @var Appwrite\Utopia\Request $request */
$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.")
;
@ -240,51 +240,51 @@ App::post('/v1/mock/tests/general/upload')
->action(function ($x, $y, $z, $file, $request, $response) {
/** @var Appwrite\Utopia\Request $request */
/** @var Utopia\Swoole\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 +293,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);
}
@ -470,7 +470,7 @@ App::get('/v1/mock/tests/general/oauth2')
->action(function ($client_id, $redirectURI, $scope, $state, $response) {
/** @var Appwrite\Utopia\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')
@ -503,13 +503,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);
}
@ -571,16 +571,16 @@ App::get('/v1/mock/tests/general/oauth2/failure')
]);
});
App::shutdown(function($utopia, $response, $request) {
App::shutdown(function ($utopia, $response, $request) {
/** @var Utopia\App $utopia */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
$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 +594,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');

View file

@ -46,7 +46,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 +58,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 +74,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 +109,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)
@ -130,38 +131,38 @@ App::init(function ($utopia, $request, $project) {
$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,7 +171,6 @@ 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) {
@ -233,7 +233,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 +256,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');

View file

@ -48,10 +48,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())

View file

@ -21,8 +21,8 @@ App::shutdown(function ($response, $layout) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Utopia\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', ''))
@ -46,14 +46,14 @@ App::get('/error/:code')
->action(function ($code, $layout) {
/** @var Appwrite\Utopia\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);
});
@ -65,14 +65,14 @@ App::get('/console')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -84,16 +84,16 @@ App::get('/console/account')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -105,10 +105,10 @@ App::get('/console/notifications')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -120,11 +120,11 @@ App::get('/console/home')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -138,17 +138,19 @@ App::get('/console/settings')
$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'];}))
->setParam('services', array_filter(Config::getParam('services'), function ($element) {
return $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);
});
@ -160,12 +162,12 @@ App::get('/console/webhooks')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -178,7 +180,7 @@ App::get('/console/webhooks/webhook')
->action(function ($id, $layout) {
/** @var Appwrite\Utopia\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 +188,7 @@ App::get('/console/webhooks/webhook')
;
$layout
->setParam('title', APP_NAME.' - Webhooks')
->setParam('title', APP_NAME . ' - Webhooks')
->setParam('body', $page);
});
@ -198,7 +200,7 @@ App::get('/console/webhooks/webhook/new')
->action(function ($layout) {
/** @var Appwrite\Utopia\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 +208,7 @@ App::get('/console/webhooks/webhook/new')
;
$layout
->setParam('title', APP_NAME.' - Webhooks')
->setParam('title', APP_NAME . ' - Webhooks')
->setParam('body', $page);
});
@ -219,12 +221,12 @@ App::get('/console/keys')
/** @var Appwrite\Utopia\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);
});
@ -236,10 +238,10 @@ App::get('/console/database')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -254,7 +256,7 @@ App::get('/console/database/collection')
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Utopia\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 +266,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)
;
@ -289,7 +291,7 @@ App::get('/console/database/document')
->action(function ($collection, $layout) {
/** @var Appwrite\Utopia\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 +302,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 +311,7 @@ App::get('/console/database/document')
;
$layout
->setParam('title', APP_NAME.' - Database Document')
->setParam('title', APP_NAME . ' - Database Document')
->setParam('body', $page);
});
@ -322,7 +324,7 @@ App::get('/console/database/document/new')
->action(function ($collection, $layout) {
/** @var Appwrite\Utopia\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 +333,7 @@ App::get('/console/database/document/new')
;
$layout
->setParam('title', APP_NAME.' - Database Document')
->setParam('title', APP_NAME . ' - Database Document')
->setParam('body', $page);
});
@ -342,8 +344,8 @@ App::get('/console/storage')
->inject('layout')
->action(function ($layout) {
/** @var Appwrite\Utopia\View $layout */
$page = new View(__DIR__.'/../../views/console/storage/index.phtml');
$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 +353,7 @@ App::get('/console/storage')
;
$layout
->setParam('title', APP_NAME.' - Storage')
->setParam('title', APP_NAME . ' - Storage')
->setParam('body', $page);
});
@ -366,15 +368,15 @@ App::get('/console/storage/bucket')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\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)
;
@ -393,7 +395,7 @@ App::get('/console/users')
->action(function ($layout) {
/** @var Appwrite\Utopia\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 +404,7 @@ App::get('/console/users')
;
$layout
->setParam('title', APP_NAME.' - Users')
->setParam('title', APP_NAME . ' - Users')
->setParam('body', $page);
});
@ -414,10 +416,10 @@ App::get('/console/users/user')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -429,10 +431,10 @@ App::get('/console/users/teams/team')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -443,14 +445,14 @@ App::get('/console/functions')
->label('scope', 'console')
->inject('layout')
->action(function ($layout) {
$page = new View(__DIR__.'/../../views/console/functions/index.phtml');
$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);
});
@ -461,18 +463,18 @@ App::get('/console/functions/function')
->label('scope', 'console')
->inject('layout')
->action(function ($layout) {
$page = new View(__DIR__.'/../../views/console/functions/function.phtml');
$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 +486,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 +496,4 @@ App::get('/console/version')
} catch (\Throwable $th) {
throw new Exception('Failed to check for a newer version', 500, Exception::GENERAL_SERVER_ERROR);
}
});
});

View file

@ -7,8 +7,8 @@ use Utopia\Config\Config;
App::init(function ($layout) {
/** @var Appwrite\Utopia\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'))
@ -52,10 +52,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');
}
}
@ -72,14 +72,14 @@ App::get('/auth/signin')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -90,14 +90,14 @@ App::get('/auth/signup')
->inject('layout')
->action(function ($layout) {
/** @var Appwrite\Utopia\View $layout */
$page = new View(__DIR__.'/../../views/home/auth/signup.phtml');
$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);
});
@ -109,14 +109,14 @@ App::get('/auth/recovery')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -128,10 +128,10 @@ App::get('/auth/confirm')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -143,10 +143,10 @@ App::get('/auth/join')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -158,10 +158,10 @@ App::get('/auth/recovery/reset')
->action(function ($layout) {
/** @var Appwrite\Utopia\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);
});
@ -173,7 +173,7 @@ App::get('/auth/oauth2/success')
->action(function ($layout) {
/** @var Appwrite\Utopia\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)
@ -191,7 +191,7 @@ App::get('/auth/magic-url')
->action(function ($layout) {
/** @var Appwrite\Utopia\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)
@ -209,7 +209,7 @@ App::get('/auth/oauth2/failure')
->action(function ($layout) {
/** @var Appwrite\Utopia\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)
@ -228,14 +228,14 @@ App::get('/error/:code')
->action(function ($code, $layout) {
/** @var Appwrite\Utopia\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);
});
@ -253,15 +253,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;
}

View file

@ -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());
@ -115,9 +116,11 @@ function logError(Throwable $error, string $action, Utopia\Route $route = null)
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(),

View file

@ -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();

View file

@ -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']);

View file

@ -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);
}
}

View file

@ -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 = [];

View file

@ -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");
}
});

View file

@ -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);
}
});

View file

@ -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');
}

View file

@ -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 = [];

View file

@ -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);
});
});

View file

@ -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'], ''));
}
});
});

View file

@ -200,7 +200,7 @@ class BuildsV1 extends Worker
} finally {
$build = $dbForProject->updateDocument('builds', $buildId, $build);
/**
/**
* Send realtime Event
*/
$target = Realtime::fromPayload(

View file

@ -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

View file

@ -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());

View file

@ -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());
}
}

View file

@ -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

View file

@ -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];
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -34,7 +34,7 @@ class Password extends Validator
{
if (!\is_string($value)) {
return false;
}
}
if (\strlen($value) < 8) {
return false;

View file

@ -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);
}

View file

@ -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);
}
/**

View file

@ -70,7 +70,7 @@ class Env
$output = '';
foreach ($this->vars as $key => $value) {
$output .= $key.'='.$value."\n";
$output .= $key . '=' . $value . "\n";
}
return $output;

View file

@ -127,4 +127,4 @@ class Audit extends Event
'events' => Event::generateEvents($this->getEvent(), $this->getParams())
]);
}
}
}

View file

@ -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
{

View file

@ -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())
]);
}
}
}

View file

@ -34,7 +34,7 @@ class Delete extends Event
/**
* Returns the set type for the delete event.
*
* @return string
* @return string
*/
public function getType(): string
{

View file

@ -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));

View file

@ -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
{

View file

@ -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';
@ -174,9 +174,9 @@ class Exception extends \Exception
/**
* Get the type of the exception.
*
*
* @return string
*/
*/
public function getType(): string
{
return $this->type;
@ -184,14 +184,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;
}
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -4,7 +4,7 @@ namespace Appwrite\Messaging;
abstract class Adapter
{
public abstract function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void;
public abstract function unsubscribe(mixed $identifier): void;
public static abstract function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void;
abstract public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void;
abstract public function unsubscribe(mixed $identifier): void;
abstract public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void;
}

View file

@ -10,7 +10,7 @@ class Realtime extends Adapter
{
/**
* Connection Tree
*
*
* [CONNECTION_ID] ->
* 'projectId' -> [PROJECT_ID]
* 'roles' -> [ROLE_x, ROLE_Y]
@ -67,7 +67,7 @@ class Realtime extends Adapter
/**
* Removes Subscription.
*
*
* @param mixed $connection
* @return void
*/
@ -129,7 +129,9 @@ class Realtime extends Adapter
*/
public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void
{
if (empty($channels) || empty($roles) || empty($projectId)) return;
if (empty($channels) || empty($roles) || empty($projectId)) {
return;
}
$permissionsChanged = array_key_exists('permissionsChanged', $options) && $options['permissionsChanged'];
$userId = array_key_exists('userId', $options) ? $options['userId'] : null;
@ -154,12 +156,12 @@ class Realtime extends Adapter
* Identifies the receivers of all subscriptions, based on the permissions and event.
*
* Example of performance with an event with user:XXX permissions and with X users spread across 10 different channels:
* - 0.014 ms (±6.88%) | 10 Connections / 100 Subscriptions
* - 0.070 ms (±3.71%) | 100 Connections / 1,000 Subscriptions
* - 0.014 ms (±6.88%) | 10 Connections / 100 Subscriptions
* - 0.070 ms (±3.71%) | 100 Connections / 1,000 Subscriptions
* - 0.846 ms (±2.74%) | 1,000 Connections / 10,000 Subscriptions
* - 10.866 ms (±1.01%) | 10,000 Connections / 100,000 Subscriptions
* - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions
* - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions
* - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions
*
* @param array $event
*/
@ -209,7 +211,7 @@ class Realtime extends Adapter
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
* @param array $channels
* @param string $userId
* @return array
* @return array
*/
public static function convertChannels(array $channels, string $userId): array
{
@ -238,7 +240,7 @@ class Realtime extends Adapter
* @param string $event
* @param Document $payload
* @param Document|null $project
* @return array
* @return array
*/
public static function fromPayload(string $event, Document $payload, Document $project = null, Document $collection = null, Document $bucket = null): array
{

View file

@ -102,7 +102,9 @@ abstract class Migration
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
foreach ($this->collections as $collection) {
if ($collection['$collection'] !== Database::METADATA) return;
if ($collection['$collection'] !== Database::METADATA) {
return;
}
$sum = 0;
$nextDocument = null;
$collectionCount = $this->projectDB->count($collection['$id']);

View file

@ -300,11 +300,11 @@ class V12 extends Migration
/**
* Migrates permissions to dedicated table.
*
* @param \Utopia\Database\Document $document
* @param string $internalId
* @return void
* @throws \Exception
* @throws \PDOException
* @param \Utopia\Database\Document $document
* @param string $internalId
* @return void
* @throws \Exception
* @throws \PDOException
*/
protected function migratePermissionsToDedicatedTable(string $collection, Document $document): void
{
@ -499,8 +499,8 @@ class V12 extends Migration
/**
* Fix run on each document
*
* @param \Utopia\Database\Document $document
* @return \Utopia\Database\Document
* @param \Utopia\Database\Document $document
* @return \Utopia\Database\Document
*/
protected function fixDocument(Document $document)
{

View file

@ -223,8 +223,8 @@ class V13 extends Migration
/**
* Fix run on each document
*
* @param \Utopia\Database\Document $document
* @return \Utopia\Database\Document
* @param \Utopia\Database\Document $document
* @return \Utopia\Database\Document
*/
protected function fixDocument(Document $document)
{
@ -273,7 +273,9 @@ class V13 extends Migration
public function migrateEvents(array $events): array
{
return array_filter(array_unique(array_map(function ($event) {
if (!in_array($event, $this->events)) return $event;
if (!in_array($event, $this->events)) {
return $event;
}
$parts = \explode('.', $event);
$first = array_shift($parts);
switch ($first) {

View file

@ -66,7 +66,7 @@ class IP extends Validator
if (\filter_var($value, FILTER_VALIDATE_IP)) {
return true;
}
break;
break;
case self::V4:
if (\filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {

View file

@ -95,8 +95,8 @@ class Origin extends Validator
return 'Unsupported platform';
}
return 'Invalid Origin. Register your new client ('.$this->host.') as a new '
.$this->platforms[$this->client].' platform on your project console dashboard';
return 'Invalid Origin. Register your new client (' . $this->host . ') as a new '
. $this->platforms[$this->client] . ' platform on your project console dashboard';
}
/**
@ -124,7 +124,7 @@ class Origin extends Validator
}
$validator = new Hostname($this->clients);
return $validator->isValid($host);
}

View file

@ -16,7 +16,6 @@ use Utopia\Storage\Device\Linode;
use Utopia\Storage\Device\Wasabi;
use Utopia\Storage\Device\Backblaze;
use Utopia\Storage\Device\S3;
use Exception;
abstract class Worker
@ -26,7 +25,7 @@ abstract class Worker
*
* @var array
*/
static protected array $errorCallbacks = [];
protected static array $errorCallbacks = [];
/**
* Associative array holding all information passed into the worker
@ -53,7 +52,8 @@ abstract class Worker
* @return void
* @throws \Exception|\Throwable
*/
public function init() {
public function init()
{
throw new Exception("Please implement init method in worker");
}
@ -64,7 +64,8 @@ abstract class Worker
* @return void
* @throws \Exception|\Throwable
*/
public function run() {
public function run()
{
throw new Exception("Please implement run method in worker");
}
@ -75,7 +76,8 @@ abstract class Worker
* @return void
* @throws \Exception|\Throwable
*/
public function shutdown() {
public function shutdown()
{
throw new Exception("Please implement shutdown method in worker");
}
@ -92,7 +94,7 @@ abstract class Worker
{
try {
$this->init();
} catch(\Throwable $error) {
} catch (\Throwable $error) {
foreach (self::$errorCallbacks as $errorCallback) {
$errorCallback($error, "init", $this->getName());
}
@ -111,7 +113,7 @@ abstract class Worker
{
try {
$this->run();
} catch(\Throwable $error) {
} catch (\Throwable $error) {
foreach (self::$errorCallbacks as $errorCallback) {
$errorCallback($error, "run", $this->getName(), $this->args);
}
@ -130,7 +132,7 @@ abstract class Worker
{
try {
$this->shutdown();
} catch(\Throwable $error) {
} catch (\Throwable $error) {
foreach (self::$errorCallbacks as $errorCallback) {
$errorCallback($error, "shutdown", $this->getName());
}
@ -217,10 +219,10 @@ abstract class Worker
}
break; // leave loop if successful
} catch(\Exception $e) {
} catch (\Exception $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
throw new \Exception('Failed to connect to database: '. $e->getMessage());
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
}
sleep($sleep);
}
@ -234,7 +236,8 @@ abstract class Worker
* @param string $projectId of the project
* @return Device
*/
protected function getFunctionsDevice($projectId): Device {
protected function getFunctionsDevice($projectId): Device
{
return $this->getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
}
@ -243,7 +246,8 @@ abstract class Worker
* @param string $projectId of the project
* @return Device
*/
protected function getFilesDevice($projectId): Device {
protected function getFilesDevice($projectId): Device
{
return $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId);
}
@ -253,7 +257,8 @@ abstract class Worker
* @param string $projectId of the project
* @return Device
*/
protected function getBuildsDevice($projectId): Device {
protected function getBuildsDevice($projectId): Device
{
return $this->getDevice(APP_STORAGE_BUILDS . '/app-' . $projectId);
}
@ -265,43 +270,44 @@ abstract class Worker
public function getDevice($root): Device
{
switch (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)) {
case Storage::DEVICE_LOCAL:default:
return new Local($root);
case Storage::DEVICE_S3:
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
$s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', '');
$s3Region = App::getEnv('_APP_STORAGE_S3_REGION', '');
$s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', '');
$s3Acl = 'private';
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
case Storage::DEVICE_DO_SPACES:
$doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
$doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', '');
$doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', '');
$doSpacesAcl = 'private';
return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl);
case Storage::DEVICE_BACKBLAZE:
$backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', '');
$backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', '');
$backblazeRegion = App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', '');
$backblazeBucket = App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', '');
$backblazeAcl = 'private';
return new Backblaze($root, $backblazeAccessKey, $backblazeSecretKey, $backblazeBucket, $backblazeRegion, $backblazeAcl);
case Storage::DEVICE_LINODE:
$linodeAccessKey = App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', '');
$linodeSecretKey = App::getEnv('_APP_STORAGE_LINODE_SECRET', '');
$linodeRegion = App::getEnv('_APP_STORAGE_LINODE_REGION', '');
$linodeBucket = App::getEnv('_APP_STORAGE_LINODE_BUCKET', '');
$linodeAcl = 'private';
return new Linode($root, $linodeAccessKey, $linodeSecretKey, $linodeBucket, $linodeRegion, $linodeAcl);
case Storage::DEVICE_WASABI:
$wasabiAccessKey = App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', '');
$wasabiSecretKey = App::getEnv('_APP_STORAGE_WASABI_SECRET', '');
$wasabiRegion = App::getEnv('_APP_STORAGE_WASABI_REGION', '');
$wasabiBucket = App::getEnv('_APP_STORAGE_WASABI_BUCKET', '');
$wasabiAcl = 'private';
return new Wasabi($root, $wasabiAccessKey, $wasabiSecretKey, $wasabiBucket, $wasabiRegion, $wasabiAcl);
case Storage::DEVICE_LOCAL:
default:
return new Local($root);
case Storage::DEVICE_S3:
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
$s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', '');
$s3Region = App::getEnv('_APP_STORAGE_S3_REGION', '');
$s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', '');
$s3Acl = 'private';
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
case Storage::DEVICE_DO_SPACES:
$doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
$doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', '');
$doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', '');
$doSpacesAcl = 'private';
return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl);
case Storage::DEVICE_BACKBLAZE:
$backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', '');
$backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', '');
$backblazeRegion = App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', '');
$backblazeBucket = App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', '');
$backblazeAcl = 'private';
return new Backblaze($root, $backblazeAccessKey, $backblazeSecretKey, $backblazeBucket, $backblazeRegion, $backblazeAcl);
case Storage::DEVICE_LINODE:
$linodeAccessKey = App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', '');
$linodeSecretKey = App::getEnv('_APP_STORAGE_LINODE_SECRET', '');
$linodeRegion = App::getEnv('_APP_STORAGE_LINODE_REGION', '');
$linodeBucket = App::getEnv('_APP_STORAGE_LINODE_BUCKET', '');
$linodeAcl = 'private';
return new Linode($root, $linodeAccessKey, $linodeSecretKey, $linodeBucket, $linodeRegion, $linodeAcl);
case Storage::DEVICE_WASABI:
$wasabiAccessKey = App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', '');
$wasabiSecretKey = App::getEnv('_APP_STORAGE_WASABI_SECRET', '');
$wasabiRegion = App::getEnv('_APP_STORAGE_WASABI_REGION', '');
$wasabiBucket = App::getEnv('_APP_STORAGE_WASABI_BUCKET', '');
$wasabiAcl = 'private';
return new Wasabi($root, $wasabiAccessKey, $wasabiSecretKey, $wasabiBucket, $wasabiRegion, $wasabiAcl);
}
}
}

Some files were not shown because too many files have changed in this diff Show more